Merge "Add clearFrameRate API in ndk"
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 0f7c489..ac101ec 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -25,6 +25,7 @@
"CrateManager.cpp",
"InstalldNativeService.cpp",
"QuotaUtils.cpp",
+ "SysTrace.cpp",
"dexopt.cpp",
"execv_helper.cpp",
"globals.cpp",
@@ -173,7 +174,7 @@
// Needs to be wherever installd is as it's execed by
// installd.
- required: ["migrate_legacy_obb_data.sh"],
+ required: ["migrate_legacy_obb_data"],
}
// OTA chroot tool
@@ -299,6 +300,6 @@
// Script to migrate legacy obb data.
sh_binary {
- name: "migrate_legacy_obb_data.sh",
+ name: "migrate_legacy_obb_data",
src: "migrate_legacy_obb_data.sh",
}
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 6ee3070..2c8adc7 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -16,8 +16,6 @@
#include "InstalldNativeService.h"
-#define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER
-
#include <errno.h>
#include <fts.h>
#include <inttypes.h>
@@ -75,6 +73,7 @@
#include "CrateManager.h"
#include "MatchExtensionGen.h"
#include "QuotaUtils.h"
+#include "SysTrace.h"
#ifndef LOG_TAG
#define LOG_TAG "installd"
@@ -1327,7 +1326,7 @@
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
for (auto userId : get_known_users(uuid_)) {
LOCK_USER();
- ATRACE_BEGIN("fixup user");
+ atrace_pm_begin("fixup user");
FTS* fts;
FTSENT* p;
auto ce_path = create_data_user_ce_path(uuid_, userId);
@@ -1417,7 +1416,7 @@
}
}
fts_close(fts);
- ATRACE_END();
+ atrace_pm_end();
}
return ok();
}
@@ -1955,7 +1954,6 @@
return error("Failed to determine free space for " + data_path);
}
- int64_t cleared = 0;
int64_t needed = targetFreeBytes - free;
if (!defy_target) {
LOG(DEBUG) << "Device " << data_path << " has " << free << " free; requested "
@@ -1971,7 +1969,7 @@
// files from the UIDs which are most over their allocated quota
// 1. Create trackers for every known UID
- ATRACE_BEGIN("create");
+ atrace_pm_begin("create");
const auto users = get_known_users(uuid_);
#ifdef GRANULAR_LOCKS
std::vector<UserLock> userLocks;
@@ -2052,11 +2050,10 @@
}
fts_close(fts);
}
- ATRACE_END();
+ atrace_pm_end();
// 2. Populate tracker stats and insert into priority queue
- ATRACE_BEGIN("populate");
- int64_t cacheTotal = 0;
+ atrace_pm_begin("populate");
auto cmp = [](std::shared_ptr<CacheTracker> left, std::shared_ptr<CacheTracker> right) {
return (left->getCacheRatio() < right->getCacheRatio());
};
@@ -2065,13 +2062,12 @@
for (const auto& it : trackers) {
it.second->loadStats();
queue.push(it.second);
- cacheTotal += it.second->cacheUsed;
}
- ATRACE_END();
+ atrace_pm_end();
// 3. Bounce across the queue, freeing items from whichever tracker is
// the most over their assigned quota
- ATRACE_BEGIN("bounce");
+ atrace_pm_begin("bounce");
std::shared_ptr<CacheTracker> active;
while (active || !queue.empty()) {
// Only look at apps under quota when explicitly requested
@@ -2111,7 +2107,6 @@
}
active->cacheUsed -= item->size;
needed -= item->size;
- cleared += item->size;
}
if (!defy_target) {
@@ -2128,7 +2123,7 @@
}
}
}
- ATRACE_END();
+ atrace_pm_end();
} else {
return error("Legacy cache logic no longer supported");
@@ -2473,84 +2468,84 @@
flags &= ~FLAG_USE_QUOTA;
}
- ATRACE_BEGIN("obb");
+ atrace_pm_begin("obb");
for (const auto& packageName : packageNames) {
auto obbCodePath = create_data_media_package_path(uuid_, userId,
"obb", packageName.c_str());
calculate_tree_size(obbCodePath, &extStats.codeSize);
}
- ATRACE_END();
+ atrace_pm_end();
// Calculating the app size of the external storage owning app in a manual way, since
// calculating it through quota apis also includes external media storage in the app storage
// numbers
if (flags & FLAG_USE_QUOTA && appId >= AID_APP_START && !ownsExternalStorage(appId)) {
- ATRACE_BEGIN("code");
+ atrace_pm_begin("code");
for (const auto& codePath : codePaths) {
calculate_tree_size(codePath, &stats.codeSize, -1,
multiuser_get_shared_gid(0, appId));
}
- ATRACE_END();
+ atrace_pm_end();
- ATRACE_BEGIN("quota");
+ atrace_pm_begin("quota");
collectQuotaStats(uuidString, userId, appId, &stats, &extStats);
- ATRACE_END();
+ atrace_pm_end();
} else {
- ATRACE_BEGIN("code");
+ atrace_pm_begin("code");
for (const auto& codePath : codePaths) {
calculate_tree_size(codePath, &stats.codeSize);
}
- ATRACE_END();
+ atrace_pm_end();
for (size_t i = 0; i < packageNames.size(); i++) {
const char* pkgname = packageNames[i].c_str();
- ATRACE_BEGIN("data");
+ atrace_pm_begin("data");
auto cePath = create_data_user_ce_package_path(uuid_, userId, pkgname, ceDataInodes[i]);
collectManualStats(cePath, &stats);
auto dePath = create_data_user_de_package_path(uuid_, userId, pkgname);
collectManualStats(dePath, &stats);
- ATRACE_END();
+ atrace_pm_end();
// In case of sdk sandbox storage (e.g. /data/misc_ce/0/sdksandbox/<package-name>),
// collect individual stats of each subdirectory (shared, storage of each sdk etc.)
if (appId >= AID_APP_START && appId <= AID_APP_END) {
- ATRACE_BEGIN("sdksandbox");
+ atrace_pm_begin("sdksandbox");
auto sdkSandboxCePath =
create_data_misc_sdk_sandbox_package_path(uuid_, true, userId, pkgname);
collectManualStatsForSubDirectories(sdkSandboxCePath, &stats);
auto sdkSandboxDePath =
create_data_misc_sdk_sandbox_package_path(uuid_, false, userId, pkgname);
collectManualStatsForSubDirectories(sdkSandboxDePath, &stats);
- ATRACE_END();
+ atrace_pm_end();
}
if (!uuid) {
- ATRACE_BEGIN("profiles");
+ atrace_pm_begin("profiles");
calculate_tree_size(
create_primary_current_profile_package_dir_path(userId, pkgname),
&stats.dataSize);
calculate_tree_size(
create_primary_reference_profile_package_dir_path(pkgname),
&stats.codeSize);
- ATRACE_END();
+ atrace_pm_end();
}
- ATRACE_BEGIN("external");
+ atrace_pm_begin("external");
auto extPath = create_data_media_package_path(uuid_, userId, "data", pkgname);
collectManualStats(extPath, &extStats);
auto mediaPath = create_data_media_package_path(uuid_, userId, "media", pkgname);
calculate_tree_size(mediaPath, &extStats.dataSize);
- ATRACE_END();
+ atrace_pm_end();
}
if (!uuid) {
- ATRACE_BEGIN("dalvik");
+ atrace_pm_begin("dalvik");
int32_t sharedGid = multiuser_get_shared_gid(0, appId);
if (sharedGid != -1) {
calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize,
sharedGid, -1);
}
- ATRACE_END();
+ atrace_pm_end();
}
}
@@ -2696,41 +2691,41 @@
}
if (flags & FLAG_USE_QUOTA) {
- ATRACE_BEGIN("code");
+ atrace_pm_begin("code");
calculate_tree_size(create_data_app_path(uuid_), &stats.codeSize, -1, -1, true);
- ATRACE_END();
+ atrace_pm_end();
- ATRACE_BEGIN("data");
+ atrace_pm_begin("data");
auto cePath = create_data_user_ce_path(uuid_, userId);
collectManualStatsForUser(cePath, &stats, true);
auto dePath = create_data_user_de_path(uuid_, userId);
collectManualStatsForUser(dePath, &stats, true);
- ATRACE_END();
+ atrace_pm_end();
if (!uuid) {
- ATRACE_BEGIN("profile");
+ atrace_pm_begin("profile");
auto userProfilePath = create_primary_cur_profile_dir_path(userId);
calculate_tree_size(userProfilePath, &stats.dataSize, -1, -1, true);
auto refProfilePath = create_primary_ref_profile_dir_path();
calculate_tree_size(refProfilePath, &stats.codeSize, -1, -1, true);
- ATRACE_END();
+ atrace_pm_end();
}
- ATRACE_BEGIN("external");
+ atrace_pm_begin("external");
auto sizes = getExternalSizesForUserWithQuota(uuidString, userId, appIds);
extStats.dataSize += sizes.totalSize;
extStats.codeSize += sizes.obbSize;
- ATRACE_END();
+ atrace_pm_end();
if (!uuid) {
- ATRACE_BEGIN("dalvik");
+ atrace_pm_begin("dalvik");
calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize,
-1, -1, true);
calculate_tree_size(create_primary_cur_profile_dir_path(userId), &stats.dataSize,
-1, -1, true);
- ATRACE_END();
+ atrace_pm_end();
}
- ATRACE_BEGIN("quota");
+ atrace_pm_begin("quota");
int64_t dataSize = extStats.dataSize;
for (auto appId : appIds) {
if (appId >= AID_APP_START) {
@@ -2742,54 +2737,54 @@
}
}
extStats.dataSize = dataSize;
- ATRACE_END();
+ atrace_pm_end();
} else {
- ATRACE_BEGIN("obb");
+ atrace_pm_begin("obb");
auto obbPath = create_data_path(uuid_) + "/media/obb";
calculate_tree_size(obbPath, &extStats.codeSize);
- ATRACE_END();
+ atrace_pm_end();
- ATRACE_BEGIN("code");
+ atrace_pm_begin("code");
calculate_tree_size(create_data_app_path(uuid_), &stats.codeSize);
- ATRACE_END();
+ atrace_pm_end();
- ATRACE_BEGIN("data");
+ atrace_pm_begin("data");
auto cePath = create_data_user_ce_path(uuid_, userId);
collectManualStatsForUser(cePath, &stats);
auto dePath = create_data_user_de_path(uuid_, userId);
collectManualStatsForUser(dePath, &stats);
- ATRACE_END();
+ atrace_pm_end();
- ATRACE_BEGIN("sdksandbox");
+ atrace_pm_begin("sdksandbox");
auto sdkSandboxCePath = create_data_misc_sdk_sandbox_path(uuid_, true, userId);
collectManualStatsForUser(sdkSandboxCePath, &stats, false, true);
auto sdkSandboxDePath = create_data_misc_sdk_sandbox_path(uuid_, false, userId);
collectManualStatsForUser(sdkSandboxDePath, &stats, false, true);
- ATRACE_END();
+ atrace_pm_end();
if (!uuid) {
- ATRACE_BEGIN("profile");
+ atrace_pm_begin("profile");
auto userProfilePath = create_primary_cur_profile_dir_path(userId);
calculate_tree_size(userProfilePath, &stats.dataSize);
auto refProfilePath = create_primary_ref_profile_dir_path();
calculate_tree_size(refProfilePath, &stats.codeSize);
- ATRACE_END();
+ atrace_pm_end();
}
- ATRACE_BEGIN("external");
+ atrace_pm_begin("external");
auto dataMediaPath = create_data_media_path(uuid_, userId);
collectManualExternalStatsForUser(dataMediaPath, &extStats);
#if MEASURE_DEBUG
LOG(DEBUG) << "Measured external data " << extStats.dataSize << " cache "
<< extStats.cacheSize;
#endif
- ATRACE_END();
+ atrace_pm_end();
if (!uuid) {
- ATRACE_BEGIN("dalvik");
+ atrace_pm_begin("dalvik");
calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize);
calculate_tree_size(create_primary_cur_profile_dir_path(userId), &stats.dataSize);
- ATRACE_END();
+ atrace_pm_end();
}
}
@@ -2837,16 +2832,16 @@
}
if (flags & FLAG_USE_QUOTA) {
- ATRACE_BEGIN("quota");
+ atrace_pm_begin("quota");
auto sizes = getExternalSizesForUserWithQuota(uuidString, userId, appIds);
totalSize = sizes.totalSize;
audioSize = sizes.audioSize;
videoSize = sizes.videoSize;
imageSize = sizes.imageSize;
obbSize = sizes.obbSize;
- ATRACE_END();
+ atrace_pm_end();
- ATRACE_BEGIN("apps");
+ atrace_pm_begin("apps");
struct stats extStats;
memset(&extStats, 0, sizeof(extStats));
for (auto appId : appIds) {
@@ -2855,9 +2850,9 @@
}
}
appSize = extStats.dataSize;
- ATRACE_END();
+ atrace_pm_end();
} else {
- ATRACE_BEGIN("manual");
+ atrace_pm_begin("manual");
FTS *fts;
FTSENT *p;
auto path = create_data_media_path(uuid_, userId);
@@ -2900,16 +2895,16 @@
}
}
fts_close(fts);
- ATRACE_END();
+ atrace_pm_end();
- ATRACE_BEGIN("obb");
+ atrace_pm_begin("obb");
auto obbPath = StringPrintf("%s/Android/obb",
create_data_media_path(uuid_, userId).c_str());
calculate_tree_size(obbPath, &obbSize);
if (!(flags & FLAG_USE_QUOTA)) {
totalSize -= obbSize;
}
- ATRACE_END();
+ atrace_pm_end();
}
std::vector<int64_t> ret;
@@ -3713,7 +3708,7 @@
ENFORCE_UID(AID_SYSTEM);
// NOTE: The lint warning doesn't apply to the use of system(3) with
// absolute parse and no command line arguments.
- if (system("/system/bin/migrate_legacy_obb_data.sh") != 0) { // NOLINT(cert-env33-c)
+ if (system("/system/bin/migrate_legacy_obb_data") != 0) { // NOLINT(cert-env33-c)
LOG(ERROR) << "Unable to migrate legacy obb data";
}
diff --git a/cmds/installd/SysTrace.cpp b/cmds/installd/SysTrace.cpp
new file mode 100644
index 0000000..fa65c77
--- /dev/null
+++ b/cmds/installd/SysTrace.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER
+
+#include "SysTrace.h"
+#include <utils/Trace.h>
+
+namespace android::installd {
+void atrace_pm_begin(const char* name) {
+ ATRACE_BEGIN(name);
+}
+
+void atrace_pm_end() {
+ ATRACE_END();
+}
+} /* namespace android::installd */
diff --git a/cmds/installd/SysTrace.h b/cmds/installd/SysTrace.h
new file mode 100644
index 0000000..18506a9
--- /dev/null
+++ b/cmds/installd/SysTrace.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 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
+
+namespace android::installd {
+void atrace_pm_begin(const char*);
+void atrace_pm_end();
+} /* namespace android::installd */
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 4d9b710..ffc082d 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -523,7 +523,6 @@
*/
bool is_valid_package_name(const std::string& packageName) {
// This logic is borrowed from PackageParser.java
- bool hasSep = false;
bool front = true;
auto it = packageName.begin();
@@ -539,7 +538,6 @@
}
}
if (c == '.') {
- hasSep = true;
front = true;
continue;
}
diff --git a/include/android/choreographer.h b/include/android/choreographer.h
index 63aa7ff..cd8e63d 100644
--- a/include/android/choreographer.h
+++ b/include/android/choreographer.h
@@ -16,6 +16,28 @@
/**
* @addtogroup Choreographer
+ *
+ * Choreographer coordinates the timing of frame rendering. This is the C version of the
+ * android.view.Choreographer object in Java.
+ *
+ * As of API level 33, apps can follow proper frame pacing and even choose a future frame to render.
+ * The API is used as follows:
+ * 1. The app posts an {@link AChoreographer_vsyncCallback} to Choreographer to run on the next
+ * frame.
+ * 2. The callback is called when it is the time to start the frame with an {@link
+ * AChoreographerFrameCallbackData} payload: information about multiple possible frame
+ * timelines.
+ * 3. Apps can choose a frame timeline from the {@link
+ * AChoreographerFrameCallbackData} payload, depending on the frame deadline they can meet when
+ * rendering the frame and their desired presentation time, and subsequently
+ * {@link ASurfaceTransaction_setFrameTimeline notify SurfaceFlinger}
+ * of the choice. Alternatively, for apps that do not choose a frame timeline, their frame would be
+ * presented at the earliest possible timeline.
+ * - The preferred frame timeline is the default frame
+ * timeline that the platform scheduled for the app, based on device configuration.
+ * 4. SurfaceFlinger attempts to follow the chosen frame timeline, by not applying transactions or
+ * latching buffers before the desired presentation time.
+ *
* @{
*/
@@ -47,7 +69,8 @@
struct AChoreographerFrameCallbackData;
/**
- * Opaque type that provides access to an AChoreographerFrameCallbackData object.
+ * Opaque type that provides access to an AChoreographerFrameCallbackData object, which contains
+ * various methods to extract frame information.
*/
typedef struct AChoreographerFrameCallbackData AChoreographerFrameCallbackData;
@@ -73,8 +96,9 @@
/**
* Prototype of the function that is called when a new frame is being rendered.
- * It's passed the frame data that should not outlive the callback, as well as the data pointer
- * provided by the application that registered a callback.
+ * It is called with \c callbackData describing multiple frame timelines, as well as the \c data
+ * pointer provided by the application that registered a callback. The \c callbackData does not
+ * outlive the callback.
*/
typedef void (*AChoreographer_vsyncCallback)(
const AChoreographerFrameCallbackData* callbackData, void* data);
@@ -110,7 +134,7 @@
__DEPRECATED_IN(29);
/**
- * Power a callback to be run on the next frame. The data pointer provided will
+ * Post a callback to be run on the next frame. The data pointer provided will
* be passed to the callback function when it's called.
*
* Available since API level 29.
@@ -131,8 +155,10 @@
uint32_t delayMillis) __INTRODUCED_IN(29);
/**
- * Posts a callback to run on the next frame. The data pointer provided will
+ * Posts a callback to be run on the next frame. The data pointer provided will
* be passed to the callback function when it's called.
+ *
+ * Available since API level 33.
*/
void AChoreographer_postVsyncCallback(AChoreographer* choreographer,
AChoreographer_vsyncCallback callback, void* data)
@@ -189,7 +215,10 @@
__INTRODUCED_IN(30);
/**
- * The time in nanoseconds when the frame started being rendered.
+ * The time in nanoseconds at which the frame started being rendered.
+ *
+ * Note that this time should \b not be used to advance animation clocks.
+ * Instead, see AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos().
*/
int64_t AChoreographerFrameCallbackData_getFrameTimeNanos(
const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33);
@@ -201,25 +230,38 @@
const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33);
/**
- * Get index of the platform-preferred FrameTimeline.
+ * Gets the index of the platform-preferred frame timeline.
+ * The preferred frame timeline is the default
+ * by which the platform scheduled the app, based on the device configuration.
*/
size_t AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex(
const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33);
/**
- * The vsync ID token used to map Choreographer data.
+ * Gets the token used by the platform to identify the frame timeline at the given \c index.
+ *
+ * \param index index of a frame timeline, in \f( [0, FrameTimelinesLength) \f). See
+ * AChoreographerFrameCallbackData_getFrameTimelinesLength()
*/
AVsyncId AChoreographerFrameCallbackData_getFrameTimelineVsyncId(
const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33);
/**
- * The time in nanoseconds which the frame at given index is expected to be presented.
+ * Gets the time in nanoseconds at which the frame described at the given \c index is expected to
+ * be presented. This time should be used to advance any animation clocks.
+ *
+ * \param index index of a frame timeline, in \f( [0, FrameTimelinesLength) \f). See
+ * AChoreographerFrameCallbackData_getFrameTimelinesLength()
*/
int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos(
const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33);
/**
- * The time in nanoseconds which the frame at given index needs to be ready by.
+ * Gets the time in nanoseconds at which the frame described at the given \c index needs to be
+ * ready by in order to be presented on time.
+ *
+ * \param index index of a frame timeline, in \f( [0, FrameTimelinesLength) \f). See
+ * AChoreographerFrameCallbackData_getFrameTimelinesLength()
*/
int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos(
const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33);
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index 9842e7e..f76e73d 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -624,20 +624,20 @@
__INTRODUCED_IN(31);
/**
- * Sets the frame timeline to use in Surface Flinger.
+ * Sets the frame timeline to use in SurfaceFlinger.
*
- * A frame timeline should be chosen based on what frame deadline the application
- * can meet when rendering the frame and the application's desired present time.
- * By setting a frame timeline, Surface Flinger tries to present the frame at the corresponding
- * expected present time.
+ * A frame timeline should be chosen based on the frame deadline the application
+ * can meet when rendering the frame and the application's desired presentation time.
+ * By setting a frame timeline, SurfaceFlinger tries to present the frame at the corresponding
+ * expected presentation time.
*
* To receive frame timelines, a callback must be posted to Choreographer using
- * AChoreographer_postExtendedFrameCallback(). The \a vsnycId can then be extracted from the
+ * AChoreographer_postVsyncCallback(). The \c vsyncId can then be extracted from the
* callback payload using AChoreographerFrameCallbackData_getFrameTimelineVsyncId().
*
- * \param vsyncId The vsync ID received from AChoreographer, setting the frame's present target to
- * the corresponding expected present time and deadline from the frame to be rendered. A stale or
- * invalid value will be ignored.
+ * \param vsyncId The vsync ID received from AChoreographer, setting the frame's presentation target
+ * to the corresponding expected presentation time and deadline from the frame to be rendered. A
+ * stale or invalid value will be ignored.
*/
void ASurfaceTransaction_setFrameTimeline(ASurfaceTransaction* transaction,
AVsyncId vsyncId) __INTRODUCED_IN(33);
diff --git a/include/ftl/details/optional.h b/include/ftl/details/optional.h
new file mode 100644
index 0000000..bff7c1e
--- /dev/null
+++ b/include/ftl/details/optional.h
@@ -0,0 +1,58 @@
+/*
+ * 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 <functional>
+#include <optional>
+
+#include <ftl/details/type_traits.h>
+
+namespace android::ftl {
+
+template <typename>
+struct Optional;
+
+namespace details {
+
+template <typename>
+struct is_optional : std::false_type {};
+
+template <typename T>
+struct is_optional<std::optional<T>> : std::true_type {};
+
+template <typename T>
+struct is_optional<Optional<T>> : std::true_type {};
+
+template <typename F, typename T>
+struct transform_result {
+ using type = Optional<std::remove_cv_t<std::invoke_result_t<F, T>>>;
+};
+
+template <typename F, typename T>
+using transform_result_t = typename transform_result<F, T>::type;
+
+template <typename F, typename T>
+struct and_then_result {
+ using type = remove_cvref_t<std::invoke_result_t<F, T>>;
+ static_assert(is_optional<type>{}, "and_then function must return an optional");
+};
+
+template <typename F, typename T>
+using and_then_result_t = typename and_then_result<F, T>::type;
+
+} // namespace details
+} // namespace android::ftl
diff --git a/include/ftl/details/type_traits.h b/include/ftl/details/type_traits.h
new file mode 100644
index 0000000..7092ec5
--- /dev/null
+++ b/include/ftl/details/type_traits.h
@@ -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.
+ */
+
+#pragma once
+
+#include <type_traits>
+
+namespace android::ftl::details {
+
+// TODO: Replace with std::remove_cvref_t in C++20.
+template <typename U>
+using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<U>>;
+
+} // namespace android::ftl::details
diff --git a/include/ftl/optional.h b/include/ftl/optional.h
index daf4502..626507f 100644
--- a/include/ftl/optional.h
+++ b/include/ftl/optional.h
@@ -18,9 +18,10 @@
#include <functional>
#include <optional>
-#include <type_traits>
#include <utility>
+#include <ftl/details/optional.h>
+
namespace android::ftl {
// Superset of std::optional<T> with monadic operations, as proposed in https://wg21.link/P0798R8.
@@ -31,41 +32,76 @@
struct Optional final : std::optional<T> {
using std::optional<T>::optional;
+ // Implicit downcast.
+ Optional(std::optional<T> other) : std::optional<T>(std::move(other)) {}
+
using std::optional<T>::has_value;
using std::optional<T>::value;
// Returns Optional<U> where F is a function that maps T to U.
template <typename F>
constexpr auto transform(F&& f) const& {
- using U = std::remove_cv_t<std::invoke_result_t<F, decltype(value())>>;
- if (has_value()) return Optional<U>(std::invoke(std::forward<F>(f), value()));
- return Optional<U>();
+ using R = details::transform_result_t<F, decltype(value())>;
+ if (has_value()) return R(std::invoke(std::forward<F>(f), value()));
+ return R();
}
template <typename F>
constexpr auto transform(F&& f) & {
- using U = std::remove_cv_t<std::invoke_result_t<F, decltype(value())>>;
- if (has_value()) return Optional<U>(std::invoke(std::forward<F>(f), value()));
- return Optional<U>();
+ using R = details::transform_result_t<F, decltype(value())>;
+ if (has_value()) return R(std::invoke(std::forward<F>(f), value()));
+ return R();
}
template <typename F>
constexpr auto transform(F&& f) const&& {
- using U = std::invoke_result_t<F, decltype(std::move(value()))>;
- if (has_value()) return Optional<U>(std::invoke(std::forward<F>(f), std::move(value())));
- return Optional<U>();
+ using R = details::transform_result_t<F, decltype(std::move(value()))>;
+ if (has_value()) return R(std::invoke(std::forward<F>(f), std::move(value())));
+ return R();
}
template <typename F>
constexpr auto transform(F&& f) && {
- using U = std::invoke_result_t<F, decltype(std::move(value()))>;
- if (has_value()) return Optional<U>(std::invoke(std::forward<F>(f), std::move(value())));
- return Optional<U>();
+ using R = details::transform_result_t<F, decltype(std::move(value()))>;
+ if (has_value()) return R(std::invoke(std::forward<F>(f), std::move(value())));
+ return R();
+ }
+
+ // Returns Optional<U> where F is a function that maps T to Optional<U>.
+ template <typename F>
+ constexpr auto and_then(F&& f) const& {
+ using R = details::and_then_result_t<F, decltype(value())>;
+ if (has_value()) return std::invoke(std::forward<F>(f), value());
+ return R();
+ }
+
+ template <typename F>
+ constexpr auto and_then(F&& f) & {
+ using R = details::and_then_result_t<F, decltype(value())>;
+ if (has_value()) return std::invoke(std::forward<F>(f), value());
+ return R();
+ }
+
+ template <typename F>
+ constexpr auto and_then(F&& f) const&& {
+ using R = details::and_then_result_t<F, decltype(std::move(value()))>;
+ if (has_value()) return std::invoke(std::forward<F>(f), std::move(value()));
+ return R();
+ }
+
+ template <typename F>
+ constexpr auto and_then(F&& f) && {
+ using R = details::and_then_result_t<F, decltype(std::move(value()))>;
+ if (has_value()) return std::invoke(std::forward<F>(f), std::move(value()));
+ return R();
}
};
-// Deduction guide.
+// Deduction guides.
template <typename T>
Optional(T) -> Optional<T>;
+template <typename T>
+Optional(std::optional<T>) -> Optional<T>;
+
} // namespace android::ftl
diff --git a/include/ftl/small_vector.h b/include/ftl/small_vector.h
index 339726e..11294c3 100644
--- a/include/ftl/small_vector.h
+++ b/include/ftl/small_vector.h
@@ -21,11 +21,12 @@
#include <algorithm>
#include <iterator>
-#include <type_traits>
#include <utility>
#include <variant>
#include <vector>
+#include <ftl/details/type_traits.h>
+
namespace android::ftl {
template <typename>
@@ -80,10 +81,6 @@
using Static = StaticVector<T, N>;
using Dynamic = SmallVector<T, 0>;
- // TODO: Replace with std::remove_cvref_t in C++20.
- template <typename U>
- using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<U>>;
-
public:
FTL_ARRAY_TRAIT(T, value_type);
FTL_ARRAY_TRAIT(T, size_type);
@@ -104,7 +101,7 @@
// Constructs at most N elements. See StaticVector for underlying constructors.
template <typename Arg, typename... Args,
- typename = std::enable_if_t<!is_small_vector<remove_cvref_t<Arg>>{}>>
+ typename = std::enable_if_t<!is_small_vector<details::remove_cvref_t<Arg>>{}>>
SmallVector(Arg&& arg, Args&&... args)
: vector_(std::in_place_type<Static>, std::forward<Arg>(arg), std::forward<Args>(args)...) {}
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index 3585392..d51d6a7 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -23,6 +23,8 @@
#include <unordered_map>
#include <vector>
+#include "android/hardware/input/InputDeviceCountryCode.h"
+
namespace android {
/*
@@ -210,8 +212,10 @@
};
void initialize(int32_t id, int32_t generation, int32_t controllerNumber,
- const InputDeviceIdentifier& identifier, const std::string& alias, bool isExternal,
- bool hasMic);
+ const InputDeviceIdentifier& identifier, const std::string& alias,
+ bool isExternal, bool hasMic,
+ hardware::input::InputDeviceCountryCode countryCode =
+ hardware::input::InputDeviceCountryCode::INVALID);
inline int32_t getId() const { return mId; }
inline int32_t getControllerNumber() const { return mControllerNumber; }
@@ -223,6 +227,7 @@
}
inline bool isExternal() const { return mIsExternal; }
inline bool hasMic() const { return mHasMic; }
+ inline hardware::input::InputDeviceCountryCode getCountryCode() const { return mCountryCode; }
inline uint32_t getSources() const { return mSources; }
const MotionRange* getMotionRange(int32_t axis, uint32_t source) const;
@@ -274,9 +279,11 @@
std::string mAlias;
bool mIsExternal;
bool mHasMic;
+ hardware::input::InputDeviceCountryCode mCountryCode;
uint32_t mSources;
int32_t mKeyboardType;
std::shared_ptr<KeyCharacterMap> mKeyCharacterMap;
+
bool mHasVibrator;
bool mHasBattery;
bool mHasButtonUnderPad;
diff --git a/libs/arect/include/android/rect.h b/libs/arect/include/android/rect.h
index b36728e..d52861a 100644
--- a/libs/arect/include/android/rect.h
+++ b/libs/arect/include/android/rect.h
@@ -57,7 +57,7 @@
} ARect;
#ifdef __cplusplus
-};
+}
#endif
#endif // ANDROID_RECT_H
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 66b03b0..246963a 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -71,15 +71,9 @@
}
cc_defaults {
- name: "libbinder_defaults",
+ name: "libbinder_common_defaults",
host_supported: true,
- // TODO(b/31559095): get headers from bionic on host
- include_dirs: [
- "bionic/libc/kernel/android/uapi/",
- "bionic/libc/kernel/uapi/",
- ],
-
srcs: [
"Binder.cpp",
"BpBinder.cpp",
@@ -87,19 +81,46 @@
"FdTrigger.cpp",
"IInterface.cpp",
"IResultReceiver.cpp",
- "OS.cpp",
"Parcel.cpp",
"ParcelFileDescriptor.cpp",
"RpcSession.cpp",
"RpcServer.cpp",
"RpcState.cpp",
- "RpcTransportRaw.cpp",
"Stability.cpp",
"Status.cpp",
"TextOutput.cpp",
+ "Trace.cpp",
"Utils.cpp",
],
+ shared_libs: [
+ "libcutils",
+ "libutils",
+ ],
+
+ static_libs: [
+ "libbase",
+ ],
+
+ header_libs: [
+ "libbinder_headers",
+ ],
+}
+
+cc_defaults {
+ name: "libbinder_android_defaults",
+
+ // TODO(b/31559095): get headers from bionic on host
+ include_dirs: [
+ "bionic/libc/kernel/android/uapi/",
+ "bionic/libc/kernel/uapi/",
+ ],
+
+ srcs: [
+ "OS.cpp",
+ "RpcTransportRaw.cpp",
+ ],
+
target: {
host: {
srcs: [
@@ -133,16 +154,9 @@
shared_libs: [
"liblog",
- "libcutils",
- "libutils",
- ],
-
- static_libs: [
- "libbase",
],
header_libs: [
- "libbinder_headers",
"libandroid_runtime_vm_headers",
],
@@ -177,6 +191,48 @@
],
}
+cc_library_shared {
+ name: "libbinder_on_trusty_mock",
+ defaults: ["libbinder_common_defaults"],
+
+ srcs: [
+ // Trusty-specific files
+ "trusty/logging.cpp",
+ "trusty/OS.cpp",
+ "trusty/RpcServerTrusty.cpp",
+ "trusty/RpcTransportTipcTrusty.cpp",
+ "trusty/TrustyStatus.cpp",
+ "trusty/socket.cpp",
+ ],
+
+ cflags: [
+ "-DBINDER_RPC_SINGLE_THREADED",
+ // Trusty libbinder uses vendor stability for its binders
+ "-D__ANDROID_VNDK__",
+ "-U__ANDROID__",
+ "-D__TRUSTY__",
+ "-DTRUSTY_USERSPACE",
+ // Flags from the Trusty build system
+ "-Werror",
+ "-Wsign-compare",
+ "-Wno-unused-function",
+ "-Wno-unused-label",
+ "-fno-common",
+ "-fno-omit-frame-pointer",
+ "-fno-threadsafe-statics",
+ ],
+ rtti: false,
+
+ local_include_dirs: [
+ "trusty/include",
+ "trusty/include_mock",
+ ],
+
+ visibility: [
+ ":__subpackages__",
+ ],
+}
+
cc_defaults {
name: "libbinder_kernel_defaults",
srcs: [
@@ -208,7 +264,8 @@
cc_library {
name: "libbinder",
defaults: [
- "libbinder_defaults",
+ "libbinder_common_defaults",
+ "libbinder_android_defaults",
"libbinder_kernel_defaults",
],
@@ -264,7 +321,10 @@
cc_library_static {
name: "libbinder_rpc_no_kernel",
- defaults: ["libbinder_defaults"],
+ defaults: [
+ "libbinder_common_defaults",
+ "libbinder_android_defaults",
+ ],
visibility: [
":__subpackages__",
],
@@ -273,7 +333,8 @@
cc_library_static {
name: "libbinder_rpc_single_threaded",
defaults: [
- "libbinder_defaults",
+ "libbinder_common_defaults",
+ "libbinder_android_defaults",
"libbinder_kernel_defaults",
],
cflags: [
@@ -286,7 +347,10 @@
cc_library_static {
name: "libbinder_rpc_single_threaded_no_kernel",
- defaults: ["libbinder_defaults"],
+ defaults: [
+ "libbinder_common_defaults",
+ "libbinder_android_defaults",
+ ],
cflags: [
"-DBINDER_RPC_SINGLE_THREADED",
],
diff --git a/libs/binder/FdTrigger.cpp b/libs/binder/FdTrigger.cpp
index d123fd1..8ee6cb0 100644
--- a/libs/binder/FdTrigger.cpp
+++ b/libs/binder/FdTrigger.cpp
@@ -22,6 +22,7 @@
#include <poll.h>
#include <android-base/macros.h>
+#include <android-base/scopeguard.h>
#include "RpcState.h"
namespace android {
@@ -53,25 +54,34 @@
#endif
}
-status_t FdTrigger::triggerablePoll(base::borrowed_fd fd, int16_t event) {
+status_t FdTrigger::triggerablePoll(const android::RpcTransportFd& transportFd, int16_t event) {
#ifdef BINDER_RPC_SINGLE_THREADED
if (mTriggered) {
return DEAD_OBJECT;
}
#endif
- LOG_ALWAYS_FATAL_IF(event == 0, "triggerablePoll %d with event 0 is not allowed", fd.get());
+ LOG_ALWAYS_FATAL_IF(event == 0, "triggerablePoll %d with event 0 is not allowed",
+ transportFd.fd.get());
pollfd pfd[]{
- {.fd = fd.get(), .events = static_cast<int16_t>(event), .revents = 0},
+ {.fd = transportFd.fd.get(), .events = static_cast<int16_t>(event), .revents = 0},
#ifndef BINDER_RPC_SINGLE_THREADED
{.fd = mRead.get(), .events = 0, .revents = 0},
#endif
};
+
+ LOG_ALWAYS_FATAL_IF(transportFd.isInPollingState() == true,
+ "Only one thread should be polling on Fd!");
+
+ transportFd.setPollingState(true);
+ auto pollingStateGuard =
+ android::base::make_scope_guard([&]() { transportFd.setPollingState(false); });
+
int ret = TEMP_FAILURE_RETRY(poll(pfd, arraysize(pfd), -1));
if (ret < 0) {
return -errno;
}
- LOG_ALWAYS_FATAL_IF(ret == 0, "poll(%d) returns 0 with infinite timeout", fd.get());
+ LOG_ALWAYS_FATAL_IF(ret == 0, "poll(%d) returns 0 with infinite timeout", transportFd.fd.get());
// At least one FD has events. Check them.
diff --git a/libs/binder/FdTrigger.h b/libs/binder/FdTrigger.h
index a25dc11..5fbf290 100644
--- a/libs/binder/FdTrigger.h
+++ b/libs/binder/FdTrigger.h
@@ -21,6 +21,8 @@
#include <android-base/unique_fd.h>
#include <utils/Errors.h>
+#include <binder/RpcTransport.h>
+
namespace android {
/** This is not a pipe. */
@@ -53,7 +55,8 @@
* true - time to read!
* false - trigger happened
*/
- [[nodiscard]] status_t triggerablePoll(base::borrowed_fd fd, int16_t event);
+ [[nodiscard]] status_t triggerablePoll(const android::RpcTransportFd& transportFd,
+ int16_t event);
private:
#ifdef BINDER_RPC_SINGLE_THREADED
diff --git a/libs/binder/OS.cpp b/libs/binder/OS.cpp
index cc4a03b..24ce2bb 100644
--- a/libs/binder/OS.cpp
+++ b/libs/binder/OS.cpp
@@ -17,6 +17,7 @@
#include "OS.h"
#include <android-base/file.h>
+#include <binder/RpcTransportRaw.h>
#include <string.h>
using android::base::ErrnoError;
@@ -58,4 +59,8 @@
return OK;
}
+std::unique_ptr<RpcTransportCtxFactory> makeDefaultRpcTransportCtxFactory() {
+ return RpcTransportCtxFactoryRaw::make();
+}
+
} // namespace android
diff --git a/libs/binder/OS.h b/libs/binder/OS.h
index d6e1c78..5ab8bab 100644
--- a/libs/binder/OS.h
+++ b/libs/binder/OS.h
@@ -20,6 +20,7 @@
#include <android-base/result.h>
#include <android-base/unique_fd.h>
+#include <binder/RpcTransport.h>
#include <utils/Errors.h>
namespace android {
@@ -30,4 +31,6 @@
status_t dupFileDescriptor(int oldFd, int* newFd);
+std::unique_ptr<RpcTransportCtxFactory> makeDefaultRpcTransportCtxFactory();
+
} // namespace android
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index 49be4dd..e581d0b 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -55,7 +55,7 @@
sp<RpcServer> RpcServer::make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory) {
// Default is without TLS.
if (rpcTransportCtxFactory == nullptr)
- rpcTransportCtxFactory = RpcTransportCtxFactoryRaw::make();
+ rpcTransportCtxFactory = makeDefaultRpcTransportCtxFactory();
auto ctx = rpcTransportCtxFactory->newServerCtx();
if (ctx == nullptr) return nullptr;
return sp<RpcServer>::make(std::move(ctx));
@@ -86,7 +86,7 @@
LOG_ALWAYS_FATAL_IF(socketAddress.addr()->sa_family != AF_INET, "expecting inet");
sockaddr_in addr{};
socklen_t len = sizeof(addr);
- if (0 != getsockname(mServer.get(), reinterpret_cast<sockaddr*>(&addr), &len)) {
+ if (0 != getsockname(mServer.fd.get(), reinterpret_cast<sockaddr*>(&addr), &len)) {
int savedErrno = errno;
ALOGE("Could not getsockname at %s: %s", socketAddress.toString().c_str(),
strerror(savedErrno));
@@ -181,7 +181,7 @@
{
RpcMutexLockGuard _l(mLock);
- LOG_ALWAYS_FATAL_IF(!mServer.ok(), "RpcServer must be setup to join.");
+ LOG_ALWAYS_FATAL_IF(!mServer.fd.ok(), "RpcServer must be setup to join.");
LOG_ALWAYS_FATAL_IF(mShutdownTrigger != nullptr, "Already joined");
mJoinThreadRunning = true;
mShutdownTrigger = FdTrigger::make();
@@ -194,24 +194,24 @@
static_assert(addr.size() >= sizeof(sockaddr_storage), "kRpcAddressSize is too small");
socklen_t addrLen = addr.size();
- unique_fd clientFd(
- TEMP_FAILURE_RETRY(accept4(mServer.get(), reinterpret_cast<sockaddr*>(addr.data()),
- &addrLen, SOCK_CLOEXEC | SOCK_NONBLOCK)));
+ RpcTransportFd clientSocket(unique_fd(TEMP_FAILURE_RETRY(
+ accept4(mServer.fd.get(), reinterpret_cast<sockaddr*>(addr.data()), &addrLen,
+ SOCK_CLOEXEC | SOCK_NONBLOCK))));
LOG_ALWAYS_FATAL_IF(addrLen > static_cast<socklen_t>(sizeof(sockaddr_storage)),
"Truncated address");
- if (clientFd < 0) {
+ if (clientSocket.fd < 0) {
ALOGE("Could not accept4 socket: %s", strerror(errno));
continue;
}
- LOG_RPC_DETAIL("accept4 on fd %d yields fd %d", mServer.get(), clientFd.get());
+ LOG_RPC_DETAIL("accept4 on fd %d yields fd %d", mServer.fd.get(), clientSocket.fd.get());
{
RpcMutexLockGuard _l(mLock);
RpcMaybeThread thread =
RpcMaybeThread(&RpcServer::establishConnection,
- sp<RpcServer>::fromExisting(this), std::move(clientFd), addr,
+ sp<RpcServer>::fromExisting(this), std::move(clientSocket), addr,
addrLen, RpcSession::join);
auto& threadRef = mConnectingThreads[thread.get_id()];
@@ -296,7 +296,7 @@
}
void RpcServer::establishConnection(
- sp<RpcServer>&& server, base::unique_fd clientFd, std::array<uint8_t, kRpcAddressSize> addr,
+ sp<RpcServer>&& server, RpcTransportFd clientFd, std::array<uint8_t, kRpcAddressSize> addr,
size_t addrLen,
std::function<void(sp<RpcSession>&&, RpcSession::PreJoinSetupResult&&)>&& joinFn) {
// mShutdownTrigger can only be cleared once connection threads have joined.
@@ -306,7 +306,7 @@
status_t status = OK;
- int clientFdForLog = clientFd.get();
+ int clientFdForLog = clientFd.fd.get();
auto client = server->mCtx->newTransport(std::move(clientFd), server->mShutdownTrigger.get());
if (client == nullptr) {
ALOGE("Dropping accept4()-ed socket because sslAccept fails");
@@ -488,15 +488,15 @@
LOG_RPC_DETAIL("Setting up socket server %s", addr.toString().c_str());
LOG_ALWAYS_FATAL_IF(hasServer(), "Each RpcServer can only have one server.");
- unique_fd serverFd(TEMP_FAILURE_RETRY(
- socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)));
- if (serverFd == -1) {
+ RpcTransportFd transportFd(unique_fd(TEMP_FAILURE_RETRY(
+ socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0))));
+ if (!transportFd.fd.ok()) {
int savedErrno = errno;
ALOGE("Could not create socket: %s", strerror(savedErrno));
return -savedErrno;
}
- if (0 != TEMP_FAILURE_RETRY(bind(serverFd.get(), addr.addr(), addr.addrSize()))) {
+ if (0 != TEMP_FAILURE_RETRY(bind(transportFd.fd.get(), addr.addr(), addr.addrSize()))) {
int savedErrno = errno;
ALOGE("Could not bind socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
return -savedErrno;
@@ -506,7 +506,7 @@
// the backlog is increased to a large number.
// TODO(b/189955605): Once we create threads dynamically & lazily, the backlog can be reduced
// to 1.
- if (0 != TEMP_FAILURE_RETRY(listen(serverFd.get(), 50 /*backlog*/))) {
+ if (0 != TEMP_FAILURE_RETRY(listen(transportFd.fd.get(), 50 /*backlog*/))) {
int savedErrno = errno;
ALOGE("Could not listen socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
return -savedErrno;
@@ -514,7 +514,7 @@
LOG_RPC_DETAIL("Successfully setup socket server %s", addr.toString().c_str());
- if (status_t status = setupExternalServer(std::move(serverFd)); status != OK) {
+ if (status_t status = setupExternalServer(std::move(transportFd.fd)); status != OK) {
ALOGE("Another thread has set up server while calling setupSocketServer. Race?");
return status;
}
@@ -542,17 +542,17 @@
bool RpcServer::hasServer() {
RpcMutexLockGuard _l(mLock);
- return mServer.ok();
+ return mServer.fd.ok();
}
unique_fd RpcServer::releaseServer() {
RpcMutexLockGuard _l(mLock);
- return std::move(mServer);
+ return std::move(mServer.fd);
}
status_t RpcServer::setupExternalServer(base::unique_fd serverFd) {
RpcMutexLockGuard _l(mLock);
- if (mServer.ok()) {
+ if (mServer.fd.ok()) {
ALOGE("Each RpcServer can only have one server.");
return INVALID_OPERATION;
}
@@ -560,4 +560,14 @@
return OK;
}
+bool RpcServer::hasActiveRequests() {
+ RpcMutexLockGuard _l(mLock);
+ for (const auto& [_, session] : mSessions) {
+ if (session->hasActiveRequests()) {
+ return true;
+ }
+ }
+ return !mServer.isInPollingState();
+}
+
} // namespace android
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 8ddfa93..49843e5 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -68,7 +68,7 @@
sp<RpcSession> RpcSession::make() {
// Default is without TLS.
- return make(RpcTransportCtxFactoryRaw::make());
+ return make(makeDefaultRpcTransportCtxFactory());
}
sp<RpcSession> RpcSession::make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory) {
@@ -162,7 +162,8 @@
return NAME_NOT_FOUND;
}
-status_t RpcSession::setupPreconnectedClient(unique_fd fd, std::function<unique_fd()>&& request) {
+status_t RpcSession::setupPreconnectedClient(base::unique_fd fd,
+ std::function<unique_fd()>&& request) {
return setupClient([&](const std::vector<uint8_t>& sessionId, bool incoming) -> status_t {
if (!fd.ok()) {
fd = request();
@@ -172,7 +173,9 @@
ALOGE("setupPreconnectedClient: %s", res.error().message().c_str());
return res.error().code() == 0 ? UNKNOWN_ERROR : -res.error().code();
}
- status_t status = initAndAddConnection(std::move(fd), sessionId, incoming);
+
+ RpcTransportFd transportFd(std::move(fd));
+ status_t status = initAndAddConnection(std::move(transportFd), sessionId, incoming);
fd = unique_fd(); // Explicitly reset after move to avoid analyzer warning.
return status;
});
@@ -190,7 +193,8 @@
return -savedErrno;
}
- auto server = mCtx->newTransport(std::move(serverFd), mShutdownTrigger.get());
+ RpcTransportFd transportFd(std::move(serverFd));
+ auto server = mCtx->newTransport(std::move(transportFd), mShutdownTrigger.get());
if (server == nullptr) {
ALOGE("Unable to set up RpcTransport");
return UNKNOWN_ERROR;
@@ -572,12 +576,14 @@
return -savedErrno;
}
- if (0 != TEMP_FAILURE_RETRY(connect(serverFd.get(), addr.addr(), addr.addrSize()))) {
+ RpcTransportFd transportFd(std::move(serverFd));
+
+ if (0 != TEMP_FAILURE_RETRY(connect(transportFd.fd.get(), addr.addr(), addr.addrSize()))) {
int connErrno = errno;
if (connErrno == EAGAIN || connErrno == EINPROGRESS) {
// For non-blocking sockets, connect() may return EAGAIN (for unix domain socket) or
// EINPROGRESS (for others). Call poll() and getsockopt() to get the error.
- status_t pollStatus = mShutdownTrigger->triggerablePoll(serverFd, POLLOUT);
+ status_t pollStatus = mShutdownTrigger->triggerablePoll(transportFd, POLLOUT);
if (pollStatus != OK) {
ALOGE("Could not POLLOUT after connect() on non-blocking socket: %s",
statusToString(pollStatus).c_str());
@@ -585,8 +591,8 @@
}
// Set connErrno to the errno that connect() would have set if the fd were blocking.
socklen_t connErrnoLen = sizeof(connErrno);
- int ret =
- getsockopt(serverFd.get(), SOL_SOCKET, SO_ERROR, &connErrno, &connErrnoLen);
+ int ret = getsockopt(transportFd.fd.get(), SOL_SOCKET, SO_ERROR, &connErrno,
+ &connErrnoLen);
if (ret == -1) {
int savedErrno = errno;
ALOGE("Could not getsockopt() after connect() on non-blocking socket: %s. "
@@ -608,16 +614,17 @@
return -connErrno;
}
}
- LOG_RPC_DETAIL("Socket at %s client with fd %d", addr.toString().c_str(), serverFd.get());
+ LOG_RPC_DETAIL("Socket at %s client with fd %d", addr.toString().c_str(),
+ transportFd.fd.get());
- return initAndAddConnection(std::move(serverFd), sessionId, incoming);
+ return initAndAddConnection(std::move(transportFd), sessionId, incoming);
}
ALOGE("Ran out of retries to connect to %s", addr.toString().c_str());
return UNKNOWN_ERROR;
}
-status_t RpcSession::initAndAddConnection(unique_fd fd, const std::vector<uint8_t>& sessionId,
+status_t RpcSession::initAndAddConnection(RpcTransportFd fd, const std::vector<uint8_t>& sessionId,
bool incoming) {
LOG_ALWAYS_FATAL_IF(mShutdownTrigger == nullptr);
auto server = mCtx->newTransport(std::move(fd), mShutdownTrigger.get());
@@ -945,4 +952,24 @@
}
}
+bool RpcSession::hasActiveConnection(const std::vector<sp<RpcConnection>>& connections) {
+ for (const auto& connection : connections) {
+ if (connection->exclusiveTid != std::nullopt && !connection->rpcTransport->isWaiting()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool RpcSession::hasActiveRequests() {
+ RpcMutexUniqueLock _l(mMutex);
+ if (hasActiveConnection(mConnections.mIncoming)) {
+ return true;
+ }
+ if (hasActiveConnection(mConnections.mOutgoing)) {
+ return true;
+ }
+ return mConnections.mWaitingThreads != 0;
+}
+
} // namespace android
diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp
index 51326f6..65e8fac 100644
--- a/libs/binder/RpcTransportRaw.cpp
+++ b/libs/binder/RpcTransportRaw.cpp
@@ -36,11 +36,11 @@
// RpcTransport with TLS disabled.
class RpcTransportRaw : public RpcTransport {
public:
- explicit RpcTransportRaw(android::base::unique_fd socket) : mSocket(std::move(socket)) {}
+ explicit RpcTransportRaw(android::RpcTransportFd socket) : mSocket(std::move(socket)) {}
status_t pollRead(void) override {
uint8_t buf;
ssize_t ret = TEMP_FAILURE_RETRY(
- ::recv(mSocket.get(), &buf, sizeof(buf), MSG_PEEK | MSG_DONTWAIT));
+ ::recv(mSocket.fd.get(), &buf, sizeof(buf), MSG_PEEK | MSG_DONTWAIT));
if (ret < 0) {
int savedErrno = errno;
if (savedErrno == EAGAIN || savedErrno == EWOULDBLOCK) {
@@ -100,7 +100,7 @@
msg.msg_controllen = CMSG_SPACE(fdsByteSize);
ssize_t processedSize = TEMP_FAILURE_RETRY(
- sendmsg(mSocket.get(), &msg, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC));
+ sendmsg(mSocket.fd.get(), &msg, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC));
if (processedSize > 0) {
sentFds = true;
}
@@ -113,10 +113,10 @@
// non-negative int and can be cast to either.
.msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs),
};
- return TEMP_FAILURE_RETRY(sendmsg(mSocket.get(), &msg, MSG_NOSIGNAL));
+ return TEMP_FAILURE_RETRY(sendmsg(mSocket.fd.get(), &msg, MSG_NOSIGNAL));
};
- return interruptableReadOrWrite(mSocket.get(), fdTrigger, iovs, niovs, send, "sendmsg",
- POLLOUT, altPoll);
+ return interruptableReadOrWrite(mSocket, fdTrigger, iovs, niovs, send, "sendmsg", POLLOUT,
+ altPoll);
}
status_t interruptableReadFully(
@@ -135,7 +135,7 @@
.msg_controllen = sizeof(msgControlBuf),
};
ssize_t processSize =
- TEMP_FAILURE_RETRY(recvmsg(mSocket.get(), &msg, MSG_NOSIGNAL));
+ TEMP_FAILURE_RETRY(recvmsg(mSocket.fd.get(), &msg, MSG_NOSIGNAL));
if (processSize < 0) {
return -1;
}
@@ -171,21 +171,23 @@
// non-negative int and can be cast to either.
.msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs),
};
- return TEMP_FAILURE_RETRY(recvmsg(mSocket.get(), &msg, MSG_NOSIGNAL));
+ return TEMP_FAILURE_RETRY(recvmsg(mSocket.fd.get(), &msg, MSG_NOSIGNAL));
};
- return interruptableReadOrWrite(mSocket.get(), fdTrigger, iovs, niovs, recv, "recvmsg",
- POLLIN, altPoll);
+ return interruptableReadOrWrite(mSocket, fdTrigger, iovs, niovs, recv, "recvmsg", POLLIN,
+ altPoll);
}
+ virtual bool isWaiting() { return mSocket.isInPollingState(); }
+
private:
- base::unique_fd mSocket;
+ android::RpcTransportFd mSocket;
};
// RpcTransportCtx with TLS disabled.
class RpcTransportCtxRaw : public RpcTransportCtx {
public:
- std::unique_ptr<RpcTransport> newTransport(android::base::unique_fd fd, FdTrigger*) const {
- return std::make_unique<RpcTransportRaw>(std::move(fd));
+ std::unique_ptr<RpcTransport> newTransport(android::RpcTransportFd socket, FdTrigger*) const {
+ return std::make_unique<RpcTransportRaw>(std::move(socket));
}
std::vector<uint8_t> getCertificate(RpcCertificateFormat) const override { return {}; }
};
diff --git a/libs/binder/RpcTransportTipcAndroid.cpp b/libs/binder/RpcTransportTipcAndroid.cpp
index c82201b..453279c 100644
--- a/libs/binder/RpcTransportTipcAndroid.cpp
+++ b/libs/binder/RpcTransportTipcAndroid.cpp
@@ -36,8 +36,7 @@
// RpcTransport for writing Trusty IPC clients in Android.
class RpcTransportTipcAndroid : public RpcTransport {
public:
- explicit RpcTransportTipcAndroid(android::base::unique_fd socket)
- : mSocket(std::move(socket)) {}
+ explicit RpcTransportTipcAndroid(android::RpcTransportFd socket) : mSocket(std::move(socket)) {}
status_t pollRead() override {
if (mReadBufferPos < mReadBufferSize) {
@@ -46,7 +45,7 @@
}
// Trusty IPC device is not a socket, so MSG_PEEK is not available
- pollfd pfd{.fd = mSocket.get(), .events = static_cast<int16_t>(POLLIN), .revents = 0};
+ pollfd pfd{.fd = mSocket.fd.get(), .events = static_cast<int16_t>(POLLIN), .revents = 0};
ssize_t ret = TEMP_FAILURE_RETRY(::poll(&pfd, 1, 0));
if (ret < 0) {
int savedErrno = errno;
@@ -84,9 +83,9 @@
// to send any.
LOG_ALWAYS_FATAL_IF(ancillaryFds != nullptr && !ancillaryFds->empty(),
"File descriptors are not supported on Trusty yet");
- return TEMP_FAILURE_RETRY(tipc_send(mSocket.get(), iovs, niovs, nullptr, 0));
+ return TEMP_FAILURE_RETRY(tipc_send(mSocket.fd.get(), iovs, niovs, nullptr, 0));
};
- return interruptableReadOrWrite(mSocket.get(), fdTrigger, iovs, niovs, writeFn, "tipc_send",
+ return interruptableReadOrWrite(mSocket, fdTrigger, iovs, niovs, writeFn, "tipc_send",
POLLOUT, altPoll);
}
@@ -120,10 +119,12 @@
return processSize;
};
- return interruptableReadOrWrite(mSocket.get(), fdTrigger, iovs, niovs, readFn, "read",
- POLLIN, altPoll);
+ return interruptableReadOrWrite(mSocket, fdTrigger, iovs, niovs, readFn, "read", POLLIN,
+ altPoll);
}
+ bool isWaiting() override { return mSocket.isInPollingState(); }
+
private:
status_t fillReadBuffer() {
if (mReadBufferPos < mReadBufferSize) {
@@ -146,8 +147,8 @@
mReadBufferSize = 0;
while (true) {
- ssize_t processSize =
- TEMP_FAILURE_RETRY(read(mSocket.get(), mReadBuffer.get(), mReadBufferCapacity));
+ ssize_t processSize = TEMP_FAILURE_RETRY(
+ read(mSocket.fd.get(), mReadBuffer.get(), mReadBufferCapacity));
if (processSize == 0) {
return DEAD_OBJECT;
} else if (processSize < 0) {
@@ -173,7 +174,7 @@
}
}
- base::unique_fd mSocket;
+ RpcTransportFd mSocket;
// For now, we copy all the input data into a temporary buffer because
// we might get multiple interruptableReadFully calls per message, but
@@ -192,7 +193,7 @@
// RpcTransportCtx for Trusty.
class RpcTransportCtxTipcAndroid : public RpcTransportCtx {
public:
- std::unique_ptr<RpcTransport> newTransport(android::base::unique_fd fd,
+ std::unique_ptr<RpcTransport> newTransport(android::RpcTransportFd fd,
FdTrigger*) const override {
return std::make_unique<RpcTransportTipcAndroid>(std::move(fd));
}
diff --git a/libs/binder/RpcTransportTls.cpp b/libs/binder/RpcTransportTls.cpp
index 09b5c17..3e98ecc 100644
--- a/libs/binder/RpcTransportTls.cpp
+++ b/libs/binder/RpcTransportTls.cpp
@@ -182,8 +182,8 @@
// If |sslError| is WANT_READ / WANT_WRITE, poll for POLLIN / POLLOUT respectively. Otherwise
// return error. Also return error if |fdTrigger| is triggered before or during poll().
status_t pollForSslError(
- android::base::borrowed_fd fd, int sslError, FdTrigger* fdTrigger, const char* fnString,
- int additionalEvent,
+ const android::RpcTransportFd& fd, int sslError, FdTrigger* fdTrigger,
+ const char* fnString, int additionalEvent,
const std::optional<android::base::function_ref<status_t()>>& altPoll) {
switch (sslError) {
case SSL_ERROR_WANT_READ:
@@ -198,7 +198,7 @@
private:
bool mHandled = false;
- status_t handlePoll(int event, android::base::borrowed_fd fd, FdTrigger* fdTrigger,
+ status_t handlePoll(int event, const android::RpcTransportFd& fd, FdTrigger* fdTrigger,
const char* fnString,
const std::optional<android::base::function_ref<status_t()>>& altPoll) {
status_t ret;
@@ -277,7 +277,7 @@
class RpcTransportTls : public RpcTransport {
public:
- RpcTransportTls(android::base::unique_fd socket, Ssl ssl)
+ RpcTransportTls(RpcTransportFd socket, Ssl ssl)
: mSocket(std::move(socket)), mSsl(std::move(ssl)) {}
status_t pollRead(void) override;
status_t interruptableWriteFully(
@@ -290,8 +290,10 @@
const std::optional<android::base::function_ref<status_t()>>& altPoll,
std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) override;
+ bool isWaiting() { return mSocket.isInPollingState(); };
+
private:
- android::base::unique_fd mSocket;
+ android::RpcTransportFd mSocket;
Ssl mSsl;
};
@@ -350,7 +352,7 @@
int sslError = mSsl.getError(writeSize);
// TODO(b/195788248): BIO should contain the FdTrigger, and send(2) / recv(2) should be
// triggerablePoll()-ed. Then additionalEvent is no longer necessary.
- status_t pollStatus = errorQueue.pollForSslError(mSocket.get(), sslError, fdTrigger,
+ status_t pollStatus = errorQueue.pollForSslError(mSocket, sslError, fdTrigger,
"SSL_write", POLLIN, altPoll);
if (pollStatus != OK) return pollStatus;
// Do not advance buffer. Try SSL_write() again.
@@ -398,7 +400,7 @@
return DEAD_OBJECT;
}
int sslError = mSsl.getError(readSize);
- status_t pollStatus = errorQueue.pollForSslError(mSocket.get(), sslError, fdTrigger,
+ status_t pollStatus = errorQueue.pollForSslError(mSocket, sslError, fdTrigger,
"SSL_read", 0, altPoll);
if (pollStatus != OK) return pollStatus;
// Do not advance buffer. Try SSL_read() again.
@@ -409,8 +411,8 @@
}
// For |ssl|, set internal FD to |fd|, and do handshake. Handshake is triggerable by |fdTrigger|.
-bool setFdAndDoHandshake(Ssl* ssl, android::base::borrowed_fd fd, FdTrigger* fdTrigger) {
- bssl::UniquePtr<BIO> bio = newSocketBio(fd);
+bool setFdAndDoHandshake(Ssl* ssl, const android::RpcTransportFd& socket, FdTrigger* fdTrigger) {
+ bssl::UniquePtr<BIO> bio = newSocketBio(socket.fd);
TEST_AND_RETURN(false, bio != nullptr);
auto [_, errorQueue] = ssl->call(SSL_set_bio, bio.get(), bio.get());
(void)bio.release(); // SSL_set_bio takes ownership.
@@ -430,7 +432,7 @@
return false;
}
int sslError = ssl->getError(ret);
- status_t pollStatus = errorQueue.pollForSslError(fd, sslError, fdTrigger,
+ status_t pollStatus = errorQueue.pollForSslError(socket, sslError, fdTrigger,
"SSL_do_handshake", 0, std::nullopt);
if (pollStatus != OK) return false;
}
@@ -442,7 +444,7 @@
typename = std::enable_if_t<std::is_base_of_v<RpcTransportCtxTls, Impl>>>
static std::unique_ptr<RpcTransportCtxTls> create(
std::shared_ptr<RpcCertificateVerifier> verifier, RpcAuth* auth);
- std::unique_ptr<RpcTransport> newTransport(android::base::unique_fd fd,
+ std::unique_ptr<RpcTransport> newTransport(RpcTransportFd fd,
FdTrigger* fdTrigger) const override;
std::vector<uint8_t> getCertificate(RpcCertificateFormat) const override;
@@ -513,15 +515,15 @@
return ret;
}
-std::unique_ptr<RpcTransport> RpcTransportCtxTls::newTransport(android::base::unique_fd fd,
+std::unique_ptr<RpcTransport> RpcTransportCtxTls::newTransport(android::RpcTransportFd socket,
FdTrigger* fdTrigger) const {
bssl::UniquePtr<SSL> ssl(SSL_new(mCtx.get()));
TEST_AND_RETURN(nullptr, ssl != nullptr);
Ssl wrapped(std::move(ssl));
preHandshake(&wrapped);
- TEST_AND_RETURN(nullptr, setFdAndDoHandshake(&wrapped, fd, fdTrigger));
- return std::make_unique<RpcTransportTls>(std::move(fd), std::move(wrapped));
+ TEST_AND_RETURN(nullptr, setFdAndDoHandshake(&wrapped, socket, fdTrigger));
+ return std::make_unique<RpcTransportTls>(std::move(socket), std::move(wrapped));
}
class RpcTransportCtxTlsServer : public RpcTransportCtxTls {
diff --git a/libs/binder/RpcTransportUtils.h b/libs/binder/RpcTransportUtils.h
index 00cb2af..32f0db8 100644
--- a/libs/binder/RpcTransportUtils.h
+++ b/libs/binder/RpcTransportUtils.h
@@ -25,8 +25,8 @@
template <typename SendOrReceive>
status_t interruptableReadOrWrite(
- int socketFd, FdTrigger* fdTrigger, iovec* iovs, int niovs, SendOrReceive sendOrReceiveFun,
- const char* funName, int16_t event,
+ const android::RpcTransportFd& socket, FdTrigger* fdTrigger, iovec* iovs, int niovs,
+ SendOrReceive sendOrReceiveFun, const char* funName, int16_t event,
const std::optional<android::base::function_ref<status_t()>>& altPoll) {
MAYBE_WAIT_IN_FLAKE_MODE;
@@ -99,7 +99,7 @@
return DEAD_OBJECT;
}
} else {
- if (status_t status = fdTrigger->triggerablePoll(socketFd, event); status != OK)
+ if (status_t status = fdTrigger->triggerablePoll(socket, event); status != OK)
return status;
if (!havePolled) havePolled = true;
}
diff --git a/libs/binder/Trace.cpp b/libs/binder/Trace.cpp
new file mode 100644
index 0000000..1ebfa1a
--- /dev/null
+++ b/libs/binder/Trace.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 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 <binder/Trace.h>
+#include <cutils/trace.h>
+
+namespace android {
+namespace binder {
+
+void atrace_begin(uint64_t tag, const char* name) {
+ ::atrace_begin(tag, name);
+}
+
+void atrace_end(uint64_t tag) {
+ ::atrace_end(tag);
+}
+
+} // namespace binder
+} // namespace android
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index 52bda0e..2c99334 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -187,6 +187,11 @@
std::vector<sp<RpcSession>> listSessions();
size_t numUninitializedSessions();
+ /**
+ * Whether any requests are currently being processed.
+ */
+ bool hasActiveRequests();
+
~RpcServer();
private:
@@ -199,7 +204,7 @@
static constexpr size_t kRpcAddressSize = 128;
static void establishConnection(
- sp<RpcServer>&& server, base::unique_fd clientFd,
+ sp<RpcServer>&& server, RpcTransportFd clientFd,
std::array<uint8_t, kRpcAddressSize> addr, size_t addrLen,
std::function<void(sp<RpcSession>&&, RpcSession::PreJoinSetupResult&&)>&& joinFn);
[[nodiscard]] status_t setupSocketServer(const RpcSocketAddress& address);
@@ -210,7 +215,7 @@
// A mode is supported if the N'th bit is on, where N is the mode enum's value.
std::bitset<8> mSupportedFileDescriptorTransportModes = std::bitset<8>().set(
static_cast<size_t>(RpcSession::FileDescriptorTransportMode::NONE));
- base::unique_fd mServer; // socket we are accepting sessions on
+ RpcTransportFd mServer; // socket we are accepting sessions on
RpcMutex mLock; // for below
std::unique_ptr<RpcMaybeThread> mJoinThread;
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index 428e272..a25ba98 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -189,6 +189,11 @@
*/
[[nodiscard]] status_t sendDecStrong(const BpBinder* binder);
+ /**
+ * Whether any requests are currently being processed.
+ */
+ bool hasActiveRequests();
+
~RpcSession();
/**
@@ -269,7 +274,7 @@
[[nodiscard]] status_t setupOneSocketConnection(const RpcSocketAddress& address,
const std::vector<uint8_t>& sessionId,
bool incoming);
- [[nodiscard]] status_t initAndAddConnection(base::unique_fd fd,
+ [[nodiscard]] status_t initAndAddConnection(RpcTransportFd fd,
const std::vector<uint8_t>& sessionId,
bool incoming);
[[nodiscard]] status_t addIncomingConnection(std::unique_ptr<RpcTransport> rpcTransport);
@@ -286,6 +291,11 @@
[[nodiscard]] status_t initShutdownTrigger();
+ /**
+ * Checks whether any connection is active (Not polling on fd)
+ */
+ bool hasActiveConnection(const std::vector<sp<RpcConnection>>& connections);
+
enum class ConnectionUse {
CLIENT,
CLIENT_ASYNC,
diff --git a/libs/binder/include/binder/RpcTransport.h b/libs/binder/include/binder/RpcTransport.h
index 5197ef9..fd52a3a 100644
--- a/libs/binder/include/binder/RpcTransport.h
+++ b/libs/binder/include/binder/RpcTransport.h
@@ -30,12 +30,14 @@
#include <utils/Errors.h>
#include <binder/RpcCertificateFormat.h>
+#include <binder/RpcThreads.h>
#include <sys/uio.h>
namespace android {
class FdTrigger;
+struct RpcTransportFd;
// Represents a socket connection.
// No thread-safety is guaranteed for these APIs.
@@ -81,6 +83,15 @@
const std::optional<android::base::function_ref<status_t()>> &altPoll,
std::vector<std::variant<base::unique_fd, base::borrowed_fd>> *ancillaryFds) = 0;
+ /**
+ * Check whether any threads are blocked while polling the transport
+ * for read operations
+ * Return:
+ * True - Specifies that there is active polling on transport.
+ * False - No active polling on transport
+ */
+ [[nodiscard]] virtual bool isWaiting() = 0;
+
protected:
RpcTransport() = default;
};
@@ -96,7 +107,7 @@
// Implementation details: for TLS, this function may incur I/O. |fdTrigger| may be used
// to interrupt I/O. This function blocks until handshake is finished.
[[nodiscard]] virtual std::unique_ptr<RpcTransport> newTransport(
- android::base::unique_fd fd, FdTrigger *fdTrigger) const = 0;
+ android::RpcTransportFd fd, FdTrigger *fdTrigger) const = 0;
// Return the preconfigured certificate of this context.
//
@@ -129,4 +140,36 @@
RpcTransportCtxFactory() = default;
};
+struct RpcTransportFd {
+private:
+ mutable bool isPolling{false};
+
+ void setPollingState(bool state) const { isPolling = state; }
+
+public:
+ base::unique_fd fd;
+
+ RpcTransportFd() = default;
+ explicit RpcTransportFd(base::unique_fd &&descriptor)
+ : isPolling(false), fd(std::move(descriptor)) {}
+
+ RpcTransportFd(RpcTransportFd &&transportFd) noexcept
+ : isPolling(transportFd.isPolling), fd(std::move(transportFd.fd)) {}
+
+ RpcTransportFd &operator=(RpcTransportFd &&transportFd) noexcept {
+ fd = std::move(transportFd.fd);
+ isPolling = transportFd.isPolling;
+ return *this;
+ }
+
+ RpcTransportFd &operator=(base::unique_fd &&descriptor) noexcept {
+ fd = std::move(descriptor);
+ isPolling = false;
+ return *this;
+ }
+
+ bool isInPollingState() const { return isPolling; }
+ friend class FdTrigger;
+};
+
} // namespace android
diff --git a/libs/binder/include/binder/Trace.h b/libs/binder/include/binder/Trace.h
new file mode 100644
index 0000000..9937842
--- /dev/null
+++ b/libs/binder/include/binder/Trace.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 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 <cutils/trace.h>
+#include <stdint.h>
+
+namespace android {
+namespace binder {
+
+// Trampoline functions allowing generated aidls to trace binder transactions without depending on
+// libcutils/libutils
+void atrace_begin(uint64_t tag, const char* name);
+void atrace_end(uint64_t tag);
+
+class ScopedTrace {
+public:
+ inline ScopedTrace(uint64_t tag, const char* name) : mTag(tag) { atrace_begin(mTag, name); }
+
+ inline ~ScopedTrace() { atrace_end(mTag); }
+
+private:
+ uint64_t mTag;
+};
+
+} // namespace binder
+} // namespace android
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 32e018d..33d28e6 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -57,6 +57,7 @@
srcs: [
"ibinder.cpp",
"ibinder_jni.cpp",
+ "libbinder.cpp",
"parcel.cpp",
"parcel_jni.cpp",
"process.cpp",
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 9778ec0..28d1f16 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -14,21 +14,19 @@
* limitations under the License.
*/
+#include <android-base/logging.h>
#include <android/binder_ibinder.h>
#include <android/binder_ibinder_platform.h>
-#include <android/binder_libbinder.h>
-#include "ibinder_internal.h"
-
#include <android/binder_stability.h>
#include <android/binder_status.h>
-#include "parcel_internal.h"
-#include "status_internal.h"
-
-#include <android-base/logging.h>
#include <binder/IPCThreadState.h>
#include <binder/IResultReceiver.h>
#include <private/android_filesystem_config.h>
+#include "ibinder_internal.h"
+#include "parcel_internal.h"
+#include "status_internal.h"
+
using DeathRecipient = ::android::IBinder::DeathRecipient;
using ::android::IBinder;
@@ -782,17 +780,6 @@
return ::android::IPCThreadState::self()->getCallingSid();
}
-android::sp<android::IBinder> AIBinder_toPlatformBinder(AIBinder* binder) {
- if (binder == nullptr) return nullptr;
- return binder->getBinder();
-}
-
-AIBinder* AIBinder_fromPlatformBinder(const android::sp<android::IBinder>& binder) {
- sp<AIBinder> ndkBinder = ABpBinder::lookupOrCreateFromBinder(binder);
- AIBinder_incStrong(ndkBinder.get());
- return ndkBinder.get();
-}
-
void AIBinder_setMinSchedulerPolicy(AIBinder* binder, int policy, int priority) {
binder->asABBinder()->setMinSchedulerPolicy(policy, priority);
}
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
index 0bf1e3d..95eee26 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
@@ -1639,7 +1639,6 @@
return AParcel_writeParcelable(parcel, value);
} else {
static_assert(dependent_false_v<T>, "unrecognized type");
- return STATUS_OK;
}
}
@@ -1707,7 +1706,6 @@
return AParcel_readParcelable(parcel, value);
} else {
static_assert(dependent_false_v<T>, "unrecognized type");
- return STATUS_OK;
}
}
diff --git a/libs/binder/ndk/include_cpp/android/binder_to_string.h b/libs/binder/ndk/include_cpp/android/binder_to_string.h
index ef71a81..d7840ec 100644
--- a/libs/binder/ndk/include_cpp/android/binder_to_string.h
+++ b/libs/binder/ndk/include_cpp/android/binder_to_string.h
@@ -162,7 +162,12 @@
} else if constexpr (std::is_same_v<bool, _T>) {
return t ? "true" : "false";
} else if constexpr (std::is_same_v<char16_t, _T>) {
+ // TODO(b/244494451): codecvt is deprecated in C++17 -- suppress the
+ // warnings. There's no replacement in the standard library yet.
+ _Pragma("clang diagnostic push")
+ _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"");
return std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>().to_bytes(t);
+ _Pragma("clang diagnostic pop");
} else if constexpr (std::is_arithmetic_v<_T>) {
return std::to_string(t);
} else if constexpr (std::is_same_v<std::string, _T>) {
diff --git a/libs/binder/ndk/include_platform/android/binder_libbinder.h b/libs/binder/ndk/include_platform/android/binder_libbinder.h
index f0c00e8..dfe12a1 100644
--- a/libs/binder/ndk/include_platform/android/binder_libbinder.h
+++ b/libs/binder/ndk/include_platform/android/binder_libbinder.h
@@ -19,7 +19,9 @@
#if !defined(__ANDROID_APEX__) && !defined(__ANDROID_VNDK__)
#include <android/binder_ibinder.h>
+#include <android/binder_parcel.h>
#include <binder/IBinder.h>
+#include <binder/Parcel.h>
/**
* Get libbinder version of binder from AIBinder.
@@ -47,4 +49,26 @@
*/
AIBinder* AIBinder_fromPlatformBinder(const android::sp<android::IBinder>& binder);
+/**
+ * View libbinder version of parcel from AParcel (mutable).
+ *
+ * The lifetime of the returned parcel is the lifetime of the input AParcel.
+ * Do not ues this reference after dropping the AParcel.
+ *
+ * \param parcel non-null parcel with ownership retained by client
+ * \return platform parcel object
+ */
+android::Parcel* AParcel_viewPlatformParcel(AParcel* parcel);
+
+/**
+ * View libbinder version of parcel from AParcel (const version).
+ *
+ * The lifetime of the returned parcel is the lifetime of the input AParcel.
+ * Do not ues this reference after dropping the AParcel.
+ *
+ * \param parcel non-null parcel with ownership retained by client
+ * \return platform parcel object
+ */
+const android::Parcel* AParcel_viewPlatformParcel(const AParcel* parcel);
+
#endif
diff --git a/libs/binder/ndk/libbinder.cpp b/libs/binder/ndk/libbinder.cpp
new file mode 100644
index 0000000..f94d81d
--- /dev/null
+++ b/libs/binder/ndk/libbinder.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 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 <android/binder_libbinder.h>
+
+#include "ibinder_internal.h"
+#include "parcel_internal.h"
+
+using ::android::IBinder;
+using ::android::Parcel;
+using ::android::sp;
+
+sp<IBinder> AIBinder_toPlatformBinder(AIBinder* binder) {
+ if (binder == nullptr) return nullptr;
+ return binder->getBinder();
+}
+
+AIBinder* AIBinder_fromPlatformBinder(const sp<IBinder>& binder) {
+ sp<AIBinder> ndkBinder = ABpBinder::lookupOrCreateFromBinder(binder);
+ AIBinder_incStrong(ndkBinder.get());
+ return ndkBinder.get();
+}
+
+Parcel* AParcel_viewPlatformParcel(AParcel* parcel) {
+ return parcel->get();
+}
+
+const Parcel* AParcel_viewPlatformParcel(const AParcel* parcel) {
+ return parcel->get();
+}
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 6bc9814..259a736 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -158,6 +158,7 @@
extern "C++" {
AIBinder_fromPlatformBinder*;
AIBinder_toPlatformBinder*;
+ AParcel_viewPlatformParcel*;
};
local:
*;
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index 1b136dc..6d29238 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -661,6 +661,15 @@
}
}
+TEST(NdkBinder, ConvertToPlatformParcel) {
+ ndk::ScopedAParcel parcel = ndk::ScopedAParcel(AParcel_create());
+ EXPECT_EQ(OK, AParcel_writeInt32(parcel.get(), 42));
+
+ android::Parcel* pparcel = AParcel_viewPlatformParcel(parcel.get());
+ pparcel->setDataPosition(0);
+ EXPECT_EQ(42, pparcel->readInt32());
+}
+
class MyResultReceiver : public BnResultReceiver {
public:
Mutex mMutex;
diff --git a/libs/binder/rust/rpcbinder/Android.bp b/libs/binder/rust/rpcbinder/Android.bp
index 067ca0d..f169390 100644
--- a/libs/binder/rust/rpcbinder/Android.bp
+++ b/libs/binder/rust/rpcbinder/Android.bp
@@ -1,3 +1,12 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
rust_library {
name: "librpcbinder_rs",
crate_name: "rpcbinder",
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 1babfd5..e460d2c 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -341,6 +341,11 @@
"binderRpcTest_shared_defaults",
"libbinder_tls_shared_deps",
],
+
+ // Add the Trusty mock library as a fake dependency so it gets built
+ required: [
+ "libbinder_on_trusty_mock",
+ ],
}
cc_test {
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 4c037b7..21b0354 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -1773,7 +1773,7 @@
}
}
mFd = rpcServer->releaseServer();
- if (!mFd.ok()) return AssertionFailure() << "releaseServer returns invalid fd";
+ if (!mFd.fd.ok()) return AssertionFailure() << "releaseServer returns invalid fd";
mCtx = newFactory(rpcSecurity, mCertVerifier, std::move(auth))->newServerCtx();
if (mCtx == nullptr) return AssertionFailure() << "newServerCtx";
mSetup = true;
@@ -1794,7 +1794,7 @@
std::vector<std::thread> threads;
while (OK == mFdTrigger->triggerablePoll(mFd, POLLIN)) {
base::unique_fd acceptedFd(
- TEMP_FAILURE_RETRY(accept4(mFd.get(), nullptr, nullptr /*length*/,
+ TEMP_FAILURE_RETRY(accept4(mFd.fd.get(), nullptr, nullptr /*length*/,
SOCK_CLOEXEC | SOCK_NONBLOCK)));
threads.emplace_back(&Server::handleOne, this, std::move(acceptedFd));
}
@@ -1803,7 +1803,8 @@
}
void handleOne(android::base::unique_fd acceptedFd) {
ASSERT_TRUE(acceptedFd.ok());
- auto serverTransport = mCtx->newTransport(std::move(acceptedFd), mFdTrigger.get());
+ RpcTransportFd transportFd(std::move(acceptedFd));
+ auto serverTransport = mCtx->newTransport(std::move(transportFd), mFdTrigger.get());
if (serverTransport == nullptr) return; // handshake failed
ASSERT_TRUE(mPostConnect(serverTransport.get(), mFdTrigger.get()));
}
@@ -1822,7 +1823,7 @@
std::unique_ptr<std::thread> mThread;
ConnectToServer mConnectToServer;
std::unique_ptr<FdTrigger> mFdTrigger = FdTrigger::make();
- base::unique_fd mFd;
+ RpcTransportFd mFd;
std::unique_ptr<RpcTransportCtx> mCtx;
std::shared_ptr<RpcCertificateVerifierSimple> mCertVerifier =
std::make_shared<RpcCertificateVerifierSimple>();
@@ -1869,7 +1870,7 @@
// connect() and do handshake
bool setUpTransport() {
mFd = mConnectToServer();
- if (!mFd.ok()) return AssertionFailure() << "Cannot connect to server";
+ if (!mFd.fd.ok()) return AssertionFailure() << "Cannot connect to server";
mClientTransport = mCtx->newTransport(std::move(mFd), mFdTrigger.get());
return mClientTransport != nullptr;
}
@@ -1898,9 +1899,11 @@
ASSERT_EQ(readOk, readMessage());
}
+ bool isTransportWaiting() { return mClientTransport->isWaiting(); }
+
private:
ConnectToServer mConnectToServer;
- base::unique_fd mFd;
+ RpcTransportFd mFd;
std::unique_ptr<FdTrigger> mFdTrigger = FdTrigger::make();
std::unique_ptr<RpcTransportCtx> mCtx;
std::shared_ptr<RpcCertificateVerifierSimple> mCertVerifier =
@@ -2147,6 +2150,56 @@
ASSERT_FALSE(client.readMessage(msg2));
}
+TEST_P(RpcTransportTest, CheckWaitingForRead) {
+ std::mutex readMutex;
+ std::condition_variable readCv;
+ bool shouldContinueReading = false;
+ // Server will write data on transport once its started
+ auto serverPostConnect = [&](RpcTransport* serverTransport, FdTrigger* fdTrigger) {
+ std::string message(RpcTransportTestUtils::kMessage);
+ iovec messageIov{message.data(), message.size()};
+ auto status = serverTransport->interruptableWriteFully(fdTrigger, &messageIov, 1,
+ std::nullopt, nullptr);
+ if (status != OK) return AssertionFailure() << statusToString(status);
+
+ {
+ std::unique_lock<std::mutex> lock(readMutex);
+ shouldContinueReading = true;
+ lock.unlock();
+ readCv.notify_all();
+ }
+ return AssertionSuccess();
+ };
+
+ // Setup Server and client
+ auto server = std::make_unique<Server>();
+ ASSERT_TRUE(server->setUp(GetParam()));
+
+ Client client(server->getConnectToServerFn());
+ ASSERT_TRUE(client.setUp(GetParam()));
+
+ ASSERT_EQ(OK, trust(&client, server));
+ ASSERT_EQ(OK, trust(server, &client));
+ server->setPostConnect(serverPostConnect);
+
+ server->start();
+ ASSERT_TRUE(client.setUpTransport());
+ {
+ // Wait till server writes data
+ std::unique_lock<std::mutex> lock(readMutex);
+ ASSERT_TRUE(readCv.wait_for(lock, 3s, [&] { return shouldContinueReading; }));
+ }
+
+ // Since there is no read polling here, we will get polling count 0
+ ASSERT_FALSE(client.isTransportWaiting());
+ ASSERT_TRUE(client.readMessage(RpcTransportTestUtils::kMessage));
+ // Thread should increment polling count, read and decrement polling count
+ // Again, polling count should be zero here
+ ASSERT_FALSE(client.isTransportWaiting());
+
+ server->shutdown();
+}
+
INSTANTIATE_TEST_CASE_P(BinderRpc, RpcTransportTest,
::testing::ValuesIn(RpcTransportTest::getRpcTranportTestParams()),
RpcTransportTest::PrintParamInfo);
diff --git a/libs/binder/tests/parcel_fuzzer/binder_ndk.h b/libs/binder/tests/parcel_fuzzer/binder_ndk.h
index 81e79b5..d19f25b 100644
--- a/libs/binder/tests/parcel_fuzzer/binder_ndk.h
+++ b/libs/binder/tests/parcel_fuzzer/binder_ndk.h
@@ -18,29 +18,27 @@
#include <android/binder_auto_utils.h>
#include <vector>
+#include <android/binder_libbinder.h>
#include <android/binder_parcel.h>
#include "parcel_fuzzer.h"
-// libbinder_ndk doesn't export this header which breaks down its API for NDK
-// and APEX users, but we need access to it to fuzz.
-#include "../../ndk/parcel_internal.h"
-
class NdkParcelAdapter {
public:
- NdkParcelAdapter() : mParcel(new AParcel(nullptr /*binder*/)) {}
+ NdkParcelAdapter() : mParcel(AParcel_create()) {}
const AParcel* aParcel() const { return mParcel.get(); }
AParcel* aParcel() { return mParcel.get(); }
- android::Parcel* parcel() { return aParcel()->get(); }
+ const android::Parcel* parcel() const { return AParcel_viewPlatformParcel(aParcel()); }
+ android::Parcel* parcel() { return AParcel_viewPlatformParcel(aParcel()); }
- const uint8_t* data() const { return aParcel()->get()->data(); }
- size_t dataSize() const { return aParcel()->get()->dataSize(); }
- size_t dataAvail() const { return aParcel()->get()->dataAvail(); }
- size_t dataPosition() const { return aParcel()->get()->dataPosition(); }
- size_t dataCapacity() const { return aParcel()->get()->dataCapacity(); }
+ const uint8_t* data() const { return parcel()->data(); }
+ size_t dataSize() const { return parcel()->dataSize(); }
+ size_t dataAvail() const { return parcel()->dataAvail(); }
+ size_t dataPosition() const { return parcel()->dataPosition(); }
+ size_t dataCapacity() const { return parcel()->dataCapacity(); }
android::status_t setData(const uint8_t* buffer, size_t len) {
- return aParcel()->get()->setData(buffer, len);
+ return parcel()->setData(buffer, len);
}
android::status_t appendFrom(const NdkParcelAdapter* parcel, int32_t start, int32_t len) {
diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
index 32494e3..25f6096 100644
--- a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
+++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
@@ -17,6 +17,9 @@
#include <fuzzbinder/random_parcel.h>
+#include <android-base/logging.h>
+#include <binder/ProcessState.h>
+
namespace android {
void fuzzService(const sp<IBinder>& binder, FuzzedDataProvider&& provider) {
@@ -60,6 +63,15 @@
options.extraFds.push_back(base::unique_fd(dup(retFds[i])));
}
}
+
+ // invariants
+
+ auto ps = ProcessState::selfOrNull();
+ if (ps) {
+ CHECK_EQ(0, ps->getThreadPoolMaxTotalThreadCount())
+ << "Binder threadpool should not be started by fuzzer because coverage can only "
+ "cover in-process calls.";
+ }
}
} // namespace android
diff --git a/libs/binder/tests/rpc_fuzzer/main.cpp b/libs/binder/tests/rpc_fuzzer/main.cpp
index a8713a2..f68a561 100644
--- a/libs/binder/tests/rpc_fuzzer/main.cpp
+++ b/libs/binder/tests/rpc_fuzzer/main.cpp
@@ -157,8 +157,6 @@
}
}
- usleep(10000);
-
if (hangupBeforeShutdown) {
connections.clear();
while (!server->listSessions().empty() || server->numUninitializedSessions()) {
@@ -167,6 +165,10 @@
}
}
+ while (server->hasActiveRequests()) {
+ usleep(10);
+ }
+
while (!server->shutdown()) usleep(1);
serverThread.join();
diff --git a/libs/binder/trusty/OS.cpp b/libs/binder/trusty/OS.cpp
index b21fe6a..46346bb 100644
--- a/libs/binder/trusty/OS.cpp
+++ b/libs/binder/trusty/OS.cpp
@@ -20,13 +20,15 @@
#include <lib/rand/rand.h>
#endif
+#include <binder/RpcTransportTipcTrusty.h>
+
#include "../OS.h"
using android::base::Result;
namespace android {
-Result<void> setNonBlocking(android::base::borrowed_fd fd) {
+Result<void> setNonBlocking(android::base::borrowed_fd /*fd*/) {
// Trusty IPC syscalls are all non-blocking by default.
return {};
}
@@ -41,9 +43,13 @@
#endif // TRUSTY_USERSPACE
}
-status_t dupFileDescriptor(int oldFd, int* newFd) {
+status_t dupFileDescriptor(int /*oldFd*/, int* /*newFd*/) {
// TODO: implement separately
return INVALID_OPERATION;
}
+std::unique_ptr<RpcTransportCtxFactory> makeDefaultRpcTransportCtxFactory() {
+ return RpcTransportCtxFactoryTipcTrusty::make();
+}
+
} // namespace android
diff --git a/libs/binder/trusty/RpcServerTrusty.cpp b/libs/binder/trusty/RpcServerTrusty.cpp
index c789614..18ce316 100644
--- a/libs/binder/trusty/RpcServerTrusty.cpp
+++ b/libs/binder/trusty/RpcServerTrusty.cpp
@@ -118,16 +118,18 @@
};
base::unique_fd clientFd(chan);
+ android::RpcTransportFd transportFd(std::move(clientFd));
+
std::array<uint8_t, RpcServer::kRpcAddressSize> addr;
constexpr size_t addrLen = sizeof(*peer);
memcpy(addr.data(), peer, addrLen);
- RpcServer::establishConnection(sp(server->mRpcServer), std::move(clientFd), addr, addrLen,
+ RpcServer::establishConnection(sp(server->mRpcServer), std::move(transportFd), addr, addrLen,
joinFn);
return rc;
}
-int RpcServerTrusty::handleMessage(const tipc_port* port, handle_t chan, void* ctx) {
+int RpcServerTrusty::handleMessage(const tipc_port* /*port*/, handle_t /*chan*/, void* ctx) {
auto* channelContext = reinterpret_cast<ChannelContext*>(ctx);
LOG_ALWAYS_FATAL_IF(channelContext == nullptr,
"bad state: message received on uninitialized channel");
@@ -144,7 +146,8 @@
return NO_ERROR;
}
-void RpcServerTrusty::handleDisconnect(const tipc_port* port, handle_t chan, void* ctx) {}
+void RpcServerTrusty::handleDisconnect(const tipc_port* /*port*/, handle_t /*chan*/,
+ void* /*ctx*/) {}
void RpcServerTrusty::handleChannelCleanup(void* ctx) {
auto* channelContext = reinterpret_cast<ChannelContext*>(ctx);
diff --git a/libs/binder/trusty/RpcTransportTipcTrusty.cpp b/libs/binder/trusty/RpcTransportTipcTrusty.cpp
index dc27eb9..0b67b9f 100644
--- a/libs/binder/trusty/RpcTransportTipcTrusty.cpp
+++ b/libs/binder/trusty/RpcTransportTipcTrusty.cpp
@@ -33,7 +33,7 @@
// RpcTransport for Trusty.
class RpcTransportTipcTrusty : public RpcTransport {
public:
- explicit RpcTransportTipcTrusty(android::base::unique_fd socket) : mSocket(std::move(socket)) {}
+ explicit RpcTransportTipcTrusty(android::RpcTransportFd socket) : mSocket(std::move(socket)) {}
~RpcTransportTipcTrusty() { releaseMessage(); }
status_t pollRead() override {
@@ -45,9 +45,9 @@
}
status_t interruptableWriteFully(
- FdTrigger* fdTrigger, iovec* iovs, int niovs,
- const std::optional<android::base::function_ref<status_t()>>& altPoll,
- const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds)
+ FdTrigger* /*fdTrigger*/, iovec* iovs, int niovs,
+ const std::optional<android::base::function_ref<status_t()>>& /*altPoll*/,
+ const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* /*ancillaryFds*/)
override {
if (niovs < 0) {
return BAD_VALUE;
@@ -64,7 +64,7 @@
.num_handles = 0, // TODO: add ancillaryFds
.handles = nullptr,
};
- ssize_t rc = send_msg(mSocket.get(), &msg);
+ ssize_t rc = send_msg(mSocket.fd.get(), &msg);
if (rc == ERR_NOT_ENOUGH_BUFFER) {
// Peer is blocked, wait until it unblocks.
// TODO: when tipc supports a send-unblocked handler,
@@ -72,7 +72,7 @@
// when the handler gets called by the library
uevent uevt;
do {
- rc = ::wait(mSocket.get(), &uevt, INFINITE_TIME);
+ rc = ::wait(mSocket.fd.get(), &uevt, INFINITE_TIME);
if (rc < 0) {
return statusFromTrusty(rc);
}
@@ -83,7 +83,7 @@
// Retry the send, it should go through this time because
// sending is now unblocked
- rc = send_msg(mSocket.get(), &msg);
+ rc = send_msg(mSocket.fd.get(), &msg);
}
if (rc < 0) {
return statusFromTrusty(rc);
@@ -95,9 +95,10 @@
}
status_t interruptableReadFully(
- FdTrigger* fdTrigger, iovec* iovs, int niovs,
- const std::optional<android::base::function_ref<status_t()>>& altPoll,
- std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) override {
+ FdTrigger* /*fdTrigger*/, iovec* iovs, int niovs,
+ const std::optional<android::base::function_ref<status_t()>>& /*altPoll*/,
+ std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* /*ancillaryFds*/)
+ override {
if (niovs < 0) {
return BAD_VALUE;
}
@@ -129,7 +130,7 @@
.num_handles = 0, // TODO: support ancillaryFds
.handles = nullptr,
};
- ssize_t rc = read_msg(mSocket.get(), mMessageInfo.id, mMessageOffset, &msg);
+ ssize_t rc = read_msg(mSocket.fd.get(), mMessageInfo.id, mMessageOffset, &msg);
if (rc < 0) {
return statusFromTrusty(rc);
}
@@ -169,6 +170,8 @@
}
}
+ bool isWaiting() override { return mSocket.isInPollingState(); }
+
private:
status_t ensureMessage(bool wait) {
int rc;
@@ -179,7 +182,7 @@
/* TODO: interruptible wait, maybe with a timeout??? */
uevent uevt;
- rc = ::wait(mSocket.get(), &uevt, wait ? INFINITE_TIME : 0);
+ rc = ::wait(mSocket.fd.get(), &uevt, wait ? INFINITE_TIME : 0);
if (rc < 0) {
if (rc == ERR_TIMED_OUT && !wait) {
// If we timed out with wait==false, then there's no message
@@ -192,7 +195,7 @@
return OK;
}
- rc = get_msg(mSocket.get(), &mMessageInfo);
+ rc = get_msg(mSocket.fd.get(), &mMessageInfo);
if (rc < 0) {
return statusFromTrusty(rc);
}
@@ -204,12 +207,12 @@
void releaseMessage() {
if (mHaveMessage) {
- put_msg(mSocket.get(), mMessageInfo.id);
+ put_msg(mSocket.fd.get(), mMessageInfo.id);
mHaveMessage = false;
}
}
- base::unique_fd mSocket;
+ android::RpcTransportFd mSocket;
bool mHaveMessage = false;
ipc_msg_info mMessageInfo;
@@ -219,9 +222,9 @@
// RpcTransportCtx for Trusty.
class RpcTransportCtxTipcTrusty : public RpcTransportCtx {
public:
- std::unique_ptr<RpcTransport> newTransport(android::base::unique_fd fd,
+ std::unique_ptr<RpcTransport> newTransport(android::RpcTransportFd socket,
FdTrigger*) const override {
- return std::make_unique<RpcTransportTipcTrusty>(std::move(fd));
+ return std::make_unique<RpcTransportTipcTrusty>(std::move(socket));
}
std::vector<uint8_t> getCertificate(RpcCertificateFormat) const override { return {}; }
};
diff --git a/libs/binder/trusty/include_mock/lib/tipc/tipc_srv.h b/libs/binder/trusty/include_mock/lib/tipc/tipc_srv.h
new file mode 100644
index 0000000..2747314
--- /dev/null
+++ b/libs/binder/trusty/include_mock/lib/tipc/tipc_srv.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <stddef.h>
+#include <trusty_ipc.h>
+#include <uapi/trusty_uuid.h>
+
+struct tipc_port_acl {
+ uint32_t flags;
+ uint32_t uuid_num;
+ const struct uuid** uuids;
+ const void* extra_data;
+};
+
+struct tipc_port {
+ const char* name;
+ uint32_t msg_max_size;
+ uint32_t msg_queue_len;
+ const struct tipc_port_acl* acl;
+ const void* priv;
+};
+
+struct tipc_srv_ops {
+ int (*on_connect)(const struct tipc_port* port, handle_t chan, const struct uuid* peer,
+ void** ctx_p);
+
+ int (*on_message)(const struct tipc_port* port, handle_t chan, void* ctx);
+
+ void (*on_disconnect)(const struct tipc_port* port, handle_t chan, void* ctx);
+
+ void (*on_channel_cleanup)(void* ctx);
+};
+
+static inline int tipc_add_service(struct tipc_hset*, const struct tipc_port*, uint32_t, uint32_t,
+ const struct tipc_srv_ops*) {
+ return 0;
+}
diff --git a/libs/binder/trusty/include_mock/openssl/rand.h b/libs/binder/trusty/include_mock/openssl/rand.h
new file mode 100644
index 0000000..07dcc1c
--- /dev/null
+++ b/libs/binder/trusty/include_mock/openssl/rand.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 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
+
+static inline int RAND_bytes(unsigned char*, int) {
+ return 0;
+}
diff --git a/libs/binder/trusty/include_mock/trusty_ipc.h b/libs/binder/trusty/include_mock/trusty_ipc.h
new file mode 100644
index 0000000..a2170ce
--- /dev/null
+++ b/libs/binder/trusty/include_mock/trusty_ipc.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 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 <stddef.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <uapi/trusty_uuid.h>
+
+#define INFINITE_TIME 1
+#define IPC_MAX_MSG_HANDLES 8
+
+#define IPC_HANDLE_POLL_HUP 0x1
+#define IPC_HANDLE_POLL_MSG 0x2
+#define IPC_HANDLE_POLL_SEND_UNBLOCKED 0x4
+
+typedef int handle_t;
+
+typedef struct ipc_msg {
+ uint32_t num_iov;
+ iovec* iov;
+ uint32_t num_handles;
+ handle_t* handles;
+} ipc_msg_t;
+
+typedef struct ipc_msg_info {
+ size_t len;
+ uint32_t id;
+ uint32_t num_handles;
+} ipc_msg_info_t;
+
+typedef struct uevent {
+ uint32_t event;
+} uevent_t;
+
+static inline handle_t port_create(const char*, uint32_t, uint32_t, uint32_t) {
+ return 0;
+}
+static inline handle_t connect(const char*, uint32_t) {
+ return 0;
+}
+static inline handle_t accept(handle_t, uuid_t*) {
+ return 0;
+}
+static inline int set_cookie(handle_t, void*) {
+ return 0;
+}
+static inline handle_t handle_set_create(void) {
+ return 0;
+}
+static inline int handle_set_ctrl(handle_t, uint32_t, struct uevent*) {
+ return 0;
+}
+static inline int wait(handle_t, uevent_t*, uint32_t) {
+ return 0;
+}
+static inline int wait_any(uevent_t*, uint32_t) {
+ return 0;
+}
+static inline int get_msg(handle_t, ipc_msg_info_t*) {
+ return 0;
+}
+static inline ssize_t read_msg(handle_t, uint32_t, uint32_t, ipc_msg_t*) {
+ return 0;
+}
+static inline int put_msg(handle_t, uint32_t) {
+ return 0;
+}
+static inline ssize_t send_msg(handle_t, ipc_msg_t*) {
+ return 0;
+}
diff --git a/libs/binder/trusty/include_mock/trusty_log.h b/libs/binder/trusty/include_mock/trusty_log.h
new file mode 100644
index 0000000..d51e752
--- /dev/null
+++ b/libs/binder/trusty/include_mock/trusty_log.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 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 <stdio.h>
+
+// Mock definitions for the Trusty logging macros. These are not
+// meant to be run, just compiled successfully.
+#define TLOGD(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#define TLOGI(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#define TLOGW(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#define TLOGE(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#define TLOGC(fmt, ...) printf(fmt, ##__VA_ARGS__)
diff --git a/libs/binder/trusty/include_mock/uapi/err.h b/libs/binder/trusty/include_mock/uapi/err.h
new file mode 100644
index 0000000..c7e117e
--- /dev/null
+++ b/libs/binder/trusty/include_mock/uapi/err.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 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
+
+enum {
+ NO_ERROR,
+ ERR_ACCESS_DENIED,
+ ERR_ALREADY_EXISTS,
+ ERR_BAD_HANDLE,
+ ERR_BAD_LEN,
+ ERR_BAD_STATE,
+ ERR_CHANNEL_CLOSED,
+ ERR_CMD_UNKNOWN,
+ ERR_GENERIC,
+ ERR_INVALID_ARGS,
+ ERR_NO_MEMORY,
+ ERR_NO_MSG,
+ ERR_NOT_ALLOWED,
+ ERR_NOT_CONFIGURED,
+ ERR_NOT_ENOUGH_BUFFER,
+ ERR_NOT_FOUND,
+ ERR_NOT_READY,
+ ERR_NOT_SUPPORTED,
+ ERR_NOT_VALID,
+ ERR_TIMED_OUT,
+ ERR_TOO_BIG,
+};
diff --git a/libs/binder/trusty/include_mock/uapi/trusty_uuid.h b/libs/binder/trusty/include_mock/uapi/trusty_uuid.h
new file mode 100644
index 0000000..f636826
--- /dev/null
+++ b/libs/binder/trusty/include_mock/uapi/trusty_uuid.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 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
+
+typedef struct uuid {
+ int placeholder;
+} uuid_t;
diff --git a/libs/binder/trusty/logging.cpp b/libs/binder/trusty/logging.cpp
index fd54744..b4243af 100644
--- a/libs/binder/trusty/logging.cpp
+++ b/libs/binder/trusty/logging.cpp
@@ -54,7 +54,7 @@
abort();
}
-static void TrustyLogLine(const char* msg, int length, android::base::LogSeverity severity,
+static void TrustyLogLine(const char* msg, int /*length*/, android::base::LogSeverity severity,
const char* tag) {
switch (severity) {
case VERBOSE:
@@ -157,7 +157,7 @@
TrustyLogger(DEFAULT, severity, tag ?: "<unknown>", file, line, message);
}
-bool ShouldLog(LogSeverity severity, const char* tag) {
+bool ShouldLog(LogSeverity /*severity*/, const char* /*tag*/) {
// This is controlled by Trusty's log level.
return true;
}
diff --git a/libs/binder/trusty/rules.mk b/libs/binder/trusty/rules.mk
index d0d0861..4e5cd18 100644
--- a/libs/binder/trusty/rules.mk
+++ b/libs/binder/trusty/rules.mk
@@ -76,7 +76,6 @@
$(LIBBINDER_DIR)/ndk/include_cpp \
MODULE_EXPORT_COMPILEFLAGS += \
- -DBINDER_NO_KERNEL_IPC \
-DBINDER_RPC_SINGLE_THREADED \
-D__ANDROID_VNDK__ \
diff --git a/libs/binderthreadstate/test.cpp b/libs/binderthreadstate/test.cpp
index 44e2fd1..2f73137 100644
--- a/libs/binderthreadstate/test.cpp
+++ b/libs/binderthreadstate/test.cpp
@@ -68,8 +68,13 @@
static void callAidl(size_t id, int32_t idx) {
sp<IAidlStuff> stuff;
- CHECK(OK == android::getService<IAidlStuff>(String16(id2name(id).c_str()), &stuff));
- CHECK(stuff->call(idx).isOk());
+ CHECK_EQ(OK, android::getService<IAidlStuff>(String16(id2name(id).c_str()), &stuff));
+ auto ret = stuff->call(idx);
+ CHECK(ret.isOk()) << ret;
+}
+
+static inline std::ostream& operator<<(std::ostream& o, const BinderCallType& s) {
+ return o << static_cast<std::underlying_type_t<BinderCallType>>(s);
}
class HidlServer : public IHidlStuff {
@@ -79,13 +84,13 @@
size_t otherId;
Return<void> callLocal() {
- CHECK(BinderCallType::NONE == getCurrentServingCall());
+ CHECK_EQ(BinderCallType::NONE, getCurrentServingCall());
return android::hardware::Status::ok();
}
Return<void> call(int32_t idx) {
LOG(INFO) << "HidlServer CALL " << thisId << " to " << otherId << " at idx: " << idx
<< " with tid: " << gettid();
- CHECK(BinderCallType::HWBINDER == getCurrentServingCall());
+ CHECK_EQ(BinderCallType::HWBINDER, getCurrentServingCall());
if (idx > 0) {
if (thisId == kP1Id && idx % 4 < 2) {
callHidl(otherId, idx - 1);
@@ -93,7 +98,7 @@
callAidl(otherId, idx - 1);
}
}
- CHECK(BinderCallType::HWBINDER == getCurrentServingCall());
+ CHECK_EQ(BinderCallType::HWBINDER, getCurrentServingCall());
return android::hardware::Status::ok();
}
};
@@ -104,13 +109,13 @@
size_t otherId;
Status callLocal() {
- CHECK(BinderCallType::NONE == getCurrentServingCall());
+ CHECK_EQ(BinderCallType::NONE, getCurrentServingCall());
return Status::ok();
}
Status call(int32_t idx) {
LOG(INFO) << "AidlServer CALL " << thisId << " to " << otherId << " at idx: " << idx
<< " with tid: " << gettid();
- CHECK(BinderCallType::BINDER == getCurrentServingCall());
+ CHECK_EQ(BinderCallType::BINDER, getCurrentServingCall());
if (idx > 0) {
if (thisId == kP2Id && idx % 4 < 2) {
callHidl(otherId, idx - 1);
@@ -118,7 +123,7 @@
callAidl(otherId, idx - 1);
}
}
- CHECK(BinderCallType::BINDER == getCurrentServingCall());
+ CHECK_EQ(BinderCallType::BINDER, getCurrentServingCall());
return Status::ok();
}
};
@@ -161,13 +166,14 @@
// AIDL
android::ProcessState::self()->setThreadPoolMaxThreadCount(1);
sp<AidlServer> aidlServer = new AidlServer(thisId, otherId);
- CHECK(OK == defaultServiceManager()->addService(String16(id2name(thisId).c_str()), aidlServer));
+ CHECK_EQ(OK,
+ defaultServiceManager()->addService(String16(id2name(thisId).c_str()), aidlServer));
android::ProcessState::self()->startThreadPool();
// HIDL
android::hardware::configureRpcThreadpool(1, true /*callerWillJoin*/);
sp<IHidlStuff> hidlServer = new HidlServer(thisId, otherId);
- CHECK(OK == hidlServer->registerAsService(id2name(thisId).c_str()));
+ CHECK_EQ(OK, hidlServer->registerAsService(id2name(thisId).c_str()));
android::hardware::joinRpcThreadpool();
return EXIT_FAILURE;
diff --git a/libs/ftl/optional_test.cpp b/libs/ftl/optional_test.cpp
index ede159a..f7410c2 100644
--- a/libs/ftl/optional_test.cpp
+++ b/libs/ftl/optional_test.cpp
@@ -20,6 +20,7 @@
#include <ftl/unit.h>
#include <gtest/gtest.h>
+#include <cstdlib>
#include <functional>
#include <numeric>
#include <utility>
@@ -32,6 +33,29 @@
using ftl::Optional;
using ftl::StaticVector;
+TEST(Optional, Construct) {
+ // Empty.
+ EXPECT_EQ(std::nullopt, Optional<int>());
+ EXPECT_EQ(std::nullopt, Optional<std::string>(std::nullopt));
+
+ // Value.
+ EXPECT_EQ('?', Optional('?'));
+ EXPECT_EQ(""s, Optional(std::string()));
+
+ // In place.
+ EXPECT_EQ("???"s, Optional<std::string>(std::in_place, 3u, '?'));
+ EXPECT_EQ("abc"s, Optional<std::string>(std::in_place, {'a', 'b', 'c'}));
+
+ // Implicit downcast.
+ {
+ Optional opt = std::optional("test"s);
+ static_assert(std::is_same_v<decltype(opt), Optional<std::string>>);
+
+ ASSERT_TRUE(opt);
+ EXPECT_EQ(opt.value(), "test"s);
+ }
+}
+
TEST(Optional, Transform) {
// Empty.
EXPECT_EQ(std::nullopt, Optional<int>().transform([](int) { return 0; }));
@@ -82,4 +106,62 @@
.transform([](const std::string& s) { return s.length(); }));
}
+namespace {
+
+Optional<int> parse_int(const std::string& str) {
+ if (const int i = std::atoi(str.c_str())) return i;
+ return std::nullopt;
+}
+
+} // namespace
+
+TEST(Optional, AndThen) {
+ // Empty.
+ EXPECT_EQ(std::nullopt, Optional<int>().and_then([](int) -> Optional<int> { return 0; }));
+ EXPECT_EQ(std::nullopt, Optional<int>().and_then([](int) { return Optional<int>(); }));
+
+ // By value.
+ EXPECT_EQ(0, Optional(0).and_then([](int x) { return Optional(x); }));
+ EXPECT_EQ(123, Optional("123").and_then(parse_int));
+ EXPECT_EQ(std::nullopt, Optional("abc").and_then(parse_int));
+
+ // By reference.
+ {
+ Optional opt = 'x';
+ EXPECT_EQ('z', opt.and_then([](char& c) {
+ c = 'y';
+ return Optional('z');
+ }));
+
+ EXPECT_EQ('y', opt);
+ }
+
+ // By rvalue reference.
+ {
+ std::string out;
+ EXPECT_EQ("xyz"s, Optional("abc"s).and_then([&out](std::string&& str) {
+ out = std::move(str);
+ return Optional("xyz"s);
+ }));
+
+ EXPECT_EQ(out, "abc"s);
+ }
+
+ // Chaining.
+ using StringVector = StaticVector<std::string, 3>;
+ EXPECT_EQ(14u, Optional(StaticVector{"-"s, "1"s})
+ .and_then([](StringVector&& v) -> Optional<StringVector> {
+ if (v.push_back("4"s)) return v;
+ return {};
+ })
+ .and_then([](const StringVector& v) -> Optional<std::string> {
+ if (v.full()) return std::accumulate(v.begin(), v.end(), std::string());
+ return {};
+ })
+ .and_then(parse_int)
+ .and_then([](int i) {
+ return i > 0 ? std::nullopt : std::make_optional(static_cast<unsigned>(-i));
+ }));
+}
+
} // namespace android::test
diff --git a/libs/gralloc/types/Android.bp b/libs/gralloc/types/Android.bp
index bd21fba..3d81c32 100644
--- a/libs/gralloc/types/Android.bp
+++ b/libs/gralloc/types/Android.bp
@@ -23,6 +23,7 @@
cc_library {
name: "libgralloctypes",
+ defaults: ["android.hardware.graphics.common-ndk_shared"],
cflags: [
"-Wall",
"-Werror",
@@ -51,7 +52,6 @@
],
shared_libs: [
- "android.hardware.graphics.common-V3-ndk",
"android.hardware.graphics.mapper@4.0",
"libhidlbase",
"liblog",
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index e138212..d3144bb 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -336,6 +336,8 @@
cc_defaults {
name: "libgui_bufferqueue-defaults",
+ defaults: ["android.hardware.graphics.common-ndk_shared"],
+
cflags: [
"-Wall",
"-Werror",
@@ -364,7 +366,6 @@
"android.hardware.graphics.bufferqueue@2.0",
"android.hardware.graphics.common@1.1",
"android.hardware.graphics.common@1.2",
- "android.hardware.graphics.common-V3-ndk",
"android.hidl.token@1.0-utils",
"libbase",
"libcutils",
diff --git a/libs/gui/OWNERS b/libs/gui/OWNERS
index 31bf895..05b5533 100644
--- a/libs/gui/OWNERS
+++ b/libs/gui/OWNERS
@@ -2,8 +2,9 @@
alecmouri@google.com
chaviw@google.com
chrisforbes@google.com
-lpy@google.com
jreck@google.com
+lpy@google.com
+pdwilliams@google.com
racarr@google.com
vishnun@google.com
diff --git a/libs/gui/ScreenCaptureResults.cpp b/libs/gui/ScreenCaptureResults.cpp
index fe38706..601a5f9 100644
--- a/libs/gui/ScreenCaptureResults.cpp
+++ b/libs/gui/ScreenCaptureResults.cpp
@@ -17,6 +17,7 @@
#include <gui/ScreenCaptureResults.h>
#include <private/gui/ParcelUtils.h>
+#include <ui/FenceResult.h>
namespace android::gui {
@@ -28,17 +29,17 @@
SAFE_PARCEL(parcel->writeBool, false);
}
- if (fence != Fence::NO_FENCE) {
+ if (fenceResult.ok() && fenceResult.value() != Fence::NO_FENCE) {
SAFE_PARCEL(parcel->writeBool, true);
- SAFE_PARCEL(parcel->write, *fence);
+ SAFE_PARCEL(parcel->write, *fenceResult.value());
} else {
SAFE_PARCEL(parcel->writeBool, false);
+ SAFE_PARCEL(parcel->writeInt32, fenceStatus(fenceResult));
}
SAFE_PARCEL(parcel->writeBool, capturedSecureLayers);
SAFE_PARCEL(parcel->writeBool, capturedHdrLayers);
SAFE_PARCEL(parcel->writeUint32, static_cast<uint32_t>(capturedDataspace));
- SAFE_PARCEL(parcel->writeInt32, result);
return NO_ERROR;
}
@@ -53,8 +54,13 @@
bool hasFence;
SAFE_PARCEL(parcel->readBool, &hasFence);
if (hasFence) {
- fence = new Fence();
- SAFE_PARCEL(parcel->read, *fence);
+ fenceResult = sp<Fence>::make();
+ SAFE_PARCEL(parcel->read, *fenceResult.value());
+ } else {
+ status_t status;
+ SAFE_PARCEL(parcel->readInt32, &status);
+ fenceResult = status == NO_ERROR ? FenceResult(Fence::NO_FENCE)
+ : FenceResult(base::unexpected(status));
}
SAFE_PARCEL(parcel->readBool, &capturedSecureLayers);
@@ -62,7 +68,6 @@
uint32_t dataspace = 0;
SAFE_PARCEL(parcel->readUint32, &dataspace);
capturedDataspace = static_cast<ui::Dataspace>(dataspace);
- SAFE_PARCEL(parcel->readInt32, &result);
return NO_ERROR;
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 34edd65..3671a15 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -2715,12 +2715,16 @@
ComposerServiceAIDL::getComposerService()->getDisplayDecorationSupport(displayToken,
&gsupport);
std::optional<DisplayDecorationSupport> support;
- if (status.isOk() && gsupport.has_value()) {
- support->format = static_cast<aidl::android::hardware::graphics::common::PixelFormat>(
- gsupport->format);
- support->alphaInterpretation =
+ // TODO (b/241277093): Remove `false && ` once b/241278870 is fixed.
+ if (false && status.isOk() && gsupport.has_value()) {
+ support.emplace(DisplayDecorationSupport{
+ .format =
+ static_cast<aidl::android::hardware::graphics::common::PixelFormat>(
+ gsupport->format),
+ .alphaInterpretation =
static_cast<aidl::android::hardware::graphics::common::AlphaInterpretation>(
- gsupport->alphaInterpretation);
+ gsupport->alphaInterpretation)
+ });
}
return support;
}
diff --git a/libs/gui/include/gui/ScreenCaptureResults.h b/libs/gui/include/gui/ScreenCaptureResults.h
index 724c11c..6e17791 100644
--- a/libs/gui/include/gui/ScreenCaptureResults.h
+++ b/libs/gui/include/gui/ScreenCaptureResults.h
@@ -19,6 +19,7 @@
#include <binder/Parcel.h>
#include <binder/Parcelable.h>
#include <ui/Fence.h>
+#include <ui/FenceResult.h>
#include <ui/GraphicBuffer.h>
namespace android::gui {
@@ -31,11 +32,10 @@
status_t readFromParcel(const android::Parcel* parcel) override;
sp<GraphicBuffer> buffer;
- sp<Fence> fence = Fence::NO_FENCE;
+ FenceResult fenceResult = Fence::NO_FENCE;
bool capturedSecureLayers{false};
bool capturedHdrLayers{false};
ui::Dataspace capturedDataspace{ui::Dataspace::V0_SRGB};
- status_t result = OK;
};
} // namespace android::gui
diff --git a/libs/gui/include/gui/SyncScreenCaptureListener.h b/libs/gui/include/gui/SyncScreenCaptureListener.h
index 0784fbc..bcf565a 100644
--- a/libs/gui/include/gui/SyncScreenCaptureListener.h
+++ b/libs/gui/include/gui/SyncScreenCaptureListener.h
@@ -34,7 +34,9 @@
ScreenCaptureResults waitForResults() {
std::future<ScreenCaptureResults> resultsFuture = resultsPromise.get_future();
const auto screenCaptureResults = resultsFuture.get();
- screenCaptureResults.fence->waitForever("");
+ if (screenCaptureResults.fenceResult.ok()) {
+ screenCaptureResults.fenceResult.value()->waitForever("");
+ }
return screenCaptureResults;
}
@@ -42,4 +44,4 @@
std::promise<ScreenCaptureResults> resultsPromise;
};
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 3e563b2..c4c2fa5 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -311,7 +311,7 @@
return err;
}
captureResults = captureListener->waitForResults();
- return captureResults.result;
+ return fenceStatus(captureResults.fenceResult);
}
void queueBuffer(sp<IGraphicBufferProducer> igbp, uint8_t r, uint8_t g, uint8_t b,
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 71f2ad4..b9358e7 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -218,7 +218,7 @@
return err;
}
captureResults = captureListener->waitForResults();
- return captureResults.result;
+ return fenceStatus(captureResults.fenceResult);
}
sp<Surface> mSurface;
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 5030d60..29e02cf 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -26,6 +26,7 @@
filegroup {
name: "inputconstants_aidl",
srcs: [
+ "android/hardware/input/InputDeviceCountryCode.aidl",
"android/os/IInputConstants.aidl",
"android/os/InputEventInjectionResult.aidl",
"android/os/InputEventInjectionSync.aidl",
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index a908969..3fe03c7 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -26,6 +26,7 @@
#include <input/InputEventLabels.h>
using android::base::StringPrintf;
+using android::hardware::input::InputDeviceCountryCode;
namespace android {
@@ -177,6 +178,7 @@
mAlias(other.mAlias),
mIsExternal(other.mIsExternal),
mHasMic(other.mHasMic),
+ mCountryCode(other.mCountryCode),
mSources(other.mSources),
mKeyboardType(other.mKeyboardType),
mKeyCharacterMap(other.mKeyCharacterMap),
@@ -192,8 +194,8 @@
}
void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t controllerNumber,
- const InputDeviceIdentifier& identifier, const std::string& alias, bool isExternal,
- bool hasMic) {
+ const InputDeviceIdentifier& identifier, const std::string& alias,
+ bool isExternal, bool hasMic, InputDeviceCountryCode countryCode) {
mId = id;
mGeneration = generation;
mControllerNumber = controllerNumber;
@@ -201,6 +203,7 @@
mAlias = alias;
mIsExternal = isExternal;
mHasMic = hasMic;
+ mCountryCode = countryCode;
mSources = 0;
mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE;
mHasVibrator = false;
diff --git a/libs/input/android/hardware/input/InputDeviceCountryCode.aidl b/libs/input/android/hardware/input/InputDeviceCountryCode.aidl
new file mode 100644
index 0000000..6bb1a60
--- /dev/null
+++ b/libs/input/android/hardware/input/InputDeviceCountryCode.aidl
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 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.hardware.input;
+
+/**
+ * Constant for HID country code declared by a HID device. These constants are declared as AIDL to
+ * be used by java and native input code.
+ *
+ * @hide
+ */
+@Backing(type="int")
+enum InputDeviceCountryCode {
+ /**
+ * Used as default value where country code is not set in the device HID descriptor
+ */
+ INVALID = -1,
+
+ /**
+ * Used as default value when country code is not supported by the HID device. The HID
+ * descriptor sets "00" as the country code in this case.
+ */
+ NOT_SUPPORTED = 0,
+
+ /**
+ * Arabic
+ */
+ ARABIC = 1,
+
+ /**
+ * Belgian
+ */
+ BELGIAN = 2,
+
+ /**
+ * Canadian (Bilingual)
+ */
+ CANADIAN_BILINGUAL = 3,
+
+ /**
+ * Canadian (French)
+ */
+ CANADIAN_FRENCH = 4,
+
+ /**
+ * Czech Republic
+ */
+ CZECH_REPUBLIC = 5,
+
+ /**
+ * Danish
+ */
+ DANISH = 6,
+
+ /**
+ * Finnish
+ */
+ FINNISH = 7,
+
+ /**
+ * French
+ */
+ FRENCH = 8,
+
+ /**
+ * German
+ */
+ GERMAN = 9,
+
+ /**
+ * Greek
+ */
+ GREEK = 10,
+
+ /**
+ * Hebrew
+ */
+ HEBREW = 11,
+
+ /**
+ * Hungary
+ */
+ HUNGARY = 12,
+
+ /**
+ * International (ISO)
+ */
+ INTERNATIONAL = 13,
+
+ /**
+ * Italian
+ */
+ ITALIAN = 14,
+
+ /**
+ * Japan (Katakana)
+ */
+ JAPAN = 15,
+
+ /**
+ * Korean
+ */
+ KOREAN = 16,
+
+ /**
+ * Latin American
+ */
+ LATIN_AMERICAN = 17,
+
+ /**
+ * Netherlands (Dutch)
+ */
+ DUTCH = 18,
+
+ /**
+ * Norwegian
+ */
+ NORWEGIAN = 19,
+
+ /**
+ * Persian
+ */
+ PERSIAN = 20,
+
+ /**
+ * Poland
+ */
+ POLAND = 21,
+
+ /**
+ * Portuguese
+ */
+ PORTUGUESE = 22,
+
+ /**
+ * Russia
+ */
+ RUSSIA = 23,
+
+ /**
+ * Slovakia
+ */
+ SLOVAKIA = 24,
+
+ /**
+ * Spanish
+ */
+ SPANISH = 25,
+
+ /**
+ * Swedish
+ */
+ SWEDISH = 26,
+
+ /**
+ * Swiss (French)
+ */
+ SWISS_FRENCH = 27,
+
+ /**
+ * Swiss (German)
+ */
+ SWISS_GERMAN = 28,
+
+ /**
+ * Switzerland
+ */
+ SWITZERLAND = 29,
+
+ /**
+ * Taiwan
+ */
+ TAIWAN = 30,
+
+ /**
+ * Turkish_Q
+ */
+ TURKISH_Q = 31,
+
+ /**
+ * UK
+ */
+ UK = 32,
+
+ /**
+ * US
+ */
+ US = 33,
+
+ /**
+ * Yugoslavia
+ */
+ YUGOSLAVIA = 34,
+
+ /**
+ * Turkish_F
+ */
+ TURKISH_F = 35,
+}
\ No newline at end of file
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index f3009dd..180dce9 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -16,6 +16,8 @@
#define LOG_TAG "AHardwareBuffer"
+#include <android/hardware_buffer.h>
+#include <android/hardware_buffer_aidl.h>
#include <vndk/hardware_buffer.h>
#include <errno.h>
@@ -32,6 +34,9 @@
#include <android/hardware/graphics/common/1.1/types.h>
#include <aidl/android/hardware/graphics/common/PixelFormat.h>
+// TODO: Better way to handle this
+#include "../binder/ndk/parcel_internal.h"
+
static constexpr int kFdBufferSize = 128 * sizeof(int); // 128 ints
using namespace android;
@@ -412,6 +417,25 @@
return OK;
}
+binder_status_t AHardwareBuffer_readFromParcel(const AParcel* _Nonnull parcel,
+ AHardwareBuffer* _Nullable* _Nonnull outBuffer) {
+ if (!parcel || !outBuffer) return STATUS_BAD_VALUE;
+ auto buffer = sp<GraphicBuffer>::make();
+ status_t status = parcel->get()->read(*buffer);
+ if (status != STATUS_OK) return status;
+ *outBuffer = AHardwareBuffer_from_GraphicBuffer(buffer.get());
+ AHardwareBuffer_acquire(*outBuffer);
+ return STATUS_OK;
+}
+
+binder_status_t AHardwareBuffer_writeToParcel(const AHardwareBuffer* _Nonnull buffer,
+ AParcel* _Nonnull parcel) {
+ const GraphicBuffer* gb = AHardwareBuffer_to_GraphicBuffer(buffer);
+ if (!gb) return STATUS_BAD_VALUE;
+ if (!parcel) return STATUS_BAD_VALUE;
+ return parcel->get()->write(*gb);
+}
+
// ----------------------------------------------------------------------------
// VNDK functions
// ----------------------------------------------------------------------------
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index dd07319..fbfecf6 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -96,6 +96,8 @@
"liblog",
"libutils",
"libui",
+ "libbinder",
+ "libbinder_ndk",
"android.hardware.graphics.common@1.1",
],
diff --git a/libs/nativewindow/include/android/hardware_buffer_aidl.h b/libs/nativewindow/include/android/hardware_buffer_aidl.h
new file mode 100644
index 0000000..906d9c6
--- /dev/null
+++ b/libs/nativewindow/include/android/hardware_buffer_aidl.h
@@ -0,0 +1,151 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file hardware_buffer_aidl.h
+ * @brief HardwareBuffer NDK AIDL glue code
+ */
+
+/**
+ * @addtogroup AHardwareBuffer
+ *
+ * Parcelable support for AHardwareBuffer. Can be used with libbinder_ndk
+ *
+ * @{
+ */
+
+#ifndef ANDROID_HARDWARE_BUFFER_AIDL_H
+#define ANDROID_HARDWARE_BUFFER_AIDL_H
+
+#include <android/binder_parcel.h>
+#include <android/hardware_buffer.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/**
+ * Read an AHardwareBuffer from a AParcel. The output buffer will have an
+ * initial reference acquired and will need to be released with
+ * AHardwareBuffer_release.
+ *
+ * Available since API level 34.
+ *
+ * \return STATUS_OK on success
+ * STATUS_BAD_VALUE if the parcel or outBuffer is null, or if there's an
+ * issue deserializing (eg, corrupted parcel)
+ * STATUS_BAD_TYPE if the parcel's current data position is not that of
+ * an AHardwareBuffer type
+ * STATUS_NO_MEMORY if an allocation fails
+ */
+binder_status_t AHardwareBuffer_readFromParcel(const AParcel* _Nonnull parcel,
+ AHardwareBuffer* _Nullable* _Nonnull outBuffer) __INTRODUCED_IN(34);
+
+/**
+ * Write an AHardwareBuffer to an AParcel.
+ *
+ * Available since API level 34.
+ *
+ * \return STATUS_OK on success.
+ * STATUS_BAD_VALUE if either buffer or parcel is null, or if the AHardwareBuffer*
+ * fails to serialize (eg, internally corrupted)
+ * STATUS_NO_MEMORY if the parcel runs out of space to store the buffer & is
+ * unable to allocate more
+ * STATUS_FDS_NOT_ALLOWED if the parcel does not allow storing FDs
+ */
+binder_status_t AHardwareBuffer_writeToParcel(const AHardwareBuffer* _Nonnull buffer,
+ AParcel* _Nonnull parcel) __INTRODUCED_IN(34);
+
+__END_DECLS
+
+// Only enable the AIDL glue helper if this is C++
+#ifdef __cplusplus
+
+namespace aidl::android::hardware {
+
+/**
+ * Wrapper class that enables interop with AIDL NDK generation
+ * Takes ownership of the AHardwareBuffer* given to it in reset() and will automatically
+ * destroy it in the destructor, similar to a smart pointer container
+ */
+class HardwareBuffer {
+public:
+ HardwareBuffer() noexcept {}
+ explicit HardwareBuffer(HardwareBuffer&& other) noexcept : mBuffer(other.release()) {}
+
+ ~HardwareBuffer() {
+ reset();
+ }
+
+ binder_status_t readFromParcel(const AParcel* _Nonnull parcel) {
+ reset();
+ return AHardwareBuffer_readFromParcel(parcel, &mBuffer);
+ }
+
+ binder_status_t writeToParcel(AParcel* _Nonnull parcel) const {
+ if (!mBuffer) {
+ return STATUS_BAD_VALUE;
+ }
+ return AHardwareBuffer_writeToParcel(mBuffer, parcel);
+ }
+
+ /**
+ * Destroys any currently owned AHardwareBuffer* and takes ownership of the given
+ * AHardwareBuffer*
+ *
+ * @param buffer The buffer to take ownership of
+ */
+ void reset(AHardwareBuffer* _Nullable buffer = nullptr) noexcept {
+ if (mBuffer) {
+ AHardwareBuffer_release(mBuffer);
+ mBuffer = nullptr;
+ }
+ mBuffer = buffer;
+ }
+
+ inline AHardwareBuffer* _Nullable operator-> () const { return mBuffer; }
+ inline AHardwareBuffer* _Nullable get() const { return mBuffer; }
+ inline explicit operator bool () const { return mBuffer != nullptr; }
+
+ HardwareBuffer& operator=(HardwareBuffer&& other) noexcept {
+ reset(other.release());
+ return *this;
+ }
+
+ /**
+ * Stops managing any contained AHardwareBuffer*, returning it to the caller. Ownership
+ * is released.
+ * @return AHardwareBuffer* or null if this was empty
+ */
+ [[nodiscard]] AHardwareBuffer* _Nullable release() noexcept {
+ AHardwareBuffer* _Nullable ret = mBuffer;
+ mBuffer = nullptr;
+ return ret;
+ }
+
+private:
+ HardwareBuffer(const HardwareBuffer& other) = delete;
+ HardwareBuffer& operator=(const HardwareBuffer& other) = delete;
+
+ AHardwareBuffer* _Nullable mBuffer = nullptr;
+};
+
+} // aidl::android::hardware
+
+#endif // __cplusplus
+
+#endif // ANDROID_HARDWARE_BUFFER_AIDL_H
+
+/** @} */
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index 6c6e42b..ce108b6 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -14,6 +14,8 @@
AHardwareBuffer_release;
AHardwareBuffer_sendHandleToUnixSocket;
AHardwareBuffer_unlock;
+ AHardwareBuffer_readFromParcel; # introduced=34
+ AHardwareBuffer_writeToParcel; # introduced=34
ANativeWindowBuffer_getHardwareBuffer; # llndk
ANativeWindow_OemStorageGet; # llndk
ANativeWindow_OemStorageSet; # llndk
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index f6f57dd..0540538 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -21,13 +21,15 @@
cc_defaults {
name: "librenderengine_defaults",
- defaults: ["renderengine_defaults"],
+ defaults: [
+ "android.hardware.graphics.composer3-ndk_shared",
+ "renderengine_defaults",
+ ],
cflags: [
"-DGL_GLEXT_PROTOTYPES",
"-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 249fec5..afbe6cf 100644
--- a/libs/renderengine/benchmark/Android.bp
+++ b/libs/renderengine/benchmark/Android.bp
@@ -24,6 +24,7 @@
cc_benchmark {
name: "librenderengine_bench",
defaults: [
+ "android.hardware.graphics.composer3-ndk_shared",
"skia_deps",
"surfaceflinger_defaults",
],
@@ -43,7 +44,6 @@
],
shared_libs: [
- "android.hardware.graphics.composer3-V1-ndk",
"libbase",
"libcutils",
"libjnigraphics",
diff --git a/libs/renderengine/tests/Android.bp b/libs/renderengine/tests/Android.bp
index bbab792..6f328d7 100644
--- a/libs/renderengine/tests/Android.bp
+++ b/libs/renderengine/tests/Android.bp
@@ -24,6 +24,7 @@
cc_test {
name: "librenderengine_test",
defaults: [
+ "android.hardware.graphics.composer3-ndk_shared",
"skia_deps",
"surfaceflinger_defaults",
],
@@ -49,7 +50,6 @@
],
shared_libs: [
- "android.hardware.graphics.composer3-V1-ndk",
"libbase",
"libcutils",
"libEGL",
diff --git a/libs/shaders/Android.bp b/libs/shaders/Android.bp
index 6b936de..960f845 100644
--- a/libs/shaders/Android.bp
+++ b/libs/shaders/Android.bp
@@ -23,13 +23,14 @@
cc_library_static {
name: "libshaders",
-
+ defaults: [
+ "android.hardware.graphics.common-ndk_shared",
+ "android.hardware.graphics.composer3-ndk_shared",
+ ],
export_include_dirs: ["include"],
local_include_dirs: ["include"],
shared_libs: [
- "android.hardware.graphics.common-V3-ndk",
- "android.hardware.graphics.composer3-V1-ndk",
"android.hardware.graphics.common@1.2",
"libnativewindow",
],
diff --git a/libs/shaders/tests/Android.bp b/libs/shaders/tests/Android.bp
index cf671bc..1e4f45a 100644
--- a/libs/shaders/tests/Android.bp
+++ b/libs/shaders/tests/Android.bp
@@ -23,6 +23,10 @@
cc_test {
name: "libshaders_test",
+ defaults: [
+ "android.hardware.graphics.common-ndk_shared",
+ "android.hardware.graphics.composer3-ndk_shared",
+ ],
test_suites: ["device-tests"],
srcs: [
"shaders_test.cpp",
@@ -31,8 +35,6 @@
"libtonemap_headers",
],
shared_libs: [
- "android.hardware.graphics.common-V3-ndk",
- "android.hardware.graphics.composer3-V1-ndk",
"android.hardware.graphics.common@1.2",
"libnativewindow",
],
diff --git a/libs/tonemap/Android.bp b/libs/tonemap/Android.bp
index 37c9824..8c8815d 100644
--- a/libs/tonemap/Android.bp
+++ b/libs/tonemap/Android.bp
@@ -23,13 +23,15 @@
cc_library_static {
name: "libtonemap",
+ defaults: [
+ "android.hardware.graphics.common-ndk_shared",
+ "android.hardware.graphics.composer3-ndk_shared",
+ ],
vendor_available: true,
local_include_dirs: ["include"],
shared_libs: [
- "android.hardware.graphics.common-V3-ndk",
- "android.hardware.graphics.composer3-V1-ndk",
"liblog",
"libnativewindow",
],
diff --git a/libs/tonemap/tests/Android.bp b/libs/tonemap/tests/Android.bp
index 58851b4..2abf515 100644
--- a/libs/tonemap/tests/Android.bp
+++ b/libs/tonemap/tests/Android.bp
@@ -23,6 +23,10 @@
cc_test {
name: "libtonemap_test",
+ defaults: [
+ "android.hardware.graphics.common-ndk_shared",
+ "android.hardware.graphics.composer3-ndk_shared",
+ ],
test_suites: ["device-tests"],
srcs: [
"tonemap_test.cpp",
@@ -31,8 +35,6 @@
"libtonemap_headers",
],
shared_libs: [
- "android.hardware.graphics.common-V3-ndk",
- "android.hardware.graphics.composer3-V1-ndk",
"libnativewindow",
],
static_libs: [
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index ca8adfa..d33dd34 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -152,6 +152,8 @@
],
defaults: [
+ "android.hardware.graphics.allocator-ndk_shared",
+ "android.hardware.graphics.common-ndk_shared",
"libui-defaults",
// Uncomment the following line to enable VALIDATE_REGIONS traces
//defaults: ["libui-validate-regions-defaults"],
@@ -161,8 +163,6 @@
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.allocator@4.0",
- "android.hardware.graphics.allocator-V1-ndk",
- "android.hardware.graphics.common-V3-ndk",
"android.hardware.graphics.common@1.2",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.1",
@@ -180,7 +180,6 @@
export_shared_lib_headers: [
"android.hardware.graphics.common@1.2",
- "android.hardware.graphics.common-V3-ndk",
"android.hardware.graphics.mapper@4.0",
"libgralloctypes",
],
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 3732fee..429760f 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -465,7 +465,7 @@
if (flattenWordCount == 13) {
usage = (uint64_t(buf[12]) << 32) | uint32_t(buf[6]);
} else {
- usage = uint64_t(usage_deprecated);
+ usage = uint64_t(ANDROID_NATIVE_UNSIGNED_CAST(usage_deprecated));
}
native_handle* h =
native_handle_create(static_cast<int>(numFds), static_cast<int>(numInts));
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 29a0e4f..5b286dc 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -148,6 +148,7 @@
srcs: [":libinputflinger_base_sources"],
shared_libs: [
"libbase",
+ "libbinder",
"libcutils",
"libinput",
"liblog",
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index 06a38c8..ff0b9a5 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -61,6 +61,7 @@
#define INDENT3 " "
using android::base::StringPrintf;
+using android::hardware::input::InputDeviceCountryCode;
namespace android {
@@ -302,6 +303,24 @@
}
/**
+ * Read country code information exposed through the sysfs path.
+ */
+static InputDeviceCountryCode readCountryCodeLocked(const std::filesystem::path& sysfsRootPath) {
+ // Check the sysfs root path
+ int hidCountryCode = static_cast<int>(InputDeviceCountryCode::INVALID);
+ std::string str;
+ if (base::ReadFileToString(sysfsRootPath / "country", &str)) {
+ hidCountryCode = std::stoi(str, nullptr, 16);
+ LOG_ALWAYS_FATAL_IF(hidCountryCode > 35 || hidCountryCode < 0,
+ "HID country code should be in range [0, 35]. Found country code "
+ "to be %d",
+ hidCountryCode);
+ }
+
+ return static_cast<InputDeviceCountryCode>(hidCountryCode);
+}
+
+/**
* Read information about batteries exposed through the sysfs path.
*/
static std::unordered_map<int32_t /*batteryId*/, RawBatteryInfo> readBatteryConfiguration(
@@ -1238,6 +1257,15 @@
}
}
+InputDeviceCountryCode EventHub::getCountryCode(int32_t deviceId) const {
+ std::scoped_lock _l(mLock);
+ Device* device = getDeviceLocked(deviceId);
+ if (device == nullptr || !device->associatedDevice) {
+ return InputDeviceCountryCode::INVALID;
+ }
+ return device->associatedDevice->countryCode;
+}
+
void EventHub::setExcludedDevices(const std::vector<std::string>& devices) {
std::scoped_lock _l(mLock);
@@ -1384,6 +1412,7 @@
return std::make_shared<AssociatedDevice>(
AssociatedDevice{.sysfsRootPath = path,
+ .countryCode = readCountryCodeLocked(path),
.batteryInfos = readBatteryConfiguration(path),
.lightInfos = readLightsConfiguration(path)});
}
@@ -1516,25 +1545,35 @@
}
std::optional<int32_t> EventHub::getBatteryCapacity(int32_t deviceId, int32_t batteryId) const {
- std::scoped_lock _l(mLock);
+ std::filesystem::path batteryPath;
+ {
+ // Do not read the sysfs node to get the battery state while holding
+ // the EventHub lock. For some peripheral devices, reading battery state
+ // can be broken and take 5+ seconds. Holding the lock in this case would
+ // block all other event processing during this time. For now, we assume this
+ // call never happens on the InputReader thread and read the sysfs node outside
+ // the lock to prevent event processing from being blocked by this call.
+ std::scoped_lock _l(mLock);
- const auto infos = getBatteryInfoLocked(deviceId);
- auto it = infos.find(batteryId);
- if (it == infos.end()) {
- return std::nullopt;
- }
+ const auto infos = getBatteryInfoLocked(deviceId);
+ auto it = infos.find(batteryId);
+ if (it == infos.end()) {
+ return std::nullopt;
+ }
+ batteryPath = it->second.path;
+ } // release lock
+
std::string buffer;
// Some devices report battery capacity as an integer through the "capacity" file
- if (base::ReadFileToString(it->second.path / BATTERY_NODES.at(InputBatteryClass::CAPACITY),
+ if (base::ReadFileToString(batteryPath / BATTERY_NODES.at(InputBatteryClass::CAPACITY),
&buffer)) {
return std::stoi(base::Trim(buffer));
}
// Other devices report capacity as an enum value POWER_SUPPLY_CAPACITY_LEVEL_XXX
// These values are taken from kernel source code include/linux/power_supply.h
- if (base::ReadFileToString(it->second.path /
- BATTERY_NODES.at(InputBatteryClass::CAPACITY_LEVEL),
+ if (base::ReadFileToString(batteryPath / BATTERY_NODES.at(InputBatteryClass::CAPACITY_LEVEL),
&buffer)) {
// Remove any white space such as trailing new line
const auto levelIt = BATTERY_LEVEL.find(base::Trim(buffer));
@@ -1547,15 +1586,27 @@
}
std::optional<int32_t> EventHub::getBatteryStatus(int32_t deviceId, int32_t batteryId) const {
- std::scoped_lock _l(mLock);
- const auto infos = getBatteryInfoLocked(deviceId);
- auto it = infos.find(batteryId);
- if (it == infos.end()) {
- return std::nullopt;
- }
+ std::filesystem::path batteryPath;
+ {
+ // Do not read the sysfs node to get the battery state while holding
+ // the EventHub lock. For some peripheral devices, reading battery state
+ // can be broken and take 5+ seconds. Holding the lock in this case would
+ // block all other event processing during this time. For now, we assume this
+ // call never happens on the InputReader thread and read the sysfs node outside
+ // the lock to prevent event processing from being blocked by this call.
+ std::scoped_lock _l(mLock);
+
+ const auto infos = getBatteryInfoLocked(deviceId);
+ auto it = infos.find(batteryId);
+ if (it == infos.end()) {
+ return std::nullopt;
+ }
+ batteryPath = it->second.path;
+ } // release lock
+
std::string buffer;
- if (!base::ReadFileToString(it->second.path / BATTERY_NODES.at(InputBatteryClass::STATUS),
+ if (!base::ReadFileToString(batteryPath / BATTERY_NODES.at(InputBatteryClass::STATUS),
&buffer)) {
ALOGE("Failed to read sysfs battery info: %s", strerror(errno));
return std::nullopt;
@@ -2553,6 +2604,9 @@
device->keyMap.keyLayoutFile.c_str());
dump += StringPrintf(INDENT3 "KeyCharacterMapFile: %s\n",
device->keyMap.keyCharacterMapFile.c_str());
+ dump += StringPrintf(INDENT3 "CountryCode: %d\n",
+ device->associatedDevice ? device->associatedDevice->countryCode
+ : InputDeviceCountryCode::INVALID);
dump += StringPrintf(INDENT3 "ConfigurationFile: %s\n",
device->configurationFile.c_str());
dump += StringPrintf(INDENT3 "VideoDevice: %s\n",
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index 5c9e63e..44a005e 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -35,6 +35,8 @@
#include "SwitchInputMapper.h"
#include "VibratorInputMapper.h"
+using android::hardware::input::InputDeviceCountryCode;
+
namespace android {
InputDevice::InputDevice(InputReaderContext* context, int32_t id, int32_t generation,
@@ -240,6 +242,7 @@
mSources = 0;
mClasses = ftl::Flags<InputDeviceClass>(0);
mControllerNumber = 0;
+ mCountryCode = InputDeviceCountryCode::INVALID;
for_each_subdevice([this](InputDeviceContext& context) {
mClasses |= context.getDeviceClasses();
@@ -251,6 +254,16 @@
}
mControllerNumber = controllerNumber;
}
+
+ InputDeviceCountryCode countryCode = context.getCountryCode();
+ if (countryCode != InputDeviceCountryCode::INVALID) {
+ if (mCountryCode != InputDeviceCountryCode::INVALID && mCountryCode != countryCode) {
+ ALOGW("InputDevice::configure(): %s device contains multiple unique country "
+ "codes",
+ getName().c_str());
+ }
+ mCountryCode = countryCode;
+ }
});
mIsExternal = mClasses.test(InputDeviceClass::EXTERNAL);
@@ -422,7 +435,7 @@
InputDeviceInfo InputDevice::getDeviceInfo() {
InputDeviceInfo outDeviceInfo;
outDeviceInfo.initialize(mId, mGeneration, mControllerNumber, mIdentifier, mAlias, mIsExternal,
- mHasMic);
+ mHasMic, mCountryCode);
for_each_mapper(
[&outDeviceInfo](InputMapper& mapper) { mapper.populateDeviceInfo(&outDeviceInfo); });
@@ -548,14 +561,6 @@
for_each_mapper([when, readTime](InputMapper& mapper) { mapper.cancelTouch(when, readTime); });
}
-std::optional<int32_t> InputDevice::getBatteryCapacity() {
- return mController ? mController->getBatteryCapacity(DEFAULT_BATTERY_ID) : std::nullopt;
-}
-
-std::optional<int32_t> InputDevice::getBatteryStatus() {
- return mController ? mController->getBatteryStatus(DEFAULT_BATTERY_ID) : std::nullopt;
-}
-
bool InputDevice::setLightColor(int32_t lightId, int32_t color) {
return mController ? mController->setLightColor(lightId, color) : false;
}
@@ -623,6 +628,10 @@
for_each_mapper([reset](InputMapper& mapper) { mapper.updateLedState(reset); });
}
+std::optional<int32_t> InputDevice::getBatteryEventHubId() const {
+ return mController ? std::make_optional(mController->getEventHubId()) : std::nullopt;
+}
+
InputDeviceContext::InputDeviceContext(InputDevice& device, int32_t eventHubId)
: mDevice(device),
mContext(device.getContext()),
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index dc41051..4750d90 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -706,23 +706,43 @@
}
std::optional<int32_t> InputReader::getBatteryCapacity(int32_t deviceId) {
- std::scoped_lock _l(mLock);
+ std::optional<int32_t> eventHubId;
+ {
+ // Do not query the battery state while holding the lock. For some peripheral devices,
+ // reading battery state can be broken and take 5+ seconds. Holding the lock in this case
+ // would block all other event processing during this time. For now, we assume this
+ // call never happens on the InputReader thread and get the battery state outside the
+ // lock to prevent event processing from being blocked by this call.
+ std::scoped_lock _l(mLock);
+ InputDevice* device = findInputDeviceLocked(deviceId);
+ if (!device) return {};
+ eventHubId = device->getBatteryEventHubId();
+ } // release lock
- InputDevice* device = findInputDeviceLocked(deviceId);
- if (device) {
- return device->getBatteryCapacity();
- }
- return std::nullopt;
+ if (!eventHubId) return {};
+ const auto batteryIds = mEventHub->getRawBatteryIds(*eventHubId);
+ if (batteryIds.empty()) return {};
+ return mEventHub->getBatteryCapacity(*eventHubId, batteryIds.front());
}
std::optional<int32_t> InputReader::getBatteryStatus(int32_t deviceId) {
- std::scoped_lock _l(mLock);
+ std::optional<int32_t> eventHubId;
+ {
+ // Do not query the battery state while holding the lock. For some peripheral devices,
+ // reading battery state can be broken and take 5+ seconds. Holding the lock in this case
+ // would block all other event processing during this time. For now, we assume this
+ // call never happens on the InputReader thread and get the battery state outside the
+ // lock to prevent event processing from being blocked by this call.
+ std::scoped_lock _l(mLock);
+ InputDevice* device = findInputDeviceLocked(deviceId);
+ if (!device) return {};
+ eventHubId = device->getBatteryEventHubId();
+ } // release lock
- InputDevice* device = findInputDeviceLocked(deviceId);
- if (device) {
- return device->getBatteryStatus();
- }
- return std::nullopt;
+ if (!eventHubId) return {};
+ const auto batteryIds = mEventHub->getRawBatteryIds(*eventHubId);
+ if (batteryIds.empty()) return {};
+ return mEventHub->getBatteryStatus(*eventHubId, batteryIds.front());
}
std::vector<InputDeviceLightInfo> InputReader::getLights(int32_t deviceId) {
diff --git a/services/inputflinger/reader/controller/PeripheralController.cpp b/services/inputflinger/reader/controller/PeripheralController.cpp
index 7673174..eaf5b51 100644
--- a/services/inputflinger/reader/controller/PeripheralController.cpp
+++ b/services/inputflinger/reader/controller/PeripheralController.cpp
@@ -521,4 +521,8 @@
return light->getLightPlayerId();
}
+int32_t PeripheralController::getEventHubId() const {
+ return getDeviceContext().getEventHubId();
+}
+
} // namespace android
diff --git a/services/inputflinger/reader/controller/PeripheralController.h b/services/inputflinger/reader/controller/PeripheralController.h
index b1bc8c7..ac951eb 100644
--- a/services/inputflinger/reader/controller/PeripheralController.h
+++ b/services/inputflinger/reader/controller/PeripheralController.h
@@ -31,6 +31,7 @@
explicit PeripheralController(InputDeviceContext& deviceContext);
~PeripheralController() override;
+ int32_t getEventHubId() const override;
void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
void dump(std::string& dump) override;
bool setLightColor(int32_t lightId, int32_t color) override;
@@ -43,6 +44,7 @@
private:
inline int32_t getDeviceId() { return mDeviceContext.getId(); }
inline InputDeviceContext& getDeviceContext() { return mDeviceContext; }
+ inline InputDeviceContext& getDeviceContext() const { return mDeviceContext; }
InputDeviceContext& mDeviceContext;
void configureLights();
diff --git a/services/inputflinger/reader/controller/PeripheralControllerInterface.h b/services/inputflinger/reader/controller/PeripheralControllerInterface.h
index 7688a43..306e361 100644
--- a/services/inputflinger/reader/controller/PeripheralControllerInterface.h
+++ b/services/inputflinger/reader/controller/PeripheralControllerInterface.h
@@ -33,6 +33,8 @@
PeripheralControllerInterface() {}
virtual ~PeripheralControllerInterface() {}
+ virtual int32_t getEventHubId() const = 0;
+
// Interface methods for Battery
virtual std::optional<int32_t> getBatteryCapacity(int32_t batteryId) = 0;
virtual std::optional<int32_t> getBatteryStatus(int32_t batteryId) = 0;
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index 8aec367..dfb98f1 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -43,6 +43,7 @@
#include "TouchVideoDevice.h"
#include "VibrationElement.h"
+#include "android/hardware/input/InputDeviceCountryCode.h"
struct inotify_event;
@@ -301,9 +302,9 @@
int32_t deviceId, int32_t lightId) const = 0;
virtual void setLightIntensities(int32_t deviceId, int32_t lightId,
std::unordered_map<LightColor, int32_t> intensities) = 0;
- /*
- * Query current input state.
- */
+ /* Query Country code associated with the input device. */
+ virtual hardware::input::InputDeviceCountryCode getCountryCode(int32_t deviceId) const = 0;
+ /* Query current input state. */
virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const = 0;
virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const = 0;
virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const = 0;
@@ -483,6 +484,8 @@
void setLightIntensities(int32_t deviceId, int32_t lightId,
std::unordered_map<LightColor, int32_t> intensities) override final;
+ hardware::input::InputDeviceCountryCode getCountryCode(int32_t deviceId) const override final;
+
void setExcludedDevices(const std::vector<std::string>& devices) override final;
int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const override final;
@@ -544,7 +547,7 @@
struct AssociatedDevice {
// The sysfs root path of the misc device.
std::filesystem::path sysfsRootPath;
-
+ hardware::input::InputDeviceCountryCode countryCode;
std::unordered_map<int32_t /*batteryId*/, RawBatteryInfo> batteryInfos;
std::unordered_map<int32_t /*lightId*/, RawLightInfo> lightInfos;
};
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index 51872ac..3ef1840 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -32,8 +32,6 @@
#include "InputReaderContext.h"
namespace android {
-// TODO b/180733860 support multiple battery in API and remove this.
-constexpr int32_t DEFAULT_BATTERY_ID = 1;
class PeripheralController;
class PeripheralControllerInterface;
@@ -100,8 +98,7 @@
void disableSensor(InputDeviceSensorType sensorType);
void flushSensor(InputDeviceSensorType sensorType);
- std::optional<int32_t> getBatteryCapacity();
- std::optional<int32_t> getBatteryStatus();
+ std::optional<int32_t> getBatteryEventHubId() const;
bool setLightColor(int32_t lightId, int32_t color);
bool setLightPlayerId(int32_t lightId, int32_t playerId);
@@ -158,6 +155,7 @@
int32_t mId;
int32_t mGeneration;
int32_t mControllerNumber;
+ hardware::input::InputDeviceCountryCode mCountryCode;
InputDeviceIdentifier mIdentifier;
std::string mAlias;
ftl::Flags<InputDeviceClass> mClasses;
@@ -311,6 +309,9 @@
}
inline std::vector<TouchVideoFrame> getVideoFrames() { return mEventHub->getVideoFrames(mId); }
+ inline hardware::input::InputDeviceCountryCode getCountryCode() const {
+ return mEventHub->getCountryCode(mId);
+ }
inline int32_t getScanCodeState(int32_t scanCode) const {
return mEventHub->getScanCodeState(mId, scanCode);
}
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
index 6a406d2..9bb6273 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
@@ -127,7 +127,6 @@
dump += StringPrintf(INDENT3 "Orientation: %d\n", getOrientation());
dump += StringPrintf(INDENT3 "KeyDowns: %zu keys currently down\n", mKeyDowns.size());
dump += StringPrintf(INDENT3 "MetaState: 0x%0x\n", mMetaState);
- dump += StringPrintf(INDENT3 "DownTime: %" PRId64 "\n", mDownTime);
}
std::optional<DisplayViewport> KeyboardInputMapper::findViewport(
@@ -196,9 +195,7 @@
}
void KeyboardInputMapper::reset(nsecs_t when) {
- mMetaState = AMETA_NONE;
- mDownTime = 0;
- mKeyDowns.clear();
+ cancelAllDownKeys(when);
mCurrentHidUsage = 0;
resetLedState();
@@ -281,6 +278,7 @@
policyFlags = 0;
}
+ nsecs_t downTime = when;
if (down) {
// Rotate key codes according to orientation if needed.
if (mParameters.orientationAware) {
@@ -292,6 +290,7 @@
if (keyDownIndex >= 0) {
// key repeat, be sure to use same keycode as before in case of rotation
keyCode = mKeyDowns[keyDownIndex].keyCode;
+ downTime = mKeyDowns[keyDownIndex].downTime;
} else {
// key down
if ((policyFlags & POLICY_FLAG_VIRTUAL) &&
@@ -305,16 +304,16 @@
KeyDown keyDown;
keyDown.keyCode = keyCode;
keyDown.scanCode = scanCode;
+ keyDown.downTime = when;
mKeyDowns.push_back(keyDown);
}
-
- mDownTime = when;
} else {
// Remove key down.
ssize_t keyDownIndex = findKeyDown(scanCode);
if (keyDownIndex >= 0) {
// key up, be sure to use same keycode as before in case of rotation
keyCode = mKeyDowns[keyDownIndex].keyCode;
+ downTime = mKeyDowns[keyDownIndex].downTime;
mKeyDowns.erase(mKeyDowns.begin() + (size_t)keyDownIndex);
} else {
// key was not actually down
@@ -333,8 +332,6 @@
keyMetaState = mMetaState;
}
- nsecs_t downTime = mDownTime;
-
// Key down on external an keyboard should wake the device.
// We don't do this for internal keyboards to prevent them from waking up in your pocket.
// For internal keyboards and devices for which the default wake behavior is explicitly
@@ -473,4 +470,19 @@
return std::nullopt;
}
+void KeyboardInputMapper::cancelAllDownKeys(nsecs_t when) {
+ size_t n = mKeyDowns.size();
+ for (size_t i = 0; i < n; i++) {
+ NotifyKeyArgs args(getContext()->getNextId(), when, systemTime(SYSTEM_TIME_MONOTONIC),
+ getDeviceId(), mSource, getDisplayId(), 0 /*policyFlags*/,
+ AKEY_EVENT_ACTION_UP,
+ AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_CANCELED,
+ mKeyDowns[i].keyCode, mKeyDowns[i].scanCode, AMETA_NONE,
+ mKeyDowns[i].downTime);
+ getListener().notifyKey(&args);
+ }
+ mKeyDowns.clear();
+ mMetaState = AMETA_NONE;
+}
+
} // namespace android
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.h b/services/inputflinger/reader/mapper/KeyboardInputMapper.h
index 0a55def..31251f4 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.h
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.h
@@ -50,6 +50,7 @@
std::optional<DisplayViewport> mViewport;
struct KeyDown {
+ nsecs_t downTime;
int32_t keyCode;
int32_t scanCode;
};
@@ -59,7 +60,6 @@
std::vector<KeyDown> mKeyDowns; // keys that are down
int32_t mMetaState;
- nsecs_t mDownTime; // time of most recent key down
int32_t mCurrentHidUsage; // most recent HID usage seen this packet, or 0 if none
@@ -98,6 +98,7 @@
void updateLedStateForModifier(LedState& ledState, int32_t led, int32_t modifier, bool reset);
std::optional<DisplayViewport> findViewport(nsecs_t when,
const InputReaderConfiguration* config);
+ void cancelAllDownKeys(nsecs_t when);
};
} // namespace android
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 2ebbd37..539e24a 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -2847,22 +2847,10 @@
}
}
- float deltaX = 0, deltaY = 0;
if (activeTouchId >= 0 && mLastCookedState.fingerIdBits.hasBit(activeTouchId)) {
- const RawPointerData::Pointer& currentPointer =
- mCurrentRawState.rawPointerData.pointerForId(activeTouchId);
- const RawPointerData::Pointer& lastPointer =
- mLastRawState.rawPointerData.pointerForId(activeTouchId);
- deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale;
- deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale;
-
- rotateDelta(mInputDeviceOrientation, &deltaX, &deltaY);
- mPointerVelocityControl.move(when, &deltaX, &deltaY);
-
- // Move the pointer using a relative motion.
// When using spots, the click will occur at the position of the anchor
// spot and all other spots will move there.
- mPointerController->move(deltaX, deltaY);
+ moveMousePointerFromPointerDelta(when, activeTouchId);
} else {
mPointerVelocityControl.reset();
}
@@ -2974,21 +2962,9 @@
mPointerGesture.currentGestureMode = PointerGesture::Mode::TAP_DRAG;
}
- float deltaX = 0, deltaY = 0;
if (mLastCookedState.fingerIdBits.hasBit(activeTouchId)) {
- const RawPointerData::Pointer& currentPointer =
- mCurrentRawState.rawPointerData.pointerForId(activeTouchId);
- const RawPointerData::Pointer& lastPointer =
- mLastRawState.rawPointerData.pointerForId(activeTouchId);
- deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale;
- deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale;
-
- rotateDelta(mInputDeviceOrientation, &deltaX, &deltaY);
- mPointerVelocityControl.move(when, &deltaX, &deltaY);
-
- // Move the pointer using a relative motion.
// When using spots, the hover or drag will occur at the position of the anchor spot.
- mPointerController->move(deltaX, deltaY);
+ moveMousePointerFromPointerDelta(when, activeTouchId);
} else {
mPointerVelocityControl.reset();
}
@@ -3395,6 +3371,20 @@
return true;
}
+void TouchInputMapper::moveMousePointerFromPointerDelta(nsecs_t when, uint32_t pointerId) {
+ const RawPointerData::Pointer& currentPointer =
+ mCurrentRawState.rawPointerData.pointerForId(pointerId);
+ const RawPointerData::Pointer& lastPointer =
+ mLastRawState.rawPointerData.pointerForId(pointerId);
+ float deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale;
+ float deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale;
+
+ rotateDelta(mInputDeviceOrientation, &deltaX, &deltaY);
+ mPointerVelocityControl.move(when, &deltaX, &deltaY);
+
+ mPointerController->move(deltaX, deltaY);
+}
+
void TouchInputMapper::dispatchPointerStylus(nsecs_t when, nsecs_t readTime, uint32_t policyFlags) {
mPointerSimple.currentCoords.clear();
mPointerSimple.currentProperties.clear();
@@ -3438,21 +3428,8 @@
bool down, hovering;
if (!mCurrentCookedState.mouseIdBits.isEmpty()) {
uint32_t id = mCurrentCookedState.mouseIdBits.firstMarkedBit();
- uint32_t currentIndex = mCurrentRawState.rawPointerData.idToIndex[id];
- float deltaX = 0, deltaY = 0;
if (mLastCookedState.mouseIdBits.hasBit(id)) {
- uint32_t lastIndex = mCurrentRawState.rawPointerData.idToIndex[id];
- deltaX = (mCurrentRawState.rawPointerData.pointers[currentIndex].x -
- mLastRawState.rawPointerData.pointers[lastIndex].x) *
- mPointerXMovementScale;
- deltaY = (mCurrentRawState.rawPointerData.pointers[currentIndex].y -
- mLastRawState.rawPointerData.pointers[lastIndex].y) *
- mPointerYMovementScale;
-
- rotateDelta(mInputDeviceOrientation, &deltaX, &deltaY);
- mPointerVelocityControl.move(when, &deltaX, &deltaY);
-
- mPointerController->move(deltaX, deltaY);
+ moveMousePointerFromPointerDelta(when, id);
} else {
mPointerVelocityControl.reset();
}
@@ -3462,6 +3439,7 @@
float x, y;
mPointerController->getPosition(&x, &y);
+ uint32_t currentIndex = mCurrentRawState.rawPointerData.idToIndex[id];
mPointerSimple.currentCoords.copyFrom(
mCurrentCookedState.cookedPointerData.pointerCoords[currentIndex]);
mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index cdf1c7d..fe17006 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -754,6 +754,10 @@
bool preparePointerGestures(nsecs_t when, bool* outCancelPreviousGesture,
bool* outFinishPreviousGesture, bool isTimeout);
+ // Moves the on-screen mouse pointer based on the movement of the pointer of the given ID
+ // between the last and current events. Uses a relative motion.
+ void moveMousePointerFromPointerDelta(nsecs_t when, uint32_t pointerId);
+
void dispatchPointerStylus(nsecs_t when, nsecs_t readTime, uint32_t policyFlags);
void abortPointerStylus(nsecs_t when, nsecs_t readTime, uint32_t policyFlags);
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 9a0c565..851043d 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -38,9 +38,12 @@
#include <gtest/gtest.h>
#include <gui/constants.h>
+#include "android/hardware/input/InputDeviceCountryCode.h"
#include "input/DisplayViewport.h"
#include "input/Input.h"
+using android::hardware::input::InputDeviceCountryCode;
+
namespace android {
using namespace ftl::flag_operators;
@@ -455,6 +458,7 @@
BitArray<MSC_MAX> mscBitmask;
std::vector<VirtualKeyDefinition> virtualKeys;
bool enabled;
+ InputDeviceCountryCode countryCode;
status_t enable() {
enabled = true;
@@ -584,6 +588,11 @@
device->keyCodeStates.replaceValueFor(keyCode, state);
}
+ void setCountryCode(int32_t deviceId, InputDeviceCountryCode countryCode) {
+ Device* device = getDevice(deviceId);
+ device->countryCode = countryCode;
+ }
+
void setScanCodeState(int32_t deviceId, int32_t scanCode, int32_t state) {
Device* device = getDevice(deviceId);
device->scanCodeStates.replaceValueFor(scanCode, state);
@@ -845,6 +854,14 @@
return AKEY_STATE_UNKNOWN;
}
+ InputDeviceCountryCode getCountryCode(int32_t deviceId) const override {
+ Device* device = getDevice(deviceId);
+ if (device) {
+ return device->countryCode;
+ }
+ return InputDeviceCountryCode::INVALID;
+ }
+
int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const override {
Device* device = getDevice(deviceId);
if (device) {
@@ -991,7 +1008,9 @@
return BATTERY_STATUS;
}
- std::vector<int32_t> getRawBatteryIds(int32_t deviceId) const override { return {}; }
+ std::vector<int32_t> getRawBatteryIds(int32_t deviceId) const override {
+ return {DEFAULT_BATTERY};
+ }
std::optional<RawBatteryInfo> getRawBatteryInfo(int32_t deviceId,
int32_t batteryId) const override {
@@ -2141,6 +2160,8 @@
~FakePeripheralController() override {}
+ int32_t getEventHubId() const { return getDeviceContext().getEventHubId(); }
+
void populateDeviceInfo(InputDeviceInfo* deviceInfo) override {}
void dump(std::string& dump) override {}
@@ -2174,6 +2195,7 @@
InputDeviceContext& mDeviceContext;
inline int32_t getDeviceId() { return mDeviceContext.getId(); }
inline InputDeviceContext& getDeviceContext() { return mDeviceContext; }
+ inline InputDeviceContext& getDeviceContext() const { return mDeviceContext; }
};
TEST_F(InputReaderTest, BatteryGetCapacity) {
@@ -2685,6 +2707,17 @@
ASSERT_EQ(ftl::Flags<InputDeviceClass>(0), mDevice->getClasses());
}
+TEST_F(InputDeviceTest, CountryCodeCorrectlyMapped) {
+ mFakeEventHub->setCountryCode(EVENTHUB_ID, InputDeviceCountryCode::INTERNATIONAL);
+
+ // Configuration
+ mDevice->addMapper<FakeInputMapper>(EVENTHUB_ID, AINPUT_SOURCE_KEYBOARD);
+ InputReaderConfiguration config;
+ mDevice->configure(ARBITRARY_TIME, &config, 0);
+
+ ASSERT_EQ(InputDeviceCountryCode::INTERNATIONAL, mDevice->getDeviceInfo().getCountryCode());
+}
+
TEST_F(InputDeviceTest, WhenDeviceCreated_EnabledIsFalse) {
ASSERT_EQ(mDevice->isEnabled(), false);
}
@@ -4088,6 +4121,37 @@
ASSERT_EQ(AMETA_NONE, mapper2.getMetaState());
}
+TEST_F(KeyboardInputMapperTest, Process_DisabledDevice) {
+ const int32_t USAGE_A = 0x070004;
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE);
+ mFakeEventHub->addKey(EVENTHUB_ID, 0, USAGE_A, AKEYCODE_A, POLICY_FLAG_WAKE);
+
+ KeyboardInputMapper& mapper =
+ addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
+ AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+ // Key down by scan code.
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_HOME, 1);
+ NotifyKeyArgs args;
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+ ASSERT_EQ(DEVICE_ID, args.deviceId);
+ ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source);
+ ASSERT_EQ(ARBITRARY_TIME, args.eventTime);
+ ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action);
+ ASSERT_EQ(AKEYCODE_HOME, args.keyCode);
+ ASSERT_EQ(KEY_HOME, args.scanCode);
+ ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags);
+
+ // Disable device, it should synthesize cancellation events for down events.
+ mFakePolicy->addDisabledDevice(DEVICE_ID);
+ configureDevice(InputReaderConfiguration::CHANGE_ENABLED_STATE);
+
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+ ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action);
+ ASSERT_EQ(AKEYCODE_HOME, args.keyCode);
+ ASSERT_EQ(KEY_HOME, args.scanCode);
+ ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_CANCELED, args.flags);
+}
+
// --- KeyboardInputMapperTest_ExternalDevice ---
class KeyboardInputMapperTest_ExternalDevice : public InputMapperTest {
diff --git a/services/sensorservice/AidlSensorHalWrapper.cpp b/services/sensorservice/AidlSensorHalWrapper.cpp
index 4d1de96..f67c610 100644
--- a/services/sensorservice/AidlSensorHalWrapper.cpp
+++ b/services/sensorservice/AidlSensorHalWrapper.cpp
@@ -726,7 +726,7 @@
.type = type,
.format = format,
.size = static_cast<int32_t>(memory->size),
- .memoryHandle = makeToAidl(memory->handle),
+ .memoryHandle = dupToAidl(memory->handle),
};
return convertToStatus(mSensors->registerDirectChannel(mem, channelHandle));
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 76429ff..5e9fe65 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -25,6 +25,7 @@
cc_defaults {
name: "libsurfaceflinger_defaults",
defaults: [
+ "android.hardware.graphics.composer3-ndk_shared",
"surfaceflinger_defaults",
"skia_renderengine_deps",
],
@@ -46,7 +47,6 @@
"android.hardware.graphics.composer@2.2",
"android.hardware.graphics.composer@2.3",
"android.hardware.graphics.composer@2.4",
- "android.hardware.graphics.composer3-V1-ndk",
"android.hardware.power@1.0",
"android.hardware.power@1.3",
"android.hardware.power-V2-cpp",
@@ -106,7 +106,6 @@
"android.hardware.graphics.composer@2.2",
"android.hardware.graphics.composer@2.3",
"android.hardware.graphics.composer@2.4",
- "android.hardware.graphics.composer3-V1-ndk",
"android.hardware.power@1.3",
"libhidlbase",
"libtimestats",
@@ -142,7 +141,6 @@
name: "libsurfaceflinger_sources",
srcs: [
"BackgroundExecutor.cpp",
- "BufferStateLayer.cpp",
"ClientCache.cpp",
"Client.cpp",
"EffectLayer.cpp",
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
deleted file mode 100644
index 0cedfc8..0000000
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ /dev/null
@@ -1,1639 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#undef LOG_TAG
-#define LOG_TAG "BufferStateLayer"
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-
-#include "BufferStateLayer.h"
-
-#include <limits>
-
-#include <FrameTimeline/FrameTimeline.h>
-#include <compositionengine/CompositionEngine.h>
-#include <gui/BufferQueue.h>
-#include <private/gui/SyncFeatures.h>
-#include <renderengine/Image.h>
-#include "TunnelModeEnabledReporter.h"
-
-#include <gui/TraceUtils.h>
-#include "EffectLayer.h"
-#include "FrameTracer/FrameTracer.h"
-#include "TimeStats/TimeStats.h"
-
-#define EARLY_RELEASE_ENABLED false
-
-#include <compositionengine/LayerFECompositionState.h>
-#include <compositionengine/OutputLayer.h>
-#include <compositionengine/impl/OutputLayerCompositionState.h>
-#include <cutils/compiler.h>
-#include <cutils/native_handle.h>
-#include <cutils/properties.h>
-#include <gui/BufferItem.h>
-#include <gui/BufferQueue.h>
-#include <gui/GLConsumer.h>
-#include <gui/LayerDebugInfo.h>
-#include <gui/Surface.h>
-#include <renderengine/RenderEngine.h>
-#include <ui/DebugUtils.h>
-#include <utils/Errors.h>
-#include <utils/Log.h>
-#include <utils/NativeHandle.h>
-#include <utils/StopWatch.h>
-#include <utils/Trace.h>
-
-#include <cmath>
-#include <cstdlib>
-#include <mutex>
-#include <sstream>
-
-#include "Colorizer.h"
-#include "DisplayDevice.h"
-#include "FrameTracer/FrameTracer.h"
-#include "TimeStats/TimeStats.h"
-
-namespace android {
-
-using PresentState = frametimeline::SurfaceFrame::PresentState;
-using gui::WindowInfo;
-namespace {
-static constexpr float defaultMaxLuminance = 1000.0;
-
-constexpr mat4 inverseOrientation(uint32_t transform) {
- const mat4 flipH(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1);
- const mat4 flipV(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1);
- const mat4 rot90(0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1);
- mat4 tr;
-
- if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
- tr = tr * rot90;
- }
- if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
- tr = tr * flipH;
- }
- if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
- tr = tr * flipV;
- }
- return inverse(tr);
-}
-
-bool assignTransform(ui::Transform* dst, ui::Transform& from) {
- if (*dst == from) {
- return false;
- }
- *dst = from;
- return true;
-}
-
-TimeStats::SetFrameRateVote frameRateToSetFrameRateVotePayload(Layer::FrameRate frameRate) {
- using FrameRateCompatibility = TimeStats::SetFrameRateVote::FrameRateCompatibility;
- using Seamlessness = TimeStats::SetFrameRateVote::Seamlessness;
- const auto frameRateCompatibility = [frameRate] {
- switch (frameRate.type) {
- case Layer::FrameRateCompatibility::Default:
- return FrameRateCompatibility::Default;
- case Layer::FrameRateCompatibility::ExactOrMultiple:
- return FrameRateCompatibility::ExactOrMultiple;
- default:
- return FrameRateCompatibility::Undefined;
- }
- }();
-
- const auto seamlessness = [frameRate] {
- switch (frameRate.seamlessness) {
- case scheduler::Seamlessness::OnlySeamless:
- return Seamlessness::ShouldBeSeamless;
- case scheduler::Seamlessness::SeamedAndSeamless:
- return Seamlessness::NotRequired;
- default:
- return Seamlessness::Undefined;
- }
- }();
-
- return TimeStats::SetFrameRateVote{.frameRate = frameRate.rate.getValue(),
- .frameRateCompatibility = frameRateCompatibility,
- .seamlessness = seamlessness};
-}
-} // namespace
-
-BufferStateLayer::BufferStateLayer(const LayerCreationArgs& args)
- : Layer(args),
- mTextureName(args.textureName),
- mCompositionState{mFlinger->getCompositionEngine().createLayerFECompositionState()},
- mHwcSlotGenerator(sp<HwcSlotGenerator>::make()) {
- ALOGV("Creating Layer %s", getDebugName());
-
- mPremultipliedAlpha = !(args.flags & ISurfaceComposerClient::eNonPremultiplied);
- mPotentialCursor = args.flags & ISurfaceComposerClient::eCursorWindow;
- mProtectedByApp = args.flags & ISurfaceComposerClient::eProtectedByApp;
- mDrawingState.dataspace = ui::Dataspace::V0_SRGB;
-}
-
-BufferStateLayer::~BufferStateLayer() {
- // The original layer and the clone layer share the same texture and buffer. Therefore, only
- // one of the layers, in this case the original layer, needs to handle the deletion. The
- // original layer and the clone should be removed at the same time so there shouldn't be any
- // issue with the clone layer trying to use the texture.
- if (mBufferInfo.mBuffer != nullptr) {
- callReleaseBufferCallback(mDrawingState.releaseBufferListener,
- mBufferInfo.mBuffer->getBuffer(), mBufferInfo.mFrameNumber,
- mBufferInfo.mFence,
- mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(
- mOwnerUid));
- }
- if (!isClone()) {
- // The original layer and the clone layer share the same texture. Therefore, only one of
- // the layers, in this case the original layer, needs to handle the deletion. The original
- // layer and the clone should be removed at the same time so there shouldn't be any issue
- // with the clone layer trying to use the deleted texture.
- mFlinger->deleteTextureAsync(mTextureName);
- }
- const int32_t layerId = getSequence();
- mFlinger->mTimeStats->onDestroy(layerId);
- mFlinger->mFrameTracer->onDestroy(layerId);
-}
-
-void BufferStateLayer::callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener,
- const sp<GraphicBuffer>& buffer,
- uint64_t framenumber,
- const sp<Fence>& releaseFence,
- uint32_t currentMaxAcquiredBufferCount) {
- if (!listener) {
- return;
- }
- ATRACE_FORMAT_INSTANT("callReleaseBufferCallback %s - %" PRIu64, getDebugName(), framenumber);
- listener->onReleaseBuffer({buffer->getId(), framenumber},
- releaseFence ? releaseFence : Fence::NO_FENCE,
- currentMaxAcquiredBufferCount);
-}
-
-// -----------------------------------------------------------------------
-// Interface implementation for Layer
-// -----------------------------------------------------------------------
-void BufferStateLayer::onLayerDisplayed(ftl::SharedFuture<FenceResult> futureFenceResult) {
- // If we are displayed on multiple displays in a single composition cycle then we would
- // need to do careful tracking to enable the use of the mLastClientCompositionFence.
- // For example we can only use it if all the displays are client comp, and we need
- // to merge all the client comp fences. We could do this, but for now we just
- // disable the optimization when a layer is composed on multiple displays.
- if (mClearClientCompositionFenceOnLayerDisplayed) {
- mLastClientCompositionFence = nullptr;
- } else {
- mClearClientCompositionFenceOnLayerDisplayed = true;
- }
-
- // The previous release fence notifies the client that SurfaceFlinger is done with the previous
- // buffer that was presented on this layer. The first transaction that came in this frame that
- // replaced the previous buffer on this layer needs this release fence, because the fence will
- // let the client know when that previous buffer is removed from the screen.
- //
- // Every other transaction on this layer does not need a release fence because no other
- // Transactions that were set on this layer this frame are going to have their preceeding buffer
- // removed from the display this frame.
- //
- // For example, if we have 3 transactions this frame. The first transaction doesn't contain a
- // buffer so it doesn't need a previous release fence because the layer still needs the previous
- // buffer. The second transaction contains a buffer so it needs a previous release fence because
- // the previous buffer will be released this frame. The third transaction also contains a
- // buffer. It replaces the buffer in the second transaction. The buffer in the second
- // transaction will now no longer be presented so it is released immediately and the third
- // transaction doesn't need a previous release fence.
- sp<CallbackHandle> ch;
- for (auto& handle : mDrawingState.callbackHandles) {
- if (handle->releasePreviousBuffer &&
- mDrawingState.releaseBufferEndpoint == handle->listener) {
- ch = handle;
- break;
- }
- }
-
- // Prevent tracing the same release multiple times.
- if (mPreviousFrameNumber != mPreviousReleasedFrameNumber) {
- mPreviousReleasedFrameNumber = mPreviousFrameNumber;
- }
-
- if (ch != nullptr) {
- ch->previousReleaseCallbackId = mPreviousReleaseCallbackId;
- ch->previousReleaseFences.emplace_back(std::move(futureFenceResult));
- ch->name = mName;
- }
-}
-
-void BufferStateLayer::onSurfaceFrameCreated(
- const std::shared_ptr<frametimeline::SurfaceFrame>& surfaceFrame) {
- while (mPendingJankClassifications.size() >= kPendingClassificationMaxSurfaceFrames) {
- // Too many SurfaceFrames pending classification. The front of the deque is probably not
- // tracked by FrameTimeline and will never be presented. This will only result in a memory
- // leak.
- ALOGW("Removing the front of pending jank deque from layer - %s to prevent memory leak",
- mName.c_str());
- std::string miniDump = mPendingJankClassifications.front()->miniDump();
- ALOGD("Head SurfaceFrame mini dump\n%s", miniDump.c_str());
- mPendingJankClassifications.pop_front();
- }
- mPendingJankClassifications.emplace_back(surfaceFrame);
-}
-
-void BufferStateLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
- for (const auto& handle : mDrawingState.callbackHandles) {
- handle->transformHint = mTransformHint;
- handle->dequeueReadyTime = dequeueReadyTime;
- handle->currentMaxAcquiredBufferCount =
- mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(mOwnerUid);
- ATRACE_FORMAT_INSTANT("releasePendingBuffer %s - %" PRIu64, getDebugName(),
- handle->previousReleaseCallbackId.framenumber);
- }
-
- for (auto& handle : mDrawingState.callbackHandles) {
- if (handle->releasePreviousBuffer &&
- mDrawingState.releaseBufferEndpoint == handle->listener) {
- handle->previousReleaseCallbackId = mPreviousReleaseCallbackId;
- break;
- }
- }
-
- std::vector<JankData> jankData;
- jankData.reserve(mPendingJankClassifications.size());
- while (!mPendingJankClassifications.empty()
- && mPendingJankClassifications.front()->getJankType()) {
- std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame =
- mPendingJankClassifications.front();
- mPendingJankClassifications.pop_front();
- jankData.emplace_back(
- JankData(surfaceFrame->getToken(), surfaceFrame->getJankType().value()));
- }
-
- mFlinger->getTransactionCallbackInvoker().addCallbackHandles(
- mDrawingState.callbackHandles, jankData);
-
- sp<Fence> releaseFence = Fence::NO_FENCE;
- for (auto& handle : mDrawingState.callbackHandles) {
- if (handle->releasePreviousBuffer &&
- mDrawingState.releaseBufferEndpoint == handle->listener) {
- releaseFence =
- handle->previousReleaseFence ? handle->previousReleaseFence : Fence::NO_FENCE;
- break;
- }
- }
-
- mDrawingState.callbackHandles = {};
-}
-
-bool BufferStateLayer::willPresentCurrentTransaction() const {
- // Returns true if the most recent Transaction applied to CurrentState will be presented.
- return (getSidebandStreamChanged() || getAutoRefresh() ||
- (mDrawingState.modified &&
- (mDrawingState.buffer != nullptr || mDrawingState.bgColorLayer != nullptr)));
-}
-
-Rect BufferStateLayer::getCrop(const Layer::State& s) const {
- return s.crop;
-}
-
-bool BufferStateLayer::setTransform(uint32_t transform) {
- if (mDrawingState.bufferTransform == transform) return false;
- mDrawingState.bufferTransform = transform;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool BufferStateLayer::setTransformToDisplayInverse(bool transformToDisplayInverse) {
- if (mDrawingState.transformToDisplayInverse == transformToDisplayInverse) return false;
- mDrawingState.sequence++;
- mDrawingState.transformToDisplayInverse = transformToDisplayInverse;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool BufferStateLayer::setCrop(const Rect& crop) {
- if (mDrawingState.crop == crop) return false;
- mDrawingState.sequence++;
- mDrawingState.crop = crop;
-
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool BufferStateLayer::setBufferCrop(const Rect& bufferCrop) {
- if (mDrawingState.bufferCrop == bufferCrop) return false;
-
- mDrawingState.sequence++;
- mDrawingState.bufferCrop = bufferCrop;
-
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool BufferStateLayer::setDestinationFrame(const Rect& destinationFrame) {
- if (mDrawingState.destinationFrame == destinationFrame) return false;
-
- mDrawingState.sequence++;
- mDrawingState.destinationFrame = destinationFrame;
-
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-// Translate destination frame into scale and position. If a destination frame is not set, use the
-// provided scale and position
-bool BufferStateLayer::updateGeometry() {
- if ((mDrawingState.flags & layer_state_t::eIgnoreDestinationFrame) ||
- mDrawingState.destinationFrame.isEmpty()) {
- // If destination frame is not set, use the requested transform set via
- // BufferStateLayer::setPosition and BufferStateLayer::setMatrix.
- return assignTransform(&mDrawingState.transform, mRequestedTransform);
- }
-
- Rect destRect = mDrawingState.destinationFrame;
- int32_t destW = destRect.width();
- int32_t destH = destRect.height();
- if (destRect.left < 0) {
- destRect.left = 0;
- destRect.right = destW;
- }
- if (destRect.top < 0) {
- destRect.top = 0;
- destRect.bottom = destH;
- }
-
- if (!mDrawingState.buffer) {
- ui::Transform t;
- t.set(destRect.left, destRect.top);
- return assignTransform(&mDrawingState.transform, t);
- }
-
- uint32_t bufferWidth = mDrawingState.buffer->getWidth();
- uint32_t bufferHeight = mDrawingState.buffer->getHeight();
- // Undo any transformations on the buffer.
- if (mDrawingState.bufferTransform & ui::Transform::ROT_90) {
- std::swap(bufferWidth, bufferHeight);
- }
- uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags();
- if (mDrawingState.transformToDisplayInverse) {
- if (invTransform & ui::Transform::ROT_90) {
- std::swap(bufferWidth, bufferHeight);
- }
- }
-
- float sx = destW / static_cast<float>(bufferWidth);
- float sy = destH / static_cast<float>(bufferHeight);
- ui::Transform t;
- t.set(sx, 0, 0, sy);
- t.set(destRect.left, destRect.top);
- return assignTransform(&mDrawingState.transform, t);
-}
-
-bool BufferStateLayer::setMatrix(const layer_state_t::matrix22_t& matrix) {
- if (mRequestedTransform.dsdx() == matrix.dsdx && mRequestedTransform.dtdy() == matrix.dtdy &&
- mRequestedTransform.dtdx() == matrix.dtdx && mRequestedTransform.dsdy() == matrix.dsdy) {
- return false;
- }
-
- ui::Transform t;
- t.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
-
- mRequestedTransform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
-
- mDrawingState.sequence++;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
-
- return true;
-}
-
-bool BufferStateLayer::setPosition(float x, float y) {
- if (mRequestedTransform.tx() == x && mRequestedTransform.ty() == y) {
- return false;
- }
-
- mRequestedTransform.set(x, y);
-
- mDrawingState.sequence++;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
-
- return true;
-}
-
-bool BufferStateLayer::setBuffer(std::shared_ptr<renderengine::ExternalTexture>& buffer,
- const BufferData& bufferData, nsecs_t postTime,
- nsecs_t desiredPresentTime, bool isAutoTimestamp,
- std::optional<nsecs_t> dequeueTime,
- const FrameTimelineInfo& info) {
- ATRACE_CALL();
-
- if (!buffer) {
- return false;
- }
-
- const bool frameNumberChanged =
- bufferData.flags.test(BufferData::BufferDataChange::frameNumberChanged);
- const uint64_t frameNumber =
- frameNumberChanged ? bufferData.frameNumber : mDrawingState.frameNumber + 1;
-
- if (mDrawingState.buffer) {
- mReleasePreviousBuffer = true;
- if (!mBufferInfo.mBuffer ||
- (!mDrawingState.buffer->hasSameBuffer(*mBufferInfo.mBuffer) ||
- mDrawingState.frameNumber != mBufferInfo.mFrameNumber)) {
- // If mDrawingState has a buffer, and we are about to update again
- // before swapping to drawing state, then the first buffer will be
- // dropped and we should decrement the pending buffer count and
- // call any release buffer callbacks if set.
- callReleaseBufferCallback(mDrawingState.releaseBufferListener,
- mDrawingState.buffer->getBuffer(), mDrawingState.frameNumber,
- mDrawingState.acquireFence,
- mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(
- mOwnerUid));
- decrementPendingBufferCount();
- if (mDrawingState.bufferSurfaceFrameTX != nullptr &&
- mDrawingState.bufferSurfaceFrameTX->getPresentState() != PresentState::Presented) {
- addSurfaceFrameDroppedForBuffer(mDrawingState.bufferSurfaceFrameTX);
- mDrawingState.bufferSurfaceFrameTX.reset();
- }
- } else if (EARLY_RELEASE_ENABLED && mLastClientCompositionFence != nullptr) {
- callReleaseBufferCallback(mDrawingState.releaseBufferListener,
- mDrawingState.buffer->getBuffer(), mDrawingState.frameNumber,
- mLastClientCompositionFence,
- mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(
- mOwnerUid));
- mLastClientCompositionFence = nullptr;
- }
- }
-
- mDrawingState.frameNumber = frameNumber;
- mDrawingState.releaseBufferListener = bufferData.releaseBufferListener;
- mDrawingState.buffer = std::move(buffer);
- mDrawingState.clientCacheId = bufferData.cachedBuffer;
-
- mDrawingState.acquireFence = bufferData.flags.test(BufferData::BufferDataChange::fenceChanged)
- ? bufferData.acquireFence
- : Fence::NO_FENCE;
- mDrawingState.acquireFenceTime = std::make_unique<FenceTime>(mDrawingState.acquireFence);
- if (mDrawingState.acquireFenceTime->getSignalTime() == Fence::SIGNAL_TIME_PENDING) {
- // We latched this buffer unsiganled, so we need to pass the acquire fence
- // on the callback instead of just the acquire time, since it's unknown at
- // this point.
- mCallbackHandleAcquireTimeOrFence = mDrawingState.acquireFence;
- } else {
- mCallbackHandleAcquireTimeOrFence = mDrawingState.acquireFenceTime->getSignalTime();
- }
-
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
-
- const int32_t layerId = getSequence();
- mFlinger->mTimeStats->setPostTime(layerId, mDrawingState.frameNumber, getName().c_str(),
- mOwnerUid, postTime, getGameMode());
- mDrawingState.desiredPresentTime = desiredPresentTime;
- mDrawingState.isAutoTimestamp = isAutoTimestamp;
-
- const nsecs_t presentTime = [&] {
- if (!isAutoTimestamp) return desiredPresentTime;
-
- const auto prediction =
- mFlinger->mFrameTimeline->getTokenManager()->getPredictionsForToken(info.vsyncId);
- if (prediction.has_value()) return prediction->presentTime;
-
- return static_cast<nsecs_t>(0);
- }();
-
- using LayerUpdateType = scheduler::LayerHistory::LayerUpdateType;
- mFlinger->mScheduler->recordLayerHistory(this, presentTime, LayerUpdateType::Buffer);
-
- setFrameTimelineVsyncForBufferTransaction(info, postTime);
-
- if (dequeueTime && *dequeueTime != 0) {
- const uint64_t bufferId = mDrawingState.buffer->getId();
- mFlinger->mFrameTracer->traceNewLayer(layerId, getName().c_str());
- mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, *dequeueTime,
- FrameTracer::FrameEvent::DEQUEUE);
- mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, postTime,
- FrameTracer::FrameEvent::QUEUE);
- }
-
- mDrawingState.releaseBufferEndpoint = bufferData.releaseBufferEndpoint;
- return true;
-}
-
-bool BufferStateLayer::setDataspace(ui::Dataspace dataspace) {
- if (mDrawingState.dataspace == dataspace) return false;
- mDrawingState.dataspace = dataspace;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool BufferStateLayer::setHdrMetadata(const HdrMetadata& hdrMetadata) {
- if (mDrawingState.hdrMetadata == hdrMetadata) return false;
- mDrawingState.hdrMetadata = hdrMetadata;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool BufferStateLayer::setSurfaceDamageRegion(const Region& surfaceDamage) {
- mDrawingState.surfaceDamageRegion = surfaceDamage;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool BufferStateLayer::setApi(int32_t api) {
- if (mDrawingState.api == api) return false;
- mDrawingState.api = api;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool BufferStateLayer::setSidebandStream(const sp<NativeHandle>& sidebandStream) {
- if (mDrawingState.sidebandStream == sidebandStream) return false;
-
- if (mDrawingState.sidebandStream != nullptr && sidebandStream == nullptr) {
- mFlinger->mTunnelModeEnabledReporter->decrementTunnelModeCount();
- } else if (sidebandStream != nullptr) {
- mFlinger->mTunnelModeEnabledReporter->incrementTunnelModeCount();
- }
-
- mDrawingState.sidebandStream = sidebandStream;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- if (!mSidebandStreamChanged.exchange(true)) {
- // mSidebandStreamChanged was false
- mFlinger->onLayerUpdate();
- }
- return true;
-}
-
-bool BufferStateLayer::setTransactionCompletedListeners(
- const std::vector<sp<CallbackHandle>>& handles) {
- // If there is no handle, we will not send a callback so reset mReleasePreviousBuffer and return
- if (handles.empty()) {
- mReleasePreviousBuffer = false;
- return false;
- }
-
- const bool willPresent = willPresentCurrentTransaction();
-
- for (const auto& handle : handles) {
- // If this transaction set a buffer on this layer, release its previous buffer
- handle->releasePreviousBuffer = mReleasePreviousBuffer;
-
- // If this layer will be presented in this frame
- if (willPresent) {
- // If this transaction set an acquire fence on this layer, set its acquire time
- handle->acquireTimeOrFence = mCallbackHandleAcquireTimeOrFence;
- handle->frameNumber = mDrawingState.frameNumber;
-
- // Store so latched time and release fence can be set
- mDrawingState.callbackHandles.push_back(handle);
-
- } else { // If this layer will NOT need to be relatched and presented this frame
- // Notify the transaction completed thread this handle is done
- mFlinger->getTransactionCallbackInvoker().registerUnpresentedCallbackHandle(handle);
- }
- }
-
- mReleasePreviousBuffer = false;
- mCallbackHandleAcquireTimeOrFence = -1;
-
- return willPresent;
-}
-
-Rect BufferStateLayer::getBufferSize(const State& /*s*/) const {
- // for buffer state layers we use the display frame size as the buffer size.
-
- if (mBufferInfo.mBuffer == nullptr) {
- return Rect::INVALID_RECT;
- }
-
- uint32_t bufWidth = mBufferInfo.mBuffer->getWidth();
- uint32_t bufHeight = mBufferInfo.mBuffer->getHeight();
-
- // Undo any transformations on the buffer and return the result.
- if (mBufferInfo.mTransform & ui::Transform::ROT_90) {
- std::swap(bufWidth, bufHeight);
- }
-
- if (getTransformToDisplayInverse()) {
- uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags();
- if (invTransform & ui::Transform::ROT_90) {
- std::swap(bufWidth, bufHeight);
- }
- }
-
- return Rect(0, 0, static_cast<int32_t>(bufWidth), static_cast<int32_t>(bufHeight));
-}
-
-FloatRect BufferStateLayer::computeSourceBounds(const FloatRect& parentBounds) const {
- if (mBufferInfo.mBuffer == nullptr) {
- return parentBounds;
- }
-
- return getBufferSize(getDrawingState()).toFloatRect();
-}
-
-// -----------------------------------------------------------------------
-bool BufferStateLayer::fenceHasSignaled() const {
- if (SurfaceFlinger::enableLatchUnsignaledConfig != LatchUnsignaledConfig::Disabled) {
- return true;
- }
-
- const bool fenceSignaled =
- getDrawingState().acquireFence->getStatus() == Fence::Status::Signaled;
- if (!fenceSignaled) {
- mFlinger->mTimeStats->incrementLatchSkipped(getSequence(),
- TimeStats::LatchSkipReason::LateAcquire);
- }
-
- return fenceSignaled;
-}
-
-bool BufferStateLayer::onPreComposition(nsecs_t refreshStartTime) {
- for (const auto& handle : mDrawingState.callbackHandles) {
- handle->refreshStartTime = refreshStartTime;
- }
- return hasReadyFrame();
-}
-
-void BufferStateLayer::setAutoRefresh(bool autoRefresh) {
- mDrawingState.autoRefresh = autoRefresh;
-}
-
-bool BufferStateLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
- // We need to update the sideband stream if the layer has both a buffer and a sideband stream.
- editCompositionState()->sidebandStreamHasFrame = hasFrameUpdate() && mSidebandStream.get();
-
- if (mSidebandStreamChanged.exchange(false)) {
- const State& s(getDrawingState());
- // mSidebandStreamChanged was true
- mSidebandStream = s.sidebandStream;
- editCompositionState()->sidebandStream = mSidebandStream;
- if (mSidebandStream != nullptr) {
- setTransactionFlags(eTransactionNeeded);
- mFlinger->setTransactionFlags(eTraversalNeeded);
- }
- recomputeVisibleRegions = true;
-
- return true;
- }
- return false;
-}
-
-bool BufferStateLayer::hasFrameUpdate() const {
- const State& c(getDrawingState());
- return (mDrawingStateModified || mDrawingState.modified) && (c.buffer != nullptr || c.bgColorLayer != nullptr);
-}
-
-void BufferStateLayer::updateTexImage(nsecs_t latchTime) {
- const State& s(getDrawingState());
-
- if (!s.buffer) {
- if (s.bgColorLayer) {
- for (auto& handle : mDrawingState.callbackHandles) {
- handle->latchTime = latchTime;
- }
- }
- return;
- }
-
- for (auto& handle : mDrawingState.callbackHandles) {
- if (handle->frameNumber == mDrawingState.frameNumber) {
- handle->latchTime = latchTime;
- }
- }
-
- const int32_t layerId = getSequence();
- const uint64_t bufferId = mDrawingState.buffer->getId();
- const uint64_t frameNumber = mDrawingState.frameNumber;
- const auto acquireFence = std::make_shared<FenceTime>(mDrawingState.acquireFence);
- mFlinger->mTimeStats->setAcquireFence(layerId, frameNumber, acquireFence);
- mFlinger->mTimeStats->setLatchTime(layerId, frameNumber, latchTime);
-
- mFlinger->mFrameTracer->traceFence(layerId, bufferId, frameNumber, acquireFence,
- FrameTracer::FrameEvent::ACQUIRE_FENCE);
- mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, latchTime,
- FrameTracer::FrameEvent::LATCH);
-
- auto& bufferSurfaceFrame = mDrawingState.bufferSurfaceFrameTX;
- if (bufferSurfaceFrame != nullptr &&
- bufferSurfaceFrame->getPresentState() != PresentState::Presented) {
- // Update only if the bufferSurfaceFrame wasn't already presented. A Presented
- // bufferSurfaceFrame could be seen here if a pending state was applied successfully and we
- // are processing the next state.
- addSurfaceFramePresentedForBuffer(bufferSurfaceFrame,
- mDrawingState.acquireFenceTime->getSignalTime(),
- latchTime);
- mDrawingState.bufferSurfaceFrameTX.reset();
- }
-
- std::deque<sp<CallbackHandle>> remainingHandles;
- mFlinger->getTransactionCallbackInvoker()
- .addOnCommitCallbackHandles(mDrawingState.callbackHandles, remainingHandles);
- mDrawingState.callbackHandles = remainingHandles;
-
- mDrawingStateModified = false;
-}
-
-void BufferStateLayer::gatherBufferInfo() {
- if (!mBufferInfo.mBuffer || !mDrawingState.buffer->hasSameBuffer(*mBufferInfo.mBuffer)) {
- decrementPendingBufferCount();
- }
-
- mPreviousReleaseCallbackId = {getCurrentBufferId(), mBufferInfo.mFrameNumber};
- mBufferInfo.mBuffer = mDrawingState.buffer;
- mBufferInfo.mFence = mDrawingState.acquireFence;
- mBufferInfo.mFrameNumber = mDrawingState.frameNumber;
- mBufferInfo.mPixelFormat =
- !mBufferInfo.mBuffer ? PIXEL_FORMAT_NONE : mBufferInfo.mBuffer->getPixelFormat();
- mBufferInfo.mFrameLatencyNeeded = true;
- mBufferInfo.mDesiredPresentTime = mDrawingState.desiredPresentTime;
- mBufferInfo.mFenceTime = std::make_shared<FenceTime>(mDrawingState.acquireFence);
- mBufferInfo.mFence = mDrawingState.acquireFence;
- mBufferInfo.mTransform = mDrawingState.bufferTransform;
- auto lastDataspace = mBufferInfo.mDataspace;
- mBufferInfo.mDataspace = translateDataspace(mDrawingState.dataspace);
- if (lastDataspace != mBufferInfo.mDataspace) {
- mFlinger->mSomeDataspaceChanged = true;
- }
- mBufferInfo.mCrop = computeBufferCrop(mDrawingState);
- mBufferInfo.mScaleMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
- mBufferInfo.mSurfaceDamage = mDrawingState.surfaceDamageRegion;
- mBufferInfo.mHdrMetadata = mDrawingState.hdrMetadata;
- mBufferInfo.mApi = mDrawingState.api;
- mBufferInfo.mTransformToDisplayInverse = mDrawingState.transformToDisplayInverse;
- mBufferInfo.mBufferSlot = mHwcSlotGenerator->getHwcCacheSlot(mDrawingState.clientCacheId);
-}
-
-Rect BufferStateLayer::computeBufferCrop(const State& s) {
- if (s.buffer && !s.bufferCrop.isEmpty()) {
- Rect bufferCrop;
- s.buffer->getBounds().intersect(s.bufferCrop, &bufferCrop);
- return bufferCrop;
- } else if (s.buffer) {
- return s.buffer->getBounds();
- } else {
- return s.bufferCrop;
- }
-}
-
-sp<Layer> BufferStateLayer::createClone() {
- LayerCreationArgs args(mFlinger.get(), nullptr, mName + " (Mirror)", 0, LayerMetadata());
- args.textureName = mTextureName;
- sp<BufferStateLayer> layer = mFlinger->getFactory().createBufferStateLayer(args);
- layer->mHwcSlotGenerator = mHwcSlotGenerator;
- layer->setInitialValuesForClone(sp<Layer>::fromExisting(this));
- return layer;
-}
-
-bool BufferStateLayer::bufferNeedsFiltering() const {
- const State& s(getDrawingState());
- if (!s.buffer) {
- return false;
- }
-
- int32_t bufferWidth = static_cast<int32_t>(s.buffer->getWidth());
- int32_t bufferHeight = static_cast<int32_t>(s.buffer->getHeight());
-
- // Undo any transformations on the buffer and return the result.
- if (s.bufferTransform & ui::Transform::ROT_90) {
- std::swap(bufferWidth, bufferHeight);
- }
-
- if (s.transformToDisplayInverse) {
- uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags();
- if (invTransform & ui::Transform::ROT_90) {
- std::swap(bufferWidth, bufferHeight);
- }
- }
-
- const Rect layerSize{getBounds()};
- int32_t layerWidth = layerSize.getWidth();
- int32_t layerHeight = layerSize.getHeight();
-
- // Align the layer orientation with the buffer before comparism
- if (mTransformHint & ui::Transform::ROT_90) {
- std::swap(layerWidth, layerHeight);
- }
-
- return layerWidth != bufferWidth || layerHeight != bufferHeight;
-}
-
-void BufferStateLayer::decrementPendingBufferCount() {
- int32_t pendingBuffers = --mPendingBufferTransactions;
- tracePendingBufferCount(pendingBuffers);
-}
-
-void BufferStateLayer::tracePendingBufferCount(int32_t pendingBuffers) {
- ATRACE_INT(mBlastTransactionName.c_str(), pendingBuffers);
-}
-
-
-/*
- * We don't want to send the layer's transform to input, but rather the
- * parent's transform. This is because BufferStateLayer's transform is
- * information about how the buffer is placed on screen. The parent's
- * transform makes more sense to send since it's information about how the
- * layer is placed on screen. This transform is used by input to determine
- * how to go from screen space back to window space.
- */
-ui::Transform BufferStateLayer::getInputTransform() const {
- sp<Layer> parent = mDrawingParent.promote();
- if (parent == nullptr) {
- return ui::Transform();
- }
-
- return parent->getTransform();
-}
-
-/**
- * Similar to getInputTransform, we need to update the bounds to include the transform.
- * This is because bounds for BSL doesn't include buffer transform, where the input assumes
- * that's already included.
- */
-Rect BufferStateLayer::getInputBounds() const {
- Rect bufferBounds = getCroppedBufferSize(getDrawingState());
- if (mDrawingState.transform.getType() == ui::Transform::IDENTITY || !bufferBounds.isValid()) {
- return bufferBounds;
- }
- return mDrawingState.transform.transform(bufferBounds);
-}
-
-bool BufferStateLayer::simpleBufferUpdate(const layer_state_t& s) const {
- const uint64_t requiredFlags = layer_state_t::eBufferChanged;
-
- const uint64_t deniedFlags = layer_state_t::eProducerDisconnect | layer_state_t::eLayerChanged |
- layer_state_t::eRelativeLayerChanged | layer_state_t::eTransparentRegionChanged |
- layer_state_t::eFlagsChanged | layer_state_t::eBlurRegionsChanged |
- layer_state_t::eLayerStackChanged | layer_state_t::eAutoRefreshChanged |
- layer_state_t::eReparent;
-
- const uint64_t allowedFlags = layer_state_t::eHasListenerCallbacksChanged |
- layer_state_t::eFrameRateSelectionPriority | layer_state_t::eFrameRateChanged |
- layer_state_t::eSurfaceDamageRegionChanged | layer_state_t::eApiChanged |
- layer_state_t::eMetadataChanged | layer_state_t::eDropInputModeChanged |
- layer_state_t::eInputInfoChanged;
-
- if ((s.what & requiredFlags) != requiredFlags) {
- ALOGV("%s: false [missing required flags 0x%" PRIx64 "]", __func__,
- (s.what | requiredFlags) & ~s.what);
- return false;
- }
-
- if (s.what & deniedFlags) {
- ALOGV("%s: false [has denied flags 0x%" PRIx64 "]", __func__, s.what & deniedFlags);
- return false;
- }
-
- if (s.what & allowedFlags) {
- ALOGV("%s: [has allowed flags 0x%" PRIx64 "]", __func__, s.what & allowedFlags);
- }
-
- if (s.what & layer_state_t::ePositionChanged) {
- if (mRequestedTransform.tx() != s.x || mRequestedTransform.ty() != s.y) {
- ALOGV("%s: false [ePositionChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eAlphaChanged) {
- if (mDrawingState.color.a != s.alpha) {
- ALOGV("%s: false [eAlphaChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eColorTransformChanged) {
- if (mDrawingState.colorTransform != s.colorTransform) {
- ALOGV("%s: false [eColorTransformChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eBackgroundColorChanged) {
- if (mDrawingState.bgColorLayer || s.bgColorAlpha != 0) {
- ALOGV("%s: false [eBackgroundColorChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eMatrixChanged) {
- if (mRequestedTransform.dsdx() != s.matrix.dsdx ||
- mRequestedTransform.dtdy() != s.matrix.dtdy ||
- mRequestedTransform.dtdx() != s.matrix.dtdx ||
- mRequestedTransform.dsdy() != s.matrix.dsdy) {
- ALOGV("%s: false [eMatrixChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eCornerRadiusChanged) {
- if (mDrawingState.cornerRadius != s.cornerRadius) {
- ALOGV("%s: false [eCornerRadiusChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eBackgroundBlurRadiusChanged) {
- if (mDrawingState.backgroundBlurRadius != static_cast<int>(s.backgroundBlurRadius)) {
- ALOGV("%s: false [eBackgroundBlurRadiusChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eTransformChanged) {
- if (mDrawingState.bufferTransform != s.transform) {
- ALOGV("%s: false [eTransformChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eTransformToDisplayInverseChanged) {
- if (mDrawingState.transformToDisplayInverse != s.transformToDisplayInverse) {
- ALOGV("%s: false [eTransformToDisplayInverseChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eCropChanged) {
- if (mDrawingState.crop != s.crop) {
- ALOGV("%s: false [eCropChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eDataspaceChanged) {
- if (mDrawingState.dataspace != s.dataspace) {
- ALOGV("%s: false [eDataspaceChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eHdrMetadataChanged) {
- if (mDrawingState.hdrMetadata != s.hdrMetadata) {
- ALOGV("%s: false [eHdrMetadataChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eSidebandStreamChanged) {
- if (mDrawingState.sidebandStream != s.sidebandStream) {
- ALOGV("%s: false [eSidebandStreamChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eColorSpaceAgnosticChanged) {
- if (mDrawingState.colorSpaceAgnostic != s.colorSpaceAgnostic) {
- ALOGV("%s: false [eColorSpaceAgnosticChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eShadowRadiusChanged) {
- if (mDrawingState.shadowRadius != s.shadowRadius) {
- ALOGV("%s: false [eShadowRadiusChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eFixedTransformHintChanged) {
- if (mDrawingState.fixedTransformHint != s.fixedTransformHint) {
- ALOGV("%s: false [eFixedTransformHintChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eTrustedOverlayChanged) {
- if (mDrawingState.isTrustedOverlay != s.isTrustedOverlay) {
- ALOGV("%s: false [eTrustedOverlayChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eStretchChanged) {
- StretchEffect temp = s.stretchEffect;
- temp.sanitize();
- if (mDrawingState.stretchEffect != temp) {
- ALOGV("%s: false [eStretchChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eBufferCropChanged) {
- if (mDrawingState.bufferCrop != s.bufferCrop) {
- ALOGV("%s: false [eBufferCropChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eDestinationFrameChanged) {
- if (mDrawingState.destinationFrame != s.destinationFrame) {
- ALOGV("%s: false [eDestinationFrameChanged changed]", __func__);
- return false;
- }
- }
-
- if (s.what & layer_state_t::eDimmingEnabledChanged) {
- if (mDrawingState.dimmingEnabled != s.dimmingEnabled) {
- ALOGV("%s: false [eDimmingEnabledChanged changed]", __func__);
- return false;
- }
- }
-
- ALOGV("%s: true", __func__);
- return true;
-}
-
-void BufferStateLayer::useSurfaceDamage() {
- if (mFlinger->mForceFullDamage) {
- surfaceDamageRegion = Region::INVALID_REGION;
- } else {
- surfaceDamageRegion = mBufferInfo.mSurfaceDamage;
- }
-}
-
-void BufferStateLayer::useEmptyDamage() {
- surfaceDamageRegion.clear();
-}
-
-bool BufferStateLayer::isOpaque(const Layer::State& s) const {
- // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the
- // layer's opaque flag.
- if ((mSidebandStream == nullptr) && (mBufferInfo.mBuffer == nullptr)) {
- return false;
- }
-
- // if the layer has the opaque flag, then we're always opaque,
- // otherwise we use the current buffer's format.
- return ((s.flags & layer_state_t::eLayerOpaque) != 0) || getOpacityForFormat(getPixelFormat());
-}
-
-bool BufferStateLayer::canReceiveInput() const {
- return !isHiddenByPolicy() && (mBufferInfo.mBuffer == nullptr || getAlpha() > 0.0f);
-}
-
-bool BufferStateLayer::isVisible() const {
- return !isHiddenByPolicy() && getAlpha() > 0.0f &&
- (mBufferInfo.mBuffer != nullptr || mSidebandStream != nullptr);
-}
-
-std::optional<compositionengine::LayerFE::LayerSettings> BufferStateLayer::prepareClientComposition(
- compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) const {
- std::optional<compositionengine::LayerFE::LayerSettings> layerSettings =
- prepareClientCompositionInternal(targetSettings);
- // Nothing to render.
- if (!layerSettings) {
- return {};
- }
-
- // HWC requests to clear this layer.
- if (targetSettings.clearContent) {
- prepareClearClientComposition(*layerSettings, false /* blackout */);
- return *layerSettings;
- }
-
- // set the shadow for the layer if needed
- prepareShadowClientComposition(*layerSettings, targetSettings.viewport);
-
- return *layerSettings;
-}
-
-std::optional<compositionengine::LayerFE::LayerSettings>
-BufferStateLayer::prepareClientCompositionInternal(
- compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) const {
- ATRACE_CALL();
-
- std::optional<compositionengine::LayerFE::LayerSettings> result =
- Layer::prepareClientComposition(targetSettings);
- if (!result) {
- return result;
- }
-
- if (CC_UNLIKELY(mBufferInfo.mBuffer == 0) && mSidebandStream != nullptr) {
- // For surfaceview of tv sideband, there is no activeBuffer
- // in bufferqueue, we need return LayerSettings.
- return result;
- }
- const bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) ||
- ((isSecure() || isProtected()) && !targetSettings.isSecure);
- const bool bufferCanBeUsedAsHwTexture =
- mBufferInfo.mBuffer->getUsage() & GraphicBuffer::USAGE_HW_TEXTURE;
- compositionengine::LayerFE::LayerSettings& layer = *result;
- if (blackOutLayer || !bufferCanBeUsedAsHwTexture) {
- ALOGE_IF(!bufferCanBeUsedAsHwTexture, "%s is blacked out as buffer is not gpu readable",
- mName.c_str());
- prepareClearClientComposition(layer, true /* blackout */);
- return layer;
- }
-
- const State& s(getDrawingState());
- layer.source.buffer.buffer = mBufferInfo.mBuffer;
- layer.source.buffer.isOpaque = isOpaque(s);
- layer.source.buffer.fence = mBufferInfo.mFence;
- layer.source.buffer.textureName = mTextureName;
- layer.source.buffer.usePremultipliedAlpha = getPremultipledAlpha();
- layer.source.buffer.isY410BT2020 = isHdrY410();
- bool hasSmpte2086 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::SMPTE2086;
- bool hasCta861_3 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::CTA861_3;
- float maxLuminance = 0.f;
- if (hasSmpte2086 && hasCta861_3) {
- maxLuminance = std::min(mBufferInfo.mHdrMetadata.smpte2086.maxLuminance,
- mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel);
- } else if (hasSmpte2086) {
- maxLuminance = mBufferInfo.mHdrMetadata.smpte2086.maxLuminance;
- } else if (hasCta861_3) {
- maxLuminance = mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel;
- } else {
- switch (layer.sourceDataspace & HAL_DATASPACE_TRANSFER_MASK) {
- case HAL_DATASPACE_TRANSFER_ST2084:
- case HAL_DATASPACE_TRANSFER_HLG:
- // Behavior-match previous releases for HDR content
- maxLuminance = defaultMaxLuminance;
- break;
- }
- }
- layer.source.buffer.maxLuminanceNits = maxLuminance;
- layer.frameNumber = mCurrentFrameNumber;
- layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getId() : 0;
-
- const bool useFiltering =
- targetSettings.needsFiltering || mNeedsFiltering || bufferNeedsFiltering();
-
- // Query the texture matrix given our current filtering mode.
- float textureMatrix[16];
- getDrawingTransformMatrix(useFiltering, textureMatrix);
-
- if (getTransformToDisplayInverse()) {
- /*
- * the code below applies the primary display's inverse transform to
- * the texture transform
- */
- uint32_t transform = DisplayDevice::getPrimaryDisplayRotationFlags();
- mat4 tr = inverseOrientation(transform);
-
- /**
- * TODO(b/36727915): This is basically a hack.
- *
- * Ensure that regardless of the parent transformation,
- * this buffer is always transformed from native display
- * orientation to display orientation. For example, in the case
- * of a camera where the buffer remains in native orientation,
- * we want the pixels to always be upright.
- */
- sp<Layer> p = mDrawingParent.promote();
- if (p != nullptr) {
- const auto parentTransform = p->getTransform();
- tr = tr * inverseOrientation(parentTransform.getOrientation());
- }
-
- // and finally apply it to the original texture matrix
- const mat4 texTransform(mat4(static_cast<const float*>(textureMatrix)) * tr);
- memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix));
- }
-
- const Rect win{getBounds()};
- float bufferWidth = getBufferSize(s).getWidth();
- float bufferHeight = getBufferSize(s).getHeight();
-
- // BufferStateLayers can have a "buffer size" of [0, 0, -1, -1] when no display frame has
- // been set and there is no parent layer bounds. In that case, the scale is meaningless so
- // ignore them.
- if (!getBufferSize(s).isValid()) {
- bufferWidth = float(win.right) - float(win.left);
- bufferHeight = float(win.bottom) - float(win.top);
- }
-
- const float scaleHeight = (float(win.bottom) - float(win.top)) / bufferHeight;
- const float scaleWidth = (float(win.right) - float(win.left)) / bufferWidth;
- const float translateY = float(win.top) / bufferHeight;
- const float translateX = float(win.left) / bufferWidth;
-
- // Flip y-coordinates because GLConsumer expects OpenGL convention.
- mat4 tr = mat4::translate(vec4(.5f, .5f, 0.f, 1.f)) * mat4::scale(vec4(1.f, -1.f, 1.f, 1.f)) *
- mat4::translate(vec4(-.5f, -.5f, 0.f, 1.f)) *
- mat4::translate(vec4(translateX, translateY, 0.f, 1.f)) *
- mat4::scale(vec4(scaleWidth, scaleHeight, 1.0f, 1.0f));
-
- layer.source.buffer.useTextureFiltering = useFiltering;
- layer.source.buffer.textureTransform = mat4(static_cast<const float*>(textureMatrix)) * tr;
-
- return layer;
-}
-
-bool BufferStateLayer::isHdrY410() const {
- // pixel format is HDR Y410 masquerading as RGBA_1010102
- return (mBufferInfo.mDataspace == ui::Dataspace::BT2020_ITU_PQ &&
- mBufferInfo.mApi == NATIVE_WINDOW_API_MEDIA &&
- mBufferInfo.mPixelFormat == HAL_PIXEL_FORMAT_RGBA_1010102);
-}
-
-sp<compositionengine::LayerFE> BufferStateLayer::getCompositionEngineLayerFE() const {
- return asLayerFE();
-}
-
-compositionengine::LayerFECompositionState* BufferStateLayer::editCompositionState() {
- return mCompositionState.get();
-}
-
-const compositionengine::LayerFECompositionState* BufferStateLayer::getCompositionState() const {
- return mCompositionState.get();
-}
-
-void BufferStateLayer::preparePerFrameCompositionState() {
- Layer::preparePerFrameCompositionState();
-
- // Sideband layers
- auto* compositionState = editCompositionState();
- if (compositionState->sidebandStream.get() && !compositionState->sidebandStreamHasFrame) {
- compositionState->compositionType =
- aidl::android::hardware::graphics::composer3::Composition::SIDEBAND;
- return;
- } else if ((mDrawingState.flags & layer_state_t::eLayerIsDisplayDecoration) != 0) {
- compositionState->compositionType =
- aidl::android::hardware::graphics::composer3::Composition::DISPLAY_DECORATION;
- } else {
- // Normal buffer layers
- compositionState->hdrMetadata = mBufferInfo.mHdrMetadata;
- compositionState->compositionType = mPotentialCursor
- ? aidl::android::hardware::graphics::composer3::Composition::CURSOR
- : aidl::android::hardware::graphics::composer3::Composition::DEVICE;
- }
-
- compositionState->buffer = getBuffer();
- compositionState->bufferSlot = (mBufferInfo.mBufferSlot == BufferQueue::INVALID_BUFFER_SLOT)
- ? 0
- : mBufferInfo.mBufferSlot;
- compositionState->acquireFence = mBufferInfo.mFence;
- compositionState->frameNumber = mBufferInfo.mFrameNumber;
- compositionState->sidebandStreamHasFrame = false;
-}
-
-void BufferStateLayer::onPostComposition(const DisplayDevice* display,
- const std::shared_ptr<FenceTime>& glDoneFence,
- const std::shared_ptr<FenceTime>& presentFence,
- const CompositorTiming& compositorTiming) {
- // mFrameLatencyNeeded is true when a new frame was latched for the
- // composition.
- if (!mBufferInfo.mFrameLatencyNeeded) return;
-
- for (const auto& handle : mDrawingState.callbackHandles) {
- handle->gpuCompositionDoneFence = glDoneFence;
- handle->compositorTiming = compositorTiming;
- }
-
- // Update mFrameTracker.
- nsecs_t desiredPresentTime = mBufferInfo.mDesiredPresentTime;
- mFrameTracker.setDesiredPresentTime(desiredPresentTime);
-
- const int32_t layerId = getSequence();
- mFlinger->mTimeStats->setDesiredTime(layerId, mCurrentFrameNumber, desiredPresentTime);
-
- const auto outputLayer = findOutputLayerForDisplay(display);
- if (outputLayer && outputLayer->requiresClientComposition()) {
- nsecs_t clientCompositionTimestamp = outputLayer->getState().clientCompositionTimestamp;
- mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), mCurrentFrameNumber,
- clientCompositionTimestamp,
- FrameTracer::FrameEvent::FALLBACK_COMPOSITION);
- // Update the SurfaceFrames in the drawing state
- if (mDrawingState.bufferSurfaceFrameTX) {
- mDrawingState.bufferSurfaceFrameTX->setGpuComposition();
- }
- for (auto& [token, surfaceFrame] : mDrawingState.bufferlessSurfaceFramesTX) {
- surfaceFrame->setGpuComposition();
- }
- }
-
- std::shared_ptr<FenceTime> frameReadyFence = mBufferInfo.mFenceTime;
- if (frameReadyFence->isValid()) {
- mFrameTracker.setFrameReadyFence(std::move(frameReadyFence));
- } else {
- // There was no fence for this frame, so assume that it was ready
- // to be presented at the desired present time.
- mFrameTracker.setFrameReadyTime(desiredPresentTime);
- }
-
- if (display) {
- const Fps refreshRate = display->refreshRateConfigs().getActiveMode()->getFps();
- const std::optional<Fps> renderRate =
- mFlinger->mScheduler->getFrameRateOverride(getOwnerUid());
-
- const auto vote = frameRateToSetFrameRateVotePayload(mDrawingState.frameRate);
- const auto gameMode = getGameMode();
-
- if (presentFence->isValid()) {
- mFlinger->mTimeStats->setPresentFence(layerId, mCurrentFrameNumber, presentFence,
- refreshRate, renderRate, vote, gameMode);
- mFlinger->mFrameTracer->traceFence(layerId, getCurrentBufferId(), mCurrentFrameNumber,
- presentFence,
- FrameTracer::FrameEvent::PRESENT_FENCE);
- mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence));
- } else if (const auto displayId = PhysicalDisplayId::tryCast(display->getId());
- displayId && mFlinger->getHwComposer().isConnected(*displayId)) {
- // The HWC doesn't support present fences, so use the refresh
- // timestamp instead.
- const nsecs_t actualPresentTime = display->getRefreshTimestamp();
- mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime,
- refreshRate, renderRate, vote, gameMode);
- mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(),
- mCurrentFrameNumber, actualPresentTime,
- FrameTracer::FrameEvent::PRESENT_FENCE);
- mFrameTracker.setActualPresentTime(actualPresentTime);
- }
- }
-
- mFrameTracker.advanceFrame();
- mBufferInfo.mFrameLatencyNeeded = false;
-}
-
-bool BufferStateLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) {
- ATRACE_FORMAT_INSTANT("latchBuffer %s - %" PRIu64, getDebugName(),
- getDrawingState().frameNumber);
-
- bool refreshRequired = latchSidebandStream(recomputeVisibleRegions);
-
- if (refreshRequired) {
- return refreshRequired;
- }
-
- // If the head buffer's acquire fence hasn't signaled yet, return and
- // try again later
- if (!fenceHasSignaled()) {
- ATRACE_NAME("!fenceHasSignaled()");
- mFlinger->onLayerUpdate();
- return false;
- }
-
- updateTexImage(latchTime);
- if (mDrawingState.buffer == nullptr) {
- return false;
- }
-
- // Capture the old state of the layer for comparisons later
- BufferInfo oldBufferInfo = mBufferInfo;
- const bool oldOpacity = isOpaque(mDrawingState);
- mPreviousFrameNumber = mCurrentFrameNumber;
- mCurrentFrameNumber = mDrawingState.frameNumber;
- gatherBufferInfo();
-
- if (oldBufferInfo.mBuffer == nullptr) {
- // the first time we receive a buffer, we need to trigger a
- // geometry invalidation.
- recomputeVisibleRegions = true;
- }
-
- if ((mBufferInfo.mCrop != oldBufferInfo.mCrop) ||
- (mBufferInfo.mTransform != oldBufferInfo.mTransform) ||
- (mBufferInfo.mScaleMode != oldBufferInfo.mScaleMode) ||
- (mBufferInfo.mTransformToDisplayInverse != oldBufferInfo.mTransformToDisplayInverse)) {
- recomputeVisibleRegions = true;
- }
-
- if (oldBufferInfo.mBuffer != nullptr) {
- uint32_t bufWidth = mBufferInfo.mBuffer->getWidth();
- uint32_t bufHeight = mBufferInfo.mBuffer->getHeight();
- if (bufWidth != oldBufferInfo.mBuffer->getWidth() ||
- bufHeight != oldBufferInfo.mBuffer->getHeight()) {
- recomputeVisibleRegions = true;
- }
- }
-
- if (oldOpacity != isOpaque(mDrawingState)) {
- recomputeVisibleRegions = true;
- }
-
- return true;
-}
-
-bool BufferStateLayer::hasReadyFrame() const {
- return hasFrameUpdate() || getSidebandStreamChanged() || getAutoRefresh();
-}
-
-bool BufferStateLayer::isProtected() const {
- return (mBufferInfo.mBuffer != nullptr) &&
- (mBufferInfo.mBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
-}
-
-// As documented in libhardware header, formats in the range
-// 0x100 - 0x1FF are specific to the HAL implementation, and
-// are known to have no alpha channel
-// TODO: move definition for device-specific range into
-// hardware.h, instead of using hard-coded values here.
-#define HARDWARE_IS_DEVICE_FORMAT(f) ((f) >= 0x100 && (f) <= 0x1FF)
-
-bool BufferStateLayer::getOpacityForFormat(PixelFormat format) {
- if (HARDWARE_IS_DEVICE_FORMAT(format)) {
- return true;
- }
- switch (format) {
- case PIXEL_FORMAT_RGBA_8888:
- case PIXEL_FORMAT_BGRA_8888:
- case PIXEL_FORMAT_RGBA_FP16:
- case PIXEL_FORMAT_RGBA_1010102:
- case PIXEL_FORMAT_R_8:
- return false;
- }
- // in all other case, we have no blending (also for unknown formats)
- return true;
-}
-
-bool BufferStateLayer::needsFiltering(const DisplayDevice* display) const {
- const auto outputLayer = findOutputLayerForDisplay(display);
- if (outputLayer == nullptr) {
- return false;
- }
-
- // We need filtering if the sourceCrop rectangle size does not match the
- // displayframe rectangle size (not a 1:1 render)
- const auto& compositionState = outputLayer->getState();
- const auto displayFrame = compositionState.displayFrame;
- const auto sourceCrop = compositionState.sourceCrop;
- return sourceCrop.getHeight() != displayFrame.getHeight() ||
- sourceCrop.getWidth() != displayFrame.getWidth();
-}
-
-bool BufferStateLayer::needsFilteringForScreenshots(
- const DisplayDevice* display, const ui::Transform& inverseParentTransform) const {
- const auto outputLayer = findOutputLayerForDisplay(display);
- if (outputLayer == nullptr) {
- return false;
- }
-
- // We need filtering if the sourceCrop rectangle size does not match the
- // viewport rectangle size (not a 1:1 render)
- const auto& compositionState = outputLayer->getState();
- const ui::Transform& displayTransform = display->getTransform();
- const ui::Transform inverseTransform = inverseParentTransform * displayTransform.inverse();
- // Undo the transformation of the displayFrame so that we're back into
- // layer-stack space.
- const Rect frame = inverseTransform.transform(compositionState.displayFrame);
- const FloatRect sourceCrop = compositionState.sourceCrop;
-
- int32_t frameHeight = frame.getHeight();
- int32_t frameWidth = frame.getWidth();
- // If the display transform had a rotational component then undo the
- // rotation so that the orientation matches the source crop.
- if (displayTransform.getOrientation() & ui::Transform::ROT_90) {
- std::swap(frameHeight, frameWidth);
- }
- return sourceCrop.getHeight() != frameHeight || sourceCrop.getWidth() != frameWidth;
-}
-
-void BufferStateLayer::latchAndReleaseBuffer() {
- if (hasReadyFrame()) {
- bool ignored = false;
- latchBuffer(ignored, systemTime());
- }
- releasePendingBuffer(systemTime());
-}
-
-PixelFormat BufferStateLayer::getPixelFormat() const {
- return mBufferInfo.mPixelFormat;
-}
-
-bool BufferStateLayer::getTransformToDisplayInverse() const {
- return mBufferInfo.mTransformToDisplayInverse;
-}
-
-Rect BufferStateLayer::getBufferCrop() const {
- // this is the crop rectangle that applies to the buffer
- // itself (as opposed to the window)
- if (!mBufferInfo.mCrop.isEmpty()) {
- // if the buffer crop is defined, we use that
- return mBufferInfo.mCrop;
- } else if (mBufferInfo.mBuffer != nullptr) {
- // otherwise we use the whole buffer
- return mBufferInfo.mBuffer->getBounds();
- } else {
- // if we don't have a buffer yet, we use an empty/invalid crop
- return Rect();
- }
-}
-
-uint32_t BufferStateLayer::getBufferTransform() const {
- return mBufferInfo.mTransform;
-}
-
-ui::Dataspace BufferStateLayer::getDataSpace() const {
- return mBufferInfo.mDataspace;
-}
-
-ui::Dataspace BufferStateLayer::translateDataspace(ui::Dataspace dataspace) {
- ui::Dataspace updatedDataspace = dataspace;
- // translate legacy dataspaces to modern dataspaces
- switch (dataspace) {
- case ui::Dataspace::SRGB:
- updatedDataspace = ui::Dataspace::V0_SRGB;
- break;
- case ui::Dataspace::SRGB_LINEAR:
- updatedDataspace = ui::Dataspace::V0_SRGB_LINEAR;
- break;
- case ui::Dataspace::JFIF:
- updatedDataspace = ui::Dataspace::V0_JFIF;
- break;
- case ui::Dataspace::BT601_625:
- updatedDataspace = ui::Dataspace::V0_BT601_625;
- break;
- case ui::Dataspace::BT601_525:
- updatedDataspace = ui::Dataspace::V0_BT601_525;
- break;
- case ui::Dataspace::BT709:
- updatedDataspace = ui::Dataspace::V0_BT709;
- break;
- default:
- break;
- }
-
- return updatedDataspace;
-}
-
-sp<GraphicBuffer> BufferStateLayer::getBuffer() const {
- return mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer() : nullptr;
-}
-
-void BufferStateLayer::getDrawingTransformMatrix(bool filteringEnabled, float outMatrix[16]) const {
- sp<GraphicBuffer> buffer = getBuffer();
- if (!buffer) {
- ALOGE("Buffer should not be null!");
- return;
- }
- GLConsumer::computeTransformMatrix(outMatrix, buffer->getWidth(), buffer->getHeight(),
- buffer->getPixelFormat(), mBufferInfo.mCrop,
- mBufferInfo.mTransform, filteringEnabled);
-}
-
-void BufferStateLayer::setInitialValuesForClone(const sp<Layer>& clonedFrom) {
- Layer::setInitialValuesForClone(clonedFrom);
-
- sp<BufferStateLayer> bufferClonedFrom =
- sp<BufferStateLayer>::fromExisting(static_cast<BufferStateLayer*>(clonedFrom.get()));
- mPremultipliedAlpha = bufferClonedFrom->mPremultipliedAlpha;
- mPotentialCursor = bufferClonedFrom->mPotentialCursor;
- mProtectedByApp = bufferClonedFrom->mProtectedByApp;
-
- updateCloneBufferInfo();
-}
-
-void BufferStateLayer::updateCloneBufferInfo() {
- if (!isClone() || !isClonedFromAlive()) {
- return;
- }
-
- sp<BufferStateLayer> clonedFrom = sp<BufferStateLayer>::fromExisting(
- static_cast<BufferStateLayer*>(getClonedFrom().get()));
- mBufferInfo = clonedFrom->mBufferInfo;
- mSidebandStream = clonedFrom->mSidebandStream;
- surfaceDamageRegion = clonedFrom->surfaceDamageRegion;
- mCurrentFrameNumber = clonedFrom->mCurrentFrameNumber.load();
- mPreviousFrameNumber = clonedFrom->mPreviousFrameNumber;
-
- // After buffer info is updated, the drawingState from the real layer needs to be copied into
- // the cloned. This is because some properties of drawingState can change when latchBuffer is
- // called. However, copying the drawingState would also overwrite the cloned layer's relatives
- // and touchableRegionCrop. Therefore, temporarily store the relatives so they can be set in
- // the cloned drawingState again.
- wp<Layer> tmpZOrderRelativeOf = mDrawingState.zOrderRelativeOf;
- SortedVector<wp<Layer>> tmpZOrderRelatives = mDrawingState.zOrderRelatives;
- wp<Layer> tmpTouchableRegionCrop = mDrawingState.touchableRegionCrop;
- WindowInfo tmpInputInfo = mDrawingState.inputInfo;
-
- cloneDrawingState(clonedFrom.get());
-
- mDrawingState.touchableRegionCrop = tmpTouchableRegionCrop;
- mDrawingState.zOrderRelativeOf = tmpZOrderRelativeOf;
- mDrawingState.zOrderRelatives = tmpZOrderRelatives;
- mDrawingState.inputInfo = tmpInputInfo;
-}
-
-void BufferStateLayer::setTransformHint(ui::Transform::RotationFlags displayTransformHint) {
- mTransformHint = getFixedTransformHint();
- if (mTransformHint == ui::Transform::ROT_INVALID) {
- mTransformHint = displayTransformHint;
- }
-}
-
-const std::shared_ptr<renderengine::ExternalTexture>& BufferStateLayer::getExternalTexture() const {
- return mBufferInfo.mBuffer;
-}
-
-} // namespace android
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index a0a52bf..e53e1c1 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -16,288 +16,13 @@
#pragma once
-#include <sys/types.h>
-#include <cstdint>
-#include <list>
-#include <stack>
-
-#include <android/gui/ISurfaceComposerClient.h>
-#include <gui/LayerState.h>
-#include <renderengine/Image.h>
-#include <renderengine/Mesh.h>
-#include <renderengine/RenderEngine.h>
-#include <renderengine/Texture.h>
-#include <system/window.h> // For NATIVE_WINDOW_SCALING_MODE_FREEZE
-#include <ui/FrameStats.h>
-#include <ui/GraphicBuffer.h>
-#include <ui/PixelFormat.h>
-#include <ui/Region.h>
-#include <utils/RefBase.h>
-#include <utils/String8.h>
-#include <utils/Timers.h>
-
-#include "Client.h"
-#include "DisplayHardware/HWComposer.h"
-#include "FrameTimeline.h"
-#include "FrameTracker.h"
-#include "HwcSlotGenerator.h"
#include "Layer.h"
-#include "LayerVector.h"
-#include "SurfaceFlinger.h"
namespace android {
-class SlotGenerationTest;
-
class BufferStateLayer : public Layer {
public:
- explicit BufferStateLayer(const LayerCreationArgs&);
-
- ~BufferStateLayer() override;
-
- // Implements Layer.
- sp<compositionengine::LayerFE> getCompositionEngineLayerFE() const override;
- compositionengine::LayerFECompositionState* editCompositionState() override;
-
- // If we have received a new buffer this frame, we will pass its surface
- // damage down to hardware composer. Otherwise, we must send a region with
- // one empty rect.
- void useSurfaceDamage() override;
- void useEmptyDamage() override;
-
- bool isOpaque(const Layer::State& s) const override;
- bool canReceiveInput() const override;
-
- // isVisible - true if this layer is visible, false otherwise
- bool isVisible() const override;
-
- // isProtected - true if the layer may contain protected content in the
- // GRALLOC_USAGE_PROTECTED sense.
- bool isProtected() const override;
-
- bool usesSourceCrop() const override { return true; }
-
- bool isHdrY410() const override;
-
- void onPostComposition(const DisplayDevice*, const std::shared_ptr<FenceTime>& glDoneFence,
- const std::shared_ptr<FenceTime>& presentFence,
- const CompositorTiming&) override;
-
- // latchBuffer - called each time the screen is redrawn and returns whether
- // the visible regions need to be recomputed (this is a fairly heavy
- // operation, so this should be set only if needed). Typically this is used
- // to figure out if the content or size of a surface has changed.
- bool latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
- bool hasReadyFrame() const override;
-
- // Calls latchBuffer if the buffer has a frame queued and then releases the buffer.
- // This is used if the buffer is just latched and releases to free up the buffer
- // and will not be shown on screen.
- // Should only be called on the main thread.
- void latchAndReleaseBuffer() override;
-
- bool getTransformToDisplayInverse() const override;
-
- Rect getBufferCrop() const override;
-
- uint32_t getBufferTransform() const override;
-
- ui::Dataspace getDataSpace() const override;
-
- sp<GraphicBuffer> getBuffer() const override;
- const std::shared_ptr<renderengine::ExternalTexture>& getExternalTexture() const override;
-
- ui::Transform::RotationFlags getTransformHint() const override { return mTransformHint; }
-
- // Implements Layer.
- const char* getType() const override { return "BufferStateLayer"; }
-
- void onLayerDisplayed(ftl::SharedFuture<FenceResult>) override;
-
- void releasePendingBuffer(nsecs_t dequeueReadyTime) override;
-
- Rect getCrop(const Layer::State& s) const;
-
- bool setTransform(uint32_t transform) override;
- bool setTransformToDisplayInverse(bool transformToDisplayInverse) override;
- bool setCrop(const Rect& crop) override;
- bool setBuffer(std::shared_ptr<renderengine::ExternalTexture>& /* buffer */,
- const BufferData& bufferData, nsecs_t postTime, nsecs_t desiredPresentTime,
- bool isAutoTimestamp, std::optional<nsecs_t> dequeueTime,
- const FrameTimelineInfo& info) override;
- bool setDataspace(ui::Dataspace dataspace) override;
- bool setHdrMetadata(const HdrMetadata& hdrMetadata) override;
- bool setSurfaceDamageRegion(const Region& surfaceDamage) override;
- bool setApi(int32_t api) override;
- bool setSidebandStream(const sp<NativeHandle>& sidebandStream) override;
- bool setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& handles) override;
- bool setPosition(float /*x*/, float /*y*/) override;
- bool setMatrix(const layer_state_t::matrix22_t& /*matrix*/);
-
- // BufferStateLayers can return Rect::INVALID_RECT if the layer does not have a display frame
- // and its parent layer is not bounded
- Rect getBufferSize(const State& s) const override;
- FloatRect computeSourceBounds(const FloatRect& parentBounds) const override;
- void setAutoRefresh(bool autoRefresh) override;
-
- bool setBufferCrop(const Rect& bufferCrop) override;
- bool setDestinationFrame(const Rect& destinationFrame) override;
- bool updateGeometry() override;
-
- bool fenceHasSignaled() const;
- bool onPreComposition(nsecs_t) override;
-
- // See mPendingBufferTransactions
- void decrementPendingBufferCount();
- std::atomic<int32_t>* getPendingBufferCounter() override { return &mPendingBufferTransactions; }
- std::string getPendingBufferCounterName() override { return mBlastTransactionName; }
-
- std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition(
- compositionengine::LayerFE::ClientCompositionTargetSettings&) const override;
-
-protected:
- void gatherBufferInfo();
- void onSurfaceFrameCreated(const std::shared_ptr<frametimeline::SurfaceFrame>& surfaceFrame);
- ui::Transform getInputTransform() const override;
- Rect getInputBounds() const override;
-
- struct BufferInfo {
- nsecs_t mDesiredPresentTime;
- std::shared_ptr<FenceTime> mFenceTime;
- sp<Fence> mFence;
- uint32_t mTransform{0};
- ui::Dataspace mDataspace{ui::Dataspace::UNKNOWN};
- Rect mCrop;
- uint32_t mScaleMode{NATIVE_WINDOW_SCALING_MODE_FREEZE};
- Region mSurfaceDamage;
- HdrMetadata mHdrMetadata;
- int mApi;
- PixelFormat mPixelFormat{PIXEL_FORMAT_NONE};
- bool mTransformToDisplayInverse{false};
-
- std::shared_ptr<renderengine::ExternalTexture> mBuffer;
- uint64_t mFrameNumber;
- int mBufferSlot{BufferQueue::INVALID_BUFFER_SLOT};
-
- bool mFrameLatencyNeeded{false};
- };
-
- BufferInfo mBufferInfo;
-
- /*
- * compositionengine::LayerFE overrides
- */
- const compositionengine::LayerFECompositionState* getCompositionState() const override;
- void preparePerFrameCompositionState() override;
-
- static bool getOpacityForFormat(PixelFormat format);
-
- // from graphics API
- const uint32_t mTextureName;
- ui::Dataspace translateDataspace(ui::Dataspace dataspace);
- void setInitialValuesForClone(const sp<Layer>& clonedFrom);
- void updateCloneBufferInfo() override;
- uint64_t mPreviousFrameNumber = 0;
-
- void setTransformHint(ui::Transform::RotationFlags displayTransformHint) override;
-
- // Transform hint provided to the producer. This must be accessed holding
- // the mStateLock.
- ui::Transform::RotationFlags mTransformHint = ui::Transform::ROT_0;
-
- bool getAutoRefresh() const { return mDrawingState.autoRefresh; }
- bool getSidebandStreamChanged() const { return mSidebandStreamChanged; }
-
- std::atomic<bool> mSidebandStreamChanged{false};
-
-private:
- friend class SlotGenerationTest;
- friend class TransactionFrameTracerTest;
- friend class TransactionSurfaceFrameTest;
-
- // We generate InputWindowHandles for all non-cursor buffered layers regardless of whether they
- // have an InputChannel. This is to enable the InputDispatcher to do PID based occlusion
- // detection.
- bool needsInputInfo() const override { return !mPotentialCursor; }
-
- // Returns true if this layer requires filtering
- bool needsFiltering(const DisplayDevice*) const override;
- bool needsFilteringForScreenshots(const DisplayDevice*,
- const ui::Transform& inverseParentTransform) const override;
-
- PixelFormat getPixelFormat() const;
-
- // Computes the transform matrix using the setFilteringEnabled to determine whether the
- // transform matrix should be computed for use with bilinear filtering.
- void getDrawingTransformMatrix(bool filteringEnabled, float outMatrix[16]) const;
-
- std::unique_ptr<compositionengine::LayerFECompositionState> mCompositionState;
-
- inline void tracePendingBufferCount(int32_t pendingBuffers);
-
- bool updateFrameEventHistory(const sp<Fence>& acquireFence, nsecs_t postedTime,
- nsecs_t requestedPresentTime);
-
- // Latch sideband stream and returns true if the dirty region should be updated.
- bool latchSidebandStream(bool& recomputeVisibleRegions);
-
- bool hasFrameUpdate() const;
-
- void updateTexImage(nsecs_t latchTime);
-
- sp<Layer> createClone() override;
-
- // Crop that applies to the buffer
- Rect computeBufferCrop(const State& s);
-
- bool willPresentCurrentTransaction() const;
-
- // Returns true if the transformed buffer size does not match the layer size and we need
- // to apply filtering.
- bool bufferNeedsFiltering() const;
-
- bool simpleBufferUpdate(const layer_state_t& s) const override;
-
- void callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener,
- const sp<GraphicBuffer>& buffer, uint64_t framenumber,
- const sp<Fence>& releaseFence,
- uint32_t currentMaxAcquiredBufferCount);
-
- std::optional<compositionengine::LayerFE::LayerSettings> prepareClientCompositionInternal(
- compositionengine::LayerFE::ClientCompositionTargetSettings&) const;
-
- ReleaseCallbackId mPreviousReleaseCallbackId = ReleaseCallbackId::INVALID_ID;
- uint64_t mPreviousReleasedFrameNumber = 0;
-
- uint64_t mPreviousBarrierFrameNumber = 0;
-
- bool mReleasePreviousBuffer = false;
-
- // Stores the last set acquire fence signal time used to populate the callback handle's acquire
- // time.
- std::variant<nsecs_t, sp<Fence>> mCallbackHandleAcquireTimeOrFence = -1;
-
- std::deque<std::shared_ptr<android::frametimeline::SurfaceFrame>> mPendingJankClassifications;
- // An upper bound on the number of SurfaceFrames in the pending classifications deque.
- static constexpr int kPendingClassificationMaxSurfaceFrames = 25;
-
- const std::string mBlastTransactionName{"BufferTX - " + mName};
- // This integer is incremented everytime a buffer arrives at the server for this layer,
- // and decremented when a buffer is dropped or latched. When changed the integer is exported
- // to systrace with ATRACE_INT and mBlastTransactionName. This way when debugging perf it is
- // possible to see when a buffer arrived at the server, and in which frame it latched.
- //
- // You can understand the trace this way:
- // - If the integer increases, a buffer arrived at the server.
- // - If the integer decreases in latchBuffer, that buffer was latched
- // - If the integer decreases in setBuffer or doTransaction, a buffer was dropped
- std::atomic<int32_t> mPendingBufferTransactions{0};
-
- // Contains requested position and matrix updates. This will be applied if the client does
- // not specify a destination frame.
- ui::Transform mRequestedTransform;
-
- sp<HwcSlotGenerator> mHwcSlotGenerator;
+ explicit BufferStateLayer(const LayerCreationArgs& args) : Layer(args){};
};
} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index 11a9e19..b5d2ad0 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -9,7 +9,10 @@
cc_defaults {
name: "libcompositionengine_defaults",
- defaults: ["surfaceflinger_defaults"],
+ defaults: [
+ "android.hardware.graphics.composer3-ndk_shared",
+ "surfaceflinger_defaults",
+ ],
cflags: [
"-DLOG_TAG=\"CompositionEngine\"",
"-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
@@ -20,7 +23,6 @@
"android.hardware.graphics.composer@2.2",
"android.hardware.graphics.composer@2.3",
"android.hardware.graphics.composer@2.4",
- "android.hardware.graphics.composer3-V1-ndk",
"android.hardware.power@1.0",
"android.hardware.power@1.3",
"android.hardware.power-V2-cpp",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index fc8dd8b..38a391b 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -152,6 +152,8 @@
virtual const compositionengine::CompositionEngine& getCompositionEngine() const = 0;
virtual void dumpState(std::string& out) const = 0;
+ bool mustRecompose() const;
+
private:
void dirtyEntireOutput();
void updateCompositionStateForBorder(const compositionengine::CompositionRefreshArgs&);
@@ -171,6 +173,9 @@
std::unique_ptr<ClientCompositionRequestCache> mClientCompositionRequestCache;
std::unique_ptr<planner::Planner> mPlanner;
std::unique_ptr<HwcAsyncWorker> mHwComposerAsyncWorker;
+
+ // Whether the content must be recomposed this frame.
+ bool mMustRecompose = false;
};
// This template factory function standardizes the implementation details of the
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 09adaed..0ebbcd0 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -243,7 +243,7 @@
return false;
}
- const nsecs_t startTime = systemTime();
+ const TimePoint startTime = TimePoint::now();
// Get any composition changes requested by the HWC device, and apply them.
std::optional<android::HWComposer::DeviceRequestedChanges> changes;
@@ -261,7 +261,7 @@
}
if (isPowerHintSessionEnabled()) {
- mPowerAdvisor->setHwcValidateTiming(mId, startTime, systemTime());
+ mPowerAdvisor->setHwcValidateTiming(mId, startTime, TimePoint::now());
mPowerAdvisor->setRequiresClientComposition(mId, requiresClientComposition);
}
@@ -365,7 +365,7 @@
auto& hwc = getCompositionEngine().getHwComposer();
- const nsecs_t startTime = systemTime();
+ const TimePoint startTime = TimePoint::now();
if (isPowerHintSessionEnabled()) {
if (!getCompositionEngine().getHwComposer().getComposer()->isSupported(
@@ -379,7 +379,7 @@
getState().previousPresentFence);
if (isPowerHintSessionEnabled()) {
- mPowerAdvisor->setHwcPresentTiming(mId, startTime, systemTime());
+ mPowerAdvisor->setHwcPresentTiming(mId, startTime, TimePoint::now());
}
fences.presentFence = hwc.getPresentFence(*halDisplayIdOpt);
@@ -421,7 +421,7 @@
// 1) It is being handled by hardware composer, which may need this to
// keep its virtual display state machine in sync, or
// 2) There is work to be done (the dirty region isn't empty)
- if (GpuVirtualDisplayId::tryCast(mId) && getDirtyRegion().isEmpty()) {
+ if (GpuVirtualDisplayId::tryCast(mId) && !mustRecompose()) {
ALOGV("Skipping display composition");
return;
}
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index ea78517..b5894cf 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -1015,17 +1015,17 @@
// frame, then nothing more until we get new layers.
// - When a display is created with a private layer stack, we won't
// emit any black frames until a layer is added to the layer stack.
- const bool mustRecompose = dirty && !(empty && wasEmpty);
+ mMustRecompose = dirty && !(empty && wasEmpty);
const char flagPrefix[] = {'-', '+'};
static_cast<void>(flagPrefix);
- ALOGV_IF("%s: %s composition for %s (%cdirty %cempty %cwasEmpty)", __FUNCTION__,
- mustRecompose ? "doing" : "skipping", getName().c_str(), flagPrefix[dirty],
- flagPrefix[empty], flagPrefix[wasEmpty]);
+ ALOGV("%s: %s composition for %s (%cdirty %cempty %cwasEmpty)", __func__,
+ mMustRecompose ? "doing" : "skipping", getName().c_str(), flagPrefix[dirty],
+ flagPrefix[empty], flagPrefix[wasEmpty]);
- mRenderSurface->beginFrame(mustRecompose);
+ mRenderSurface->beginFrame(mMustRecompose);
- if (mustRecompose) {
+ if (mMustRecompose) {
outputState.lastCompositionHadVisibleLayers = !empty;
}
}
@@ -1631,5 +1631,9 @@
mRenderSurface->prepareFrame(state.usesClientComposition, state.usesDeviceComposition);
}
+bool Output::mustRecompose() const {
+ return mMustRecompose;
+}
+
} // namespace impl
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 51ca213..95459c0 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -971,16 +971,40 @@
// We expect no calls to queueBuffer if composition was skipped.
EXPECT_CALL(*renderSurface, queueBuffer(_)).Times(0);
+ EXPECT_CALL(*renderSurface, beginFrame(false));
gpuDisplay->editState().isEnabled = true;
gpuDisplay->editState().usesClientComposition = false;
gpuDisplay->editState().layerStackSpace.setContent(Rect(0, 0, 1, 1));
gpuDisplay->editState().dirtyRegion = Region::INVALID_REGION;
+ gpuDisplay->editState().lastCompositionHadVisibleLayers = true;
+ gpuDisplay->beginFrame();
gpuDisplay->finishFrame({}, std::move(mResultWithoutBuffer));
}
-TEST_F(DisplayFinishFrameTest, performsCompositionIfDirty) {
+TEST_F(DisplayFinishFrameTest, skipsCompositionIfEmpty) {
+ auto args = getDisplayCreationArgsForGpuVirtualDisplay();
+ std::shared_ptr<impl::Display> gpuDisplay = impl::createDisplay(mCompositionEngine, args);
+
+ mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
+ gpuDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
+
+ // We expect no calls to queueBuffer if composition was skipped.
+ EXPECT_CALL(*renderSurface, queueBuffer(_)).Times(0);
+ EXPECT_CALL(*renderSurface, beginFrame(false));
+
+ gpuDisplay->editState().isEnabled = true;
+ gpuDisplay->editState().usesClientComposition = false;
+ gpuDisplay->editState().layerStackSpace.setContent(Rect(0, 0, 1, 1));
+ gpuDisplay->editState().dirtyRegion = Region(Rect(0, 0, 1, 1));
+ gpuDisplay->editState().lastCompositionHadVisibleLayers = false;
+
+ gpuDisplay->beginFrame();
+ gpuDisplay->finishFrame({}, std::move(mResultWithoutBuffer));
+}
+
+TEST_F(DisplayFinishFrameTest, performsCompositionIfDirtyAndNotEmpty) {
auto args = getDisplayCreationArgsForGpuVirtualDisplay();
std::shared_ptr<impl::Display> gpuDisplay = impl::createDisplay(mCompositionEngine, args);
@@ -989,11 +1013,15 @@
// We expect a single call to queueBuffer when composition is not skipped.
EXPECT_CALL(*renderSurface, queueBuffer(_)).Times(1);
+ EXPECT_CALL(*renderSurface, beginFrame(true));
gpuDisplay->editState().isEnabled = true;
gpuDisplay->editState().usesClientComposition = false;
gpuDisplay->editState().layerStackSpace.setContent(Rect(0, 0, 1, 1));
gpuDisplay->editState().dirtyRegion = Region(Rect(0, 0, 1, 1));
+ gpuDisplay->editState().lastCompositionHadVisibleLayers = true;
+
+ gpuDisplay->beginFrame();
gpuDisplay->finishFrame({}, std::move(mResultWithBuffer));
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
index c8bd5e4..e220541 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
@@ -38,7 +38,7 @@
MOCK_METHOD(bool, usePowerHintSession, (), (override));
MOCK_METHOD(bool, supportsPowerHintSession, (), (override));
MOCK_METHOD(bool, isPowerHintSessionRunning, (), (override));
- MOCK_METHOD(void, setTargetWorkDuration, (int64_t targetDuration), (override));
+ MOCK_METHOD(void, setTargetWorkDuration, (Duration targetDuration), (override));
MOCK_METHOD(void, sendActualWorkDuration, (), (override));
MOCK_METHOD(void, sendPredictedWorkDuration, (), (override));
MOCK_METHOD(void, enablePowerHint, (bool enabled), (override));
@@ -46,25 +46,24 @@
MOCK_METHOD(void, setGpuFenceTime,
(DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime), (override));
MOCK_METHOD(void, setHwcValidateTiming,
- (DisplayId displayId, nsecs_t valiateStartTime, nsecs_t validateEndTime),
+ (DisplayId displayId, TimePoint validateStartTime, TimePoint validateEndTime),
(override));
MOCK_METHOD(void, setHwcPresentTiming,
- (DisplayId displayId, nsecs_t presentStartTime, nsecs_t presentEndTime),
+ (DisplayId displayId, TimePoint presentStartTime, TimePoint presentEndTime),
(override));
MOCK_METHOD(void, setSkippedValidate, (DisplayId displayId, bool skipped), (override));
MOCK_METHOD(void, setRequiresClientComposition,
(DisplayId displayId, bool requiresClientComposition), (override));
- MOCK_METHOD(void, setExpectedPresentTime, (nsecs_t expectedPresentTime), (override));
- MOCK_METHOD(void, setSfPresentTiming, (nsecs_t presentFenceTime, nsecs_t presentEndTime),
+ MOCK_METHOD(void, setExpectedPresentTime, (TimePoint expectedPresentTime), (override));
+ MOCK_METHOD(void, setSfPresentTiming, (TimePoint presentFenceTime, TimePoint presentEndTime),
(override));
MOCK_METHOD(void, setHwcPresentDelayedTime,
- (DisplayId displayId,
- std::chrono::steady_clock::time_point earliestFrameStartTime));
- MOCK_METHOD(void, setFrameDelay, (nsecs_t frameDelayDuration), (override));
- MOCK_METHOD(void, setCommitStart, (nsecs_t commitStartTime), (override));
- MOCK_METHOD(void, setCompositeEnd, (nsecs_t compositeEndtime), (override));
+ (DisplayId displayId, TimePoint earliestFrameStartTime));
+ MOCK_METHOD(void, setFrameDelay, (Duration frameDelayDuration), (override));
+ MOCK_METHOD(void, setCommitStart, (TimePoint commitStartTime), (override));
+ MOCK_METHOD(void, setCompositeEnd, (TimePoint compositeEndTime), (override));
MOCK_METHOD(void, setDisplays, (std::vector<DisplayId> & displayIds), (override));
- MOCK_METHOD(void, setTotalFrameTargetWorkDuration, (int64_t targetDuration), (override));
+ MOCK_METHOD(void, setTotalFrameTargetWorkDuration, (Duration targetDuration), (override));
};
} // namespace mock
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index bff301e..2866a34 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -104,7 +104,7 @@
mCompositionDisplay->getRenderSurface()->initialize();
- setPowerMode(args.initialPowerMode);
+ if (args.initialPowerMode.has_value()) setPowerMode(args.initialPowerMode.value());
// initialize the display orientation transform.
setProjection(ui::ROTATION_0, Rect::INVALID_RECT, Rect::INVALID_RECT);
@@ -170,19 +170,21 @@
void DisplayDevice::setPowerMode(hal::PowerMode mode) {
mPowerMode = mode;
- getCompositionDisplay()->setCompositionEnabled(mPowerMode != hal::PowerMode::OFF);
+
+ getCompositionDisplay()->setCompositionEnabled(mPowerMode.has_value() &&
+ *mPowerMode != hal::PowerMode::OFF);
}
void DisplayDevice::enableLayerCaching(bool enable) {
getCompositionDisplay()->setLayerCachingEnabled(enable);
}
-hal::PowerMode DisplayDevice::getPowerMode() const {
+std::optional<hal::PowerMode> DisplayDevice::getPowerMode() const {
return mPowerMode;
}
bool DisplayDevice::isPoweredOn() const {
- return mPowerMode != hal::PowerMode::OFF;
+ return mPowerMode && *mPowerMode != hal::PowerMode::OFF;
}
void DisplayDevice::setActiveMode(DisplayModeId id) {
@@ -369,7 +371,7 @@
}
result += "\n powerMode="s;
- result += to_string(mPowerMode);
+ result += mPowerMode.has_value() ? to_string(mPowerMode.value()) : "OFF(reset)";
result += '\n';
if (mRefreshRateConfigs) {
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 10fc095..3eead17 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -181,7 +181,7 @@
/* ------------------------------------------------------------------------
* Display power mode management.
*/
- hardware::graphics::composer::hal::PowerMode getPowerMode() const;
+ std::optional<hardware::graphics::composer::hal::PowerMode> getPowerMode() const;
void setPowerMode(hardware::graphics::composer::hal::PowerMode mode);
bool isPoweredOn() const;
@@ -280,8 +280,8 @@
static ui::Transform::RotationFlags sPrimaryDisplayRotationFlags;
- hardware::graphics::composer::hal::PowerMode mPowerMode =
- hardware::graphics::composer::hal::PowerMode::OFF;
+ // allow initial power mode as null.
+ std::optional<hardware::graphics::composer::hal::PowerMode> mPowerMode;
DisplayModePtr mActiveMode;
std::optional<float> mStagedBrightness = std::nullopt;
float mBrightness = -1.f;
@@ -365,8 +365,7 @@
HdrCapabilities hdrCapabilities;
int32_t supportedPerFrameMetadata{0};
std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>> hwcColorModes;
- hardware::graphics::composer::hal::PowerMode initialPowerMode{
- hardware::graphics::composer::hal::PowerMode::ON};
+ std::optional<hardware::graphics::composer::hal::PowerMode> initialPowerMode;
bool isPrimary{false};
DisplayModes supportedModes;
DisplayModeId activeModeId;
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 566537b..cb2c8c5 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -59,8 +59,6 @@
using android::hardware::power::Mode;
using android::hardware::power::WorkDuration;
-using scheduler::OneShotTimer;
-
PowerAdvisor::~PowerAdvisor() = default;
namespace {
@@ -196,7 +194,7 @@
return mPowerHintSessionRunning;
}
-void PowerAdvisor::setTargetWorkDuration(int64_t targetDuration) {
+void PowerAdvisor::setTargetWorkDuration(Duration targetDuration) {
if (!usePowerHintSession()) {
ALOGV("Power hint session target duration cannot be set, skipping");
return;
@@ -215,13 +213,13 @@
ALOGV("Actual work duration power hint cannot be sent, skipping");
return;
}
- const std::optional<nsecs_t> actualDuration = estimateWorkDuration(false);
+ const std::optional<Duration> actualDuration = estimateWorkDuration(false);
if (actualDuration.has_value()) {
std::lock_guard lock(mPowerHalMutex);
HalWrapper* const halWrapper = getPowerHal();
if (halWrapper != nullptr) {
- halWrapper->sendActualWorkDuration(*actualDuration + kTargetSafetyMargin.count(),
- systemTime());
+ halWrapper->sendActualWorkDuration(*actualDuration + kTargetSafetyMargin,
+ TimePoint::now());
}
}
}
@@ -232,14 +230,14 @@
return;
}
- const std::optional<nsecs_t> predictedDuration = estimateWorkDuration(true);
+ const std::optional<Duration> predictedDuration = estimateWorkDuration(true);
if (predictedDuration.has_value()) {
std::lock_guard lock(mPowerHalMutex);
HalWrapper* const halWrapper = getPowerHal();
if (halWrapper != nullptr) {
- halWrapper->sendActualWorkDuration(*predictedDuration + kTargetSafetyMargin.count(),
- systemTime());
+ halWrapper->sendActualWorkDuration(*predictedDuration + kTargetSafetyMargin,
+ TimePoint::now());
}
}
}
@@ -281,22 +279,22 @@
}
}
displayData.lastValidGpuStartTime = displayData.gpuStartTime;
- displayData.lastValidGpuEndTime = signalTime;
+ displayData.lastValidGpuEndTime = TimePoint::fromNs(signalTime);
}
}
displayData.gpuEndFenceTime = std::move(fenceTime);
- displayData.gpuStartTime = systemTime();
+ displayData.gpuStartTime = TimePoint::now();
}
-void PowerAdvisor::setHwcValidateTiming(DisplayId displayId, nsecs_t validateStartTime,
- nsecs_t validateEndTime) {
+void PowerAdvisor::setHwcValidateTiming(DisplayId displayId, TimePoint validateStartTime,
+ TimePoint validateEndTime) {
DisplayTimingData& displayData = mDisplayTimingData[displayId];
displayData.hwcValidateStartTime = validateStartTime;
displayData.hwcValidateEndTime = validateEndTime;
}
-void PowerAdvisor::setHwcPresentTiming(DisplayId displayId, nsecs_t presentStartTime,
- nsecs_t presentEndTime) {
+void PowerAdvisor::setHwcPresentTiming(DisplayId displayId, TimePoint presentStartTime,
+ TimePoint presentEndTime) {
DisplayTimingData& displayData = mDisplayTimingData[displayId];
displayData.hwcPresentStartTime = presentStartTime;
displayData.hwcPresentEndTime = presentEndTime;
@@ -311,43 +309,41 @@
mDisplayTimingData[displayId].usedClientComposition = requiresClientComposition;
}
-void PowerAdvisor::setExpectedPresentTime(nsecs_t expectedPresentTime) {
+void PowerAdvisor::setExpectedPresentTime(TimePoint expectedPresentTime) {
mExpectedPresentTimes.append(expectedPresentTime);
}
-void PowerAdvisor::setSfPresentTiming(nsecs_t presentFenceTime, nsecs_t presentEndTime) {
+void PowerAdvisor::setSfPresentTiming(TimePoint presentFenceTime, TimePoint presentEndTime) {
mLastSfPresentEndTime = presentEndTime;
mLastPresentFenceTime = presentFenceTime;
}
-void PowerAdvisor::setFrameDelay(nsecs_t frameDelayDuration) {
+void PowerAdvisor::setFrameDelay(Duration frameDelayDuration) {
mFrameDelayDuration = frameDelayDuration;
}
-void PowerAdvisor::setHwcPresentDelayedTime(
- DisplayId displayId, std::chrono::steady_clock::time_point earliestFrameStartTime) {
- mDisplayTimingData[displayId].hwcPresentDelayedTime =
- (earliestFrameStartTime - std::chrono::steady_clock::now()).count() + systemTime();
+void PowerAdvisor::setHwcPresentDelayedTime(DisplayId displayId, TimePoint earliestFrameStartTime) {
+ mDisplayTimingData[displayId].hwcPresentDelayedTime = earliestFrameStartTime;
}
-void PowerAdvisor::setCommitStart(nsecs_t commitStartTime) {
+void PowerAdvisor::setCommitStart(TimePoint commitStartTime) {
mCommitStartTimes.append(commitStartTime);
}
-void PowerAdvisor::setCompositeEnd(nsecs_t compositeEnd) {
- mLastPostcompDuration = compositeEnd - mLastSfPresentEndTime;
+void PowerAdvisor::setCompositeEnd(TimePoint compositeEndTime) {
+ mLastPostcompDuration = compositeEndTime - mLastSfPresentEndTime;
}
void PowerAdvisor::setDisplays(std::vector<DisplayId>& displayIds) {
mDisplayIds = displayIds;
}
-void PowerAdvisor::setTotalFrameTargetWorkDuration(nsecs_t targetDuration) {
+void PowerAdvisor::setTotalFrameTargetWorkDuration(Duration targetDuration) {
mTotalFrameTargetDuration = targetDuration;
}
std::vector<DisplayId> PowerAdvisor::getOrderedDisplayIds(
- std::optional<nsecs_t> DisplayTimingData::*sortBy) {
+ std::optional<TimePoint> DisplayTimingData::*sortBy) {
std::vector<DisplayId> sortedDisplays;
std::copy_if(mDisplayIds.begin(), mDisplayIds.end(), std::back_inserter(sortedDisplays),
[&](DisplayId id) {
@@ -360,33 +356,34 @@
return sortedDisplays;
}
-std::optional<nsecs_t> PowerAdvisor::estimateWorkDuration(bool earlyHint) {
+std::optional<Duration> PowerAdvisor::estimateWorkDuration(bool earlyHint) {
if (earlyHint && (!mExpectedPresentTimes.isFull() || !mCommitStartTimes.isFull())) {
return std::nullopt;
}
// Tracks when we finish presenting to hwc
- nsecs_t estimatedEndTime = mCommitStartTimes[0];
+ TimePoint estimatedEndTime = mCommitStartTimes[0];
// How long we spent this frame not doing anything, waiting for fences or vsync
- nsecs_t idleDuration = 0;
+ Duration idleDuration = 0ns;
// Most recent previous gpu end time in the current frame, probably from a prior display, used
// as the start time for the next gpu operation if it ran over time since it probably blocked
- std::optional<nsecs_t> previousValidGpuEndTime;
+ std::optional<TimePoint> previousValidGpuEndTime;
// The currently estimated gpu end time for the frame,
// used to accumulate gpu time as we iterate over the active displays
- std::optional<nsecs_t> estimatedGpuEndTime;
+ std::optional<TimePoint> estimatedGpuEndTime;
// If we're predicting at the start of the frame, we use last frame as our reference point
// If we're predicting at the end of the frame, we use the current frame as a reference point
- nsecs_t referenceFrameStartTime = (earlyHint ? mCommitStartTimes[-1] : mCommitStartTimes[0]);
+ TimePoint referenceFrameStartTime = (earlyHint ? mCommitStartTimes[-1] : mCommitStartTimes[0]);
// When the prior frame should be presenting to the display
// If we're predicting at the start of the frame, we use last frame's expected present time
// If we're predicting at the end of the frame, the present fence time is already known
- nsecs_t lastFramePresentTime = (earlyHint ? mExpectedPresentTimes[-1] : mLastPresentFenceTime);
+ TimePoint lastFramePresentTime =
+ (earlyHint ? mExpectedPresentTimes[-1] : mLastPresentFenceTime);
// The timing info for the previously calculated display, if there was one
std::optional<DisplayTimeline> previousDisplayReferenceTiming;
@@ -427,10 +424,10 @@
// Track how long we spent waiting for the fence, can be excluded from the timing estimate
idleDuration += estimatedTiming.probablyWaitsForPresentFence
? lastFramePresentTime - estimatedTiming.presentFenceWaitStartTime
- : 0;
+ : 0ns;
// Track how long we spent waiting to present, can be excluded from the timing estimate
- idleDuration += earlyHint ? 0 : referenceTiming.hwcPresentDelayDuration;
+ idleDuration += earlyHint ? 0ns : referenceTiming.hwcPresentDelayDuration;
// Estimate the reference frame's gpu timing
auto gpuTiming = displayData.estimateGpuTiming(previousValidGpuEndTime);
@@ -438,15 +435,15 @@
previousValidGpuEndTime = gpuTiming->startTime + gpuTiming->duration;
// Estimate the prediction frame's gpu end time from the reference frame
- estimatedGpuEndTime =
- std::max(estimatedTiming.hwcPresentStartTime, estimatedGpuEndTime.value_or(0)) +
+ estimatedGpuEndTime = std::max(estimatedTiming.hwcPresentStartTime,
+ estimatedGpuEndTime.value_or(TimePoint{0ns})) +
gpuTiming->duration;
}
previousDisplayReferenceTiming = referenceTiming;
}
- ATRACE_INT64("Idle duration", idleDuration);
+ ATRACE_INT64("Idle duration", idleDuration.ns());
- nsecs_t estimatedFlingerEndTime = earlyHint ? estimatedEndTime : mLastSfPresentEndTime;
+ TimePoint estimatedFlingerEndTime = earlyHint ? estimatedEndTime : mLastSfPresentEndTime;
// Don't count time spent idly waiting in the estimate as we could do more work in that time
estimatedEndTime -= idleDuration;
@@ -454,21 +451,22 @@
// We finish the frame when both present and the gpu are done, so wait for the later of the two
// Also add the frame delay duration since the target did not move while we were delayed
- nsecs_t totalDuration = mFrameDelayDuration +
- std::max(estimatedEndTime, estimatedGpuEndTime.value_or(0)) - mCommitStartTimes[0];
+ Duration totalDuration = mFrameDelayDuration +
+ std::max(estimatedEndTime, estimatedGpuEndTime.value_or(TimePoint{0ns})) -
+ mCommitStartTimes[0];
// We finish SurfaceFlinger when post-composition finishes, so add that in here
- nsecs_t flingerDuration =
+ Duration flingerDuration =
estimatedFlingerEndTime + mLastPostcompDuration - mCommitStartTimes[0];
// Combine the two timings into a single normalized one
- nsecs_t combinedDuration = combineTimingEstimates(totalDuration, flingerDuration);
+ Duration combinedDuration = combineTimingEstimates(totalDuration, flingerDuration);
return std::make_optional(combinedDuration);
}
-nsecs_t PowerAdvisor::combineTimingEstimates(nsecs_t totalDuration, nsecs_t flingerDuration) {
- nsecs_t targetDuration;
+Duration PowerAdvisor::combineTimingEstimates(Duration totalDuration, Duration flingerDuration) {
+ Duration targetDuration{0ns};
{
std::lock_guard lock(mPowerHalMutex);
targetDuration = *getPowerHal()->getTargetWorkDuration();
@@ -477,17 +475,18 @@
// Normalize total to the flinger target (vsync period) since that's how often we actually send
// hints
- nsecs_t normalizedTotalDuration = (targetDuration * totalDuration) / *mTotalFrameTargetDuration;
+ Duration normalizedTotalDuration = Duration::fromNs((targetDuration.ns() * totalDuration.ns()) /
+ mTotalFrameTargetDuration->ns());
return std::max(flingerDuration, normalizedTotalDuration);
}
PowerAdvisor::DisplayTimeline PowerAdvisor::DisplayTimeline::estimateTimelineFromReference(
- nsecs_t fenceTime, nsecs_t displayStartTime) {
+ TimePoint fenceTime, TimePoint displayStartTime) {
DisplayTimeline estimated;
estimated.hwcPresentStartTime = displayStartTime;
// We don't predict waiting for vsync alignment yet
- estimated.hwcPresentDelayDuration = 0;
+ estimated.hwcPresentDelayDuration = 0ns;
// How long we expect to run before we start waiting for the fence
// For now just re-use last frame's post-present duration and assume it will not change much
@@ -502,12 +501,11 @@
}
PowerAdvisor::DisplayTimeline PowerAdvisor::DisplayTimingData::calculateDisplayTimeline(
- nsecs_t fenceTime) {
+ TimePoint fenceTime) {
DisplayTimeline timeline;
// How long between calling hwc present and trying to wait on the fence
- const nsecs_t fenceWaitStartDelay =
- (skippedValidate ? kFenceWaitStartDelaySkippedValidate : kFenceWaitStartDelayValidated)
- .count();
+ const Duration fenceWaitStartDelay =
+ (skippedValidate ? kFenceWaitStartDelaySkippedValidate : kFenceWaitStartDelayValidated);
// Did our reference frame wait for an appropriate vsync before calling into hwc
const bool waitedOnHwcPresentTime = hwcPresentDelayedTime.has_value() &&
@@ -522,7 +520,7 @@
// How long hwc present was delayed waiting for the next appropriate vsync
timeline.hwcPresentDelayDuration =
- (waitedOnHwcPresentTime ? *hwcPresentDelayedTime - *hwcPresentStartTime : 0);
+ (waitedOnHwcPresentTime ? *hwcPresentDelayedTime - *hwcPresentStartTime : 0ns);
// When we started waiting for the present fence after calling into hwc present
timeline.presentFenceWaitStartTime =
timeline.hwcPresentStartTime + timeline.hwcPresentDelayDuration + fenceWaitStartDelay;
@@ -537,23 +535,26 @@
}
std::optional<PowerAdvisor::GpuTimeline> PowerAdvisor::DisplayTimingData::estimateGpuTiming(
- std::optional<nsecs_t> previousEnd) {
+ std::optional<TimePoint> previousEndTime) {
if (!(usedClientComposition && lastValidGpuStartTime.has_value() && gpuEndFenceTime)) {
return std::nullopt;
}
- const nsecs_t latestGpuStartTime = std::max(previousEnd.value_or(0), *gpuStartTime);
- const nsecs_t latestGpuEndTime = gpuEndFenceTime->getSignalTime();
- nsecs_t gpuDuration = 0;
- if (latestGpuEndTime != Fence::SIGNAL_TIME_INVALID &&
- latestGpuEndTime != Fence::SIGNAL_TIME_PENDING) {
+ const TimePoint latestGpuStartTime =
+ std::max(previousEndTime.value_or(TimePoint{0ns}), *gpuStartTime);
+ const nsecs_t gpuEndFenceSignal = gpuEndFenceTime->getSignalTime();
+ Duration gpuDuration{0ns};
+ if (gpuEndFenceSignal != Fence::SIGNAL_TIME_INVALID &&
+ gpuEndFenceSignal != Fence::SIGNAL_TIME_PENDING) {
+ const TimePoint latestGpuEndTime = TimePoint::fromNs(gpuEndFenceSignal);
+
// If we know how long the most recent gpu duration was, use that
gpuDuration = latestGpuEndTime - latestGpuStartTime;
} else if (lastValidGpuEndTime.has_value()) {
// If we don't have the fence data, use the most recent information we do have
gpuDuration = *lastValidGpuEndTime - *lastValidGpuStartTime;
- if (latestGpuEndTime == Fence::SIGNAL_TIME_PENDING) {
+ if (gpuEndFenceSignal == Fence::SIGNAL_TIME_PENDING) {
// If pending but went over the previous duration, use current time as the end
- gpuDuration = std::max(gpuDuration, systemTime() - latestGpuStartTime);
+ gpuDuration = std::max(gpuDuration, Duration{TimePoint::now() - latestGpuStartTime});
}
}
return GpuTimeline{.duration = gpuDuration, .startTime = latestGpuStartTime};
@@ -614,15 +615,15 @@
bool startPowerHintSession() override { return false; }
- void setTargetWorkDuration(int64_t) override {}
+ void setTargetWorkDuration(Duration) override {}
- void sendActualWorkDuration(int64_t, nsecs_t) override {}
+ void sendActualWorkDuration(Duration, TimePoint) override {}
bool shouldReconnectHAL() override { return false; }
std::vector<int32_t> getPowerHintSessionThreadIds() override { return std::vector<int32_t>{}; }
- std::optional<int64_t> getTargetWorkDuration() override { return std::nullopt; }
+ std::optional<Duration> getTargetWorkDuration() override { return std::nullopt; }
private:
const sp<V1_3::IPower> mPowerHal = nullptr;
@@ -640,9 +641,6 @@
}
mSupportsPowerHint = checkPowerHintSessionSupported();
-
- // Currently set to 0 to disable rate limiter by default
- mAllowedActualDeviation = base::GetIntProperty<nsecs_t>("debug.sf.allowed_actual_deviation", 0);
}
AidlPowerHalWrapper::~AidlPowerHalWrapper() {
@@ -730,9 +728,9 @@
ALOGV("Cannot start power hint session, skipping");
return false;
}
- auto ret =
- mPowerHal->createHintSession(getpid(), static_cast<int32_t>(getuid()),
- mPowerHintThreadIds, mTargetDuration, &mPowerHintSession);
+ auto ret = mPowerHal->createHintSession(getpid(), static_cast<int32_t>(getuid()),
+ mPowerHintThreadIds, mTargetDuration.ns(),
+ &mPowerHintSession);
if (!ret.isOk()) {
ALOGW("Failed to start power hint session with error: %s",
ret.exceptionToString(ret.exceptionCode()).c_str());
@@ -742,14 +740,14 @@
return isPowerHintSessionRunning();
}
-void AidlPowerHalWrapper::setTargetWorkDuration(int64_t targetDuration) {
+void AidlPowerHalWrapper::setTargetWorkDuration(Duration targetDuration) {
ATRACE_CALL();
mTargetDuration = targetDuration;
- if (sTraceHintSessionData) ATRACE_INT64("Time target", targetDuration);
+ if (sTraceHintSessionData) ATRACE_INT64("Time target", targetDuration.ns());
if (isPowerHintSessionRunning() && (targetDuration != mLastTargetDurationSent)) {
- ALOGV("Sending target time: %" PRId64 "ns", targetDuration);
+ ALOGV("Sending target time: %" PRId64 "ns", targetDuration.ns());
mLastTargetDurationSent = targetDuration;
- auto ret = mPowerHintSession->updateTargetWorkDuration(targetDuration);
+ auto ret = mPowerHintSession->updateTargetWorkDuration(targetDuration.ns());
if (!ret.isOk()) {
ALOGW("Failed to set power hint target work duration with error: %s",
ret.exceptionMessage().c_str());
@@ -758,65 +756,40 @@
}
}
-bool AidlPowerHalWrapper::shouldReportActualDurations() {
- // Report if we have never reported before or will go stale next frame
- if (!mLastActualDurationSent.has_value() ||
- (mLastTargetDurationSent + systemTime() - mLastActualReportTimestamp) >
- kStaleTimeout.count()) {
- return true;
- }
-
- if (!mActualDuration.has_value()) {
- return false;
- }
- // Report if the change in actual duration exceeds the threshold
- return abs(*mActualDuration - *mLastActualDurationSent) > mAllowedActualDeviation;
-}
-
-void AidlPowerHalWrapper::sendActualWorkDuration(int64_t actualDuration, nsecs_t timestamp) {
+void AidlPowerHalWrapper::sendActualWorkDuration(Duration actualDuration, TimePoint timestamp) {
ATRACE_CALL();
-
- if (actualDuration < 0 || !isPowerHintSessionRunning()) {
+ if (actualDuration < 0ns || !isPowerHintSessionRunning()) {
ALOGV("Failed to send actual work duration, skipping");
return;
}
- const nsecs_t reportedDuration = actualDuration;
-
- mActualDuration = reportedDuration;
+ mActualDuration = actualDuration;
WorkDuration duration;
- duration.durationNanos = reportedDuration;
- duration.timeStampNanos = timestamp;
+ duration.durationNanos = actualDuration.ns();
+ duration.timeStampNanos = timestamp.ns();
mPowerHintQueue.push_back(duration);
if (sTraceHintSessionData) {
- ATRACE_INT64("Measured duration", actualDuration);
- ATRACE_INT64("Target error term", actualDuration - mTargetDuration);
+ ATRACE_INT64("Measured duration", actualDuration.ns());
+ ATRACE_INT64("Target error term", Duration{actualDuration - mTargetDuration}.ns());
- ATRACE_INT64("Reported duration", reportedDuration);
- ATRACE_INT64("Reported target", mLastTargetDurationSent);
- ATRACE_INT64("Reported target error term", reportedDuration - mLastTargetDurationSent);
+ ATRACE_INT64("Reported duration", actualDuration.ns());
+ ATRACE_INT64("Reported target", mLastTargetDurationSent.ns());
+ ATRACE_INT64("Reported target error term",
+ Duration{actualDuration - mLastTargetDurationSent}.ns());
}
ALOGV("Sending actual work duration of: %" PRId64 " on reported target: %" PRId64
" with error: %" PRId64,
- reportedDuration, mLastTargetDurationSent, reportedDuration - mLastTargetDurationSent);
+ actualDuration.ns(), mLastTargetDurationSent.ns(),
+ Duration{actualDuration - mLastTargetDurationSent}.ns());
- // This rate limiter queues similar duration reports to the powerhal into
- // batches to avoid excessive binder calls. The criteria to send a given batch
- // are outlined in shouldReportActualDurationsNow()
- if (shouldReportActualDurations()) {
- ALOGV("Sending hint update batch");
- mLastActualReportTimestamp = systemTime();
- auto ret = mPowerHintSession->reportActualWorkDuration(mPowerHintQueue);
- if (!ret.isOk()) {
- ALOGW("Failed to report actual work durations with error: %s",
- ret.exceptionMessage().c_str());
- mShouldReconnectHal = true;
- }
- mPowerHintQueue.clear();
- // We save the actual duration here for rate limiting
- mLastActualDurationSent = actualDuration;
+ auto ret = mPowerHintSession->reportActualWorkDuration(mPowerHintQueue);
+ if (!ret.isOk()) {
+ ALOGW("Failed to report actual work durations with error: %s",
+ ret.exceptionMessage().c_str());
+ mShouldReconnectHal = true;
}
+ mPowerHintQueue.clear();
}
bool AidlPowerHalWrapper::shouldReconnectHAL() {
@@ -827,14 +800,10 @@
return mPowerHintThreadIds;
}
-std::optional<int64_t> AidlPowerHalWrapper::getTargetWorkDuration() {
+std::optional<Duration> AidlPowerHalWrapper::getTargetWorkDuration() {
return mTargetDuration;
}
-void AidlPowerHalWrapper::setAllowedActualDeviation(nsecs_t allowedDeviation) {
- mAllowedActualDeviation = allowedDeviation;
-}
-
const bool AidlPowerHalWrapper::sTraceHintSessionData =
base::GetBoolProperty(std::string("debug.sf.trace_hint_sessions"), false);
@@ -845,7 +814,7 @@
// Grab old hint session values before we destroy any existing wrapper
std::vector<int32_t> oldPowerHintSessionThreadIds;
- std::optional<int64_t> oldTargetWorkDuration;
+ std::optional<Duration> oldTargetWorkDuration;
if (mHalWrapper != nullptr) {
oldPowerHintSessionThreadIds = mHalWrapper->getPowerHintSessionThreadIds();
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
index 53db612..1c9d123 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
@@ -27,6 +27,7 @@
#include <android/hardware/power/IPower.h>
#include <compositionengine/impl/OutputCompositionState.h>
+#include <scheduler/Time.h>
#include <ui/DisplayIdentification.h>
#include "../Scheduler/OneShotTimer.h"
@@ -53,7 +54,7 @@
virtual bool supportsPowerHintSession() = 0;
virtual bool isPowerHintSessionRunning() = 0;
// Sends a power hint that updates to the target work duration for the frame
- virtual void setTargetWorkDuration(nsecs_t targetDuration) = 0;
+ virtual void setTargetWorkDuration(Duration targetDuration) = 0;
// Sends a power hint for the actual known work duration at the end of the frame
virtual void sendActualWorkDuration() = 0;
// Sends a power hint for the upcoming frame predicted from previous frame timing
@@ -65,33 +66,33 @@
// Provides PowerAdvisor with a copy of the gpu fence so it can determine the gpu end time
virtual void setGpuFenceTime(DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime) = 0;
// Reports the start and end times of a hwc validate call this frame for a given display
- virtual void setHwcValidateTiming(DisplayId displayId, nsecs_t validateStartTime,
- nsecs_t validateEndTime) = 0;
+ virtual void setHwcValidateTiming(DisplayId displayId, TimePoint validateStartTime,
+ TimePoint validateEndTime) = 0;
// Reports the start and end times of a hwc present call this frame for a given display
- virtual void setHwcPresentTiming(DisplayId displayId, nsecs_t presentStartTime,
- nsecs_t presentEndTime) = 0;
+ virtual void setHwcPresentTiming(DisplayId displayId, TimePoint presentStartTime,
+ TimePoint presentEndTime) = 0;
// Reports the expected time that the current frame will present to the display
- virtual void setExpectedPresentTime(nsecs_t expectedPresentTime) = 0;
+ virtual void setExpectedPresentTime(TimePoint expectedPresentTime) = 0;
// Reports the most recent present fence time and end time once known
- virtual void setSfPresentTiming(nsecs_t presentFenceTime, nsecs_t presentEndTime) = 0;
+ virtual void setSfPresentTiming(TimePoint presentFenceTime, TimePoint presentEndTime) = 0;
// Reports whether a display used client composition this frame
virtual void setRequiresClientComposition(DisplayId displayId,
bool requiresClientComposition) = 0;
// Reports whether a given display skipped validation this frame
virtual void setSkippedValidate(DisplayId displayId, bool skipped) = 0;
// Reports when a hwc present is delayed, and the time that it will resume
- virtual void setHwcPresentDelayedTime(
- DisplayId displayId, std::chrono::steady_clock::time_point earliestFrameStartTime) = 0;
+ virtual void setHwcPresentDelayedTime(DisplayId displayId,
+ TimePoint earliestFrameStartTime) = 0;
// Reports the start delay for SurfaceFlinger this frame
- virtual void setFrameDelay(nsecs_t frameDelayDuration) = 0;
+ virtual void setFrameDelay(Duration frameDelayDuration) = 0;
// Reports the SurfaceFlinger commit start time this frame
- virtual void setCommitStart(nsecs_t commitStartTime) = 0;
+ virtual void setCommitStart(TimePoint commitStartTime) = 0;
// Reports the SurfaceFlinger composite end time this frame
- virtual void setCompositeEnd(nsecs_t compositeEndTime) = 0;
+ virtual void setCompositeEnd(TimePoint compositeEndTime) = 0;
// Reports the list of the currently active displays
virtual void setDisplays(std::vector<DisplayId>& displayIds) = 0;
// Sets the target duration for the entire pipeline including the gpu
- virtual void setTotalFrameTargetWorkDuration(nsecs_t targetDuration) = 0;
+ virtual void setTotalFrameTargetWorkDuration(Duration targetDuration) = 0;
};
namespace impl {
@@ -111,11 +112,11 @@
virtual void restartPowerHintSession() = 0;
virtual void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) = 0;
virtual bool startPowerHintSession() = 0;
- virtual void setTargetWorkDuration(nsecs_t targetDuration) = 0;
- virtual void sendActualWorkDuration(nsecs_t actualDuration, nsecs_t timestamp) = 0;
+ virtual void setTargetWorkDuration(Duration targetDuration) = 0;
+ virtual void sendActualWorkDuration(Duration actualDuration, TimePoint timestamp) = 0;
virtual bool shouldReconnectHAL() = 0;
virtual std::vector<int32_t> getPowerHintSessionThreadIds() = 0;
- virtual std::optional<nsecs_t> getTargetWorkDuration() = 0;
+ virtual std::optional<Duration> getTargetWorkDuration() = 0;
};
PowerAdvisor(SurfaceFlinger& flinger);
@@ -129,29 +130,27 @@
bool usePowerHintSession() override;
bool supportsPowerHintSession() override;
bool isPowerHintSessionRunning() override;
- void setTargetWorkDuration(nsecs_t targetDuration) override;
+ void setTargetWorkDuration(Duration targetDuration) override;
void sendActualWorkDuration() override;
void sendPredictedWorkDuration() override;
void enablePowerHint(bool enabled) override;
bool startPowerHintSession(const std::vector<int32_t>& threadIds) override;
void setGpuFenceTime(DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime);
- void setHwcValidateTiming(DisplayId displayId, nsecs_t valiateStartTime,
- nsecs_t validateEndTime) override;
- void setHwcPresentTiming(DisplayId displayId, nsecs_t presentStartTime,
- nsecs_t presentEndTime) override;
+ void setHwcValidateTiming(DisplayId displayId, TimePoint validateStartTime,
+ TimePoint validateEndTime) override;
+ void setHwcPresentTiming(DisplayId displayId, TimePoint presentStartTime,
+ TimePoint presentEndTime) override;
void setSkippedValidate(DisplayId displayId, bool skipped) override;
void setRequiresClientComposition(DisplayId displayId, bool requiresClientComposition) override;
- void setExpectedPresentTime(nsecs_t expectedPresentTime) override;
- void setSfPresentTiming(nsecs_t presentFenceTime, nsecs_t presentEndTime) override;
- void setHwcPresentDelayedTime(
- DisplayId displayId,
- std::chrono::steady_clock::time_point earliestFrameStartTime) override;
+ void setExpectedPresentTime(TimePoint expectedPresentTime) override;
+ void setSfPresentTiming(TimePoint presentFenceTime, TimePoint presentEndTime) override;
+ void setHwcPresentDelayedTime(DisplayId displayId, TimePoint earliestFrameStartTime) override;
- void setFrameDelay(nsecs_t frameDelayDuration) override;
- void setCommitStart(nsecs_t commitStartTime) override;
- void setCompositeEnd(nsecs_t compositeEndTime) override;
+ void setFrameDelay(Duration frameDelayDuration) override;
+ void setCommitStart(TimePoint commitStartTime) override;
+ void setCompositeEnd(TimePoint compositeEndTime) override;
void setDisplays(std::vector<DisplayId>& displayIds) override;
- void setTotalFrameTargetWorkDuration(nsecs_t targetDuration) override;
+ void setTotalFrameTargetWorkDuration(Duration targetDuration) override;
private:
friend class PowerAdvisorTest;
@@ -178,44 +177,45 @@
// Higher-level timing data used for estimation
struct DisplayTimeline {
// The start of hwc present, or the start of validate if it happened there instead
- nsecs_t hwcPresentStartTime = -1;
+ TimePoint hwcPresentStartTime;
// The end of hwc present or validate, whichever one actually presented
- nsecs_t hwcPresentEndTime = -1;
+ TimePoint hwcPresentEndTime;
// How long the actual hwc present was delayed after hwcPresentStartTime
- nsecs_t hwcPresentDelayDuration = 0;
+ Duration hwcPresentDelayDuration{0ns};
// When we think we started waiting for the present fence after calling into hwc present and
// after potentially waiting for the earliest present time
- nsecs_t presentFenceWaitStartTime = -1;
+ TimePoint presentFenceWaitStartTime;
// How long we ran after we finished waiting for the fence but before hwc present finished
- nsecs_t postPresentFenceHwcPresentDuration = 0;
+ Duration postPresentFenceHwcPresentDuration{0ns};
// Are we likely to have waited for the present fence during composition
bool probablyWaitsForPresentFence = false;
// Estimate one frame's timeline from that of a previous frame
- DisplayTimeline estimateTimelineFromReference(nsecs_t fenceTime, nsecs_t displayStartTime);
+ DisplayTimeline estimateTimelineFromReference(TimePoint fenceTime,
+ TimePoint displayStartTime);
};
struct GpuTimeline {
- nsecs_t duration = 0;
- nsecs_t startTime = -1;
+ Duration duration{0ns};
+ TimePoint startTime;
};
// Power hint session data recorded from the pipeline
struct DisplayTimingData {
std::unique_ptr<FenceTime> gpuEndFenceTime;
- std::optional<nsecs_t> gpuStartTime;
- std::optional<nsecs_t> lastValidGpuEndTime;
- std::optional<nsecs_t> lastValidGpuStartTime;
- std::optional<nsecs_t> hwcPresentStartTime;
- std::optional<nsecs_t> hwcPresentEndTime;
- std::optional<nsecs_t> hwcValidateStartTime;
- std::optional<nsecs_t> hwcValidateEndTime;
- std::optional<nsecs_t> hwcPresentDelayedTime;
+ std::optional<TimePoint> gpuStartTime;
+ std::optional<TimePoint> lastValidGpuEndTime;
+ std::optional<TimePoint> lastValidGpuStartTime;
+ std::optional<TimePoint> hwcPresentStartTime;
+ std::optional<TimePoint> hwcPresentEndTime;
+ std::optional<TimePoint> hwcValidateStartTime;
+ std::optional<TimePoint> hwcValidateEndTime;
+ std::optional<TimePoint> hwcPresentDelayedTime;
bool usedClientComposition = false;
bool skippedValidate = false;
// Calculate high-level timing milestones from more granular display timing data
- DisplayTimeline calculateDisplayTimeline(nsecs_t fenceTime);
+ DisplayTimeline calculateDisplayTimeline(TimePoint fenceTime);
// Estimate the gpu duration for a given display from previous gpu timing data
- std::optional<GpuTimeline> estimateGpuTiming(std::optional<nsecs_t> previousEnd);
+ std::optional<GpuTimeline> estimateGpuTiming(std::optional<TimePoint> previousEndTime);
};
template <class T, size_t N>
@@ -240,30 +240,31 @@
};
// Filter and sort the display ids by a given property
- std::vector<DisplayId> getOrderedDisplayIds(std::optional<nsecs_t> DisplayTimingData::*sortBy);
+ std::vector<DisplayId> getOrderedDisplayIds(
+ std::optional<TimePoint> DisplayTimingData::*sortBy);
// Estimates a frame's total work duration including gpu time.
// Runs either at the beginning or end of a frame, using the most recent data available
- std::optional<nsecs_t> estimateWorkDuration(bool earlyHint);
+ std::optional<Duration> estimateWorkDuration(bool earlyHint);
// There are two different targets and actual work durations we care about,
// this normalizes them together and takes the max of the two
- nsecs_t combineTimingEstimates(nsecs_t totalDuration, nsecs_t flingerDuration);
+ Duration combineTimingEstimates(Duration totalDuration, Duration flingerDuration);
std::unordered_map<DisplayId, DisplayTimingData> mDisplayTimingData;
// Current frame's delay
- nsecs_t mFrameDelayDuration = 0;
+ Duration mFrameDelayDuration{0ns};
// Last frame's post-composition duration
- nsecs_t mLastPostcompDuration = 0;
+ Duration mLastPostcompDuration{0ns};
// Buffer of recent commit start times
- RingBuffer<nsecs_t, 2> mCommitStartTimes;
+ RingBuffer<TimePoint, 2> mCommitStartTimes;
// Buffer of recent expected present times
- RingBuffer<nsecs_t, 2> mExpectedPresentTimes;
+ RingBuffer<TimePoint, 2> mExpectedPresentTimes;
// Most recent present fence time, provided by SF after composition engine finishes presenting
- nsecs_t mLastPresentFenceTime = -1;
+ TimePoint mLastPresentFenceTime;
// Most recent composition engine present end time, returned with the present fence from SF
- nsecs_t mLastSfPresentEndTime = -1;
+ TimePoint mLastSfPresentEndTime;
// Target duration for the entire pipeline including gpu
- std::optional<nsecs_t> mTotalFrameTargetDuration;
+ std::optional<Duration> mTotalFrameTargetDuration;
// Updated list of display IDs
std::vector<DisplayId> mDisplayIds;
@@ -273,11 +274,11 @@
// An adjustable safety margin which pads the "actual" value sent to PowerHAL,
// encouraging more aggressive boosting to give SurfaceFlinger a larger margin for error
- static constexpr const std::chrono::nanoseconds kTargetSafetyMargin = 1ms;
+ static constexpr const Duration kTargetSafetyMargin{1ms};
// How long we expect hwc to run after the present call until it waits for the fence
- static constexpr const std::chrono::nanoseconds kFenceWaitStartDelayValidated = 150us;
- static constexpr const std::chrono::nanoseconds kFenceWaitStartDelaySkippedValidate = 250us;
+ static constexpr const Duration kFenceWaitStartDelayValidated{150us};
+ static constexpr const Duration kFenceWaitStartDelaySkippedValidate{250us};
};
class AidlPowerHalWrapper : public PowerAdvisor::HalWrapper {
@@ -294,21 +295,17 @@
void restartPowerHintSession() override;
void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) override;
bool startPowerHintSession() override;
- void setTargetWorkDuration(nsecs_t targetDuration) override;
- void sendActualWorkDuration(nsecs_t actualDuration, nsecs_t timestamp) override;
+ void setTargetWorkDuration(Duration targetDuration) override;
+ void sendActualWorkDuration(Duration actualDuration, TimePoint timestamp) override;
bool shouldReconnectHAL() override;
std::vector<int32_t> getPowerHintSessionThreadIds() override;
- std::optional<nsecs_t> getTargetWorkDuration() override;
+ std::optional<Duration> getTargetWorkDuration() override;
private:
friend class AidlPowerHalWrapperTest;
bool checkPowerHintSessionSupported();
void closePowerHintSession();
- bool shouldReportActualDurations();
-
- // Used for testing
- void setAllowedActualDeviation(nsecs_t);
const sp<hardware::power::IPower> mPowerHal = nullptr;
bool mHasExpensiveRendering = false;
@@ -323,24 +320,15 @@
// Queue of actual durations saved to report
std::vector<hardware::power::WorkDuration> mPowerHintQueue;
// The latest values we have received for target and actual
- nsecs_t mTargetDuration = kDefaultTarget.count();
- std::optional<nsecs_t> mActualDuration;
+ Duration mTargetDuration = kDefaultTargetDuration;
+ std::optional<Duration> mActualDuration;
// The list of thread ids, stored so we can restart the session from this class if needed
std::vector<int32_t> mPowerHintThreadIds;
bool mSupportsPowerHint = false;
- // Keep track of the last messages sent for rate limiter change detection
- std::optional<nsecs_t> mLastActualDurationSent;
- // Timestamp of the last report we sent, used to avoid stale sessions
- nsecs_t mLastActualReportTimestamp = 0;
- nsecs_t mLastTargetDurationSent = kDefaultTarget.count();
- // Max amount the error term can vary without causing an actual value report
- nsecs_t mAllowedActualDeviation = -1;
+ Duration mLastTargetDurationSent = kDefaultTargetDuration;
// Whether we should emit ATRACE_INT data for hint sessions
static const bool sTraceHintSessionData;
- static constexpr const std::chrono::nanoseconds kDefaultTarget = 16ms;
- // Amount of time after the last message was sent before the session goes stale
- // actually 100ms but we use 80 here to give some slack
- static constexpr const std::chrono::nanoseconds kStaleTimeout = 80ms;
+ static constexpr Duration kDefaultTargetDuration{16ms};
};
} // namespace impl
diff --git a/services/surfaceflinger/EffectLayer.cpp b/services/surfaceflinger/EffectLayer.cpp
index d161c51..7180fa6 100644
--- a/services/surfaceflinger/EffectLayer.cpp
+++ b/services/surfaceflinger/EffectLayer.cpp
@@ -41,122 +41,7 @@
namespace android {
// ---------------------------------------------------------------------------
-EffectLayer::EffectLayer(const LayerCreationArgs& args)
- : Layer(args),
- mCompositionState{mFlinger->getCompositionEngine().createLayerFECompositionState()} {}
-
+EffectLayer::EffectLayer(const LayerCreationArgs& args) : BufferStateLayer(args) {}
EffectLayer::~EffectLayer() = default;
-std::optional<compositionengine::LayerFE::LayerSettings> EffectLayer::prepareClientComposition(
- compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) const {
- std::optional<compositionengine::LayerFE::LayerSettings> layerSettings =
- Layer::prepareClientComposition(targetSettings);
- // Nothing to render.
- if (!layerSettings) {
- return {};
- }
-
- // set the shadow for the layer if needed
- prepareShadowClientComposition(*layerSettings, targetSettings.viewport);
-
- // If fill bounds are occluded or the fill color is invalid skip the fill settings.
- if (targetSettings.realContentIsVisible && fillsColor()) {
- // Set color for color fill settings.
- layerSettings->source.solidColor = getColor().rgb;
- return layerSettings;
- } else if (hasBlur() || drawShadows()) {
- layerSettings->skipContentDraw = true;
- return layerSettings;
- }
-
- return {};
-}
-
-bool EffectLayer::isVisible() const {
- return hasSomethingToDraw() && !isHiddenByPolicy() && (getAlpha() > 0.0_hf || hasBlur());
-}
-
-bool EffectLayer::setColor(const half3& color) {
- if (mDrawingState.color.r == color.r && mDrawingState.color.g == color.g &&
- mDrawingState.color.b == color.b) {
- return false;
- }
-
- mDrawingState.sequence++;
- mDrawingState.color.r = color.r;
- mDrawingState.color.g = color.g;
- mDrawingState.color.b = color.b;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool EffectLayer::setDataspace(ui::Dataspace dataspace) {
- if (mDrawingState.dataspace == dataspace) {
- return false;
- }
-
- mDrawingState.sequence++;
- mDrawingState.dataspace = dataspace;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-void EffectLayer::preparePerFrameCompositionState() {
- Layer::preparePerFrameCompositionState();
-
- auto* compositionState = editCompositionState();
- compositionState->color = getColor();
- compositionState->compositionType =
- aidl::android::hardware::graphics::composer3::Composition::SOLID_COLOR;
-}
-
-sp<compositionengine::LayerFE> EffectLayer::getCompositionEngineLayerFE() const {
- // There's no need to get a CE Layer if the EffectLayer isn't going to draw anything. In that
- // case, it acts more like a ContainerLayer so returning a null CE Layer makes more sense
- if (hasSomethingToDraw()) {
- return asLayerFE();
- } else {
- return nullptr;
- }
-}
-
-compositionengine::LayerFECompositionState* EffectLayer::editCompositionState() {
- return mCompositionState.get();
-}
-
-const compositionengine::LayerFECompositionState* EffectLayer::getCompositionState() const {
- return mCompositionState.get();
-}
-
-bool EffectLayer::isOpaque(const Layer::State& s) const {
- // Consider the layer to be opaque if its opaque flag is set or its effective
- // alpha (considering the alpha of its parents as well) is 1.0;
- return (s.flags & layer_state_t::eLayerOpaque) != 0 || (fillsColor() && getAlpha() == 1.0_hf);
-}
-
-ui::Dataspace EffectLayer::getDataSpace() const {
- return mDrawingState.dataspace;
-}
-
-sp<Layer> EffectLayer::createClone() {
- sp<EffectLayer> layer = mFlinger->getFactory().createEffectLayer(
- LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, LayerMetadata()));
- layer->setInitialValuesForClone(sp<Layer>::fromExisting(this));
- return layer;
-}
-
-bool EffectLayer::fillsColor() const {
- return mDrawingState.color.r >= 0.0_hf && mDrawingState.color.g >= 0.0_hf &&
- mDrawingState.color.b >= 0.0_hf;
-}
-
-bool EffectLayer::hasBlur() const {
- return getBackgroundBlurRadius() > 0 || getDrawingState().blurRegions.size() > 0;
-}
-
} // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/EffectLayer.h b/services/surfaceflinger/EffectLayer.h
index 747b0bf..311d493 100644
--- a/services/surfaceflinger/EffectLayer.h
+++ b/services/surfaceflinger/EffectLayer.h
@@ -19,7 +19,7 @@
#include <cstdint>
-#include "Layer.h"
+#include "BufferStateLayer.h"
namespace android {
@@ -27,45 +27,10 @@
// * fill the bounds of the layer with a color
// * render a shadow cast by the bounds of the layer
// If no effects are enabled, the layer is considered to be invisible.
-class EffectLayer : public Layer {
+class EffectLayer : public BufferStateLayer {
public:
explicit EffectLayer(const LayerCreationArgs&);
~EffectLayer() override;
-
- sp<compositionengine::LayerFE> getCompositionEngineLayerFE() const override;
- compositionengine::LayerFECompositionState* editCompositionState() override;
-
- const char* getType() const override { return "EffectLayer"; }
- bool isVisible() const override;
-
- bool setColor(const half3& color) override;
-
- bool setDataspace(ui::Dataspace dataspace) override;
-
- ui::Dataspace getDataSpace() const override;
-
- bool isOpaque(const Layer::State& s) const override;
-
-protected:
- /*
- * compositionengine::LayerFE overrides
- */
- const compositionengine::LayerFECompositionState* getCompositionState() const override;
- void preparePerFrameCompositionState() override;
- std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition(
- compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings)
- const override;
-
- std::unique_ptr<compositionengine::LayerFECompositionState> mCompositionState;
-
- sp<Layer> createClone() override;
-
-private:
- // Returns true if there is a valid color to fill.
- bool fillsColor() const;
- // Returns true if this layer has a blur value.
- bool hasBlur() const;
- bool hasSomethingToDraw() const { return fillsColor() || drawShadows() || hasBlur(); }
};
} // namespace android
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 8a401eb..108047e 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -29,6 +29,7 @@
#include <android-base/stringprintf.h>
#include <android/native_window.h>
#include <binder/IPCThreadState.h>
+#include <compositionengine/CompositionEngine.h>
#include <compositionengine/Display.h>
#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/OutputLayer.h>
@@ -39,8 +40,10 @@
#include <ftl/enum.h>
#include <ftl/fake_guard.h>
#include <gui/BufferItem.h>
+#include <gui/GLConsumer.h>
#include <gui/LayerDebugInfo.h>
#include <gui/Surface.h>
+#include <gui/TraceUtils.h>
#include <math.h>
#include <private/android_filesystem_config.h>
#include <renderengine/RenderEngine.h>
@@ -62,7 +65,6 @@
#include <mutex>
#include <sstream>
-#include "Colorizer.h"
#include "DisplayDevice.h"
#include "DisplayHardware/HWComposer.h"
#include "EffectLayer.h"
@@ -74,11 +76,72 @@
#include "TunnelModeEnabledReporter.h"
#define DEBUG_RESIZE 0
+#define EARLY_RELEASE_ENABLED false
namespace android {
namespace {
constexpr int kDumpTableRowLength = 159;
+
+static constexpr float defaultMaxLuminance = 1000.0;
+
const ui::Transform kIdentityTransform;
+
+constexpr mat4 inverseOrientation(uint32_t transform) {
+ const mat4 flipH(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1);
+ const mat4 flipV(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1);
+ const mat4 rot90(0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1);
+ mat4 tr;
+
+ if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+ tr = tr * rot90;
+ }
+ if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
+ tr = tr * flipH;
+ }
+ if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
+ tr = tr * flipV;
+ }
+ return inverse(tr);
+}
+
+bool assignTransform(ui::Transform* dst, ui::Transform& from) {
+ if (*dst == from) {
+ return false;
+ }
+ *dst = from;
+ return true;
+}
+
+TimeStats::SetFrameRateVote frameRateToSetFrameRateVotePayload(Layer::FrameRate frameRate) {
+ using FrameRateCompatibility = TimeStats::SetFrameRateVote::FrameRateCompatibility;
+ using Seamlessness = TimeStats::SetFrameRateVote::Seamlessness;
+ const auto frameRateCompatibility = [frameRate] {
+ switch (frameRate.type) {
+ case Layer::FrameRateCompatibility::Default:
+ return FrameRateCompatibility::Default;
+ case Layer::FrameRateCompatibility::ExactOrMultiple:
+ return FrameRateCompatibility::ExactOrMultiple;
+ default:
+ return FrameRateCompatibility::Undefined;
+ }
+ }();
+
+ const auto seamlessness = [frameRate] {
+ switch (frameRate.seamlessness) {
+ case scheduler::Seamlessness::OnlySeamless:
+ return Seamlessness::ShouldBeSeamless;
+ case scheduler::Seamlessness::SeamedAndSeamless:
+ return Seamlessness::NotRequired;
+ default:
+ return Seamlessness::Undefined;
+ }
+ }();
+
+ return TimeStats::SetFrameRateVote{.frameRate = frameRate.rate.getValue(),
+ .frameRateCompatibility = frameRateCompatibility,
+ .seamlessness = seamlessness};
+}
+
} // namespace
using namespace ftl::flag_operators;
@@ -100,7 +163,12 @@
mWindowType(static_cast<WindowInfo::Type>(
args.metadata.getInt32(gui::METADATA_WINDOW_TYPE, 0))),
mLayerCreationFlags(args.flags),
- mBorderEnabled(false) {
+ mBorderEnabled(false),
+ mTextureName(args.textureName),
+ mCompositionState{mFlinger->getCompositionEngine().createLayerFECompositionState()},
+ mHwcSlotGenerator(sp<HwcSlotGenerator>::make()) {
+ ALOGV("Creating Layer %s", getDebugName());
+
uint32_t layerFlags = 0;
if (args.flags & ISurfaceComposerClient::eHidden) layerFlags |= layer_state_t::eLayerHidden;
if (args.flags & ISurfaceComposerClient::eOpaque) layerFlags |= layer_state_t::eLayerOpaque;
@@ -124,6 +192,7 @@
mDrawingState.acquireFence = sp<Fence>::make(-1);
mDrawingState.acquireFenceTime = std::make_shared<FenceTime>(mDrawingState.acquireFence);
mDrawingState.dataspace = ui::Dataspace::UNKNOWN;
+ mDrawingState.dataspaceRequested = false;
mDrawingState.hdrMetadata.validTypes = 0;
mDrawingState.surfaceDamageRegion = Region::INVALID_REGION;
mDrawingState.cornerRadius = 0.0f;
@@ -165,6 +234,11 @@
mOwnerUid = mCallingUid;
mOwnerPid = mCallingPid;
}
+
+ mPremultipliedAlpha = !(args.flags & ISurfaceComposerClient::eNonPremultiplied);
+ mPotentialCursor = args.flags & ISurfaceComposerClient::eCursorWindow;
+ mProtectedByApp = args.flags & ISurfaceComposerClient::eProtectedByApp;
+ mDrawingState.dataspace = ui::Dataspace::V0_SRGB;
}
void Layer::onFirstRef() {
@@ -172,6 +246,28 @@
}
Layer::~Layer() {
+ // The original layer and the clone layer share the same texture and buffer. Therefore, only
+ // one of the layers, in this case the original layer, needs to handle the deletion. The
+ // original layer and the clone should be removed at the same time so there shouldn't be any
+ // issue with the clone layer trying to use the texture.
+ if (mBufferInfo.mBuffer != nullptr) {
+ callReleaseBufferCallback(mDrawingState.releaseBufferListener,
+ mBufferInfo.mBuffer->getBuffer(), mBufferInfo.mFrameNumber,
+ mBufferInfo.mFence,
+ mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(
+ mOwnerUid));
+ }
+ if (!isClone()) {
+ // The original layer and the clone layer share the same texture. Therefore, only one of
+ // the layers, in this case the original layer, needs to handle the deletion. The original
+ // layer and the clone should be removed at the same time so there shouldn't be any issue
+ // with the clone layer trying to use the deleted texture.
+ mFlinger->deleteTextureAsync(mTextureName);
+ }
+ const int32_t layerId = getSequence();
+ mFlinger->mTimeStats->onDestroy(layerId);
+ mFlinger->mFrameTracer->onDestroy(layerId);
+
sp<Client> c(mClientRef.promote());
if (c != 0) {
c->detachLayer(this);
@@ -204,13 +300,6 @@
// callbacks
// ---------------------------------------------------------------------------
-/*
- * onLayerDisplayed is only meaningful for BufferLayer, but, is called through
- * Layer. So, the implementation is done in BufferLayer. When called on a
- * EffectLayer object, it's essentially a NOP.
- */
-void Layer::onLayerDisplayed(ftl::SharedFuture<FenceResult>) {}
-
void Layer::removeRelativeZ(const std::vector<Layer*>& layersInTree) {
if (mDrawingState.zOrderRelativeOf == nullptr) {
return;
@@ -499,6 +588,46 @@
// Retrieve it from the scheduler which maintains an instance of LayerHistory, and store it in
// LayerFECompositionState where it would be visible to Flattener.
compositionState->fps = mFlinger->getLayerFramerate(systemTime(), getSequence());
+
+ if (hasBufferOrSidebandStream()) {
+ preparePerFrameBufferCompositionState();
+ } else {
+ preparePerFrameEffectsCompositionState();
+ }
+}
+
+void Layer::preparePerFrameBufferCompositionState() {
+ // Sideband layers
+ auto* compositionState = editCompositionState();
+ if (compositionState->sidebandStream.get() && !compositionState->sidebandStreamHasFrame) {
+ compositionState->compositionType =
+ aidl::android::hardware::graphics::composer3::Composition::SIDEBAND;
+ return;
+ } else if ((mDrawingState.flags & layer_state_t::eLayerIsDisplayDecoration) != 0) {
+ compositionState->compositionType =
+ aidl::android::hardware::graphics::composer3::Composition::DISPLAY_DECORATION;
+ } else {
+ // Normal buffer layers
+ compositionState->hdrMetadata = mBufferInfo.mHdrMetadata;
+ compositionState->compositionType = mPotentialCursor
+ ? aidl::android::hardware::graphics::composer3::Composition::CURSOR
+ : aidl::android::hardware::graphics::composer3::Composition::DEVICE;
+ }
+
+ compositionState->buffer = getBuffer();
+ compositionState->bufferSlot = (mBufferInfo.mBufferSlot == BufferQueue::INVALID_BUFFER_SLOT)
+ ? 0
+ : mBufferInfo.mBufferSlot;
+ compositionState->acquireFence = mBufferInfo.mFence;
+ compositionState->frameNumber = mBufferInfo.mFrameNumber;
+ compositionState->sidebandStreamHasFrame = false;
+}
+
+void Layer::preparePerFrameEffectsCompositionState() {
+ auto* compositionState = editCompositionState();
+ compositionState->color = getColor();
+ compositionState->compositionType =
+ aidl::android::hardware::graphics::composer3::Composition::SOLID_COLOR;
}
void Layer::prepareCursorCompositionState() {
@@ -521,22 +650,6 @@
return sp<compositionengine::LayerFE>::fromExisting(layerFE);
}
-sp<compositionengine::LayerFE> Layer::getCompositionEngineLayerFE() const {
- return nullptr;
-}
-
-compositionengine::LayerFECompositionState* Layer::editCompositionState() {
- return nullptr;
-}
-
-const compositionengine::LayerFECompositionState* Layer::getCompositionState() const {
- return nullptr;
-}
-
-bool Layer::onPreComposition(nsecs_t) {
- return false;
-}
-
void Layer::prepareCompositionState(compositionengine::LayerFE::StateSubset subset) {
using StateSubset = compositionengine::LayerFE::StateSubset;
@@ -571,6 +684,29 @@
std::optional<compositionengine::LayerFE::LayerSettings> Layer::prepareClientComposition(
compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) const {
+ std::optional<compositionengine::LayerFE::LayerSettings> layerSettings =
+ prepareClientCompositionInternal(targetSettings);
+ // Nothing to render.
+ if (!layerSettings) {
+ return {};
+ }
+
+ // HWC requests to clear this layer.
+ if (targetSettings.clearContent) {
+ prepareClearClientComposition(*layerSettings, false /* blackout */);
+ return layerSettings;
+ }
+
+ // set the shadow for the layer if needed
+ prepareShadowClientComposition(*layerSettings, targetSettings.viewport);
+
+ return layerSettings;
+}
+
+std::optional<compositionengine::LayerFE::LayerSettings> Layer::prepareClientCompositionInternal(
+ compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) const {
+ ATRACE_CALL();
+
if (!getCompositionState()) {
return {};
}
@@ -632,6 +768,13 @@
layerSettings.stretchEffect = getStretchEffect();
// Record the name of the layer for debugging further down the stack.
layerSettings.name = getName();
+
+ if (hasEffect()) {
+ prepareEffectsClientComposition(layerSettings, targetSettings);
+ return layerSettings;
+ }
+
+ prepareBufferStateClientComposition(layerSettings, targetSettings);
return layerSettings;
}
@@ -648,6 +791,132 @@
layerSettings.name = getName();
}
+void Layer::prepareEffectsClientComposition(
+ compositionengine::LayerFE::LayerSettings& layerSettings,
+ compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) const {
+ // If fill bounds are occluded or the fill color is invalid skip the fill settings.
+ if (targetSettings.realContentIsVisible && fillsColor()) {
+ // Set color for color fill settings.
+ layerSettings.source.solidColor = getColor().rgb;
+ } else if (hasBlur() || drawShadows()) {
+ layerSettings.skipContentDraw = true;
+ }
+}
+
+void Layer::prepareBufferStateClientComposition(
+ compositionengine::LayerFE::LayerSettings& layerSettings,
+ compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) const {
+ if (CC_UNLIKELY(!mBufferInfo.mBuffer)) {
+ // For surfaceview of tv sideband, there is no activeBuffer
+ // in bufferqueue, we need return LayerSettings.
+ return;
+ }
+ const bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) ||
+ ((isSecure() || isProtected()) && !targetSettings.isSecure);
+ const bool bufferCanBeUsedAsHwTexture =
+ mBufferInfo.mBuffer->getUsage() & GraphicBuffer::USAGE_HW_TEXTURE;
+ if (blackOutLayer || !bufferCanBeUsedAsHwTexture) {
+ ALOGE_IF(!bufferCanBeUsedAsHwTexture, "%s is blacked out as buffer is not gpu readable",
+ mName.c_str());
+ prepareClearClientComposition(layerSettings, true /* blackout */);
+ return;
+ }
+
+ const State& s(getDrawingState());
+ layerSettings.source.buffer.buffer = mBufferInfo.mBuffer;
+ layerSettings.source.buffer.isOpaque = isOpaque(s);
+ layerSettings.source.buffer.fence = mBufferInfo.mFence;
+ layerSettings.source.buffer.textureName = mTextureName;
+ layerSettings.source.buffer.usePremultipliedAlpha = getPremultipledAlpha();
+ layerSettings.source.buffer.isY410BT2020 = isHdrY410();
+ bool hasSmpte2086 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::SMPTE2086;
+ bool hasCta861_3 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::CTA861_3;
+ float maxLuminance = 0.f;
+ if (hasSmpte2086 && hasCta861_3) {
+ maxLuminance = std::min(mBufferInfo.mHdrMetadata.smpte2086.maxLuminance,
+ mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel);
+ } else if (hasSmpte2086) {
+ maxLuminance = mBufferInfo.mHdrMetadata.smpte2086.maxLuminance;
+ } else if (hasCta861_3) {
+ maxLuminance = mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel;
+ } else {
+ switch (layerSettings.sourceDataspace & HAL_DATASPACE_TRANSFER_MASK) {
+ case HAL_DATASPACE_TRANSFER_ST2084:
+ case HAL_DATASPACE_TRANSFER_HLG:
+ // Behavior-match previous releases for HDR content
+ maxLuminance = defaultMaxLuminance;
+ break;
+ }
+ }
+ layerSettings.source.buffer.maxLuminanceNits = maxLuminance;
+ layerSettings.frameNumber = mCurrentFrameNumber;
+ layerSettings.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getId() : 0;
+
+ const bool useFiltering =
+ targetSettings.needsFiltering || mNeedsFiltering || bufferNeedsFiltering();
+
+ // Query the texture matrix given our current filtering mode.
+ float textureMatrix[16];
+ getDrawingTransformMatrix(useFiltering, textureMatrix);
+
+ if (getTransformToDisplayInverse()) {
+ /*
+ * the code below applies the primary display's inverse transform to
+ * the texture transform
+ */
+ uint32_t transform = DisplayDevice::getPrimaryDisplayRotationFlags();
+ mat4 tr = inverseOrientation(transform);
+
+ /**
+ * TODO(b/36727915): This is basically a hack.
+ *
+ * Ensure that regardless of the parent transformation,
+ * this buffer is always transformed from native display
+ * orientation to display orientation. For example, in the case
+ * of a camera where the buffer remains in native orientation,
+ * we want the pixels to always be upright.
+ */
+ sp<Layer> p = mDrawingParent.promote();
+ if (p != nullptr) {
+ const auto parentTransform = p->getTransform();
+ tr = tr * inverseOrientation(parentTransform.getOrientation());
+ }
+
+ // and finally apply it to the original texture matrix
+ const mat4 texTransform(mat4(static_cast<const float*>(textureMatrix)) * tr);
+ memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix));
+ }
+
+ const Rect win{getBounds()};
+ float bufferWidth = getBufferSize(s).getWidth();
+ float bufferHeight = getBufferSize(s).getHeight();
+
+ // BufferStateLayers can have a "buffer size" of [0, 0, -1, -1] when no display frame has
+ // been set and there is no parent layer bounds. In that case, the scale is meaningless so
+ // ignore them.
+ if (!getBufferSize(s).isValid()) {
+ bufferWidth = float(win.right) - float(win.left);
+ bufferHeight = float(win.bottom) - float(win.top);
+ }
+
+ const float scaleHeight = (float(win.bottom) - float(win.top)) / bufferHeight;
+ const float scaleWidth = (float(win.right) - float(win.left)) / bufferWidth;
+ const float translateY = float(win.top) / bufferHeight;
+ const float translateX = float(win.left) / bufferWidth;
+
+ // Flip y-coordinates because GLConsumer expects OpenGL convention.
+ mat4 tr = mat4::translate(vec4(.5f, .5f, 0.f, 1.f)) * mat4::scale(vec4(1.f, -1.f, 1.f, 1.f)) *
+ mat4::translate(vec4(-.5f, -.5f, 0.f, 1.f)) *
+ mat4::translate(vec4(translateX, translateY, 0.f, 1.f)) *
+ mat4::scale(vec4(scaleWidth, scaleHeight, 1.0f, 1.0f));
+
+ layerSettings.source.buffer.useTextureFiltering = useFiltering;
+ layerSettings.source.buffer.textureTransform =
+ mat4(static_cast<const float*>(textureMatrix)) * tr;
+
+ return;
+}
+
aidl::android::hardware::graphics::composer3::Composition Layer::getCompositionType(
const DisplayDevice& display) const {
const auto outputLayer = findOutputLayerForDisplay(&display);
@@ -736,16 +1005,6 @@
mTransactionFlags |= mask;
}
-bool Layer::setPosition(float x, float y) {
- if (mDrawingState.transform.tx() == x && mDrawingState.transform.ty() == y) return false;
- mDrawingState.sequence++;
- mDrawingState.transform.set(x, y);
-
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
bool Layer::setChildLayer(const sp<Layer>& childLayer, int32_t z) {
ssize_t idx = mCurrentChildren.indexOf(childLayer);
if (idx < 0) {
@@ -939,24 +1198,6 @@
setTransactionFlags(eTransactionNeeded);
return true;
}
-bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix) {
- if (matrix.dsdx == mDrawingState.transform.dsdx() &&
- matrix.dtdy == mDrawingState.transform.dtdy() &&
- matrix.dtdx == mDrawingState.transform.dtdx() &&
- matrix.dsdy == mDrawingState.transform.dsdy()) {
- return false;
- }
-
- ui::Transform t;
- t.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
-
- mDrawingState.sequence++;
- mDrawingState.transform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
- mDrawingState.modified = true;
-
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
bool Layer::setTransparentRegionHint(const Region& transparent) {
mDrawingState.sequence++;
@@ -2188,14 +2429,6 @@
return mRemovedFromDrawingState;
}
-ui::Transform Layer::getInputTransform() const {
- return getTransform();
-}
-
-Rect Layer::getInputBounds() const {
- return getCroppedBufferSize(getDrawingState());
-}
-
// Applies the given transform to the region, while protecting against overflows caused by any
// offsets. If applying the offset in the transform to any of the Rects in the region would result
// in an overflow, they are not added to the output Region.
@@ -2459,10 +2692,6 @@
mDrawingState.inputInfo.inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL);
}
-bool Layer::canReceiveInput() const {
- return !isHiddenByPolicy();
-}
-
compositionengine::OutputLayer* Layer::findOutputLayerForDisplay(
const DisplayDevice* display) const {
if (!display) return nullptr;
@@ -2477,6 +2706,40 @@
void Layer::setInitialValuesForClone(const sp<Layer>& clonedFrom) {
cloneDrawingState(clonedFrom.get());
mClonedFrom = clonedFrom;
+ mPremultipliedAlpha = clonedFrom->mPremultipliedAlpha;
+ mPotentialCursor = clonedFrom->mPotentialCursor;
+ mProtectedByApp = clonedFrom->mProtectedByApp;
+ updateCloneBufferInfo();
+}
+
+void Layer::updateCloneBufferInfo() {
+ if (!isClone() || !isClonedFromAlive()) {
+ return;
+ }
+
+ sp<Layer> clonedFrom = getClonedFrom();
+ mBufferInfo = clonedFrom->mBufferInfo;
+ mSidebandStream = clonedFrom->mSidebandStream;
+ surfaceDamageRegion = clonedFrom->surfaceDamageRegion;
+ mCurrentFrameNumber = clonedFrom->mCurrentFrameNumber.load();
+ mPreviousFrameNumber = clonedFrom->mPreviousFrameNumber;
+
+ // After buffer info is updated, the drawingState from the real layer needs to be copied into
+ // the cloned. This is because some properties of drawingState can change when latchBuffer is
+ // called. However, copying the drawingState would also overwrite the cloned layer's relatives
+ // and touchableRegionCrop. Therefore, temporarily store the relatives so they can be set in
+ // the cloned drawingState again.
+ wp<Layer> tmpZOrderRelativeOf = mDrawingState.zOrderRelativeOf;
+ SortedVector<wp<Layer>> tmpZOrderRelatives = mDrawingState.zOrderRelatives;
+ wp<Layer> tmpTouchableRegionCrop = mDrawingState.touchableRegionCrop;
+ WindowInfo tmpInputInfo = mDrawingState.inputInfo;
+
+ cloneDrawingState(clonedFrom.get());
+
+ mDrawingState.touchableRegionCrop = tmpTouchableRegionCrop;
+ mDrawingState.zOrderRelativeOf = tmpZOrderRelativeOf;
+ mDrawingState.zOrderRelatives = tmpZOrderRelatives;
+ mDrawingState.inputInfo = tmpInputInfo;
}
void Layer::updateMirrorInfo() {
@@ -2684,18 +2947,1299 @@
mDrawingState.callbackHandles = {};
}
-bool Layer::setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& handles) {
- if (handles.empty()) {
+void Layer::callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener,
+ const sp<GraphicBuffer>& buffer, uint64_t framenumber,
+ const sp<Fence>& releaseFence,
+ uint32_t currentMaxAcquiredBufferCount) {
+ if (!listener) {
+ return;
+ }
+ ATRACE_FORMAT_INSTANT("callReleaseBufferCallback %s - %" PRIu64, getDebugName(), framenumber);
+ listener->onReleaseBuffer({buffer->getId(), framenumber},
+ releaseFence ? releaseFence : Fence::NO_FENCE,
+ currentMaxAcquiredBufferCount);
+}
+
+void Layer::onLayerDisplayed(ftl::SharedFuture<FenceResult> futureFenceResult) {
+ // If we are displayed on multiple displays in a single composition cycle then we would
+ // need to do careful tracking to enable the use of the mLastClientCompositionFence.
+ // For example we can only use it if all the displays are client comp, and we need
+ // to merge all the client comp fences. We could do this, but for now we just
+ // disable the optimization when a layer is composed on multiple displays.
+ if (mClearClientCompositionFenceOnLayerDisplayed) {
+ mLastClientCompositionFence = nullptr;
+ } else {
+ mClearClientCompositionFenceOnLayerDisplayed = true;
+ }
+
+ // The previous release fence notifies the client that SurfaceFlinger is done with the previous
+ // buffer that was presented on this layer. The first transaction that came in this frame that
+ // replaced the previous buffer on this layer needs this release fence, because the fence will
+ // let the client know when that previous buffer is removed from the screen.
+ //
+ // Every other transaction on this layer does not need a release fence because no other
+ // Transactions that were set on this layer this frame are going to have their preceding buffer
+ // removed from the display this frame.
+ //
+ // For example, if we have 3 transactions this frame. The first transaction doesn't contain a
+ // buffer so it doesn't need a previous release fence because the layer still needs the previous
+ // buffer. The second transaction contains a buffer so it needs a previous release fence because
+ // the previous buffer will be released this frame. The third transaction also contains a
+ // buffer. It replaces the buffer in the second transaction. The buffer in the second
+ // transaction will now no longer be presented so it is released immediately and the third
+ // transaction doesn't need a previous release fence.
+ sp<CallbackHandle> ch;
+ for (auto& handle : mDrawingState.callbackHandles) {
+ if (handle->releasePreviousBuffer &&
+ mDrawingState.releaseBufferEndpoint == handle->listener) {
+ ch = handle;
+ break;
+ }
+ }
+
+ // Prevent tracing the same release multiple times.
+ if (mPreviousFrameNumber != mPreviousReleasedFrameNumber) {
+ mPreviousReleasedFrameNumber = mPreviousFrameNumber;
+ }
+
+ if (ch != nullptr) {
+ ch->previousReleaseCallbackId = mPreviousReleaseCallbackId;
+ ch->previousReleaseFences.emplace_back(std::move(futureFenceResult));
+ ch->name = mName;
+ }
+}
+
+void Layer::onSurfaceFrameCreated(
+ const std::shared_ptr<frametimeline::SurfaceFrame>& surfaceFrame) {
+ while (mPendingJankClassifications.size() >= kPendingClassificationMaxSurfaceFrames) {
+ // Too many SurfaceFrames pending classification. The front of the deque is probably not
+ // tracked by FrameTimeline and will never be presented. This will only result in a memory
+ // leak.
+ ALOGW("Removing the front of pending jank deque from layer - %s to prevent memory leak",
+ mName.c_str());
+ std::string miniDump = mPendingJankClassifications.front()->miniDump();
+ ALOGD("Head SurfaceFrame mini dump\n%s", miniDump.c_str());
+ mPendingJankClassifications.pop_front();
+ }
+ mPendingJankClassifications.emplace_back(surfaceFrame);
+}
+
+void Layer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
+ for (const auto& handle : mDrawingState.callbackHandles) {
+ handle->transformHint = mTransformHint;
+ handle->dequeueReadyTime = dequeueReadyTime;
+ handle->currentMaxAcquiredBufferCount =
+ mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(mOwnerUid);
+ ATRACE_FORMAT_INSTANT("releasePendingBuffer %s - %" PRIu64, getDebugName(),
+ handle->previousReleaseCallbackId.framenumber);
+ }
+
+ for (auto& handle : mDrawingState.callbackHandles) {
+ if (handle->releasePreviousBuffer &&
+ mDrawingState.releaseBufferEndpoint == handle->listener) {
+ handle->previousReleaseCallbackId = mPreviousReleaseCallbackId;
+ break;
+ }
+ }
+
+ std::vector<JankData> jankData;
+ jankData.reserve(mPendingJankClassifications.size());
+ while (!mPendingJankClassifications.empty() &&
+ mPendingJankClassifications.front()->getJankType()) {
+ std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame =
+ mPendingJankClassifications.front();
+ mPendingJankClassifications.pop_front();
+ jankData.emplace_back(
+ JankData(surfaceFrame->getToken(), surfaceFrame->getJankType().value()));
+ }
+
+ mFlinger->getTransactionCallbackInvoker().addCallbackHandles(mDrawingState.callbackHandles,
+ jankData);
+
+ sp<Fence> releaseFence = Fence::NO_FENCE;
+ for (auto& handle : mDrawingState.callbackHandles) {
+ if (handle->releasePreviousBuffer &&
+ mDrawingState.releaseBufferEndpoint == handle->listener) {
+ releaseFence =
+ handle->previousReleaseFence ? handle->previousReleaseFence : Fence::NO_FENCE;
+ break;
+ }
+ }
+
+ mDrawingState.callbackHandles = {};
+}
+
+bool Layer::willPresentCurrentTransaction() const {
+ // Returns true if the most recent Transaction applied to CurrentState will be presented.
+ return (getSidebandStreamChanged() || getAutoRefresh() ||
+ (mDrawingState.modified &&
+ (mDrawingState.buffer != nullptr || mDrawingState.bgColorLayer != nullptr)));
+}
+
+bool Layer::setTransform(uint32_t transform) {
+ if (mDrawingState.bufferTransform == transform) return false;
+ mDrawingState.bufferTransform = transform;
+ mDrawingState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
+bool Layer::setTransformToDisplayInverse(bool transformToDisplayInverse) {
+ if (mDrawingState.transformToDisplayInverse == transformToDisplayInverse) return false;
+ mDrawingState.sequence++;
+ mDrawingState.transformToDisplayInverse = transformToDisplayInverse;
+ mDrawingState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
+bool Layer::setBufferCrop(const Rect& bufferCrop) {
+ if (mDrawingState.bufferCrop == bufferCrop) return false;
+
+ mDrawingState.sequence++;
+ mDrawingState.bufferCrop = bufferCrop;
+
+ mDrawingState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
+bool Layer::setDestinationFrame(const Rect& destinationFrame) {
+ if (mDrawingState.destinationFrame == destinationFrame) return false;
+
+ mDrawingState.sequence++;
+ mDrawingState.destinationFrame = destinationFrame;
+
+ mDrawingState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
+// Translate destination frame into scale and position. If a destination frame is not set, use the
+// provided scale and position
+bool Layer::updateGeometry() {
+ if ((mDrawingState.flags & layer_state_t::eIgnoreDestinationFrame) ||
+ mDrawingState.destinationFrame.isEmpty()) {
+ // If destination frame is not set, use the requested transform set via
+ // Layer::setPosition and Layer::setMatrix.
+ return assignTransform(&mDrawingState.transform, mRequestedTransform);
+ }
+
+ Rect destRect = mDrawingState.destinationFrame;
+ int32_t destW = destRect.width();
+ int32_t destH = destRect.height();
+ if (destRect.left < 0) {
+ destRect.left = 0;
+ destRect.right = destW;
+ }
+ if (destRect.top < 0) {
+ destRect.top = 0;
+ destRect.bottom = destH;
+ }
+
+ if (!mDrawingState.buffer) {
+ ui::Transform t;
+ t.set(destRect.left, destRect.top);
+ return assignTransform(&mDrawingState.transform, t);
+ }
+
+ uint32_t bufferWidth = mDrawingState.buffer->getWidth();
+ uint32_t bufferHeight = mDrawingState.buffer->getHeight();
+ // Undo any transformations on the buffer.
+ if (mDrawingState.bufferTransform & ui::Transform::ROT_90) {
+ std::swap(bufferWidth, bufferHeight);
+ }
+ uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags();
+ if (mDrawingState.transformToDisplayInverse) {
+ if (invTransform & ui::Transform::ROT_90) {
+ std::swap(bufferWidth, bufferHeight);
+ }
+ }
+
+ float sx = destW / static_cast<float>(bufferWidth);
+ float sy = destH / static_cast<float>(bufferHeight);
+ ui::Transform t;
+ t.set(sx, 0, 0, sy);
+ t.set(destRect.left, destRect.top);
+ return assignTransform(&mDrawingState.transform, t);
+}
+
+bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix) {
+ if (mRequestedTransform.dsdx() == matrix.dsdx && mRequestedTransform.dtdy() == matrix.dtdy &&
+ mRequestedTransform.dtdx() == matrix.dtdx && mRequestedTransform.dsdy() == matrix.dsdy) {
return false;
}
+ mRequestedTransform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
+
+ mDrawingState.sequence++;
+ mDrawingState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+
+ return true;
+}
+
+bool Layer::setPosition(float x, float y) {
+ if (mRequestedTransform.tx() == x && mRequestedTransform.ty() == y) {
+ return false;
+ }
+
+ mRequestedTransform.set(x, y);
+
+ mDrawingState.sequence++;
+ mDrawingState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+
+ return true;
+}
+
+bool Layer::setBuffer(std::shared_ptr<renderengine::ExternalTexture>& buffer,
+ const BufferData& bufferData, nsecs_t postTime, nsecs_t desiredPresentTime,
+ bool isAutoTimestamp, std::optional<nsecs_t> dequeueTime,
+ const FrameTimelineInfo& info) {
+ ATRACE_CALL();
+
+ if (!buffer) {
+ return false;
+ }
+
+ const bool frameNumberChanged =
+ bufferData.flags.test(BufferData::BufferDataChange::frameNumberChanged);
+ const uint64_t frameNumber =
+ frameNumberChanged ? bufferData.frameNumber : mDrawingState.frameNumber + 1;
+
+ if (mDrawingState.buffer) {
+ mReleasePreviousBuffer = true;
+ if (!mBufferInfo.mBuffer ||
+ (!mDrawingState.buffer->hasSameBuffer(*mBufferInfo.mBuffer) ||
+ mDrawingState.frameNumber != mBufferInfo.mFrameNumber)) {
+ // If mDrawingState has a buffer, and we are about to update again
+ // before swapping to drawing state, then the first buffer will be
+ // dropped and we should decrement the pending buffer count and
+ // call any release buffer callbacks if set.
+ callReleaseBufferCallback(mDrawingState.releaseBufferListener,
+ mDrawingState.buffer->getBuffer(), mDrawingState.frameNumber,
+ mDrawingState.acquireFence,
+ mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(
+ mOwnerUid));
+ decrementPendingBufferCount();
+ if (mDrawingState.bufferSurfaceFrameTX != nullptr &&
+ mDrawingState.bufferSurfaceFrameTX->getPresentState() != PresentState::Presented) {
+ addSurfaceFrameDroppedForBuffer(mDrawingState.bufferSurfaceFrameTX);
+ mDrawingState.bufferSurfaceFrameTX.reset();
+ }
+ } else if (EARLY_RELEASE_ENABLED && mLastClientCompositionFence != nullptr) {
+ callReleaseBufferCallback(mDrawingState.releaseBufferListener,
+ mDrawingState.buffer->getBuffer(), mDrawingState.frameNumber,
+ mLastClientCompositionFence,
+ mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(
+ mOwnerUid));
+ mLastClientCompositionFence = nullptr;
+ }
+ }
+
+ mDrawingState.frameNumber = frameNumber;
+ mDrawingState.releaseBufferListener = bufferData.releaseBufferListener;
+ mDrawingState.buffer = std::move(buffer);
+ mDrawingState.clientCacheId = bufferData.cachedBuffer;
+
+ mDrawingState.acquireFence = bufferData.flags.test(BufferData::BufferDataChange::fenceChanged)
+ ? bufferData.acquireFence
+ : Fence::NO_FENCE;
+ mDrawingState.acquireFenceTime = std::make_unique<FenceTime>(mDrawingState.acquireFence);
+ if (mDrawingState.acquireFenceTime->getSignalTime() == Fence::SIGNAL_TIME_PENDING) {
+ // We latched this buffer unsiganled, so we need to pass the acquire fence
+ // on the callback instead of just the acquire time, since it's unknown at
+ // this point.
+ mCallbackHandleAcquireTimeOrFence = mDrawingState.acquireFence;
+ } else {
+ mCallbackHandleAcquireTimeOrFence = mDrawingState.acquireFenceTime->getSignalTime();
+ }
+
+ mDrawingState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+
+ const int32_t layerId = getSequence();
+ mFlinger->mTimeStats->setPostTime(layerId, mDrawingState.frameNumber, getName().c_str(),
+ mOwnerUid, postTime, getGameMode());
+ mDrawingState.desiredPresentTime = desiredPresentTime;
+ mDrawingState.isAutoTimestamp = isAutoTimestamp;
+
+ const nsecs_t presentTime = [&] {
+ if (!isAutoTimestamp) return desiredPresentTime;
+
+ const auto prediction =
+ mFlinger->mFrameTimeline->getTokenManager()->getPredictionsForToken(info.vsyncId);
+ if (prediction.has_value()) return prediction->presentTime;
+
+ return static_cast<nsecs_t>(0);
+ }();
+
+ using LayerUpdateType = scheduler::LayerHistory::LayerUpdateType;
+ mFlinger->mScheduler->recordLayerHistory(this, presentTime, LayerUpdateType::Buffer);
+
+ setFrameTimelineVsyncForBufferTransaction(info, postTime);
+
+ if (dequeueTime && *dequeueTime != 0) {
+ const uint64_t bufferId = mDrawingState.buffer->getId();
+ mFlinger->mFrameTracer->traceNewLayer(layerId, getName().c_str());
+ mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, *dequeueTime,
+ FrameTracer::FrameEvent::DEQUEUE);
+ mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, postTime,
+ FrameTracer::FrameEvent::QUEUE);
+ }
+
+ mDrawingState.releaseBufferEndpoint = bufferData.releaseBufferEndpoint;
+ return true;
+}
+
+bool Layer::setDataspace(ui::Dataspace dataspace) {
+ mDrawingState.dataspaceRequested = true;
+ if (mDrawingState.dataspace == dataspace) return false;
+ mDrawingState.dataspace = dataspace;
+ mDrawingState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
+bool Layer::setHdrMetadata(const HdrMetadata& hdrMetadata) {
+ if (mDrawingState.hdrMetadata == hdrMetadata) return false;
+ mDrawingState.hdrMetadata = hdrMetadata;
+ mDrawingState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
+bool Layer::setSurfaceDamageRegion(const Region& surfaceDamage) {
+ mDrawingState.surfaceDamageRegion = surfaceDamage;
+ mDrawingState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
+bool Layer::setApi(int32_t api) {
+ if (mDrawingState.api == api) return false;
+ mDrawingState.api = api;
+ mDrawingState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
+bool Layer::setSidebandStream(const sp<NativeHandle>& sidebandStream) {
+ if (mDrawingState.sidebandStream == sidebandStream) return false;
+
+ if (mDrawingState.sidebandStream != nullptr && sidebandStream == nullptr) {
+ mFlinger->mTunnelModeEnabledReporter->decrementTunnelModeCount();
+ } else if (sidebandStream != nullptr) {
+ mFlinger->mTunnelModeEnabledReporter->incrementTunnelModeCount();
+ }
+
+ mDrawingState.sidebandStream = sidebandStream;
+ mDrawingState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ if (!mSidebandStreamChanged.exchange(true)) {
+ // mSidebandStreamChanged was false
+ mFlinger->onLayerUpdate();
+ }
+ return true;
+}
+
+bool Layer::setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& handles) {
+ // If there is no handle, we will not send a callback so reset mReleasePreviousBuffer and return
+ if (handles.empty()) {
+ mReleasePreviousBuffer = false;
+ return false;
+ }
+
+ const bool willPresent = willPresentCurrentTransaction();
+
for (const auto& handle : handles) {
- mFlinger->getTransactionCallbackInvoker().registerUnpresentedCallbackHandle(handle);
+ // If this transaction set a buffer on this layer, release its previous buffer
+ handle->releasePreviousBuffer = mReleasePreviousBuffer;
+
+ // If this layer will be presented in this frame
+ if (willPresent) {
+ // If this transaction set an acquire fence on this layer, set its acquire time
+ handle->acquireTimeOrFence = mCallbackHandleAcquireTimeOrFence;
+ handle->frameNumber = mDrawingState.frameNumber;
+
+ // Store so latched time and release fence can be set
+ mDrawingState.callbackHandles.push_back(handle);
+
+ } else { // If this layer will NOT need to be relatched and presented this frame
+ // Notify the transaction completed thread this handle is done
+ mFlinger->getTransactionCallbackInvoker().registerUnpresentedCallbackHandle(handle);
+ }
+ }
+
+ mReleasePreviousBuffer = false;
+ mCallbackHandleAcquireTimeOrFence = -1;
+
+ return willPresent;
+}
+
+Rect Layer::getBufferSize(const State& /*s*/) const {
+ // for buffer state layers we use the display frame size as the buffer size.
+
+ if (mBufferInfo.mBuffer == nullptr) {
+ return Rect::INVALID_RECT;
+ }
+
+ uint32_t bufWidth = mBufferInfo.mBuffer->getWidth();
+ uint32_t bufHeight = mBufferInfo.mBuffer->getHeight();
+
+ // Undo any transformations on the buffer and return the result.
+ if (mBufferInfo.mTransform & ui::Transform::ROT_90) {
+ std::swap(bufWidth, bufHeight);
+ }
+
+ if (getTransformToDisplayInverse()) {
+ uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags();
+ if (invTransform & ui::Transform::ROT_90) {
+ std::swap(bufWidth, bufHeight);
+ }
+ }
+
+ return Rect(0, 0, static_cast<int32_t>(bufWidth), static_cast<int32_t>(bufHeight));
+}
+
+FloatRect Layer::computeSourceBounds(const FloatRect& parentBounds) const {
+ if (mBufferInfo.mBuffer == nullptr) {
+ return parentBounds;
+ }
+
+ return getBufferSize(getDrawingState()).toFloatRect();
+}
+
+bool Layer::fenceHasSignaled() const {
+ if (SurfaceFlinger::enableLatchUnsignaledConfig != LatchUnsignaledConfig::Disabled) {
+ return true;
+ }
+
+ const bool fenceSignaled =
+ getDrawingState().acquireFence->getStatus() == Fence::Status::Signaled;
+ if (!fenceSignaled) {
+ mFlinger->mTimeStats->incrementLatchSkipped(getSequence(),
+ TimeStats::LatchSkipReason::LateAcquire);
+ }
+
+ return fenceSignaled;
+}
+
+bool Layer::onPreComposition(nsecs_t refreshStartTime) {
+ for (const auto& handle : mDrawingState.callbackHandles) {
+ handle->refreshStartTime = refreshStartTime;
+ }
+ return hasReadyFrame();
+}
+
+void Layer::setAutoRefresh(bool autoRefresh) {
+ mDrawingState.autoRefresh = autoRefresh;
+}
+
+bool Layer::latchSidebandStream(bool& recomputeVisibleRegions) {
+ // We need to update the sideband stream if the layer has both a buffer and a sideband stream.
+ editCompositionState()->sidebandStreamHasFrame = hasFrameUpdate() && mSidebandStream.get();
+
+ if (mSidebandStreamChanged.exchange(false)) {
+ const State& s(getDrawingState());
+ // mSidebandStreamChanged was true
+ mSidebandStream = s.sidebandStream;
+ editCompositionState()->sidebandStream = mSidebandStream;
+ if (mSidebandStream != nullptr) {
+ setTransactionFlags(eTransactionNeeded);
+ mFlinger->setTransactionFlags(eTraversalNeeded);
+ }
+ recomputeVisibleRegions = true;
+
+ return true;
+ }
+ return false;
+}
+
+bool Layer::hasFrameUpdate() const {
+ const State& c(getDrawingState());
+ return (mDrawingStateModified || mDrawingState.modified) &&
+ (c.buffer != nullptr || c.bgColorLayer != nullptr);
+}
+
+void Layer::updateTexImage(nsecs_t latchTime) {
+ const State& s(getDrawingState());
+
+ if (!s.buffer) {
+ if (s.bgColorLayer) {
+ for (auto& handle : mDrawingState.callbackHandles) {
+ handle->latchTime = latchTime;
+ }
+ }
+ return;
+ }
+
+ for (auto& handle : mDrawingState.callbackHandles) {
+ if (handle->frameNumber == mDrawingState.frameNumber) {
+ handle->latchTime = latchTime;
+ }
+ }
+
+ const int32_t layerId = getSequence();
+ const uint64_t bufferId = mDrawingState.buffer->getId();
+ const uint64_t frameNumber = mDrawingState.frameNumber;
+ const auto acquireFence = std::make_shared<FenceTime>(mDrawingState.acquireFence);
+ mFlinger->mTimeStats->setAcquireFence(layerId, frameNumber, acquireFence);
+ mFlinger->mTimeStats->setLatchTime(layerId, frameNumber, latchTime);
+
+ mFlinger->mFrameTracer->traceFence(layerId, bufferId, frameNumber, acquireFence,
+ FrameTracer::FrameEvent::ACQUIRE_FENCE);
+ mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, latchTime,
+ FrameTracer::FrameEvent::LATCH);
+
+ auto& bufferSurfaceFrame = mDrawingState.bufferSurfaceFrameTX;
+ if (bufferSurfaceFrame != nullptr &&
+ bufferSurfaceFrame->getPresentState() != PresentState::Presented) {
+ // Update only if the bufferSurfaceFrame wasn't already presented. A Presented
+ // bufferSurfaceFrame could be seen here if a pending state was applied successfully and we
+ // are processing the next state.
+ addSurfaceFramePresentedForBuffer(bufferSurfaceFrame,
+ mDrawingState.acquireFenceTime->getSignalTime(),
+ latchTime);
+ mDrawingState.bufferSurfaceFrameTX.reset();
+ }
+
+ std::deque<sp<CallbackHandle>> remainingHandles;
+ mFlinger->getTransactionCallbackInvoker()
+ .addOnCommitCallbackHandles(mDrawingState.callbackHandles, remainingHandles);
+ mDrawingState.callbackHandles = remainingHandles;
+
+ mDrawingStateModified = false;
+}
+
+void Layer::gatherBufferInfo() {
+ if (!mBufferInfo.mBuffer || !mDrawingState.buffer->hasSameBuffer(*mBufferInfo.mBuffer)) {
+ decrementPendingBufferCount();
+ }
+
+ mPreviousReleaseCallbackId = {getCurrentBufferId(), mBufferInfo.mFrameNumber};
+ mBufferInfo.mBuffer = mDrawingState.buffer;
+ mBufferInfo.mFence = mDrawingState.acquireFence;
+ mBufferInfo.mFrameNumber = mDrawingState.frameNumber;
+ mBufferInfo.mPixelFormat =
+ !mBufferInfo.mBuffer ? PIXEL_FORMAT_NONE : mBufferInfo.mBuffer->getPixelFormat();
+ mBufferInfo.mFrameLatencyNeeded = true;
+ mBufferInfo.mDesiredPresentTime = mDrawingState.desiredPresentTime;
+ mBufferInfo.mFenceTime = std::make_shared<FenceTime>(mDrawingState.acquireFence);
+ mBufferInfo.mFence = mDrawingState.acquireFence;
+ mBufferInfo.mTransform = mDrawingState.bufferTransform;
+ auto lastDataspace = mBufferInfo.mDataspace;
+ mBufferInfo.mDataspace = translateDataspace(mDrawingState.dataspace);
+ if (lastDataspace != mBufferInfo.mDataspace) {
+ mFlinger->mSomeDataspaceChanged = true;
+ }
+ mBufferInfo.mCrop = computeBufferCrop(mDrawingState);
+ mBufferInfo.mScaleMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
+ mBufferInfo.mSurfaceDamage = mDrawingState.surfaceDamageRegion;
+ mBufferInfo.mHdrMetadata = mDrawingState.hdrMetadata;
+ mBufferInfo.mApi = mDrawingState.api;
+ mBufferInfo.mTransformToDisplayInverse = mDrawingState.transformToDisplayInverse;
+ mBufferInfo.mBufferSlot = mHwcSlotGenerator->getHwcCacheSlot(mDrawingState.clientCacheId);
+}
+
+Rect Layer::computeBufferCrop(const State& s) {
+ if (s.buffer && !s.bufferCrop.isEmpty()) {
+ Rect bufferCrop;
+ s.buffer->getBounds().intersect(s.bufferCrop, &bufferCrop);
+ return bufferCrop;
+ } else if (s.buffer) {
+ return s.buffer->getBounds();
+ } else {
+ return s.bufferCrop;
+ }
+}
+
+sp<Layer> Layer::createClone() {
+ LayerCreationArgs args(mFlinger.get(), nullptr, mName + " (Mirror)", 0, LayerMetadata());
+ args.textureName = mTextureName;
+ sp<BufferStateLayer> layer = mFlinger->getFactory().createBufferStateLayer(args);
+ layer->mHwcSlotGenerator = mHwcSlotGenerator;
+ layer->setInitialValuesForClone(sp<Layer>::fromExisting(this));
+ return layer;
+}
+
+bool Layer::bufferNeedsFiltering() const {
+ const State& s(getDrawingState());
+ if (!s.buffer) {
+ return false;
+ }
+
+ int32_t bufferWidth = static_cast<int32_t>(s.buffer->getWidth());
+ int32_t bufferHeight = static_cast<int32_t>(s.buffer->getHeight());
+
+ // Undo any transformations on the buffer and return the result.
+ if (s.bufferTransform & ui::Transform::ROT_90) {
+ std::swap(bufferWidth, bufferHeight);
+ }
+
+ if (s.transformToDisplayInverse) {
+ uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags();
+ if (invTransform & ui::Transform::ROT_90) {
+ std::swap(bufferWidth, bufferHeight);
+ }
+ }
+
+ const Rect layerSize{getBounds()};
+ int32_t layerWidth = layerSize.getWidth();
+ int32_t layerHeight = layerSize.getHeight();
+
+ // Align the layer orientation with the buffer before comparism
+ if (mTransformHint & ui::Transform::ROT_90) {
+ std::swap(layerWidth, layerHeight);
+ }
+
+ return layerWidth != bufferWidth || layerHeight != bufferHeight;
+}
+
+void Layer::decrementPendingBufferCount() {
+ int32_t pendingBuffers = --mPendingBufferTransactions;
+ tracePendingBufferCount(pendingBuffers);
+}
+
+void Layer::tracePendingBufferCount(int32_t pendingBuffers) {
+ ATRACE_INT(mBlastTransactionName.c_str(), pendingBuffers);
+}
+
+/*
+ * We don't want to send the layer's transform to input, but rather the
+ * parent's transform. This is because Layer's transform is
+ * information about how the buffer is placed on screen. The parent's
+ * transform makes more sense to send since it's information about how the
+ * layer is placed on screen. This transform is used by input to determine
+ * how to go from screen space back to window space.
+ */
+ui::Transform Layer::getInputTransform() const {
+ if (!hasBufferOrSidebandStream()) {
+ return getTransform();
+ }
+ sp<Layer> parent = mDrawingParent.promote();
+ if (parent == nullptr) {
+ return ui::Transform();
+ }
+
+ return parent->getTransform();
+}
+
+/**
+ * Similar to getInputTransform, we need to update the bounds to include the transform.
+ * This is because bounds don't include the buffer transform, where the input assumes
+ * that's already included.
+ */
+Rect Layer::getInputBounds() const {
+ if (!hasBufferOrSidebandStream()) {
+ return getCroppedBufferSize(getDrawingState());
+ }
+
+ Rect bufferBounds = getCroppedBufferSize(getDrawingState());
+ if (mDrawingState.transform.getType() == ui::Transform::IDENTITY || !bufferBounds.isValid()) {
+ return bufferBounds;
+ }
+ return mDrawingState.transform.transform(bufferBounds);
+}
+
+bool Layer::simpleBufferUpdate(const layer_state_t& s) const {
+ const uint64_t requiredFlags = layer_state_t::eBufferChanged;
+
+ const uint64_t deniedFlags = layer_state_t::eProducerDisconnect | layer_state_t::eLayerChanged |
+ layer_state_t::eRelativeLayerChanged | layer_state_t::eTransparentRegionChanged |
+ layer_state_t::eFlagsChanged | layer_state_t::eBlurRegionsChanged |
+ layer_state_t::eLayerStackChanged | layer_state_t::eAutoRefreshChanged |
+ layer_state_t::eReparent;
+
+ const uint64_t allowedFlags = layer_state_t::eHasListenerCallbacksChanged |
+ layer_state_t::eFrameRateSelectionPriority | layer_state_t::eFrameRateChanged |
+ layer_state_t::eSurfaceDamageRegionChanged | layer_state_t::eApiChanged |
+ layer_state_t::eMetadataChanged | layer_state_t::eDropInputModeChanged |
+ layer_state_t::eInputInfoChanged;
+
+ if ((s.what & requiredFlags) != requiredFlags) {
+ ALOGV("%s: false [missing required flags 0x%" PRIx64 "]", __func__,
+ (s.what | requiredFlags) & ~s.what);
+ return false;
+ }
+
+ if (s.what & deniedFlags) {
+ ALOGV("%s: false [has denied flags 0x%" PRIx64 "]", __func__, s.what & deniedFlags);
+ return false;
+ }
+
+ if (s.what & allowedFlags) {
+ ALOGV("%s: [has allowed flags 0x%" PRIx64 "]", __func__, s.what & allowedFlags);
+ }
+
+ if (s.what & layer_state_t::ePositionChanged) {
+ if (mRequestedTransform.tx() != s.x || mRequestedTransform.ty() != s.y) {
+ ALOGV("%s: false [ePositionChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eAlphaChanged) {
+ if (mDrawingState.color.a != s.alpha) {
+ ALOGV("%s: false [eAlphaChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eColorTransformChanged) {
+ if (mDrawingState.colorTransform != s.colorTransform) {
+ ALOGV("%s: false [eColorTransformChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eBackgroundColorChanged) {
+ if (mDrawingState.bgColorLayer || s.bgColorAlpha != 0) {
+ ALOGV("%s: false [eBackgroundColorChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eMatrixChanged) {
+ if (mRequestedTransform.dsdx() != s.matrix.dsdx ||
+ mRequestedTransform.dtdy() != s.matrix.dtdy ||
+ mRequestedTransform.dtdx() != s.matrix.dtdx ||
+ mRequestedTransform.dsdy() != s.matrix.dsdy) {
+ ALOGV("%s: false [eMatrixChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eCornerRadiusChanged) {
+ if (mDrawingState.cornerRadius != s.cornerRadius) {
+ ALOGV("%s: false [eCornerRadiusChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eBackgroundBlurRadiusChanged) {
+ if (mDrawingState.backgroundBlurRadius != static_cast<int>(s.backgroundBlurRadius)) {
+ ALOGV("%s: false [eBackgroundBlurRadiusChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eTransformChanged) {
+ if (mDrawingState.bufferTransform != s.transform) {
+ ALOGV("%s: false [eTransformChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eTransformToDisplayInverseChanged) {
+ if (mDrawingState.transformToDisplayInverse != s.transformToDisplayInverse) {
+ ALOGV("%s: false [eTransformToDisplayInverseChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eCropChanged) {
+ if (mDrawingState.crop != s.crop) {
+ ALOGV("%s: false [eCropChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eDataspaceChanged) {
+ if (mDrawingState.dataspace != s.dataspace) {
+ ALOGV("%s: false [eDataspaceChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eHdrMetadataChanged) {
+ if (mDrawingState.hdrMetadata != s.hdrMetadata) {
+ ALOGV("%s: false [eHdrMetadataChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eSidebandStreamChanged) {
+ if (mDrawingState.sidebandStream != s.sidebandStream) {
+ ALOGV("%s: false [eSidebandStreamChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eColorSpaceAgnosticChanged) {
+ if (mDrawingState.colorSpaceAgnostic != s.colorSpaceAgnostic) {
+ ALOGV("%s: false [eColorSpaceAgnosticChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eShadowRadiusChanged) {
+ if (mDrawingState.shadowRadius != s.shadowRadius) {
+ ALOGV("%s: false [eShadowRadiusChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eFixedTransformHintChanged) {
+ if (mDrawingState.fixedTransformHint != s.fixedTransformHint) {
+ ALOGV("%s: false [eFixedTransformHintChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eTrustedOverlayChanged) {
+ if (mDrawingState.isTrustedOverlay != s.isTrustedOverlay) {
+ ALOGV("%s: false [eTrustedOverlayChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eStretchChanged) {
+ StretchEffect temp = s.stretchEffect;
+ temp.sanitize();
+ if (mDrawingState.stretchEffect != temp) {
+ ALOGV("%s: false [eStretchChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eBufferCropChanged) {
+ if (mDrawingState.bufferCrop != s.bufferCrop) {
+ ALOGV("%s: false [eBufferCropChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eDestinationFrameChanged) {
+ if (mDrawingState.destinationFrame != s.destinationFrame) {
+ ALOGV("%s: false [eDestinationFrameChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ if (s.what & layer_state_t::eDimmingEnabledChanged) {
+ if (mDrawingState.dimmingEnabled != s.dimmingEnabled) {
+ ALOGV("%s: false [eDimmingEnabledChanged changed]", __func__);
+ return false;
+ }
+ }
+
+ ALOGV("%s: true", __func__);
+ return true;
+}
+
+bool Layer::isHdrY410() const {
+ // pixel format is HDR Y410 masquerading as RGBA_1010102
+ return (mBufferInfo.mDataspace == ui::Dataspace::BT2020_ITU_PQ &&
+ mBufferInfo.mApi == NATIVE_WINDOW_API_MEDIA &&
+ mBufferInfo.mPixelFormat == HAL_PIXEL_FORMAT_RGBA_1010102);
+}
+
+sp<compositionengine::LayerFE> Layer::getCompositionEngineLayerFE() const {
+ // There's no need to get a CE Layer if the layer isn't going to draw anything.
+ if (hasSomethingToDraw()) {
+ return asLayerFE();
+ } else {
+ return nullptr;
+ }
+}
+
+compositionengine::LayerFECompositionState* Layer::editCompositionState() {
+ return mCompositionState.get();
+}
+
+const compositionengine::LayerFECompositionState* Layer::getCompositionState() const {
+ return mCompositionState.get();
+}
+
+void Layer::useSurfaceDamage() {
+ if (mFlinger->mForceFullDamage) {
+ surfaceDamageRegion = Region::INVALID_REGION;
+ } else {
+ surfaceDamageRegion = mBufferInfo.mSurfaceDamage;
+ }
+}
+
+void Layer::useEmptyDamage() {
+ surfaceDamageRegion.clear();
+}
+
+bool Layer::isOpaque(const Layer::State& s) const {
+ // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the
+ // layer's opaque flag.
+ if (!hasSomethingToDraw()) {
+ return false;
+ }
+
+ // if the layer has the opaque flag, then we're always opaque
+ if ((s.flags & layer_state_t::eLayerOpaque) == layer_state_t::eLayerOpaque) {
+ return true;
+ }
+
+ // If the buffer has no alpha channel, then we are opaque
+ if (hasBufferOrSidebandStream() && isOpaqueFormat(getPixelFormat())) {
+ return true;
+ }
+
+ // Lastly consider the layer opaque if drawing a color with alpha == 1.0
+ return fillsColor() && getAlpha() == 1.0_hf;
+}
+
+bool Layer::canReceiveInput() const {
+ return !isHiddenByPolicy() && (mBufferInfo.mBuffer == nullptr || getAlpha() > 0.0f);
+}
+
+bool Layer::isVisible() const {
+ if (!hasSomethingToDraw()) {
+ return false;
+ }
+
+ if (isHiddenByPolicy()) {
+ return false;
+ }
+
+ return getAlpha() > 0.0f || hasBlur();
+}
+
+void Layer::onPostComposition(const DisplayDevice* display,
+ const std::shared_ptr<FenceTime>& glDoneFence,
+ const std::shared_ptr<FenceTime>& presentFence,
+ const CompositorTiming& compositorTiming) {
+ // mFrameLatencyNeeded is true when a new frame was latched for the
+ // composition.
+ if (!mBufferInfo.mFrameLatencyNeeded) return;
+
+ for (const auto& handle : mDrawingState.callbackHandles) {
+ handle->gpuCompositionDoneFence = glDoneFence;
+ handle->compositorTiming = compositorTiming;
+ }
+
+ // Update mFrameTracker.
+ nsecs_t desiredPresentTime = mBufferInfo.mDesiredPresentTime;
+ mFrameTracker.setDesiredPresentTime(desiredPresentTime);
+
+ const int32_t layerId = getSequence();
+ mFlinger->mTimeStats->setDesiredTime(layerId, mCurrentFrameNumber, desiredPresentTime);
+
+ const auto outputLayer = findOutputLayerForDisplay(display);
+ if (outputLayer && outputLayer->requiresClientComposition()) {
+ nsecs_t clientCompositionTimestamp = outputLayer->getState().clientCompositionTimestamp;
+ mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), mCurrentFrameNumber,
+ clientCompositionTimestamp,
+ FrameTracer::FrameEvent::FALLBACK_COMPOSITION);
+ // Update the SurfaceFrames in the drawing state
+ if (mDrawingState.bufferSurfaceFrameTX) {
+ mDrawingState.bufferSurfaceFrameTX->setGpuComposition();
+ }
+ for (auto& [token, surfaceFrame] : mDrawingState.bufferlessSurfaceFramesTX) {
+ surfaceFrame->setGpuComposition();
+ }
+ }
+
+ std::shared_ptr<FenceTime> frameReadyFence = mBufferInfo.mFenceTime;
+ if (frameReadyFence->isValid()) {
+ mFrameTracker.setFrameReadyFence(std::move(frameReadyFence));
+ } else {
+ // There was no fence for this frame, so assume that it was ready
+ // to be presented at the desired present time.
+ mFrameTracker.setFrameReadyTime(desiredPresentTime);
+ }
+
+ if (display) {
+ const Fps refreshRate = display->refreshRateConfigs().getActiveMode()->getFps();
+ const std::optional<Fps> renderRate =
+ mFlinger->mScheduler->getFrameRateOverride(getOwnerUid());
+
+ const auto vote = frameRateToSetFrameRateVotePayload(mDrawingState.frameRate);
+ const auto gameMode = getGameMode();
+
+ if (presentFence->isValid()) {
+ mFlinger->mTimeStats->setPresentFence(layerId, mCurrentFrameNumber, presentFence,
+ refreshRate, renderRate, vote, gameMode);
+ mFlinger->mFrameTracer->traceFence(layerId, getCurrentBufferId(), mCurrentFrameNumber,
+ presentFence,
+ FrameTracer::FrameEvent::PRESENT_FENCE);
+ mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence));
+ } else if (const auto displayId = PhysicalDisplayId::tryCast(display->getId());
+ displayId && mFlinger->getHwComposer().isConnected(*displayId)) {
+ // The HWC doesn't support present fences, so use the refresh
+ // timestamp instead.
+ const nsecs_t actualPresentTime = display->getRefreshTimestamp();
+ mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime,
+ refreshRate, renderRate, vote, gameMode);
+ mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(),
+ mCurrentFrameNumber, actualPresentTime,
+ FrameTracer::FrameEvent::PRESENT_FENCE);
+ mFrameTracker.setActualPresentTime(actualPresentTime);
+ }
+ }
+
+ mFrameTracker.advanceFrame();
+ mBufferInfo.mFrameLatencyNeeded = false;
+}
+
+bool Layer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) {
+ ATRACE_FORMAT_INSTANT("latchBuffer %s - %" PRIu64, getDebugName(),
+ getDrawingState().frameNumber);
+
+ bool refreshRequired = latchSidebandStream(recomputeVisibleRegions);
+
+ if (refreshRequired) {
+ return refreshRequired;
+ }
+
+ // If the head buffer's acquire fence hasn't signaled yet, return and
+ // try again later
+ if (!fenceHasSignaled()) {
+ ATRACE_NAME("!fenceHasSignaled()");
+ mFlinger->onLayerUpdate();
+ return false;
+ }
+
+ updateTexImage(latchTime);
+ if (mDrawingState.buffer == nullptr) {
+ return false;
+ }
+
+ // Capture the old state of the layer for comparisons later
+ BufferInfo oldBufferInfo = mBufferInfo;
+ const bool oldOpacity = isOpaque(mDrawingState);
+ mPreviousFrameNumber = mCurrentFrameNumber;
+ mCurrentFrameNumber = mDrawingState.frameNumber;
+ gatherBufferInfo();
+
+ if (oldBufferInfo.mBuffer == nullptr) {
+ // the first time we receive a buffer, we need to trigger a
+ // geometry invalidation.
+ recomputeVisibleRegions = true;
+ }
+
+ if ((mBufferInfo.mCrop != oldBufferInfo.mCrop) ||
+ (mBufferInfo.mTransform != oldBufferInfo.mTransform) ||
+ (mBufferInfo.mScaleMode != oldBufferInfo.mScaleMode) ||
+ (mBufferInfo.mTransformToDisplayInverse != oldBufferInfo.mTransformToDisplayInverse)) {
+ recomputeVisibleRegions = true;
+ }
+
+ if (oldBufferInfo.mBuffer != nullptr) {
+ uint32_t bufWidth = mBufferInfo.mBuffer->getWidth();
+ uint32_t bufHeight = mBufferInfo.mBuffer->getHeight();
+ if (bufWidth != oldBufferInfo.mBuffer->getWidth() ||
+ bufHeight != oldBufferInfo.mBuffer->getHeight()) {
+ recomputeVisibleRegions = true;
+ }
+ }
+
+ if (oldOpacity != isOpaque(mDrawingState)) {
+ recomputeVisibleRegions = true;
}
return true;
}
+bool Layer::hasReadyFrame() const {
+ return hasFrameUpdate() || getSidebandStreamChanged() || getAutoRefresh();
+}
+
+bool Layer::isProtected() const {
+ return (mBufferInfo.mBuffer != nullptr) &&
+ (mBufferInfo.mBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
+}
+
+// As documented in libhardware header, formats in the range
+// 0x100 - 0x1FF are specific to the HAL implementation, and
+// are known to have no alpha channel
+// TODO: move definition for device-specific range into
+// hardware.h, instead of using hard-coded values here.
+#define HARDWARE_IS_DEVICE_FORMAT(f) ((f) >= 0x100 && (f) <= 0x1FF)
+
+bool Layer::isOpaqueFormat(PixelFormat format) {
+ if (HARDWARE_IS_DEVICE_FORMAT(format)) {
+ return true;
+ }
+ switch (format) {
+ case PIXEL_FORMAT_RGBA_8888:
+ case PIXEL_FORMAT_BGRA_8888:
+ case PIXEL_FORMAT_RGBA_FP16:
+ case PIXEL_FORMAT_RGBA_1010102:
+ case PIXEL_FORMAT_R_8:
+ return false;
+ }
+ // in all other case, we have no blending (also for unknown formats)
+ return true;
+}
+
+bool Layer::needsFiltering(const DisplayDevice* display) const {
+ if (!hasBufferOrSidebandStream()) {
+ return false;
+ }
+ const auto outputLayer = findOutputLayerForDisplay(display);
+ if (outputLayer == nullptr) {
+ return false;
+ }
+
+ // We need filtering if the sourceCrop rectangle size does not match the
+ // displayframe rectangle size (not a 1:1 render)
+ const auto& compositionState = outputLayer->getState();
+ const auto displayFrame = compositionState.displayFrame;
+ const auto sourceCrop = compositionState.sourceCrop;
+ return sourceCrop.getHeight() != displayFrame.getHeight() ||
+ sourceCrop.getWidth() != displayFrame.getWidth();
+}
+
+bool Layer::needsFilteringForScreenshots(const DisplayDevice* display,
+ const ui::Transform& inverseParentTransform) const {
+ if (!hasBufferOrSidebandStream()) {
+ return false;
+ }
+ const auto outputLayer = findOutputLayerForDisplay(display);
+ if (outputLayer == nullptr) {
+ return false;
+ }
+
+ // We need filtering if the sourceCrop rectangle size does not match the
+ // viewport rectangle size (not a 1:1 render)
+ const auto& compositionState = outputLayer->getState();
+ const ui::Transform& displayTransform = display->getTransform();
+ const ui::Transform inverseTransform = inverseParentTransform * displayTransform.inverse();
+ // Undo the transformation of the displayFrame so that we're back into
+ // layer-stack space.
+ const Rect frame = inverseTransform.transform(compositionState.displayFrame);
+ const FloatRect sourceCrop = compositionState.sourceCrop;
+
+ int32_t frameHeight = frame.getHeight();
+ int32_t frameWidth = frame.getWidth();
+ // If the display transform had a rotational component then undo the
+ // rotation so that the orientation matches the source crop.
+ if (displayTransform.getOrientation() & ui::Transform::ROT_90) {
+ std::swap(frameHeight, frameWidth);
+ }
+ return sourceCrop.getHeight() != frameHeight || sourceCrop.getWidth() != frameWidth;
+}
+
+void Layer::latchAndReleaseBuffer() {
+ if (hasReadyFrame()) {
+ bool ignored = false;
+ latchBuffer(ignored, systemTime());
+ }
+ releasePendingBuffer(systemTime());
+}
+
+PixelFormat Layer::getPixelFormat() const {
+ return mBufferInfo.mPixelFormat;
+}
+
+bool Layer::getTransformToDisplayInverse() const {
+ return mBufferInfo.mTransformToDisplayInverse;
+}
+
+Rect Layer::getBufferCrop() const {
+ // this is the crop rectangle that applies to the buffer
+ // itself (as opposed to the window)
+ if (!mBufferInfo.mCrop.isEmpty()) {
+ // if the buffer crop is defined, we use that
+ return mBufferInfo.mCrop;
+ } else if (mBufferInfo.mBuffer != nullptr) {
+ // otherwise we use the whole buffer
+ return mBufferInfo.mBuffer->getBounds();
+ } else {
+ // if we don't have a buffer yet, we use an empty/invalid crop
+ return Rect();
+ }
+}
+
+uint32_t Layer::getBufferTransform() const {
+ return mBufferInfo.mTransform;
+}
+
+ui::Dataspace Layer::getDataSpace() const {
+ return mDrawingState.dataspaceRequested ? getRequestedDataSpace() : ui::Dataspace::UNKNOWN;
+}
+
+ui::Dataspace Layer::getRequestedDataSpace() const {
+ return hasBufferOrSidebandStream() ? mBufferInfo.mDataspace : mDrawingState.dataspace;
+}
+
+ui::Dataspace Layer::translateDataspace(ui::Dataspace dataspace) {
+ ui::Dataspace updatedDataspace = dataspace;
+ // translate legacy dataspaces to modern dataspaces
+ switch (dataspace) {
+ case ui::Dataspace::SRGB:
+ updatedDataspace = ui::Dataspace::V0_SRGB;
+ break;
+ case ui::Dataspace::SRGB_LINEAR:
+ updatedDataspace = ui::Dataspace::V0_SRGB_LINEAR;
+ break;
+ case ui::Dataspace::JFIF:
+ updatedDataspace = ui::Dataspace::V0_JFIF;
+ break;
+ case ui::Dataspace::BT601_625:
+ updatedDataspace = ui::Dataspace::V0_BT601_625;
+ break;
+ case ui::Dataspace::BT601_525:
+ updatedDataspace = ui::Dataspace::V0_BT601_525;
+ break;
+ case ui::Dataspace::BT709:
+ updatedDataspace = ui::Dataspace::V0_BT709;
+ break;
+ default:
+ break;
+ }
+
+ return updatedDataspace;
+}
+
+sp<GraphicBuffer> Layer::getBuffer() const {
+ return mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer() : nullptr;
+}
+
+void Layer::getDrawingTransformMatrix(bool filteringEnabled, float outMatrix[16]) const {
+ sp<GraphicBuffer> buffer = getBuffer();
+ if (!buffer) {
+ ALOGE("Buffer should not be null!");
+ return;
+ }
+ GLConsumer::computeTransformMatrix(outMatrix, buffer->getWidth(), buffer->getHeight(),
+ buffer->getPixelFormat(), mBufferInfo.mCrop,
+ mBufferInfo.mTransform, filteringEnabled);
+}
+
+void Layer::setTransformHint(ui::Transform::RotationFlags displayTransformHint) {
+ mTransformHint = getFixedTransformHint();
+ if (mTransformHint == ui::Transform::ROT_INVALID) {
+ mTransformHint = displayTransformHint;
+ }
+}
+
+const std::shared_ptr<renderengine::ExternalTexture>& Layer::getExternalTexture() const {
+ return mBufferInfo.mBuffer;
+}
+
+bool Layer::setColor(const half3& color) {
+ if (mDrawingState.color.r == color.r && mDrawingState.color.g == color.g &&
+ mDrawingState.color.b == color.b) {
+ return false;
+ }
+
+ mDrawingState.sequence++;
+ mDrawingState.color.r = color.r;
+ mDrawingState.color.g = color.g;
+ mDrawingState.color.b = color.b;
+ mDrawingState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
+bool Layer::fillsColor() const {
+ return !hasBufferOrSidebandStream() && mDrawingState.color.r >= 0.0_hf &&
+ mDrawingState.color.g >= 0.0_hf && mDrawingState.color.b >= 0.0_hf;
+}
+
+bool Layer::hasBlur() const {
+ return getBackgroundBlurRadius() > 0 || getDrawingState().blurRegions.size() > 0;
+}
+
// ---------------------------------------------------------------------------
std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index b05a4a0..f6b9b0f 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -48,12 +48,10 @@
#include <vector>
#include "Client.h"
-#include "ClientCache.h"
-#include "DisplayHardware/ComposerHal.h"
#include "DisplayHardware/HWComposer.h"
#include "FrameTracker.h"
+#include "HwcSlotGenerator.h"
#include "LayerVector.h"
-#include "RenderArea.h"
#include "Scheduler/LayerInfo.h"
#include "SurfaceFlinger.h"
#include "Tracing/LayerTracing.h"
@@ -170,10 +168,9 @@
gui::WindowInfo inputInfo;
wp<Layer> touchableRegionCrop;
- // dataspace is only used by BufferStateLayer and EffectLayer
ui::Dataspace dataspace;
+ bool dataspaceRequested;
- // The fields below this point are only used by BufferStateLayer
uint64_t frameNumber;
ui::Transform transform;
uint32_t bufferTransform;
@@ -307,17 +304,17 @@
static void miniDumpHeader(std::string& result);
// Provide unique string for each class type in the Layer hierarchy
- virtual const char* getType() const = 0;
+ virtual const char* getType() const { return "Layer"; }
// true if this layer is visible, false otherwise
- virtual bool isVisible() const = 0;
+ virtual bool isVisible() const;
- virtual sp<Layer> createClone() = 0;
+ virtual sp<Layer> createClone();
// Set a 2x2 transformation matrix on the layer. This transform
// will be applied after parent transforms, but before any final
// producer specified transform.
- virtual bool setMatrix(const layer_state_t::matrix22_t& matrix);
+ bool setMatrix(const layer_state_t::matrix22_t& matrix);
// This second set of geometry attributes are controlled by
// setGeometryAppliesWithResize, and their default mode is to be
@@ -327,9 +324,9 @@
// setPosition operates in parent buffer space (pre parent-transform) or display
// space for top-level layers.
- virtual bool setPosition(float x, float y);
+ bool setPosition(float x, float y);
// Buffer space
- virtual bool setCrop(const Rect& crop);
+ bool setCrop(const Rect& crop);
// TODO(b/38182121): Could we eliminate the various latching modes by
// using the layer hierarchy?
@@ -338,7 +335,7 @@
virtual bool setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t relativeZ);
virtual bool setAlpha(float alpha);
- virtual bool setColor(const half3& /*color*/) { return false; };
+ bool setColor(const half3& /*color*/);
// Set rounded corner radius for this layer and its children.
//
@@ -364,30 +361,25 @@
virtual bool isColorSpaceAgnostic() const { return mDrawingState.colorSpaceAgnostic; }
virtual bool isDimmingEnabled() const { return getDrawingState().dimmingEnabled; };
- // Used only to set BufferStateLayer state
- virtual bool setTransform(uint32_t /*transform*/) { return false; };
- virtual bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/) { return false; };
- virtual bool setBuffer(std::shared_ptr<renderengine::ExternalTexture>& /* buffer */,
- const BufferData& /* bufferData */, nsecs_t /* postTime */,
- nsecs_t /*desiredPresentTime*/, bool /*isAutoTimestamp*/,
- std::optional<nsecs_t> /* dequeueTime */,
- const FrameTimelineInfo& /*info*/) {
- return false;
- };
- virtual bool setDataspace(ui::Dataspace /*dataspace*/) { return false; };
- virtual bool setHdrMetadata(const HdrMetadata& /*hdrMetadata*/) { return false; };
- virtual bool setSurfaceDamageRegion(const Region& /*surfaceDamage*/) { return false; };
- virtual bool setApi(int32_t /*api*/) { return false; };
- virtual bool setSidebandStream(const sp<NativeHandle>& /*sidebandStream*/) { return false; };
- virtual bool setTransactionCompletedListeners(
- const std::vector<sp<CallbackHandle>>& /*handles*/);
+ bool setTransform(uint32_t /*transform*/);
+ bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/);
+ bool setBuffer(std::shared_ptr<renderengine::ExternalTexture>& /* buffer */,
+ const BufferData& /* bufferData */, nsecs_t /* postTime */,
+ nsecs_t /*desiredPresentTime*/, bool /*isAutoTimestamp*/,
+ std::optional<nsecs_t> /* dequeueTime */, const FrameTimelineInfo& /*info*/);
+ bool setDataspace(ui::Dataspace /*dataspace*/);
+ bool setHdrMetadata(const HdrMetadata& /*hdrMetadata*/);
+ bool setSurfaceDamageRegion(const Region& /*surfaceDamage*/);
+ bool setApi(int32_t /*api*/);
+ bool setSidebandStream(const sp<NativeHandle>& /*sidebandStream*/);
+ bool setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& /*handles*/);
virtual bool setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace);
virtual bool setColorSpaceAgnostic(const bool agnostic);
virtual bool setDimmingEnabled(const bool dimmingEnabled);
virtual bool setDefaultFrameRateCompatibility(FrameRateCompatibility compatibility);
virtual bool setFrameRateSelectionPriority(int32_t priority);
virtual bool setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHint);
- virtual void setAutoRefresh(bool /* autoRefresh */) {}
+ void setAutoRefresh(bool /* autoRefresh */);
bool setDropInputMode(gui::DropInputMode);
// If the variable is not set on the layer, it traverses up the tree to inherit the frame
@@ -396,16 +388,17 @@
//
virtual FrameRateCompatibility getDefaultFrameRateCompatibility() const;
//
- virtual ui::Dataspace getDataSpace() const { return ui::Dataspace::UNKNOWN; }
+ ui::Dataspace getDataSpace() const;
+ ui::Dataspace getRequestedDataSpace() const;
virtual sp<compositionengine::LayerFE> getCompositionEngineLayerFE() const;
- virtual compositionengine::LayerFECompositionState* editCompositionState();
+ compositionengine::LayerFECompositionState* editCompositionState();
// If we have received a new buffer this frame, we will pass its surface
// damage down to hardware composer. Otherwise, we must send a region with
// one empty rect.
- virtual void useSurfaceDamage() {}
- virtual void useEmptyDamage() {}
+ void useSurfaceDamage();
+ void useEmptyDamage();
Region getVisibleRegion(const DisplayDevice*) const;
/*
@@ -415,18 +408,18 @@
* pixel format includes an alpha channel) and the "opaque" flag set
* on the layer. It does not examine the current plane alpha value.
*/
- virtual bool isOpaque(const Layer::State&) const { return false; }
+ bool isOpaque(const Layer::State&) const;
/*
* Returns whether this layer can receive input.
*/
- virtual bool canReceiveInput() const;
+ bool canReceiveInput() const;
/*
* isProtected - true if the layer may contain protected contents in the
* GRALLOC_USAGE_PROTECTED sense.
*/
- virtual bool isProtected() const { return false; }
+ bool isProtected() const;
/*
* isFixedSize - true if content has a fixed size
@@ -436,7 +429,7 @@
/*
* usesSourceCrop - true if content should use a source crop
*/
- virtual bool usesSourceCrop() const { return false; }
+ bool usesSourceCrop() const { return hasBufferOrSidebandStream(); }
// Most layers aren't created from the main thread, and therefore need to
// grab the SF state lock to access HWC, but ContainerLayer does, so we need
@@ -447,8 +440,8 @@
Region getActiveTransparentRegion(const Layer::State& s) const {
return s.transparentRegionHint;
}
- virtual Rect getCrop(const Layer::State& s) const { return s.crop; }
- virtual bool needsFiltering(const DisplayDevice*) const { return false; }
+ Rect getCrop(const Layer::State& s) const { return s.crop; }
+ bool needsFiltering(const DisplayDevice*) const;
// True if this layer requires filtering
// This method is distinct from needsFiltering() in how the filter
@@ -459,25 +452,25 @@
// different.
// If the parent transform needs to be undone when capturing the layer, then
// the inverse parent transform is also required.
- virtual bool needsFilteringForScreenshots(const DisplayDevice*, const ui::Transform&) const {
- return false;
- }
+ bool needsFilteringForScreenshots(const DisplayDevice*, const ui::Transform&) const;
- virtual void updateCloneBufferInfo(){};
+ // from graphics API
+ ui::Dataspace translateDataspace(ui::Dataspace dataspace);
+ void updateCloneBufferInfo();
+ uint64_t mPreviousFrameNumber = 0;
- virtual bool isHdrY410() const { return false; }
+ bool isHdrY410() const;
/*
* called after composition.
* returns true if the layer latched a new buffer this frame.
*/
- virtual void onPostComposition(const DisplayDevice*,
- const std::shared_ptr<FenceTime>& /*glDoneFence*/,
- const std::shared_ptr<FenceTime>& /*presentFence*/,
- const CompositorTiming&) {}
+ void onPostComposition(const DisplayDevice*, const std::shared_ptr<FenceTime>& /*glDoneFence*/,
+ const std::shared_ptr<FenceTime>& /*presentFence*/,
+ const CompositorTiming&);
// If a buffer was replaced this frame, release the former buffer
- virtual void releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) { }
+ void releasePendingBuffer(nsecs_t /*dequeueReadyTime*/);
/*
* latchBuffer - called each time the screen is redrawn and returns whether
@@ -485,54 +478,55 @@
* operation, so this should be set only if needed). Typically this is used
* to figure out if the content or size of a surface has changed.
*/
- virtual bool latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/) {
- return false;
- }
+ bool latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/);
- virtual void latchAndReleaseBuffer() {}
+ /*
+ * Calls latchBuffer if the buffer has a frame queued and then releases the buffer.
+ * This is used if the buffer is just latched and releases to free up the buffer
+ * and will not be shown on screen.
+ * Should only be called on the main thread.
+ */
+ void latchAndReleaseBuffer();
/*
* returns the rectangle that crops the content of the layer and scales it
* to the layer's size.
*/
- virtual Rect getBufferCrop() const { return Rect(); }
+ Rect getBufferCrop() const;
/*
* Returns the transform applied to the buffer.
*/
- virtual uint32_t getBufferTransform() const { return 0; }
+ uint32_t getBufferTransform() const;
- virtual sp<GraphicBuffer> getBuffer() const { return nullptr; }
- virtual const std::shared_ptr<renderengine::ExternalTexture>& getExternalTexture() const {
- return mDrawingState.buffer;
- };
+ sp<GraphicBuffer> getBuffer() const;
+ const std::shared_ptr<renderengine::ExternalTexture>& getExternalTexture() const;
- virtual ui::Transform::RotationFlags getTransformHint() const { return ui::Transform::ROT_0; }
+ ui::Transform::RotationFlags getTransformHint() const { return mTransformHint; }
/*
* Returns if a frame is ready
*/
- virtual bool hasReadyFrame() const { return false; }
+ bool hasReadyFrame() const;
virtual int32_t getQueuedFrameCount() const { return 0; }
/**
* Returns active buffer size in the correct orientation. Buffer size is determined by undoing
- * any buffer transformations. If the layer has no buffer then return INVALID_RECT.
+ * any buffer transformations. Returns Rect::INVALID_RECT if the layer has no buffer or the
+ * layer does not have a display frame and its parent is not bounded.
*/
- virtual Rect getBufferSize(const Layer::State&) const { return Rect::INVALID_RECT; }
+ Rect getBufferSize(const Layer::State&) const;
/**
* Returns the source bounds. If the bounds are not defined, it is inferred from the
* buffer size. Failing that, the bounds are determined from the passed in parent bounds.
* For the root layer, this is the display viewport size.
*/
- virtual FloatRect computeSourceBounds(const FloatRect& parentBounds) const {
- return parentBounds;
- }
+ FloatRect computeSourceBounds(const FloatRect& parentBounds) const;
virtual FrameRate getFrameRateForLayerTree() const;
- virtual bool getTransformToDisplayInverse() const { return false; }
+ bool getTransformToDisplayInverse() const;
// Returns how rounded corners should be drawn for this layer.
// A layer can override its parent's rounded corner settings if the parent's rounded
@@ -541,26 +535,51 @@
bool hasRoundedCorners() const override { return getRoundedCornerState().hasRoundedCorners(); }
- virtual PixelFormat getPixelFormat() const { return PIXEL_FORMAT_NONE; }
+ PixelFormat getPixelFormat() const;
/**
- * Return whether this layer needs an input info. For most layer types
- * this is only true if they explicitly set an input-info but BufferLayer
- * overrides this so we can generate input-info for Buffered layers that don't
- * have them (for input occlusion detection checks).
+ * Return whether this layer needs an input info. We generate InputWindowHandles for all
+ * non-cursor buffered layers regardless of whether they have an InputChannel. This is to enable
+ * the InputDispatcher to do PID based occlusion detection.
*/
- virtual bool needsInputInfo() const { return hasInputInfo(); }
+ bool needsInputInfo() const {
+ return (hasInputInfo() || hasBufferOrSidebandStream()) && !mPotentialCursor;
+ }
// Implements RefBase.
void onFirstRef() override;
+ struct BufferInfo {
+ nsecs_t mDesiredPresentTime;
+ std::shared_ptr<FenceTime> mFenceTime;
+ sp<Fence> mFence;
+ uint32_t mTransform{0};
+ ui::Dataspace mDataspace{ui::Dataspace::UNKNOWN};
+ Rect mCrop;
+ uint32_t mScaleMode{NATIVE_WINDOW_SCALING_MODE_FREEZE};
+ Region mSurfaceDamage;
+ HdrMetadata mHdrMetadata;
+ int mApi;
+ PixelFormat mPixelFormat{PIXEL_FORMAT_NONE};
+ bool mTransformToDisplayInverse{false};
+
+ std::shared_ptr<renderengine::ExternalTexture> mBuffer;
+ uint64_t mFrameNumber;
+ int mBufferSlot{BufferQueue::INVALID_BUFFER_SLOT};
+
+ bool mFrameLatencyNeeded{false};
+ };
+
+ BufferInfo mBufferInfo;
+
// implements compositionengine::LayerFE
- const compositionengine::LayerFECompositionState* getCompositionState() const override;
- bool onPreComposition(nsecs_t) override;
+ const compositionengine::LayerFECompositionState* getCompositionState() const;
+ bool fenceHasSignaled() const;
+ bool onPreComposition(nsecs_t);
void prepareCompositionState(compositionengine::LayerFE::StateSubset subset) override;
std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition(
compositionengine::LayerFE::ClientCompositionTargetSettings&) const override;
- void onLayerDisplayed(ftl::SharedFuture<FenceResult>) override;
+ void onLayerDisplayed(ftl::SharedFuture<FenceResult>);
void setWasClientComposed(const sp<Fence>& fence) override {
mLastClientCompositionFence = fence;
@@ -838,13 +857,17 @@
float getBorderWidth();
const half4& getBorderColor();
- virtual bool setBufferCrop(const Rect& /* bufferCrop */) { return false; }
- virtual bool setDestinationFrame(const Rect& /* destinationFrame */) { return false; }
- virtual std::atomic<int32_t>* getPendingBufferCounter() { return nullptr; }
- virtual std::string getPendingBufferCounterName() { return ""; }
- virtual bool updateGeometry() { return false; }
+ bool setBufferCrop(const Rect& /* bufferCrop */);
+ bool setDestinationFrame(const Rect& /* destinationFrame */);
+ // See mPendingBufferTransactions
+ void decrementPendingBufferCount();
+ std::atomic<int32_t>* getPendingBufferCounter() { return &mPendingBufferTransactions; }
+ std::string getPendingBufferCounterName() { return mBlastTransactionName; }
+ bool updateGeometry();
- virtual bool simpleBufferUpdate(const layer_state_t&) const { return false; }
+ bool simpleBufferUpdate(const layer_state_t&) const;
+
+ static bool isOpaqueFormat(PixelFormat format);
protected:
friend class impl::SurfaceInterceptor;
@@ -858,9 +881,12 @@
friend class TransactionSurfaceFrameTest;
virtual void setInitialValuesForClone(const sp<Layer>& clonedFrom);
- virtual void preparePerFrameCompositionState();
+ void preparePerFrameCompositionState();
+ void preparePerFrameBufferCompositionState();
+ void preparePerFrameEffectsCompositionState();
virtual void commitTransaction(State& stateToCommit);
- virtual void onSurfaceFrameCreated(const std::shared_ptr<frametimeline::SurfaceFrame>&) {}
+ void gatherBufferInfo();
+ void onSurfaceFrameCreated(const std::shared_ptr<frametimeline::SurfaceFrame>&);
sp<compositionengine::LayerFE> asLayerFE() const;
sp<Layer> getClonedFrom() { return mClonedFrom != nullptr ? mClonedFrom.promote() : nullptr; }
@@ -913,7 +939,7 @@
* "replaceTouchableRegionWithCrop" is specified. In this case, the layer will receive input
* in this layer's space, regardless of the specified crop layer.
*/
- virtual Rect getInputBounds() const;
+ Rect getInputBounds() const;
// constant
sp<SurfaceFlinger> mFlinger;
@@ -984,7 +1010,14 @@
sp<Fence> mLastClientCompositionFence;
bool mClearClientCompositionFenceOnLayerDisplayed = false;
private:
- virtual void setTransformHint(ui::Transform::RotationFlags) {}
+ friend class SlotGenerationTest;
+ friend class TransactionFrameTracerTest;
+ friend class TransactionSurfaceFrameTest;
+
+ bool getAutoRefresh() const { return mDrawingState.autoRefresh; }
+ bool getSidebandStreamChanged() const { return mSidebandStreamChanged; }
+
+ std::atomic<bool> mSidebandStreamChanged{false};
// Returns true if the layer can draw shadows on its border.
virtual bool canDrawShadows() const { return true; }
@@ -1029,6 +1062,52 @@
// Fills in the frame and transform info for the gui::WindowInfo.
void fillInputFrameInfo(gui::WindowInfo&, const ui::Transform& screenToDisplay);
+ // Computes the transform matrix using the setFilteringEnabled to determine whether the
+ // transform matrix should be computed for use with bilinear filtering.
+ void getDrawingTransformMatrix(bool filteringEnabled, float outMatrix[16]) const;
+
+ inline void tracePendingBufferCount(int32_t pendingBuffers);
+
+ // Latch sideband stream and returns true if the dirty region should be updated.
+ bool latchSidebandStream(bool& recomputeVisibleRegions);
+
+ bool hasFrameUpdate() const;
+
+ void updateTexImage(nsecs_t latchTime);
+
+ // Crop that applies to the buffer
+ Rect computeBufferCrop(const State& s);
+
+ bool willPresentCurrentTransaction() const;
+
+ // Returns true if the transformed buffer size does not match the layer size and we need
+ // to apply filtering.
+ bool bufferNeedsFiltering() const;
+
+ void callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener,
+ const sp<GraphicBuffer>& buffer, uint64_t framenumber,
+ const sp<Fence>& releaseFence,
+ uint32_t currentMaxAcquiredBufferCount);
+
+ std::optional<compositionengine::LayerFE::LayerSettings> prepareClientCompositionInternal(
+ compositionengine::LayerFE::ClientCompositionTargetSettings&) const;
+ // Returns true if there is a valid color to fill.
+ bool fillsColor() const;
+ // Returns true if this layer has a blur value.
+ bool hasBlur() const;
+ bool hasEffect() const { return fillsColor() || drawShadows() || hasBlur(); }
+ bool hasBufferOrSidebandStream() const {
+ return ((mSidebandStream != nullptr) || (mBufferInfo.mBuffer != nullptr));
+ }
+
+ bool hasSomethingToDraw() const { return hasEffect() || hasBufferOrSidebandStream(); }
+ void prepareBufferStateClientComposition(
+ compositionengine::LayerFE::LayerSettings&,
+ compositionengine::LayerFE::ClientCompositionTargetSettings&) const;
+ void prepareEffectsClientComposition(
+ compositionengine::LayerFE::LayerSettings&,
+ compositionengine::LayerFE::ClientCompositionTargetSettings&) const;
+
// Cached properties computed from drawing state
// Effective transform taking into account parent transforms and any parent scaling, which is
// a transform from the current layer coordinate space to display(screen) coordinate space.
@@ -1078,6 +1157,49 @@
bool mBorderEnabled = false;
float mBorderWidth;
half4 mBorderColor;
+
+ void setTransformHint(ui::Transform::RotationFlags);
+
+ const uint32_t mTextureName;
+
+ // Transform hint provided to the producer. This must be accessed holding
+ // the mStateLock.
+ ui::Transform::RotationFlags mTransformHint = ui::Transform::ROT_0;
+
+ std::unique_ptr<compositionengine::LayerFECompositionState> mCompositionState;
+
+ ReleaseCallbackId mPreviousReleaseCallbackId = ReleaseCallbackId::INVALID_ID;
+ uint64_t mPreviousReleasedFrameNumber = 0;
+
+ uint64_t mPreviousBarrierFrameNumber = 0;
+
+ bool mReleasePreviousBuffer = false;
+
+ // Stores the last set acquire fence signal time used to populate the callback handle's acquire
+ // time.
+ std::variant<nsecs_t, sp<Fence>> mCallbackHandleAcquireTimeOrFence = -1;
+
+ std::deque<std::shared_ptr<android::frametimeline::SurfaceFrame>> mPendingJankClassifications;
+ // An upper bound on the number of SurfaceFrames in the pending classifications deque.
+ static constexpr int kPendingClassificationMaxSurfaceFrames = 25;
+
+ const std::string mBlastTransactionName{"BufferTX - " + mName};
+ // This integer is incremented everytime a buffer arrives at the server for this layer,
+ // and decremented when a buffer is dropped or latched. When changed the integer is exported
+ // to systrace with ATRACE_INT and mBlastTransactionName. This way when debugging perf it is
+ // possible to see when a buffer arrived at the server, and in which frame it latched.
+ //
+ // You can understand the trace this way:
+ // - If the integer increases, a buffer arrived at the server.
+ // - If the integer decreases in latchBuffer, that buffer was latched
+ // - If the integer decreases in setBuffer or doTransaction, a buffer was dropped
+ std::atomic<int32_t> mPendingBufferTransactions{0};
+
+ // Contains requested position and matrix updates. This will be applied if the client does
+ // not specify a destination frame.
+ ui::Transform mRequestedTransform;
+
+ sp<HwcSlotGenerator> mHwcSlotGenerator;
};
std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate);
diff --git a/services/surfaceflinger/OWNERS b/services/surfaceflinger/OWNERS
index 2ece51c..6011d0d 100644
--- a/services/surfaceflinger/OWNERS
+++ b/services/surfaceflinger/OWNERS
@@ -2,6 +2,7 @@
alecmouri@google.com
chaviw@google.com
lpy@google.com
+pdwilliams@google.com
racarr@google.com
scroggo@google.com
-vishnun@google.com
\ No newline at end of file
+vishnun@google.com
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 803eb4f..a48c921 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -42,9 +42,9 @@
DisplayModeIterator modeIt;
float overallScore;
struct {
- float belowThreshold;
- float aboveThreshold;
- } fixedRateLayersScore;
+ float modeBelowThreshold;
+ float modeAboveThreshold;
+ } fixedRateBelowThresholdLayersScore;
};
template <typename Iterator>
@@ -385,7 +385,7 @@
const auto weight = layer.weight;
- for (auto& [modeIt, overallScore, fixedRateScore] : scores) {
+ for (auto& [modeIt, overallScore, fixedRateBelowThresholdLayersScore] : scores) {
const auto& [id, mode] = *modeIt;
const bool isSeamlessSwitch = mode->getGroup() == mActiveModeIt->second->getGroup();
@@ -431,7 +431,7 @@
calculateLayerScoreLocked(layer, mode->getFps(), isSeamlessSwitch);
const float weightedLayerScore = weight * layerScore;
- // Layer with fixed source has a special consideration depends on the
+ // Layer with fixed source has a special consideration which depends on the
// mConfig.frameRateMultipleThreshold. We don't want these layers to score
// refresh rates above the threshold, but we also don't want to favor the lower
// ones by having a greater number of layers scoring them. Instead, we calculate
@@ -451,21 +451,22 @@
return false;
}
}(layer.vote);
- const bool layerAboveThreshold = mConfig.frameRateMultipleThreshold != 0 &&
- mode->getFps() >= Fps::fromValue(mConfig.frameRateMultipleThreshold) &&
+ const bool layerBelowThreshold = mConfig.frameRateMultipleThreshold != 0 &&
layer.desiredRefreshRate <
Fps::fromValue(mConfig.frameRateMultipleThreshold / 2);
- if (fixedSourceLayer) {
- if (layerAboveThreshold) {
+ if (fixedSourceLayer && layerBelowThreshold) {
+ const bool modeAboveThreshold =
+ mode->getFps() >= Fps::fromValue(mConfig.frameRateMultipleThreshold);
+ if (modeAboveThreshold) {
ALOGV("%s gives %s fixed source (above threshold) score of %.4f",
formatLayerInfo(layer, weight).c_str(), to_string(mode->getFps()).c_str(),
layerScore);
- fixedRateScore.aboveThreshold += weightedLayerScore;
+ fixedRateBelowThresholdLayersScore.modeAboveThreshold += weightedLayerScore;
} else {
ALOGV("%s gives %s fixed source (below threshold) score of %.4f",
formatLayerInfo(layer, weight).c_str(), to_string(mode->getFps()).c_str(),
layerScore);
- fixedRateScore.belowThreshold += weightedLayerScore;
+ fixedRateBelowThresholdLayersScore.modeBelowThreshold += weightedLayerScore;
}
} else {
ALOGV("%s gives %s score of %.4f", formatLayerInfo(layer, weight).c_str(),
@@ -476,7 +477,7 @@
}
// We want to find the best refresh rate without the fixed source layers,
- // so we could know whether we should add the aboveThreshold scores or not.
+ // so we could know whether we should add the modeAboveThreshold scores or not.
// If the best refresh rate is already above the threshold, it means that
// some non-fixed source layers already scored it, so we can just add the score
// for all fixed source layers, even the ones that are above the threshold.
@@ -500,10 +501,10 @@
}();
// Now we can add the fixed rate layers score
- for (auto& [modeIt, overallScore, fixedRateScore] : scores) {
- overallScore += fixedRateScore.belowThreshold;
+ for (auto& [modeIt, overallScore, fixedRateBelowThresholdLayersScore] : scores) {
+ overallScore += fixedRateBelowThresholdLayersScore.modeBelowThreshold;
if (maxScoreAboveThreshold) {
- overallScore += fixedRateScore.aboveThreshold;
+ overallScore += fixedRateBelowThresholdLayersScore.modeAboveThreshold;
}
ALOGV("%s adjusted overallScore is %.4f", to_string(modeIt->second->getFps()).c_str(),
overallScore);
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
index 13cd304..e23945d 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
@@ -19,6 +19,7 @@
#define LOG_TAG "VSyncReactor"
//#define LOG_NDEBUG 0
+#include <assert.h>
#include <cutils/properties.h>
#include <log/log.h>
#include <utils/Trace.h>
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/Time.h b/services/surfaceflinger/Scheduler/include/scheduler/Time.h
index f00d456..2ca55d4 100644
--- a/services/surfaceflinger/Scheduler/include/scheduler/Time.h
+++ b/services/surfaceflinger/Scheduler/include/scheduler/Time.h
@@ -41,6 +41,8 @@
static constexpr TimePoint fromNs(nsecs_t);
+ static TimePoint now() { return scheduler::SchedulerClock::now(); };
+
nsecs_t ns() const;
};
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index bdc8406..c4165e7 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1056,7 +1056,7 @@
}
const auto& schedule = mScheduler->getVsyncSchedule();
- outStats->vsyncTime = schedule.vsyncDeadlineAfter(scheduler::SchedulerClock::now()).ns();
+ outStats->vsyncTime = schedule.vsyncDeadlineAfter(TimePoint::now()).ns();
outStats->vsyncPeriod = schedule.period().ns();
return NO_ERROR;
}
@@ -1972,7 +1972,7 @@
: calculateExpectedPresentTime(frameTime);
ATRACE_FORMAT("%s %" PRId64 " vsyncIn %.2fms%s", __func__, vsyncId.value,
- ticks<std::milli, float>(mExpectedPresentTime - scheduler::SchedulerClock::now()),
+ ticks<std::milli, float>(mExpectedPresentTime - TimePoint::now()),
mExpectedPresentTime == expectedVsyncTime ? "" : " (adjusted)");
const Period vsyncPeriod = mScheduler->getVsyncSchedule().period();
@@ -2059,16 +2059,16 @@
activeDisplay->getPowerMode() == hal::PowerMode::ON;
if (mPowerHintSessionEnabled) {
const auto& display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()).get();
- const nsecs_t vsyncPeriod = display->getActiveMode()->getVsyncPeriod();
- mPowerAdvisor->setCommitStart(frameTime.ns());
- mPowerAdvisor->setExpectedPresentTime(mExpectedPresentTime.ns());
+ const Period vsyncPeriod = Period::fromNs(display->getActiveMode()->getVsyncPeriod());
+ mPowerAdvisor->setCommitStart(frameTime);
+ mPowerAdvisor->setExpectedPresentTime(mExpectedPresentTime);
// Frame delay is how long we should have minus how long we actually have.
const Duration idealSfWorkDuration = mVsyncModulator->getVsyncConfig().sfWorkDuration;
const Duration frameDelay = idealSfWorkDuration - (mExpectedPresentTime - frameTime);
- mPowerAdvisor->setFrameDelay(frameDelay.ns());
- mPowerAdvisor->setTotalFrameTargetWorkDuration(idealSfWorkDuration.ns());
+ mPowerAdvisor->setFrameDelay(frameDelay);
+ mPowerAdvisor->setTotalFrameTargetWorkDuration(idealSfWorkDuration);
mPowerAdvisor->setTargetWorkDuration(vsyncPeriod);
// Send early hint here to make sure there's not another frame pending
@@ -2228,8 +2228,9 @@
// Send a power hint hint after presentation is finished
if (mPowerHintSessionEnabled) {
- mPowerAdvisor->setSfPresentTiming(mPreviousPresentFences[0].fenceTime->getSignalTime(),
- systemTime());
+ mPowerAdvisor->setSfPresentTiming(TimePoint::fromNs(mPreviousPresentFences[0]
+ .fenceTime->getSignalTime()),
+ TimePoint::now());
if (mPowerHintSessionMode.late) {
mPowerAdvisor->sendActualWorkDuration();
}
@@ -2279,7 +2280,7 @@
}
if (mPowerHintSessionEnabled) {
- mPowerAdvisor->setCompositeEnd(systemTime());
+ mPowerAdvisor->setCompositeEnd(TimePoint::now());
}
}
@@ -2376,7 +2377,7 @@
auto presentFenceTime = std::make_shared<FenceTime>(presentFence);
mPreviousPresentFences[0] = {presentFence, presentFenceTime};
- const TimePoint presentTime = scheduler::SchedulerClock::now();
+ const TimePoint presentTime = TimePoint::now();
// Set presentation information before calling Layer::releasePendingBuffer, such that jank
// information from previous' frame classification is already available when sending jank info
@@ -2793,7 +2794,8 @@
ALOGV("Display Orientation: %s", toCString(creationArgs.physicalOrientation));
// virtual displays are always considered enabled
- creationArgs.initialPowerMode = state.isVirtual() ? hal::PowerMode::ON : hal::PowerMode::OFF;
+ creationArgs.initialPowerMode =
+ state.isVirtual() ? std::make_optional(hal::PowerMode::ON) : std::nullopt;
sp<DisplayDevice> display = getFactory().createDisplayDevice(creationArgs);
@@ -4574,7 +4576,11 @@
switch (args.flags & ISurfaceComposerClient::eFXSurfaceMask) {
case ISurfaceComposerClient::eFXSurfaceBufferQueue:
- case ISurfaceComposerClient::eFXSurfaceBufferState: {
+ case ISurfaceComposerClient::eFXSurfaceContainer:
+ case ISurfaceComposerClient::eFXSurfaceBufferState:
+ args.flags |= ISurfaceComposerClient::eNoColorFill;
+ FMT_FALLTHROUGH;
+ case ISurfaceComposerClient::eFXSurfaceEffect: {
result = createBufferStateLayer(args, outHandle, &layer);
std::atomic<int32_t>* pendingBufferCounter = layer->getPendingBufferCounter();
if (pendingBufferCounter) {
@@ -4583,12 +4589,6 @@
pendingBufferCounter);
}
} break;
- case ISurfaceComposerClient::eFXSurfaceContainer:
- args.flags |= ISurfaceComposerClient::eNoColorFill;
- FMT_FALLTHROUGH;
- case ISurfaceComposerClient::eFXSurfaceEffect:
- result = createEffectLayer(args, outHandle, &layer);
- break;
default:
result = BAD_VALUE;
break;
@@ -4712,8 +4712,8 @@
const auto displayId = display->getPhysicalId();
ALOGD("Setting power mode %d on display %s", mode, to_string(displayId).c_str());
- const hal::PowerMode currentMode = display->getPowerMode();
- if (mode == currentMode) {
+ std::optional<hal::PowerMode> currentMode = display->getPowerMode();
+ if (currentMode.has_value() && mode == *currentMode) {
return;
}
@@ -4729,7 +4729,7 @@
mInterceptor->savePowerModeUpdate(display->getSequenceId(), static_cast<int32_t>(mode));
}
const auto refreshRate = display->refreshRateConfigs().getActiveMode()->getFps();
- if (currentMode == hal::PowerMode::OFF) {
+ if (*currentMode == hal::PowerMode::OFF) {
// Turn on the display
if (display->isInternal() && (!activeDisplay || !activeDisplay->isPoweredOn())) {
onActiveDisplayChangedLocked(display);
@@ -4759,7 +4759,7 @@
if (SurfaceFlinger::setSchedAttr(false) != NO_ERROR) {
ALOGW("Couldn't set uclamp.min on display off: %s\n", strerror(errno));
}
- if (isDisplayActiveLocked(display) && currentMode != hal::PowerMode::DOZE_SUSPEND) {
+ if (isDisplayActiveLocked(display) && *currentMode != hal::PowerMode::DOZE_SUSPEND) {
mScheduler->disableHardwareVsync(true);
mScheduler->onScreenReleased(mAppConnectionHandle);
}
@@ -4773,7 +4773,7 @@
} else if (mode == hal::PowerMode::DOZE || mode == hal::PowerMode::ON) {
// Update display while dozing
getHwComposer().setPowerMode(displayId, mode);
- if (isDisplayActiveLocked(display) && currentMode == hal::PowerMode::DOZE_SUSPEND) {
+ if (isDisplayActiveLocked(display) && *currentMode == hal::PowerMode::DOZE_SUSPEND) {
ALOGI("Force repainting for DOZE_SUSPEND -> DOZE or ON.");
mVisibleRegionsDirty = true;
scheduleRepaint();
@@ -6439,7 +6439,7 @@
std::unique_ptr<RenderArea> renderArea = renderAreaFuture.get();
if (!renderArea) {
ALOGW("Skipping screen capture because of invalid render area.");
- captureResults.result = NO_MEMORY;
+ captureResults.fenceResult = base::unexpected(NO_MEMORY);
captureListener->onScreenCaptureCompleted(captureResults);
return ftl::yield<FenceResult>(base::unexpected(NO_ERROR)).share();
}
@@ -6456,9 +6456,7 @@
return ftl::Future(std::move(renderFuture))
.then([captureListener, captureResults = std::move(captureResults)](
FenceResult fenceResult) mutable -> FenceResult {
- // TODO(b/232535621): Change ScreenCaptureResults to store a FenceResult.
- captureResults.result = fenceStatus(fenceResult);
- captureResults.fence = std::move(fenceResult).value_or(Fence::NO_FENCE);
+ captureResults.fenceResult = std::move(fenceResult);
captureListener->onScreenCaptureCompleted(captureResults);
return base::unexpected(NO_ERROR);
})
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
index 5c96f35..15a791e 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -34,6 +34,7 @@
#include "SurfaceInterceptor.h"
#include "DisplayHardware/ComposerHal.h"
+#include "FrameTimeline/FrameTimeline.h"
#include "Scheduler/Scheduler.h"
#include "Scheduler/VsyncConfiguration.h"
#include "Scheduler/VsyncController.h"
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index 276431e..13ce65d 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -23,7 +23,10 @@
cc_test {
name: "SurfaceFlinger_test",
- defaults: ["surfaceflinger_defaults"],
+ defaults: [
+ "android.hardware.graphics.common-ndk_shared",
+ "surfaceflinger_defaults",
+ ],
test_suites: ["device-tests"],
srcs: [
"BootDisplayMode_test.cpp",
@@ -64,7 +67,6 @@
"android.hardware.graphics.composer@2.1",
],
shared_libs: [
- "android.hardware.graphics.common-V3-ndk",
"android.hardware.graphics.common@1.2",
"libandroid",
"libbase",
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index 353b813..775de4a 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -55,19 +55,12 @@
#pragma clang diagnostic ignored "-Wconversion"
class CredentialsTest : public ::testing::Test {
protected:
- void SetUp() override {
- // Start the tests as root.
- seteuid(AID_ROOT);
-
- ASSERT_NO_FATAL_FAILURE(initClient());
- }
+ void SetUp() override { ASSERT_NO_FATAL_FAILURE(initClient()); }
void TearDown() override {
mComposerClient->dispose();
mBGSurfaceControl.clear();
mComposerClient.clear();
- // Finish the tests as root.
- seteuid(AID_ROOT);
}
sp<IBinder> mDisplay;
@@ -102,31 +95,6 @@
}
/**
- * Sets UID to imitate Graphic's process.
- */
- void setGraphicsUID() {
- seteuid(AID_ROOT);
- seteuid(AID_GRAPHICS);
- }
-
- /**
- * Sets UID to imitate System's process.
- */
- void setSystemUID() {
- seteuid(AID_ROOT);
- seteuid(AID_SYSTEM);
- }
-
- /**
- * Sets UID to imitate a process that doesn't have any special privileges in
- * our code.
- */
- void setBinUID() {
- seteuid(AID_ROOT);
- seteuid(AID_BIN);
- }
-
- /**
* Template function the check a condition for different types of users: root
* graphics, system, and non-supported user. Root, graphics, and system should
* always equal privilegedValue, and non-supported user should equal unprivilegedValue.
@@ -134,24 +102,34 @@
template <typename T>
void checkWithPrivileges(std::function<T()> condition, T privilegedValue, T unprivilegedValue) {
// Check with root.
- seteuid(AID_ROOT);
- ASSERT_EQ(privilegedValue, condition());
+ {
+ UIDFaker f(AID_SYSTEM);
+ ASSERT_EQ(privilegedValue, condition());
+ }
// Check as a Graphics user.
- setGraphicsUID();
- ASSERT_EQ(privilegedValue, condition());
+ {
+ UIDFaker f(AID_GRAPHICS);
+ ASSERT_EQ(privilegedValue, condition());
+ }
// Check as a system user.
- setSystemUID();
- ASSERT_EQ(privilegedValue, condition());
+ {
+ UIDFaker f(AID_SYSTEM);
+ ASSERT_EQ(privilegedValue, condition());
+ }
// Check as a non-supported user.
- setBinUID();
- ASSERT_EQ(unprivilegedValue, condition());
+ {
+ UIDFaker f(AID_BIN);
+ ASSERT_EQ(unprivilegedValue, condition());
+ }
// Check as shell since shell has some additional permissions
- seteuid(AID_SHELL);
- ASSERT_EQ(unprivilegedValue, condition());
+ {
+ UIDFaker f(AID_SHELL);
+ ASSERT_EQ(privilegedValue, condition());
+ }
}
};
@@ -160,17 +138,23 @@
ASSERT_NO_FATAL_FAILURE(initClient());
// Graphics can init the client.
- setGraphicsUID();
- ASSERT_NO_FATAL_FAILURE(initClient());
+ {
+ UIDFaker f(AID_GRAPHICS);
+ ASSERT_NO_FATAL_FAILURE(initClient());
+ }
// System can init the client.
- setSystemUID();
- ASSERT_NO_FATAL_FAILURE(initClient());
+ {
+ UIDFaker f(AID_SYSTEM);
+ ASSERT_NO_FATAL_FAILURE(initClient());
+ }
// Anyone else can init the client.
- setBinUID();
- mComposerClient = sp<SurfaceComposerClient>::make();
- ASSERT_NO_FATAL_FAILURE(initClient());
+ {
+ UIDFaker f(AID_BIN);
+ mComposerClient = sp<SurfaceComposerClient>::make();
+ ASSERT_NO_FATAL_FAILURE(initClient());
+ }
}
TEST_F(CredentialsTest, GetBuiltInDisplayAccessTest) {
@@ -184,7 +168,7 @@
TEST_F(CredentialsTest, AllowedGetterMethodsTest) {
// The following methods are tested with a UID that is not root, graphics,
// or system, to show that anyone can access them.
- setBinUID();
+ UIDFaker f(AID_BIN);
const auto display = SurfaceComposerClient::getInternalDisplayToken();
ASSERT_TRUE(display != nullptr);
@@ -253,24 +237,34 @@
};
// Check with root.
- seteuid(AID_ROOT);
- ASSERT_FALSE(condition());
+ {
+ UIDFaker f(AID_ROOT);
+ ASSERT_FALSE(condition());
+ }
// Check as a Graphics user.
- setGraphicsUID();
- ASSERT_TRUE(condition());
+ {
+ UIDFaker f(AID_GRAPHICS);
+ ASSERT_TRUE(condition());
+ }
// Check as a system user.
- setSystemUID();
- ASSERT_TRUE(condition());
+ {
+ UIDFaker f(AID_SYSTEM);
+ ASSERT_TRUE(condition());
+ }
// Check as a non-supported user.
- setBinUID();
- ASSERT_FALSE(condition());
+ {
+ UIDFaker f(AID_BIN);
+ ASSERT_FALSE(condition());
+ }
// Check as shell since shell has some additional permissions
- seteuid(AID_SHELL);
- ASSERT_FALSE(condition());
+ {
+ UIDFaker f(AID_SHELL);
+ ASSERT_FALSE(condition());
+ }
condition = [=]() {
sp<IBinder> testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, false);
@@ -315,21 +309,27 @@
// Historically, only root and shell can access the getLayerDebugInfo which
// is called when we call dumpsys. I don't see a reason why we should change this.
std::vector<LayerDebugInfo> outLayers;
+ binder::Status status = binder::Status::ok();
// Check with root.
- seteuid(AID_ROOT);
- binder::Status status = sf->getLayerDebugInfo(&outLayers);
- ASSERT_EQ(NO_ERROR, statusTFromBinderStatus(status));
+ {
+ UIDFaker f(AID_ROOT);
+ status = sf->getLayerDebugInfo(&outLayers);
+ ASSERT_EQ(NO_ERROR, statusTFromBinderStatus(status));
+ }
// Check as a shell.
- seteuid(AID_SHELL);
- status = sf->getLayerDebugInfo(&outLayers);
- ASSERT_EQ(NO_ERROR, statusTFromBinderStatus(status));
+ {
+ UIDFaker f(AID_SHELL);
+ status = sf->getLayerDebugInfo(&outLayers);
+ ASSERT_EQ(NO_ERROR, statusTFromBinderStatus(status));
+ }
// Check as anyone else.
- seteuid(AID_ROOT);
- seteuid(AID_BIN);
- status = sf->getLayerDebugInfo(&outLayers);
- ASSERT_EQ(PERMISSION_DENIED, statusTFromBinderStatus(status));
+ {
+ UIDFaker f(AID_BIN);
+ status = sf->getLayerDebugInfo(&outLayers);
+ ASSERT_EQ(PERMISSION_DENIED, statusTFromBinderStatus(status));
+ }
}
TEST_F(CredentialsTest, IsWideColorDisplayBasicCorrectness) {
diff --git a/services/surfaceflinger/tests/LayerState_test.cpp b/services/surfaceflinger/tests/LayerState_test.cpp
index fbbf322..2181370 100644
--- a/services/surfaceflinger/tests/LayerState_test.cpp
+++ b/services/surfaceflinger/tests/LayerState_test.cpp
@@ -90,13 +90,12 @@
ASSERT_EQ(args.grayscale, args2.grayscale);
}
-TEST(LayerStateTest, ParcellingScreenCaptureResults) {
+TEST(LayerStateTest, ParcellingScreenCaptureResultsWithFence) {
ScreenCaptureResults results;
results.buffer = sp<GraphicBuffer>::make(100u, 200u, PIXEL_FORMAT_RGBA_8888, 1u, 0u);
- results.fence = sp<Fence>::make(dup(fileno(tmpfile())));
+ results.fenceResult = sp<Fence>::make(dup(fileno(tmpfile())));
results.capturedSecureLayers = true;
results.capturedDataspace = ui::Dataspace::DISPLAY_P3;
- results.result = BAD_VALUE;
Parcel p;
results.writeToParcel(&p);
@@ -110,10 +109,41 @@
ASSERT_EQ(results.buffer->getWidth(), results2.buffer->getWidth());
ASSERT_EQ(results.buffer->getHeight(), results2.buffer->getHeight());
ASSERT_EQ(results.buffer->getPixelFormat(), results2.buffer->getPixelFormat());
- ASSERT_EQ(results.fence->isValid(), results2.fence->isValid());
+ ASSERT_TRUE(results.fenceResult.ok());
+ ASSERT_TRUE(results2.fenceResult.ok());
+ ASSERT_EQ(results.fenceResult.value()->isValid(), results2.fenceResult.value()->isValid());
ASSERT_EQ(results.capturedSecureLayers, results2.capturedSecureLayers);
ASSERT_EQ(results.capturedDataspace, results2.capturedDataspace);
- ASSERT_EQ(results.result, results2.result);
+}
+
+TEST(LayerStateTest, ParcellingScreenCaptureResultsWithNoFenceOrError) {
+ ScreenCaptureResults results;
+
+ Parcel p;
+ results.writeToParcel(&p);
+ p.setDataPosition(0);
+
+ ScreenCaptureResults results2;
+ results2.readFromParcel(&p);
+
+ ASSERT_TRUE(results2.fenceResult.ok());
+ ASSERT_EQ(results2.fenceResult.value(), Fence::NO_FENCE);
+}
+
+TEST(LayerStateTest, ParcellingScreenCaptureResultsWithFenceError) {
+ ScreenCaptureResults results;
+ results.fenceResult = base::unexpected(BAD_VALUE);
+
+ Parcel p;
+ results.writeToParcel(&p);
+ p.setDataPosition(0);
+
+ ScreenCaptureResults results2;
+ results2.readFromParcel(&p);
+
+ ASSERT_FALSE(results.fenceResult.ok());
+ ASSERT_FALSE(results2.fenceResult.ok());
+ ASSERT_EQ(results.fenceResult.error(), results2.fenceResult.error());
}
} // namespace test
diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp
index 704815d..06afdb1 100644
--- a/services/surfaceflinger/tests/fakehwc/Android.bp
+++ b/services/surfaceflinger/tests/fakehwc/Android.bp
@@ -9,7 +9,10 @@
cc_test {
name: "sffakehwc_test",
- defaults: ["surfaceflinger_defaults"],
+ defaults: [
+ "android.hardware.graphics.composer3-ndk_shared",
+ "surfaceflinger_defaults",
+ ],
test_suites: ["device-tests"],
srcs: [
"FakeComposerClient.cpp",
@@ -23,7 +26,6 @@
"android.hardware.graphics.composer@2.2",
"android.hardware.graphics.composer@2.3",
"android.hardware.graphics.composer@2.4",
- "android.hardware.graphics.composer3-V1-ndk",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@3.0",
"android.hardware.graphics.mapper@4.0",
diff --git a/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp b/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp
index 69d30c4..513f779 100644
--- a/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp
+++ b/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp
@@ -50,10 +50,8 @@
sp<NiceMock<MockIPower>> mMockHal = nullptr;
sp<NiceMock<MockIPowerHintSession>> mMockSession = nullptr;
void verifyAndClearExpectations();
- void sendActualWorkDurationGroup(std::vector<WorkDuration> durations,
- std::chrono::nanoseconds sleepBeforeLastSend);
- std::chrono::nanoseconds mAllowedDeviation;
- std::chrono::nanoseconds mStaleTimeout;
+ void sendActualWorkDurationGroup(std::vector<WorkDuration> durations);
+ static constexpr std::chrono::duration kStaleTimeout = 100ms;
};
void AidlPowerHalWrapperTest::SetUp() {
@@ -61,9 +59,6 @@
mMockSession = sp<NiceMock<MockIPowerHintSession>>::make();
ON_CALL(*mMockHal.get(), getHintSessionPreferredRate(_)).WillByDefault(Return(Status::ok()));
mWrapper = std::make_unique<AidlPowerHalWrapper>(mMockHal);
- mWrapper->setAllowedActualDeviation(std::chrono::nanoseconds{10ms}.count());
- mAllowedDeviation = std::chrono::nanoseconds{mWrapper->mAllowedActualDeviation};
- mStaleTimeout = AidlPowerHalWrapper::kStaleTimeout;
}
void AidlPowerHalWrapperTest::verifyAndClearExpectations() {
@@ -71,14 +66,11 @@
Mock::VerifyAndClearExpectations(mMockSession.get());
}
-void AidlPowerHalWrapperTest::sendActualWorkDurationGroup(
- std::vector<WorkDuration> durations, std::chrono::nanoseconds sleepBeforeLastSend) {
+void AidlPowerHalWrapperTest::sendActualWorkDurationGroup(std::vector<WorkDuration> durations) {
for (size_t i = 0; i < durations.size(); i++) {
- if (i == durations.size() - 1) {
- std::this_thread::sleep_for(sleepBeforeLastSend);
- }
auto duration = durations[i];
- mWrapper->sendActualWorkDuration(duration.durationNanos, duration.timeStampNanos);
+ mWrapper->sendActualWorkDuration(Duration::fromNs(duration.durationNanos),
+ TimePoint::fromNs(duration.timeStampNanos));
}
}
@@ -164,13 +156,13 @@
for (const auto& test : testCases) {
// reset to 100ms baseline
- mWrapper->setTargetWorkDuration(1);
- mWrapper->setTargetWorkDuration(base.count());
+ mWrapper->setTargetWorkDuration(1ns);
+ mWrapper->setTargetWorkDuration(base);
- auto target = test.first;
+ std::chrono::nanoseconds target = test.first;
EXPECT_CALL(*mMockSession.get(), updateTargetWorkDuration(target.count()))
.Times(test.second ? 1 : 0);
- mWrapper->setTargetWorkDuration(target.count());
+ mWrapper->setTargetWorkDuration(target);
verifyAndClearExpectations();
}
}
@@ -187,7 +179,7 @@
EXPECT_CALL(*mMockSession.get(), updateTargetWorkDuration(1))
.WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_ILLEGAL_STATE)));
- mWrapper->setTargetWorkDuration(1);
+ mWrapper->setTargetWorkDuration(1ns);
EXPECT_TRUE(mWrapper->shouldReconnectHAL());
}
@@ -206,58 +198,24 @@
// 100ms
const std::vector<std::pair<std::vector<std::pair<std::chrono::nanoseconds, nsecs_t>>, bool>>
testCases = {{{{-1ms, 100}}, false},
- {{{100ms - (mAllowedDeviation / 2), 100}}, false},
- {{{100ms + (mAllowedDeviation / 2), 100}}, false},
- {{{100ms + (mAllowedDeviation + 1ms), 100}}, true},
- {{{100ms - (mAllowedDeviation + 1ms), 100}}, true},
+ {{{50ms, 100}}, true},
{{{100ms, 100}, {200ms, 200}}, true},
{{{100ms, 500}, {100ms, 600}, {3ms, 600}}, true}};
for (const auto& test : testCases) {
// reset actual duration
- sendActualWorkDurationGroup({base}, mStaleTimeout);
+ sendActualWorkDurationGroup({base});
auto raw = test.first;
std::vector<WorkDuration> durations(raw.size());
std::transform(raw.begin(), raw.end(), durations.begin(),
[](auto d) { return toWorkDuration(d); });
- EXPECT_CALL(*mMockSession.get(), reportActualWorkDuration(durations))
- .Times(test.second ? 1 : 0);
- sendActualWorkDurationGroup(durations, 0ms);
- verifyAndClearExpectations();
- }
-}
-
-TEST_F(AidlPowerHalWrapperTest, sendActualWorkDuration_exceedsStaleTime) {
- ASSERT_TRUE(mWrapper->supportsPowerHintSession());
-
- std::vector<int32_t> threadIds = {1, 2};
- mWrapper->setPowerHintSessionThreadIds(threadIds);
- EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
- .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
- ASSERT_TRUE(mWrapper->startPowerHintSession());
- verifyAndClearExpectations();
-
- auto base = toWorkDuration(100ms, 0);
- // test cases with actual work durations and whether it should update hint against baseline
- // 100ms
- const std::vector<std::tuple<std::vector<std::pair<std::chrono::nanoseconds, nsecs_t>>,
- std::chrono::nanoseconds, bool>>
- testCases = {{{{100ms, 100}}, mStaleTimeout, true},
- {{{100ms + (mAllowedDeviation / 2), 100}}, mStaleTimeout, true},
- {{{100ms, 100}}, mStaleTimeout / 2, false}};
-
- for (const auto& test : testCases) {
- // reset actual duration
- sendActualWorkDurationGroup({base}, mStaleTimeout);
-
- auto raw = std::get<0>(test);
- std::vector<WorkDuration> durations(raw.size());
- std::transform(raw.begin(), raw.end(), durations.begin(),
- [](auto d) { return toWorkDuration(d); });
- EXPECT_CALL(*mMockSession.get(), reportActualWorkDuration(durations))
- .Times(std::get<2>(test) ? 1 : 0);
- sendActualWorkDurationGroup(durations, std::get<1>(test));
+ for (auto& duration : durations) {
+ EXPECT_CALL(*mMockSession.get(),
+ reportActualWorkDuration(std::vector<WorkDuration>{duration}))
+ .Times(test.second ? 1 : 0);
+ }
+ sendActualWorkDurationGroup(durations);
verifyAndClearExpectations();
}
}
@@ -275,7 +233,7 @@
duration.durationNanos = 1;
EXPECT_CALL(*mMockSession.get(), reportActualWorkDuration(_))
.WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_ILLEGAL_STATE)));
- sendActualWorkDurationGroup({duration}, 0ms);
+ sendActualWorkDurationGroup({duration});
EXPECT_TRUE(mWrapper->shouldReconnectHAL());
}
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 004f31c..dec14d0 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -135,15 +135,17 @@
cc_defaults {
name: "libsurfaceflinger_mocks_defaults",
+ defaults: [
+ "android.hardware.graphics.common-ndk_static",
+ "android.hardware.graphics.composer3-ndk_static",
+ ],
static_libs: [
"android.hardware.common-V2-ndk",
"android.hardware.common.fmq-V1-ndk",
- "android.hardware.graphics.common-V3-ndk",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
"android.hardware.graphics.composer@2.3",
"android.hardware.graphics.composer@2.4",
- "android.hardware.graphics.composer3-V1-ndk",
"android.hardware.power@1.0",
"android.hardware.power@1.1",
"android.hardware.power@1.2",
diff --git a/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp
index 8711a42..2d66d3c 100644
--- a/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp
@@ -39,15 +39,15 @@
public:
void SetUp() override;
void startPowerHintSession();
- void fakeBasicFrameTiming(nsecs_t startTime, nsecs_t vsyncPeriod);
- void setExpectedTiming(nsecs_t startTime, nsecs_t vsyncPeriod);
- nsecs_t getFenceWaitDelayDuration(bool skipValidate);
+ void fakeBasicFrameTiming(TimePoint startTime, Duration vsyncPeriod);
+ void setExpectedTiming(Duration totalFrameTargetDuration, TimePoint expectedPresentTime);
+ Duration getFenceWaitDelayDuration(bool skipValidate);
protected:
TestableSurfaceFlinger mFlinger;
std::unique_ptr<PowerAdvisor> mPowerAdvisor;
NiceMock<MockAidlPowerHalWrapper>* mMockAidlWrapper;
- nsecs_t kErrorMargin = std::chrono::nanoseconds(1ms).count();
+ Duration kErrorMargin = 1ms;
};
void PowerAdvisorTest::SetUp() FTL_FAKE_GUARD(mPowerAdvisor->mPowerHalMutex) {
@@ -67,21 +67,21 @@
mPowerAdvisor->startPowerHintSession(threadIds);
}
-void PowerAdvisorTest::setExpectedTiming(nsecs_t totalFrameTarget, nsecs_t expectedPresentTime) {
- mPowerAdvisor->setTotalFrameTargetWorkDuration(totalFrameTarget);
+void PowerAdvisorTest::setExpectedTiming(Duration totalFrameTargetDuration,
+ TimePoint expectedPresentTime) {
+ mPowerAdvisor->setTotalFrameTargetWorkDuration(totalFrameTargetDuration);
mPowerAdvisor->setExpectedPresentTime(expectedPresentTime);
}
-void PowerAdvisorTest::fakeBasicFrameTiming(nsecs_t startTime, nsecs_t vsyncPeriod) {
+void PowerAdvisorTest::fakeBasicFrameTiming(TimePoint startTime, Duration vsyncPeriod) {
mPowerAdvisor->setCommitStart(startTime);
- mPowerAdvisor->setFrameDelay(0);
+ mPowerAdvisor->setFrameDelay(0ns);
mPowerAdvisor->setTargetWorkDuration(vsyncPeriod);
}
-nsecs_t PowerAdvisorTest::getFenceWaitDelayDuration(bool skipValidate) {
+Duration PowerAdvisorTest::getFenceWaitDelayDuration(bool skipValidate) {
return (skipValidate ? PowerAdvisor::kFenceWaitStartDelaySkippedValidate
- : PowerAdvisor::kFenceWaitStartDelayValidated)
- .count();
+ : PowerAdvisor::kFenceWaitStartDelayValidated);
}
namespace {
@@ -93,11 +93,11 @@
std::vector<DisplayId> displayIds{PhysicalDisplayId::fromPort(42u)};
// 60hz
- const nsecs_t vsyncPeriod = std::chrono::nanoseconds(1s).count() / 60;
- const nsecs_t presentDuration = std::chrono::nanoseconds(5ms).count();
- const nsecs_t postCompDuration = std::chrono::nanoseconds(1ms).count();
+ const Duration vsyncPeriod{std::chrono::nanoseconds(1s) / 60};
+ const Duration presentDuration = 5ms;
+ const Duration postCompDuration = 1ms;
- nsecs_t startTime = 100;
+ TimePoint startTime{100ns};
// advisor only starts on frame 2 so do an initial no-op frame
fakeBasicFrameTiming(startTime, vsyncPeriod);
@@ -109,14 +109,14 @@
// increment the frame
startTime += vsyncPeriod;
- const nsecs_t expectedDuration = kErrorMargin + presentDuration + postCompDuration;
+ const Duration expectedDuration = kErrorMargin + presentDuration + postCompDuration;
EXPECT_CALL(*mMockAidlWrapper, sendActualWorkDuration(Eq(expectedDuration), _)).Times(1);
fakeBasicFrameTiming(startTime, vsyncPeriod);
setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
mPowerAdvisor->setDisplays(displayIds);
- mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1000000, startTime + 1500000);
- mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2000000, startTime + 2500000);
+ mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1ms, startTime + 1500us);
+ mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2ms, startTime + 2500us);
mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
mPowerAdvisor->sendActualWorkDuration();
}
@@ -128,12 +128,12 @@
std::vector<DisplayId> displayIds{PhysicalDisplayId::fromPort(42u)};
// 60hz
- const nsecs_t vsyncPeriod = std::chrono::nanoseconds(1s).count() / 60;
- const nsecs_t presentDuration = std::chrono::nanoseconds(5ms).count();
- const nsecs_t postCompDuration = std::chrono::nanoseconds(1ms).count();
- const nsecs_t hwcBlockedDuration = std::chrono::nanoseconds(500us).count();
+ const Duration vsyncPeriod{std::chrono::nanoseconds(1s) / 60};
+ const Duration presentDuration = 5ms;
+ const Duration postCompDuration = 1ms;
+ const Duration hwcBlockedDuration = 500us;
- nsecs_t startTime = 100;
+ TimePoint startTime{100ns};
// advisor only starts on frame 2 so do an initial no-op frame
fakeBasicFrameTiming(startTime, vsyncPeriod);
@@ -145,17 +145,17 @@
// increment the frame
startTime += vsyncPeriod;
- const nsecs_t expectedDuration = kErrorMargin + presentDuration +
+ const Duration expectedDuration = kErrorMargin + presentDuration +
getFenceWaitDelayDuration(false) - hwcBlockedDuration + postCompDuration;
EXPECT_CALL(*mMockAidlWrapper, sendActualWorkDuration(Eq(expectedDuration), _)).Times(1);
fakeBasicFrameTiming(startTime, vsyncPeriod);
setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
mPowerAdvisor->setDisplays(displayIds);
- mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1000000, startTime + 1500000);
- mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2000000, startTime + 3000000);
+ mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1ms, startTime + 1500us);
+ mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2ms, startTime + 3ms);
// now report the fence as having fired during the display HWC time
- mPowerAdvisor->setSfPresentTiming(startTime + 2000000 + hwcBlockedDuration,
+ mPowerAdvisor->setSfPresentTiming(startTime + 2ms + hwcBlockedDuration,
startTime + presentDuration);
mPowerAdvisor->sendActualWorkDuration();
}
@@ -168,12 +168,12 @@
GpuVirtualDisplayId(1)};
// 60hz
- const nsecs_t vsyncPeriod = std::chrono::nanoseconds(1s).count() / 60;
+ const Duration vsyncPeriod{std::chrono::nanoseconds(1s) / 60};
// make present duration much later than the hwc display by itself will account for
- const nsecs_t presentDuration = std::chrono::nanoseconds(10ms).count();
- const nsecs_t postCompDuration = std::chrono::nanoseconds(1ms).count();
+ const Duration presentDuration{10ms};
+ const Duration postCompDuration{1ms};
- nsecs_t startTime = 100;
+ TimePoint startTime{100ns};
// advisor only starts on frame 2 so do an initial no-op frame
fakeBasicFrameTiming(startTime, vsyncPeriod);
@@ -185,7 +185,7 @@
// increment the frame
startTime += vsyncPeriod;
- const nsecs_t expectedDuration = kErrorMargin + presentDuration + postCompDuration;
+ const Duration expectedDuration = kErrorMargin + presentDuration + postCompDuration;
EXPECT_CALL(*mMockAidlWrapper, sendActualWorkDuration(Eq(expectedDuration), _)).Times(1);
fakeBasicFrameTiming(startTime, vsyncPeriod);
@@ -193,8 +193,8 @@
mPowerAdvisor->setDisplays(displayIds);
// don't report timing for the gpu displays since they don't use hwc
- mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1000000, startTime + 1500000);
- mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2000000, startTime + 2500000);
+ mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1ms, startTime + 1500us);
+ mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2ms, startTime + 2500us);
mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
mPowerAdvisor->sendActualWorkDuration();
}
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 1484bcd..188fd58 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -564,9 +564,10 @@
TestableRefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId60,
{.frameRateMultipleThreshold = 120});
- std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}};
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}, {.weight = 1.f}};
auto& lr1 = layers[0];
auto& lr2 = layers[1];
+ auto& lr3 = layers[2];
lr1.desiredRefreshRate = 24_Hz;
lr1.vote = LayerVoteType::ExplicitDefault;
@@ -662,6 +663,25 @@
lr2.vote = LayerVoteType::ExplicitExact;
lr2.name = "120Hz ExplicitExact";
EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers));
+
+ lr1.desiredRefreshRate = 10_Hz;
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.name = "30Hz ExplicitExactOrMultiple";
+ lr2.desiredRefreshRate = 120_Hz;
+ lr2.vote = LayerVoteType::Heuristic;
+ lr2.name = "120Hz ExplicitExact";
+ EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers));
+
+ lr1.desiredRefreshRate = 30_Hz;
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.name = "30Hz ExplicitExactOrMultiple";
+ lr2.desiredRefreshRate = 30_Hz;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr2.name = "30Hz ExplicitExactOrMultiple";
+ lr3.vote = LayerVoteType::Heuristic;
+ lr3.desiredRefreshRate = 120_Hz;
+ lr3.name = "120Hz Heuristic";
+ EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers));
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60) {
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 42585b5..6c6c9aa 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -728,6 +728,7 @@
mHwcDisplayId(hwcDisplayId) {
mCreationArgs.connectionType = connectionType;
mCreationArgs.isPrimary = isPrimary;
+ mCreationArgs.initialPowerMode = hal::PowerMode::ON;
}
sp<IBinder> token() const { return mDisplayToken; }
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.h
index 657ced3..c2c3d77 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.h
@@ -17,6 +17,7 @@
#pragma once
#include <gmock/gmock.h>
+#include <scheduler/Time.h>
#include "DisplayHardware/PowerAdvisor.h"
@@ -42,8 +43,8 @@
MOCK_METHOD(void, setPowerHintSessionThreadIds, (const std::vector<int32_t>& threadIds),
(override));
MOCK_METHOD(bool, startPowerHintSession, (), (override));
- MOCK_METHOD(void, setTargetWorkDuration, (nsecs_t targetDuration), (override));
- MOCK_METHOD(void, sendActualWorkDuration, (nsecs_t actualDuration, nsecs_t timestamp),
+ MOCK_METHOD(void, setTargetWorkDuration, (Duration targetDuration), (override));
+ MOCK_METHOD(void, sendActualWorkDuration, (Duration actualDuration, TimePoint timestamp),
(override));
MOCK_METHOD(bool, shouldReconnectHAL, (), (override));
};
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
index aede250..fb1b394 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
@@ -36,7 +36,7 @@
MOCK_METHOD(bool, usePowerHintSession, (), (override));
MOCK_METHOD(bool, supportsPowerHintSession, (), (override));
MOCK_METHOD(bool, isPowerHintSessionRunning, (), (override));
- MOCK_METHOD(void, setTargetWorkDuration, (int64_t targetDuration), (override));
+ MOCK_METHOD(void, setTargetWorkDuration, (Duration targetDuration), (override));
MOCK_METHOD(void, sendActualWorkDuration, (), (override));
MOCK_METHOD(void, sendPredictedWorkDuration, (), (override));
MOCK_METHOD(void, enablePowerHint, (bool enabled), (override));
@@ -44,25 +44,24 @@
MOCK_METHOD(void, setGpuFenceTime,
(DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime), (override));
MOCK_METHOD(void, setHwcValidateTiming,
- (DisplayId displayId, nsecs_t valiateStartTime, nsecs_t validateEndTime),
+ (DisplayId displayId, TimePoint validateStartTime, TimePoint validateEndTime),
(override));
MOCK_METHOD(void, setHwcPresentTiming,
- (DisplayId displayId, nsecs_t presentStartTime, nsecs_t presentEndTime),
+ (DisplayId displayId, TimePoint presentStartTime, TimePoint presentEndTime),
(override));
MOCK_METHOD(void, setSkippedValidate, (DisplayId displayId, bool skipped), (override));
MOCK_METHOD(void, setRequiresClientComposition,
(DisplayId displayId, bool requiresClientComposition), (override));
- MOCK_METHOD(void, setExpectedPresentTime, (nsecs_t expectedPresentTime), (override));
- MOCK_METHOD(void, setSfPresentTiming, (nsecs_t presentFenceTime, nsecs_t presentEndTime),
+ MOCK_METHOD(void, setExpectedPresentTime, (TimePoint expectedPresentTime), (override));
+ MOCK_METHOD(void, setSfPresentTiming, (TimePoint presentFenceTime, TimePoint presentEndTime),
(override));
MOCK_METHOD(void, setHwcPresentDelayedTime,
- (DisplayId displayId,
- std::chrono::steady_clock::time_point earliestFrameStartTime));
- MOCK_METHOD(void, setFrameDelay, (nsecs_t frameDelayDuration), (override));
- MOCK_METHOD(void, setCommitStart, (nsecs_t commitStartTime), (override));
- MOCK_METHOD(void, setCompositeEnd, (nsecs_t compositeEndtime), (override));
+ (DisplayId displayId, TimePoint earliestFrameStartTime));
+ MOCK_METHOD(void, setFrameDelay, (Duration frameDelayDuration), (override));
+ MOCK_METHOD(void, setCommitStart, (TimePoint commitStartTime), (override));
+ MOCK_METHOD(void, setCompositeEnd, (TimePoint compositeEndTime), (override));
MOCK_METHOD(void, setDisplays, (std::vector<DisplayId> & displayIds), (override));
- MOCK_METHOD(void, setTotalFrameTargetWorkDuration, (int64_t targetDuration), (override));
+ MOCK_METHOD(void, setTotalFrameTargetWorkDuration, (Duration targetDuration), (override));
};
} // namespace android::Hwc2::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
index d086d79..48d05cb 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
@@ -18,14 +18,14 @@
#include <gmock/gmock.h>
-#include "Layer.h"
+#include "BufferStateLayer.h"
namespace android::mock {
-class MockLayer : public Layer {
+class MockLayer : public BufferStateLayer {
public:
MockLayer(SurfaceFlinger* flinger, std::string name)
- : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 0, {})) {
+ : BufferStateLayer(LayerCreationArgs(flinger, nullptr, std::move(name), 0, {})) {
EXPECT_CALL(*this, getDefaultFrameRateCompatibility())
.WillOnce(testing::Return(scheduler::LayerInfo::FrameRateCompatibility::Default));
}
diff --git a/services/surfaceflinger/tests/utils/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
index cb7040a..224868c 100644
--- a/services/surfaceflinger/tests/utils/ScreenshotUtils.h
+++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
@@ -18,6 +18,7 @@
#include <gui/AidlStatusUtil.h>
#include <gui/SyncScreenCaptureListener.h>
#include <private/gui/ComposerServiceAIDL.h>
+#include <ui/FenceResult.h>
#include <ui/Rect.h>
#include <utils/String8.h>
#include <functional>
@@ -46,7 +47,7 @@
return err;
}
captureResults = captureListener->waitForResults();
- return captureResults.result;
+ return fenceStatus(captureResults.fenceResult);
}
static void captureScreen(std::unique_ptr<ScreenCapture>* sc) {
@@ -80,7 +81,7 @@
return err;
}
captureResults = captureListener->waitForResults();
- return captureResults.result;
+ return fenceStatus(captureResults.fenceResult);
}
static void captureLayers(std::unique_ptr<ScreenCapture>* sc, LayerCaptureArgs& captureArgs) {
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 1815c46..9c6d19f 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -19,6 +19,8 @@
#include <android/hardware/graphics/common/1.0/types.h>
#include <grallocusage/GrallocUsageConversion.h>
#include <graphicsenv/GraphicsEnv.h>
+#include <hardware/gralloc.h>
+#include <hardware/gralloc1.h>
#include <log/log.h>
#include <sync/sync.h>
#include <system/window.h>
@@ -42,6 +44,26 @@
namespace {
+static uint64_t convertGralloc1ToBufferUsage(uint64_t producerUsage,
+ uint64_t consumerUsage) {
+ static_assert(uint64_t(GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN) ==
+ uint64_t(GRALLOC1_PRODUCER_USAGE_CPU_READ_OFTEN),
+ "expected ConsumerUsage and ProducerUsage CPU_READ_OFTEN "
+ "bits to match");
+ uint64_t merged = producerUsage | consumerUsage;
+ if ((merged & (GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN)) ==
+ GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN) {
+ merged &= ~uint64_t(GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN);
+ merged |= BufferUsage::CPU_READ_OFTEN;
+ }
+ if ((merged & (GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN)) ==
+ GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN) {
+ merged &= ~uint64_t(GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN);
+ merged |= BufferUsage::CPU_WRITE_OFTEN;
+ }
+ return merged;
+}
+
const VkSurfaceTransformFlagsKHR kSupportedTransforms =
VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR |
VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR |
@@ -1337,7 +1359,7 @@
num_images = 1;
}
- int32_t legacy_usage = 0;
+ uint64_t native_usage = 0;
if (dispatch.GetSwapchainGrallocUsage2ANDROID) {
uint64_t consumer_usage, producer_usage;
ATRACE_BEGIN("GetSwapchainGrallocUsage2ANDROID");
@@ -1349,10 +1371,11 @@
ALOGE("vkGetSwapchainGrallocUsage2ANDROID failed: %d", result);
return VK_ERROR_SURFACE_LOST_KHR;
}
- legacy_usage =
- android_convertGralloc1To0Usage(producer_usage, consumer_usage);
+ native_usage =
+ convertGralloc1ToBufferUsage(consumer_usage, producer_usage);
} else if (dispatch.GetSwapchainGrallocUsageANDROID) {
ATRACE_BEGIN("GetSwapchainGrallocUsageANDROID");
+ int32_t legacy_usage = 0;
result = dispatch.GetSwapchainGrallocUsageANDROID(
device, create_info->imageFormat, create_info->imageUsage,
&legacy_usage);
@@ -1361,8 +1384,9 @@
ALOGE("vkGetSwapchainGrallocUsageANDROID failed: %d", result);
return VK_ERROR_SURFACE_LOST_KHR;
}
+ native_usage = static_cast<uint64_t>(legacy_usage);
}
- uint64_t native_usage = static_cast<uint64_t>(legacy_usage);
+ native_usage |= surface.consumer_usage;
bool createProtectedSwapchain = false;
if (create_info->flags & VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR) {