Merge "Remove unsafe cast in Client::createWithSurfaceParent" into rvc-dev
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 8637a31..28fdaa4 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -237,6 +237,7 @@
{ OPT, "events/kmem/rss_stat/enable" },
{ OPT, "events/kmem/ion_heap_grow/enable" },
{ OPT, "events/kmem/ion_heap_shrink/enable" },
+ { OPT, "events/ion/ion_stat/enable" },
} },
};
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 040ddde..9b2f4a8 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -107,6 +107,8 @@
chmod 0666 /sys/kernel/tracing/events/kmem/ion_heap_grow/enable
chmod 0666 /sys/kernel/debug/tracing/events/kmem/ion_heap_shrink/enable
chmod 0666 /sys/kernel/tracing/events/kmem/ion_heap_shrink/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/ion/ion_stat/enable
+ chmod 0666 /sys/kernel/tracing/events/ion/ion_stat/enable
chmod 0666 /sys/kernel/debug/tracing/events/mm_event/mm_event_record/enable
chmod 0666 /sys/kernel/tracing/events/mm_event/mm_event_record/enable
chmod 0666 /sys/kernel/debug/tracing/events/signal/signal_generate/enable
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 1911119..9ba4819 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -169,6 +169,7 @@
#define OTA_METADATA_DIR "/metadata/ota"
#define SNAPSHOTCTL_LOG_DIR "/data/misc/snapshotctl_log"
#define LINKERCONFIG_DIR "/linkerconfig"
+#define PACKAGE_DEX_USE_LIST "/data/system/package-dex-usage.list"
// TODO(narayan): Since this information has to be kept in sync
// with tombstoned, we should just put it in a common header.
@@ -1612,6 +1613,7 @@
if (!PropertiesHelper::IsUserBuild()) {
ds.AddDir(PROFILE_DATA_DIR_CUR, true);
ds.AddDir(PROFILE_DATA_DIR_REF, true);
+ ds.AddZipEntry(ZIP_ROOT_DIR + PACKAGE_DEX_USE_LIST, PACKAGE_DEX_USE_LIST);
}
ds.AddDir(PREREBOOT_DATA_DIR, false);
add_mountinfo();
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index ebca892..ffa8724 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -318,6 +318,16 @@
// Phenotype property name for enabling profiling the boot class path.
static const char* PROFILE_BOOT_CLASS_PATH = "profilebootclasspath";
+static bool IsBootClassPathProfilingEnable() {
+ std::string profile_boot_class_path = GetProperty("dalvik.vm.profilebootclasspath", "");
+ profile_boot_class_path =
+ server_configurable_flags::GetServerConfigurableFlag(
+ RUNTIME_NATIVE_BOOT_NAMESPACE,
+ PROFILE_BOOT_CLASS_PATH,
+ /*default_value=*/ profile_boot_class_path);
+ return profile_boot_class_path == "true";
+}
+
class RunDex2Oat : public ExecVHelper {
public:
RunDex2Oat(int zip_fd,
@@ -450,14 +460,7 @@
ENABLE_JITZYGOTE_IMAGE,
/*default_value=*/ "");
- std::string profile_boot_class_path = GetProperty("dalvik.vm.profilebootclasspath", "");
- profile_boot_class_path =
- server_configurable_flags::GetServerConfigurableFlag(
- RUNTIME_NATIVE_BOOT_NAMESPACE,
- PROFILE_BOOT_CLASS_PATH,
- /*default_value=*/ profile_boot_class_path);
-
- if (use_jitzygote_image == "true" || profile_boot_class_path == "true") {
+ if (use_jitzygote_image == "true" || IsBootClassPathProfilingEnable()) {
boot_image = StringPrintf("--boot-image=%s", kJitZygoteImage);
} else {
boot_image = MapPropertyToArg("dalvik.vm.boot-image", "--boot-image=%s");
@@ -896,7 +899,15 @@
}
RunProfman profman_merge;
- profman_merge.SetupMerge(profiles_fd, reference_profile_fd);
+ const std::vector<unique_fd>& apk_fds = std::vector<unique_fd>();
+ const std::vector<std::string>& dex_locations = std::vector<std::string>();
+ profman_merge.SetupMerge(
+ profiles_fd,
+ reference_profile_fd,
+ apk_fds,
+ dex_locations,
+ /* for_snapshot= */ false,
+ IsBootClassPathProfilingEnable());
pid_t pid = fork();
if (pid == 0) {
/* child -- drop privileges before continuing */
@@ -2810,7 +2821,13 @@
}
RunProfman args;
- args.SetupMerge(profiles_fd, snapshot_fd, apk_fds, dex_locations, /*for_snapshot=*/true);
+ // This is specifically a snapshot for an app, so don't use boot image profiles.
+ args.SetupMerge(profiles_fd,
+ snapshot_fd,
+ apk_fds,
+ dex_locations,
+ /* for_snapshot= */ true,
+ /* for_boot_image= */ false);
pid_t pid = fork();
if (pid == 0) {
/* child -- drop privileges before continuing */
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index cbbea12..1f9892a 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -49,14 +49,28 @@
const std::string iface = name.substr(lastDot+1, firstSlash-lastDot-1);
const std::string instance = name.substr(firstSlash+1);
- for (const auto& manifest : {
- vintf::VintfObject::GetDeviceHalManifest(),
- vintf::VintfObject::GetFrameworkHalManifest()
+ struct ManifestWithDescription {
+ std::shared_ptr<const vintf::HalManifest> manifest;
+ const char* description;
+ };
+ for (const ManifestWithDescription& mwd : {
+ ManifestWithDescription{ vintf::VintfObject::GetDeviceHalManifest(), "device" },
+ ManifestWithDescription{ vintf::VintfObject::GetFrameworkHalManifest(), "framework" },
}) {
- if (manifest != nullptr && manifest->hasAidlInstance(package, iface, instance)) {
+ if (mwd.manifest == nullptr) {
+ LOG(ERROR) << "NULL VINTF MANIFEST!: " << mwd.description;
+ // note, we explicitly do not retry here, so that we can detect VINTF
+ // or other bugs (b/151696835)
+ continue;
+ }
+ if (mwd.manifest->hasAidlInstance(package, iface, instance)) {
+ LOG(INFO) << "Found " << name << " in " << mwd.description << " VINTF manifest.";
return true;
}
}
+
+ // Although it is tested, explicitly rebuilding qualified name, in case it
+ // becomes something unexpected.
LOG(ERROR) << "Could not find " << package << "." << iface << "/" << instance
<< " in the VINTF manifest.";
return false;
@@ -72,13 +86,20 @@
#endif // !VENDORSERVICEMANAGER
ServiceManager::ServiceManager(std::unique_ptr<Access>&& access) : mAccess(std::move(access)) {
-#ifndef VENDORSERVICEMANAGER
- // can process these at any times, don't want to delay first VINTF client
- std::thread([] {
- vintf::VintfObject::GetDeviceHalManifest();
- vintf::VintfObject::GetFrameworkHalManifest();
- }).detach();
-#endif // !VENDORSERVICEMANAGER
+// TODO(b/151696835): reenable performance hack when we solve bug, since with
+// this hack and other fixes, it is unlikely we will see even an ephemeral
+// failure when the manifest parse fails. The goal is that the manifest will
+// be read incorrectly and cause the process trying to register a HAL to
+// fail. If this is in fact an early boot kernel contention issue, then we
+// will get no failure, and by its absence, be signalled to invest more
+// effort in re-adding this performance hack.
+// #ifndef VENDORSERVICEMANAGER
+// // can process these at any times, don't want to delay first VINTF client
+// std::thread([] {
+// vintf::VintfObject::GetDeviceHalManifest();
+// vintf::VintfObject::GetFrameworkHalManifest();
+// }).detach();
+// #endif // !VENDORSERVICEMANAGER
}
ServiceManager::~ServiceManager() {
// this should only happen in tests
@@ -547,4 +568,4 @@
return Status::ok();
}
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/include/ui/FatVector.h b/include/ui/FatVector.h
new file mode 120000
index 0000000..c2047c0
--- /dev/null
+++ b/include/ui/FatVector.h
@@ -0,0 +1 @@
+../../libs/ui/include/ui/FatVector.h
\ No newline at end of file
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index b0d9521..56591bd 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -19,8 +19,6 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include <cutils/properties.h>
-
#include <gui/BLASTBufferQueue.h>
#include <gui/BufferItemConsumer.h>
#include <gui/GLConsumer.h>
@@ -95,7 +93,8 @@
if (needsDisconnect != nullptr) *needsDisconnect = disconnect;
}
-BLASTBufferQueue::BLASTBufferQueue(const sp<SurfaceControl>& surface, int width, int height)
+BLASTBufferQueue::BLASTBufferQueue(const sp<SurfaceControl>& surface, int width, int height,
+ bool enableTripleBuffering)
: mSurfaceControl(surface),
mWidth(width),
mHeight(height),
@@ -105,8 +104,7 @@
// explicitly so that dequeueBuffer will block
mProducer->setDequeueTimeout(std::numeric_limits<int64_t>::max());
- int8_t disableTripleBuffer = property_get_bool("ro.sf.disable_triple_buffer", 0);
- if (!disableTripleBuffer) {
+ if (enableTripleBuffering) {
mProducer->setMaxDequeuedBufferCount(2);
}
mBufferItemConsumer =
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index a1803d8..8d80833 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -28,7 +28,6 @@
#include <inttypes.h>
-#include <cutils/properties.h>
#include <cutils/atomic.h>
#include <gui/BufferItem.h>
diff --git a/libs/gui/DebugEGLImageTracker.cpp b/libs/gui/DebugEGLImageTracker.cpp
index ab6f364..5762dab 100644
--- a/libs/gui/DebugEGLImageTracker.cpp
+++ b/libs/gui/DebugEGLImageTracker.cpp
@@ -14,13 +14,14 @@
* limitations under the License.
*/
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
-#include <cutils/properties.h>
#include <gui/DebugEGLImageTracker.h>
#include <cinttypes>
#include <unordered_map>
+using android::base::GetBoolProperty;
using android::base::StringAppendF;
std::mutex DebugEGLImageTracker::mInstanceLock;
@@ -57,10 +58,7 @@
DebugEGLImageTracker *DebugEGLImageTracker::getInstance() {
std::lock_guard lock(mInstanceLock);
if (mInstance == nullptr) {
- char value[PROPERTY_VALUE_MAX];
- property_get("debug.sf.enable_egl_image_tracker", value, "0");
- const bool enabled = static_cast<bool>(atoi(value));
-
+ const bool enabled = GetBoolProperty("debug.sf.enable_egl_image_tracker", false);
if (enabled) {
mInstance = new DebugEGLImageTrackerImpl();
} else {
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 6fd53cf..2a27a9a 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -931,8 +931,11 @@
}
virtual status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t defaultConfig, float minRefreshRate,
- float maxRefreshRate) {
+ int32_t defaultConfig,
+ float primaryRefreshRateMin,
+ float primaryRefreshRateMax,
+ float appRequestRefreshRateMin,
+ float appRequestRefreshRateMax) {
Parcel data, reply;
status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
if (result != NO_ERROR) {
@@ -949,14 +952,26 @@
ALOGE("setDesiredDisplayConfigSpecs failed to write defaultConfig: %d", result);
return result;
}
- result = data.writeFloat(minRefreshRate);
+ result = data.writeFloat(primaryRefreshRateMin);
if (result != NO_ERROR) {
- ALOGE("setDesiredDisplayConfigSpecs failed to write minRefreshRate: %d", result);
+ ALOGE("setDesiredDisplayConfigSpecs failed to write primaryRefreshRateMin: %d", result);
return result;
}
- result = data.writeFloat(maxRefreshRate);
+ result = data.writeFloat(primaryRefreshRateMax);
if (result != NO_ERROR) {
- ALOGE("setDesiredDisplayConfigSpecs failed to write maxRefreshRate: %d", result);
+ ALOGE("setDesiredDisplayConfigSpecs failed to write primaryRefreshRateMax: %d", result);
+ return result;
+ }
+ result = data.writeFloat(appRequestRefreshRateMin);
+ if (result != NO_ERROR) {
+ ALOGE("setDesiredDisplayConfigSpecs failed to write appRequestRefreshRateMin: %d",
+ result);
+ return result;
+ }
+ result = data.writeFloat(appRequestRefreshRateMax);
+ if (result != NO_ERROR) {
+ ALOGE("setDesiredDisplayConfigSpecs failed to write appRequestRefreshRateMax: %d",
+ result);
return result;
}
@@ -971,9 +986,14 @@
virtual status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
int32_t* outDefaultConfig,
- float* outMinRefreshRate,
- float* outMaxRefreshRate) {
- if (!outDefaultConfig || !outMinRefreshRate || !outMaxRefreshRate) return BAD_VALUE;
+ float* outPrimaryRefreshRateMin,
+ float* outPrimaryRefreshRateMax,
+ float* outAppRequestRefreshRateMin,
+ float* outAppRequestRefreshRateMax) {
+ if (!outDefaultConfig || !outPrimaryRefreshRateMin || !outPrimaryRefreshRateMax ||
+ !outAppRequestRefreshRateMin || !outAppRequestRefreshRateMax) {
+ return BAD_VALUE;
+ }
Parcel data, reply;
status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
if (result != NO_ERROR) {
@@ -996,14 +1016,26 @@
ALOGE("getDesiredDisplayConfigSpecs failed to read defaultConfig: %d", result);
return result;
}
- result = reply.readFloat(outMinRefreshRate);
+ result = reply.readFloat(outPrimaryRefreshRateMin);
if (result != NO_ERROR) {
- ALOGE("getDesiredDisplayConfigSpecs failed to read minRefreshRate: %d", result);
+ ALOGE("getDesiredDisplayConfigSpecs failed to read primaryRefreshRateMin: %d", result);
return result;
}
- result = reply.readFloat(outMaxRefreshRate);
+ result = reply.readFloat(outPrimaryRefreshRateMax);
if (result != NO_ERROR) {
- ALOGE("getDesiredDisplayConfigSpecs failed to read maxRefreshRate: %d", result);
+ ALOGE("getDesiredDisplayConfigSpecs failed to read primaryRefreshRateMax: %d", result);
+ return result;
+ }
+ result = reply.readFloat(outAppRequestRefreshRateMin);
+ if (result != NO_ERROR) {
+ ALOGE("getDesiredDisplayConfigSpecs failed to read appRequestRefreshRateMin: %d",
+ result);
+ return result;
+ }
+ result = reply.readFloat(outAppRequestRefreshRateMax);
+ if (result != NO_ERROR) {
+ ALOGE("getDesiredDisplayConfigSpecs failed to read appRequestRefreshRateMax: %d",
+ result);
return result;
}
return reply.readInt32();
@@ -1835,20 +1867,38 @@
ALOGE("setDesiredDisplayConfigSpecs: failed to read defaultConfig: %d", result);
return result;
}
- float minRefreshRate;
- result = data.readFloat(&minRefreshRate);
+ float primaryRefreshRateMin;
+ result = data.readFloat(&primaryRefreshRateMin);
if (result != NO_ERROR) {
- ALOGE("setDesiredDisplayConfigSpecs: failed to read minRefreshRate: %d", result);
+ ALOGE("setDesiredDisplayConfigSpecs: failed to read primaryRefreshRateMin: %d",
+ result);
return result;
}
- float maxRefreshRate;
- result = data.readFloat(&maxRefreshRate);
+ float primaryRefreshRateMax;
+ result = data.readFloat(&primaryRefreshRateMax);
if (result != NO_ERROR) {
- ALOGE("setDesiredDisplayConfigSpecs: failed to read maxRefreshRate: %d", result);
+ ALOGE("setDesiredDisplayConfigSpecs: failed to read primaryRefreshRateMax: %d",
+ result);
return result;
}
- result = setDesiredDisplayConfigSpecs(displayToken, defaultConfig, minRefreshRate,
- maxRefreshRate);
+ float appRequestRefreshRateMin;
+ result = data.readFloat(&appRequestRefreshRateMin);
+ if (result != NO_ERROR) {
+ ALOGE("setDesiredDisplayConfigSpecs: failed to read appRequestRefreshRateMin: %d",
+ result);
+ return result;
+ }
+ float appRequestRefreshRateMax;
+ result = data.readFloat(&appRequestRefreshRateMax);
+ if (result != NO_ERROR) {
+ ALOGE("setDesiredDisplayConfigSpecs: failed to read appRequestRefreshRateMax: %d",
+ result);
+ return result;
+ }
+ result =
+ setDesiredDisplayConfigSpecs(displayToken, defaultConfig, primaryRefreshRateMin,
+ primaryRefreshRateMax, appRequestRefreshRateMin,
+ appRequestRefreshRateMax);
if (result != NO_ERROR) {
ALOGE("setDesiredDisplayConfigSpecs: failed to call setDesiredDisplayConfigSpecs: "
"%d",
@@ -1862,11 +1912,16 @@
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> displayToken = data.readStrongBinder();
int32_t defaultConfig;
- float minRefreshRate;
- float maxRefreshRate;
+ float primaryRefreshRateMin;
+ float primaryRefreshRateMax;
+ float appRequestRefreshRateMin;
+ float appRequestRefreshRateMax;
- status_t result = getDesiredDisplayConfigSpecs(displayToken, &defaultConfig,
- &minRefreshRate, &maxRefreshRate);
+ status_t result =
+ getDesiredDisplayConfigSpecs(displayToken, &defaultConfig,
+ &primaryRefreshRateMin, &primaryRefreshRateMax,
+ &appRequestRefreshRateMin,
+ &appRequestRefreshRateMax);
if (result != NO_ERROR) {
ALOGE("getDesiredDisplayConfigSpecs: failed to get getDesiredDisplayConfigSpecs: "
"%d",
@@ -1879,14 +1934,28 @@
ALOGE("getDesiredDisplayConfigSpecs: failed to write defaultConfig: %d", result);
return result;
}
- result = reply->writeFloat(minRefreshRate);
+ result = reply->writeFloat(primaryRefreshRateMin);
if (result != NO_ERROR) {
- ALOGE("getDesiredDisplayConfigSpecs: failed to write minRefreshRate: %d", result);
+ ALOGE("getDesiredDisplayConfigSpecs: failed to write primaryRefreshRateMin: %d",
+ result);
return result;
}
- result = reply->writeFloat(maxRefreshRate);
+ result = reply->writeFloat(primaryRefreshRateMax);
if (result != NO_ERROR) {
- ALOGE("getDesiredDisplayConfigSpecs: failed to write maxRefreshRate: %d", result);
+ ALOGE("getDesiredDisplayConfigSpecs: failed to write primaryRefreshRateMax: %d",
+ result);
+ return result;
+ }
+ result = reply->writeFloat(appRequestRefreshRateMin);
+ if (result != NO_ERROR) {
+ ALOGE("getDesiredDisplayConfigSpecs: failed to write appRequestRefreshRateMin: %d",
+ result);
+ return result;
+ }
+ result = reply->writeFloat(appRequestRefreshRateMax);
+ if (result != NO_ERROR) {
+ ALOGE("getDesiredDisplayConfigSpecs: failed to write appRequestRefreshRateMax: %d",
+ result);
return result;
}
reply->writeInt32(result);
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index d9cbeb7..a52f298 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1698,22 +1698,26 @@
status_t SurfaceComposerClient::setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
int32_t defaultConfig,
- float minRefreshRate,
- float maxRefreshRate) {
- return ComposerService::getComposerService()->setDesiredDisplayConfigSpecs(displayToken,
- defaultConfig,
- minRefreshRate,
- maxRefreshRate);
+ float primaryRefreshRateMin,
+ float primaryRefreshRateMax,
+ float appRequestRefreshRateMin,
+ float appRequestRefreshRateMax) {
+ return ComposerService::getComposerService()
+ ->setDesiredDisplayConfigSpecs(displayToken, defaultConfig, primaryRefreshRateMin,
+ primaryRefreshRateMax, appRequestRefreshRateMin,
+ appRequestRefreshRateMax);
}
status_t SurfaceComposerClient::getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
int32_t* outDefaultConfig,
- float* outMinRefreshRate,
- float* outMaxRefreshRate) {
- return ComposerService::getComposerService()->getDesiredDisplayConfigSpecs(displayToken,
- outDefaultConfig,
- outMinRefreshRate,
- outMaxRefreshRate);
+ float* outPrimaryRefreshRateMin,
+ float* outPrimaryRefreshRateMax,
+ float* outAppRequestRefreshRateMin,
+ float* outAppRequestRefreshRateMax) {
+ return ComposerService::getComposerService()
+ ->getDesiredDisplayConfigSpecs(displayToken, outDefaultConfig, outPrimaryRefreshRateMin,
+ outPrimaryRefreshRateMax, outAppRequestRefreshRateMin,
+ outAppRequestRefreshRateMax);
}
status_t SurfaceComposerClient::getDisplayColorModes(const sp<IBinder>& display,
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index b902615..2320771 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -66,7 +66,9 @@
: public ConsumerBase::FrameAvailableListener, public BufferItemConsumer::BufferFreedListener
{
public:
- BLASTBufferQueue(const sp<SurfaceControl>& surface, int width, int height);
+ BLASTBufferQueue(const sp<SurfaceControl>& surface, int width, int height,
+ bool enableTripleBuffering = true);
+
sp<IGraphicBufferProducer> getIGraphicBufferProducer() const {
return mProducer;
}
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index b4a3fbe..0d33b3f 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -426,19 +426,36 @@
*/
virtual status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) = 0;
- /*
- * Sets the refresh rate boundaries for display configuration.
- * For all other parameters, default configuration is used. The index for the default is
- * corresponding to the configs returned from getDisplayConfigs().
+ /* Sets the refresh rate boundaries for the display.
+ *
+ * The primary refresh rate range represents display manager's general guidance on the display
+ * configs we'll consider when switching refresh rates. Unless we get an explicit signal from an
+ * app, we should stay within this range.
+ *
+ * The app request refresh rate range allows us to consider more display configs when switching
+ * refresh rates. Although we should generally stay within the primary range, specific
+ * considerations, such as layer frame rate settings specified via the setFrameRate() api, may
+ * cause us to go outside the primary range. We never go outside the app request range. The app
+ * request range will be greater than or equal to the primary refresh rate range, never smaller.
+ *
+ * defaultConfig is used to narrow the list of display configs SurfaceFlinger will consider
+ * switching between. Only configs with a config group and resolution matching defaultConfig
+ * will be considered for switching. The defaultConfig index corresponds to the list of configs
+ * returned from getDisplayConfigs().
*/
virtual status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t defaultConfig, float minRefreshRate,
- float maxRefreshRate) = 0;
+ int32_t defaultConfig,
+ float primaryRefreshRateMin,
+ float primaryRefreshRateMax,
+ float appRequestRefreshRateMin,
+ float appRequestRefreshRateMax) = 0;
virtual status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
int32_t* outDefaultConfig,
- float* outMinRefreshRate,
- float* outMaxRefreshRate) = 0;
+ float* outPrimaryRefreshRateMin,
+ float* outPrimaryRefreshRateMax,
+ float* outAppRequestRefreshRateMin,
+ float* outAppRequestRefreshRateMax) = 0;
/*
* Gets whether brightness operations are supported on a display.
*
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 2fb9538..531aed7 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -118,21 +118,19 @@
// Shorthand for getDisplayConfigs element at getActiveConfig index.
static status_t getActiveDisplayConfig(const sp<IBinder>& display, DisplayConfig*);
- // Sets the refresh rate boundaries for display configuration.
- // For all other parameters, default configuration is used. The index for the default is
- // corresponting to the configs returned from getDisplayConfigs().
+ // Sets the refresh rate boundaries for the display.
static status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t defaultConfig, float minRefreshRate,
- float maxRefreshRate);
- // Gets the refresh rate boundaries for display configuration.
- // For all other parameters, default configuration is used. The index for the default is
- // corresponting to the configs returned from getDisplayConfigs().
- // The reason is passed in for telemetry tracking, and it corresponds to the list of all
- // the policy rules that were used.
+ int32_t defaultConfig, float primaryRefreshRateMin,
+ float primaryRefreshRateMax,
+ float appRequestRefreshRateMin,
+ float appRequestRefreshRateMax);
+ // Gets the refresh rate boundaries for the display.
static status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
int32_t* outDefaultConfig,
- float* outMinRefreshRate,
- float* outMaxRefreshRate);
+ float* outPrimaryRefreshRateMin,
+ float* outPrimaryRefreshRateMax,
+ float* outAppRequestRefreshRateMin,
+ float* outAppRequestRefreshRateMax);
// Gets the list of supported color modes for the given display
static status_t getDisplayColorModes(const sp<IBinder>& display,
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 7f960ab..a6bcd10 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -39,6 +39,7 @@
shared_libs: [
"android.hardware.configstore@1.0",
"android.hardware.configstore-utils",
+ "libSurfaceFlingerProp",
"libbase",
"liblog",
"libEGL",
@@ -53,6 +54,8 @@
"libutils",
"libnativewindow"
],
+
+ header_libs: ["libsurfaceflinger_headers"],
}
// Build a separate binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 2de6b69..a1d12a5 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -18,17 +18,17 @@
#include <gtest/gtest.h>
+#include <SurfaceFlingerProperties.h>
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <binder/ProcessState.h>
#include <configstore/Utils.h>
-#include <cutils/properties.h>
-#include <inttypes.h>
#include <gui/BufferItemConsumer.h>
#include <gui/IDisplayEventConnection.h>
#include <gui/IProducerListener.h>
#include <gui/ISurfaceComposer.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
+#include <inttypes.h>
#include <private/gui/ComposerService.h>
#include <ui/Rect.h>
#include <utils/String8.h>
@@ -46,11 +46,9 @@
using Transaction = SurfaceComposerClient::Transaction;
-static bool hasWideColorDisplay =
- getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
+static bool hasWideColorDisplay = android::sysprop::has_wide_color_display(false);
-static bool hasHdrDisplay =
- getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasHDRDisplay>(false);
+static bool hasHdrDisplay = android::sysprop::has_HDR_display(false);
class FakeSurfaceComposer;
class FakeProducerFrameEventHistory;
@@ -836,14 +834,19 @@
return NO_ERROR;
}
status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& /*displayToken*/,
- int32_t /*defaultConfig*/, float /*minRefreshRate*/,
- float /*maxRefreshRate*/) {
+ int32_t /*defaultConfig*/,
+ float /*primaryRefreshRateMin*/,
+ float /*primaryRefreshRateMax*/,
+ float /*appRequestRefreshRateMin*/,
+ float /*appRequestRefreshRateMax*/) {
return NO_ERROR;
}
status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& /*displayToken*/,
int32_t* /*outDefaultConfig*/,
- float* /*outMinRefreshRate*/,
- float* /*outMaxRefreshRate*/) override {
+ float* /*outPrimaryRefreshRateMin*/,
+ float* /*outPrimaryRefreshRateMax*/,
+ float* /*outAppRequestRefreshRateMin*/,
+ float* /*outAppRequestRefreshRateMax*/) override {
return NO_ERROR;
};
status_t notifyPowerHint(int32_t /*hintId*/) override { return NO_ERROR; }
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index ef7cc7d..11af23e 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -468,7 +468,7 @@
msg.body.key.deviceId = deviceId;
msg.body.key.source = source;
msg.body.key.displayId = displayId;
- msg.body.key.hmac = hmac;
+ msg.body.key.hmac = std::move(hmac);
msg.body.key.action = action;
msg.body.key.flags = flags;
msg.body.key.keyCode = keyCode;
@@ -526,7 +526,7 @@
msg.body.motion.deviceId = deviceId;
msg.body.motion.source = source;
msg.body.motion.displayId = displayId;
- msg.body.motion.hmac = hmac;
+ msg.body.motion.hmac = std::move(hmac);
msg.body.motion.action = action;
msg.body.motion.actionButton = actionButton;
msg.body.motion.flags = flags;
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index 55400c7..5baec2f 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -59,7 +59,6 @@
],
shared_libs: [
- "libhardware",
"libcutils",
"liblog",
"libutils",
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index b0b4f6c..92e7e71 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -208,9 +208,20 @@
LOG_ALWAYS_FATAL("failed to initialize EGL");
}
+ const auto eglVersion = eglQueryStringImplementationANDROID(display, EGL_VERSION);
+ if (!eglVersion) {
+ checkGlError(__FUNCTION__, __LINE__);
+ LOG_ALWAYS_FATAL("eglQueryStringImplementationANDROID(EGL_VERSION) failed");
+ }
+
+ const auto eglExtensions = eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS);
+ if (!eglExtensions) {
+ checkGlError(__FUNCTION__, __LINE__);
+ LOG_ALWAYS_FATAL("eglQueryStringImplementationANDROID(EGL_EXTENSIONS) failed");
+ }
+
GLExtensions& extensions = GLExtensions::getInstance();
- extensions.initWithEGLStrings(eglQueryStringImplementationANDROID(display, EGL_VERSION),
- eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS));
+ extensions.initWithEGLStrings(eglVersion, eglExtensions);
// The code assumes that ES2 or later is available if this extension is
// supported.
diff --git a/libs/renderengine/gl/filters/BlurFilter.cpp b/libs/renderengine/gl/filters/BlurFilter.cpp
index db55d17..19f18c0 100644
--- a/libs/renderengine/gl/filters/BlurFilter.cpp
+++ b/libs/renderengine/gl/filters/BlurFilter.cpp
@@ -68,6 +68,8 @@
status_t BlurFilter::setAsDrawTarget(const DisplaySettings& display, uint32_t radius) {
ATRACE_NAME("BlurFilter::setAsDrawTarget");
mRadius = radius;
+ mDisplayX = display.physicalDisplay.left;
+ mDisplayY = display.physicalDisplay.top;
if (mDisplayWidth < display.physicalDisplay.width() ||
mDisplayHeight < display.physicalDisplay.height()) {
@@ -182,8 +184,8 @@
if (mix >= 1 || multiPass) {
mLastDrawTarget->bindAsReadBuffer();
glBlitFramebuffer(0, 0, mLastDrawTarget->getBufferWidth(),
- mLastDrawTarget->getBufferHeight(), 0, 0, mDisplayWidth, mDisplayHeight,
- GL_COLOR_BUFFER_BIT, GL_LINEAR);
+ mLastDrawTarget->getBufferHeight(), mDisplayX, mDisplayY, mDisplayWidth,
+ mDisplayHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR);
return NO_ERROR;
}
diff --git a/libs/renderengine/gl/filters/BlurFilter.h b/libs/renderengine/gl/filters/BlurFilter.h
index 9d3fc60..593a8fd 100644
--- a/libs/renderengine/gl/filters/BlurFilter.h
+++ b/libs/renderengine/gl/filters/BlurFilter.h
@@ -68,6 +68,8 @@
GLFramebuffer mPongFbo;
uint32_t mDisplayWidth = 0;
uint32_t mDisplayHeight = 0;
+ uint32_t mDisplayX = 0;
+ uint32_t mDisplayY = 0;
// Buffer holding the final blur pass.
GLFramebuffer* mLastDrawTarget;
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index bf487c4..82ce757 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -67,19 +67,20 @@
// ----------------------------------------------------------------------------
Region::Region() {
- mStorage.add(Rect(0,0));
+ mStorage.push_back(Rect(0, 0));
}
Region::Region(const Region& rhs)
- : mStorage(rhs.mStorage)
{
+ mStorage.clear();
+ mStorage.insert(mStorage.begin(), rhs.mStorage.begin(), rhs.mStorage.end());
#if defined(VALIDATE_REGIONS)
validate(rhs, "rhs copy-ctor");
#endif
}
Region::Region(const Rect& rhs) {
- mStorage.add(rhs);
+ mStorage.push_back(rhs);
}
Region::~Region()
@@ -100,8 +101,8 @@
* final, correctly ordered region buffer. Each rectangle will be compared with the span directly
* above it, and subdivided to resolve any remaining T-junctions.
*/
-static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end,
- Vector<Rect>& dst, int spanDirection) {
+static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, FatVector<Rect>& dst,
+ int spanDirection) {
dst.clear();
const Rect* current = end - 1;
@@ -109,7 +110,7 @@
// add first span immediately
do {
- dst.add(*current);
+ dst.push_back(*current);
current--;
} while (current->top == lastTop && current >= begin);
@@ -147,12 +148,12 @@
if (prev.right <= left) break;
if (prev.right > left && prev.right < right) {
- dst.add(Rect(prev.right, top, right, bottom));
+ dst.push_back(Rect(prev.right, top, right, bottom));
right = prev.right;
}
if (prev.left > left && prev.left < right) {
- dst.add(Rect(prev.left, top, right, bottom));
+ dst.push_back(Rect(prev.left, top, right, bottom));
right = prev.left;
}
@@ -166,12 +167,12 @@
if (prev.left >= right) break;
if (prev.left > left && prev.left < right) {
- dst.add(Rect(left, top, prev.left, bottom));
+ dst.push_back(Rect(left, top, prev.left, bottom));
left = prev.left;
}
if (prev.right > left && prev.right < right) {
- dst.add(Rect(left, top, prev.right, bottom));
+ dst.push_back(Rect(left, top, prev.right, bottom));
left = prev.right;
}
// if an entry in the previous span is too far left, nothing further right in the
@@ -183,7 +184,7 @@
}
if (left < right) {
- dst.add(Rect(left, top, right, bottom));
+ dst.push_back(Rect(left, top, right, bottom));
}
current--;
@@ -201,13 +202,14 @@
if (r.isEmpty()) return r;
if (r.isRect()) return r;
- Vector<Rect> reversed;
+ FatVector<Rect> reversed;
reverseRectsResolvingJunctions(r.begin(), r.end(), reversed, direction_RTL);
Region outputRegion;
- reverseRectsResolvingJunctions(reversed.begin(), reversed.end(),
- outputRegion.mStorage, direction_LTR);
- outputRegion.mStorage.add(r.getBounds()); // to make region valid, mStorage must end with bounds
+ reverseRectsResolvingJunctions(reversed.data(), reversed.data() + reversed.size(),
+ outputRegion.mStorage, direction_LTR);
+ outputRegion.mStorage.push_back(
+ r.getBounds()); // to make region valid, mStorage must end with bounds
#if defined(VALIDATE_REGIONS)
validate(outputRegion, "T-Junction free region");
@@ -222,7 +224,8 @@
validate(*this, "this->operator=");
validate(rhs, "rhs.operator=");
#endif
- mStorage = rhs.mStorage;
+ mStorage.clear();
+ mStorage.insert(mStorage.begin(), rhs.mStorage.begin(), rhs.mStorage.end());
return *this;
}
@@ -231,7 +234,7 @@
if (mStorage.size() >= 2) {
const Rect bounds(getBounds());
mStorage.clear();
- mStorage.add(bounds);
+ mStorage.push_back(bounds);
}
return *this;
}
@@ -255,25 +258,25 @@
void Region::clear()
{
mStorage.clear();
- mStorage.add(Rect(0,0));
+ mStorage.push_back(Rect(0, 0));
}
void Region::set(const Rect& r)
{
mStorage.clear();
- mStorage.add(r);
+ mStorage.push_back(r);
}
void Region::set(int32_t w, int32_t h)
{
mStorage.clear();
- mStorage.add(Rect(w, h));
+ mStorage.push_back(Rect(w, h));
}
void Region::set(uint32_t w, uint32_t h)
{
mStorage.clear();
- mStorage.add(Rect(w, h));
+ mStorage.push_back(Rect(w, h));
}
bool Region::isTriviallyEqual(const Region& region) const {
@@ -299,13 +302,16 @@
void Region::addRectUnchecked(int l, int t, int r, int b)
{
Rect rect(l,t,r,b);
- size_t where = mStorage.size() - 1;
- mStorage.insertAt(rect, where, 1);
+ mStorage.insert(mStorage.end() - 1, rect);
}
// ----------------------------------------------------------------------------
Region& Region::orSelf(const Rect& r) {
+ if (isEmpty()) {
+ set(r);
+ return *this;
+ }
return operationSelf(r, op_or);
}
Region& Region::xorSelf(const Rect& r) {
@@ -326,6 +332,10 @@
// ----------------------------------------------------------------------------
Region& Region::orSelf(const Region& rhs) {
+ if (isEmpty()) {
+ *this = rhs;
+ return *this;
+ }
return operationSelf(rhs, op_or);
}
Region& Region::xorSelf(const Region& rhs) {
@@ -350,7 +360,7 @@
Region& Region::scaleSelf(float sx, float sy) {
size_t count = mStorage.size();
- Rect* rects = mStorage.editArray();
+ Rect* rects = mStorage.data();
while (count) {
rects->left = static_cast<int32_t>(static_cast<float>(rects->left) * sx + 0.5f);
rects->right = static_cast<int32_t>(static_cast<float>(rects->right) * sx + 0.5f);
@@ -455,10 +465,10 @@
class Region::rasterizer : public region_operator<Rect>::region_rasterizer
{
Rect bounds;
- Vector<Rect>& storage;
+ FatVector<Rect>& storage;
Rect* head;
Rect* tail;
- Vector<Rect> span;
+ FatVector<Rect> span;
Rect* cur;
public:
explicit rasterizer(Region& reg)
@@ -485,8 +495,8 @@
flushSpan();
}
if (storage.size()) {
- bounds.top = storage.itemAt(0).top;
- bounds.bottom = storage.top().bottom;
+ bounds.top = storage.front().top;
+ bounds.bottom = storage.back().bottom;
if (storage.size() == 1) {
storage.clear();
}
@@ -494,7 +504,7 @@
bounds.left = 0;
bounds.right = 0;
}
- storage.add(bounds);
+ storage.push_back(bounds);
}
void Region::rasterizer::operator()(const Rect& rect)
@@ -509,15 +519,15 @@
return;
}
}
- span.add(rect);
- cur = span.editArray() + (span.size() - 1);
+ span.push_back(rect);
+ cur = span.data() + (span.size() - 1);
}
void Region::rasterizer::flushSpan()
{
bool merge = false;
if (tail-head == ssize_t(span.size())) {
- Rect const* p = span.editArray();
+ Rect const* p = span.data();
Rect const* q = head;
if (p->top == q->bottom) {
merge = true;
@@ -532,17 +542,17 @@
}
}
if (merge) {
- const int bottom = span[0].bottom;
+ const int bottom = span.front().bottom;
Rect* r = head;
while (r != tail) {
r->bottom = bottom;
r++;
}
} else {
- bounds.left = min(span.itemAt(0).left, bounds.left);
- bounds.right = max(span.top().right, bounds.right);
- storage.appendVector(span);
- tail = storage.editArray() + storage.size();
+ bounds.left = min(span.front().left, bounds.left);
+ bounds.right = max(span.back().right, bounds.right);
+ storage.insert(storage.end(), span.begin(), span.end());
+ tail = storage.data() + storage.size();
head = tail - span.size();
}
span.clear();
@@ -550,7 +560,7 @@
bool Region::validate(const Region& reg, const char* name, bool silent)
{
- if (reg.mStorage.isEmpty()) {
+ if (reg.mStorage.empty()) {
ALOGE_IF(!silent, "%s: mStorage is empty, which is never valid", name);
// return immediately as the code below assumes mStorage is non-empty
return false;
@@ -689,9 +699,8 @@
}
sk_dst.op(sk_lhs, sk_rhs, sk_op);
- if (sk_dst.isEmpty() && dst.isEmpty())
- return;
-
+ if (sk_dst.empty() && dst.empty()) return;
+
bool same = true;
Region::const_iterator head = dst.begin();
Region::const_iterator const tail = dst.end();
@@ -786,7 +795,7 @@
validate(reg, "translate (before)");
#endif
size_t count = reg.mStorage.size();
- Rect* rects = reg.mStorage.editArray();
+ Rect* rects = reg.mStorage.data();
while (count) {
rects->offsetBy(dx, dy);
rects++;
@@ -866,24 +875,25 @@
ALOGE("Region::unflatten() failed, invalid region");
return BAD_VALUE;
}
- mStorage = result.mStorage;
+ mStorage.clear();
+ mStorage.insert(mStorage.begin(), result.mStorage.begin(), result.mStorage.end());
return NO_ERROR;
}
// ----------------------------------------------------------------------------
Region::const_iterator Region::begin() const {
- return mStorage.array();
+ return mStorage.data();
}
Region::const_iterator Region::end() const {
// Workaround for b/77643177
// mStorage should never be empty, but somehow it is and it's causing
// an abort in ubsan
- if (mStorage.isEmpty()) return mStorage.array();
+ if (mStorage.empty()) return mStorage.data();
size_t numRects = isRect() ? 1 : mStorage.size() - 1;
- return mStorage.array() + numRects;
+ return mStorage.data() + numRects;
}
Rect const* Region::getArray(size_t* count) const {
diff --git a/libs/ui/include/ui/FatVector.h b/libs/ui/include/ui/FatVector.h
new file mode 100644
index 0000000..25fe3a0
--- /dev/null
+++ b/libs/ui/include/ui/FatVector.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_REGION_FAT_VECTOR_H
+#define ANDROID_REGION_FAT_VECTOR_H
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <utils/Log.h>
+#include <type_traits>
+
+#include <vector>
+
+namespace android {
+
+template <typename T, size_t SIZE = 4>
+class InlineStdAllocator {
+public:
+ struct Allocation {
+ private:
+ Allocation(const Allocation&) = delete;
+ void operator=(const Allocation&) = delete;
+
+ public:
+ Allocation() {}
+ // char array instead of T array, so memory is uninitialized, with no destructors run
+ char array[sizeof(T) * SIZE];
+ bool inUse = false;
+ };
+
+ typedef T value_type; // needed to implement std::allocator
+ typedef T* pointer; // needed to implement std::allocator
+
+ explicit InlineStdAllocator(Allocation& allocation) : mAllocation(allocation) {}
+ InlineStdAllocator(const InlineStdAllocator& other) : mAllocation(other.mAllocation) {}
+ ~InlineStdAllocator() {}
+
+ T* allocate(size_t num, const void* = 0) {
+ if (!mAllocation.inUse && num <= SIZE) {
+ mAllocation.inUse = true;
+ return static_cast<T*>(static_cast<void*>(mAllocation.array));
+ } else {
+ return static_cast<T*>(static_cast<void*>(malloc(num * sizeof(T))));
+ }
+ }
+
+ void deallocate(pointer p, size_t) {
+ if (p == static_cast<T*>(static_cast<void*>(mAllocation.array))) {
+ mAllocation.inUse = false;
+ } else {
+ // 'free' instead of delete here - destruction handled separately
+ free(p);
+ }
+ }
+ Allocation& mAllocation;
+};
+
+/**
+ * std::vector with SIZE elements preallocated into an internal buffer.
+ *
+ * Useful for avoiding the cost of malloc in cases where only SIZE or
+ * fewer elements are needed in the common case.
+ */
+template <typename T, size_t SIZE = 4>
+class FatVector : public std::vector<T, InlineStdAllocator<T, SIZE>> {
+public:
+ FatVector()
+ : std::vector<T, InlineStdAllocator<T, SIZE>>(InlineStdAllocator<T, SIZE>(mAllocation)) {
+ this->reserve(SIZE);
+ }
+
+ explicit FatVector(size_t capacity) : FatVector() { this->resize(capacity); }
+
+private:
+ typename InlineStdAllocator<T, SIZE>::Allocation mAllocation;
+};
+
+} // namespace android
+
+#endif // ANDROID_REGION_FAT_VECTOR_H
diff --git a/libs/ui/include/ui/Region.h b/libs/ui/include/ui/Region.h
index 2db3b10..6bb7b8d 100644
--- a/libs/ui/include/ui/Region.h
+++ b/libs/ui/include/ui/Region.h
@@ -21,13 +21,13 @@
#include <sys/types.h>
#include <ostream>
-#include <utils/Vector.h>
-
#include <ui/Rect.h>
#include <utils/Flattenable.h>
#include <android-base/macros.h>
+#include "FatVector.h"
+
#include <string>
namespace android {
@@ -180,7 +180,7 @@
// with an extra Rect as the last element which is set to the
// bounds of the region. However, if the region is
// a simple Rect then mStorage contains only that rect.
- Vector<Rect> mStorage;
+ FatVector<Rect> mStorage;
};
@@ -235,4 +235,3 @@
}; // namespace android
#endif // ANDROID_UI_REGION_H
-
diff --git a/libs/ui/include_vndk/ui/FatVector.h b/libs/ui/include_vndk/ui/FatVector.h
new file mode 120000
index 0000000..bf30166
--- /dev/null
+++ b/libs/ui/include_vndk/ui/FatVector.h
@@ -0,0 +1 @@
+../../include/ui/FatVector.h
\ No newline at end of file
diff --git a/libs/vr/libvrflinger/tests/Android.bp b/libs/vr/libvrflinger/tests/Android.bp
index 410e234..7fafd3b 100644
--- a/libs/vr/libvrflinger/tests/Android.bp
+++ b/libs/vr/libvrflinger/tests/Android.bp
@@ -11,6 +11,7 @@
"libutils",
"libnativewindow",
"libpdx_default_transport",
+ "libSurfaceFlingerProp",
]
static_libs = [
@@ -32,5 +33,6 @@
"-Wall",
"-Werror",
],
+ header_libs: ["libsurfaceflinger_headers"],
name: "vrflinger_test",
}
diff --git a/libs/vr/libvrflinger/tests/vrflinger_test.cpp b/libs/vr/libvrflinger/tests/vrflinger_test.cpp
index 7075e88..efd6d1d 100644
--- a/libs/vr/libvrflinger/tests/vrflinger_test.cpp
+++ b/libs/vr/libvrflinger/tests/vrflinger_test.cpp
@@ -1,3 +1,4 @@
+#include <SurfaceFlingerProperties.h>
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/types.h>
#include <android/hardware_buffer.h>
@@ -147,9 +148,7 @@
// Exit immediately if the device doesn't support vr flinger. This ConfigStore
// check is the same mechanism used by surface flinger to decide if it should
// initialize vr flinger.
- bool vr_flinger_enabled =
- getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::useVrFlinger>(
- false);
+ bool vr_flinger_enabled = android::sysprop::use_vr_flinger(false);
if (!vr_flinger_enabled) {
return;
}
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index e255b9d..3997134 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -75,7 +75,6 @@
"bionic_libc_platform_headers",
"gl_headers",
"libsystem_headers",
- "libhardware_headers",
"libnativebase_headers",
],
export_header_lib_headers: ["gl_headers"],
@@ -154,6 +153,7 @@
"libnativebridge_lazy",
"libnativeloader_lazy",
"libutils",
+ "libSurfaceFlingerProp",
],
static_libs: [
"libEGL_getProcAddress",
@@ -165,6 +165,7 @@
symbol_file: "libEGL.map.txt",
versions: ["29"],
},
+ header_libs: ["libsurfaceflinger_headers"],
}
cc_test {
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index e19802b..d664e4d 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -222,13 +222,6 @@
return cnx->dso;
}
- // Check if we should use ANGLE early, so loading each driver doesn't require repeated queries.
- if (android::GraphicsEnv::getInstance().shouldUseAngle()) {
- cnx->shouldUseAngle = true;
- } else {
- cnx->shouldUseAngle = false;
- }
-
// Firstly, try to load ANGLE driver.
driver_t* hnd = attempt_to_load_angle(cnx);
if (!hnd) {
@@ -278,6 +271,12 @@
if (!hnd) {
android::GraphicsEnv::getInstance().setDriverLoaded(android::GpuStatsInfo::Api::API_GL,
false, systemTime() - openTime);
+ } else {
+ // init_angle_backend will check if loaded driver is ANGLE or not,
+ // will set cnx->useAngle appropriately.
+ // Do this here so that we use ANGLE path when driver is ANGLE (e.g. loaded as native),
+ // not just loading ANGLE as option.
+ init_angle_backend(hnd->dso[0], cnx);
}
LOG_ALWAYS_FATAL_IF(!hnd,
@@ -317,14 +316,7 @@
delete hnd;
cnx->dso = nullptr;
- cnx->shouldUseAngle = false;
- cnx->angleDecided = false;
cnx->useAngle = false;
-
- if (cnx->vendorEGL) {
- dlclose(cnx->vendorEGL);
- cnx->vendorEGL = nullptr;
- }
}
void Loader::init_api(void* dso,
@@ -491,7 +483,7 @@
return dso;
}
-static void* load_angle_from_namespace(const char* kind, android_namespace_t* ns) {
+static void* load_angle(const char* kind, android_namespace_t* ns) {
const android_dlextinfo dlextinfo = {
.flags = ANDROID_DLEXT_USE_NAMESPACE,
.library_namespace = ns,
@@ -511,69 +503,6 @@
return nullptr;
}
-static void* load_angle(const char* kind, android_namespace_t* ns, egl_connection_t* cnx) {
- void* so = nullptr;
-
- if ((cnx->shouldUseAngle) || android::GraphicsEnv::getInstance().shouldUseAngle()) {
- so = load_angle_from_namespace(kind, ns);
- cnx->shouldUseAngle = true;
- } else {
- cnx->shouldUseAngle = false;
- }
-
- if (so) {
- ALOGV("Loaded ANGLE %s library for '%s' (instead of native)", kind,
- android::GraphicsEnv::getInstance().getAngleAppName().c_str());
- cnx->useAngle = true;
-
- char prop[PROPERTY_VALUE_MAX];
-
- property_get("debug.hwui.renderer", prop, "UNSET");
- ALOGV("Skia's renderer set to %s", prop);
-
- EGLint angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
- property_get("debug.angle.backend", prop, "0");
- switch (atoi(prop)) {
- case 1:
- ALOGV("%s: Requesting OpenGLES back-end", __FUNCTION__);
- angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE;
- break;
- case 2:
- ALOGV("%s: Requesting Vulkan back-end", __FUNCTION__);
- angleBackendDefault = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
- break;
- default:
- break;
- }
-
- cnx->angleBackend = angleBackendDefault;
- if (!cnx->vendorEGL && (cnx->angleBackend == EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE)) {
- // Find and load vendor libEGL for ANGLE's GL back-end to use.
- char prop[PROPERTY_VALUE_MAX + 1];
- for (auto key : HAL_SUBNAME_KEY_PROPERTIES) {
- if (property_get(key, prop, nullptr) <= 0) {
- continue;
- }
- void* dso = load_system_driver("EGL", prop, true);
- if (dso) {
- cnx->vendorEGL = dso;
- break;
- }
- }
- if (!cnx->vendorEGL) {
- cnx->vendorEGL = load_system_driver("EGL", nullptr, true);
- }
- }
- } else {
- ALOGV("Loaded native %s library for '%s' (instead of ANGLE)", kind,
- android::GraphicsEnv::getInstance().getAngleAppName().c_str());
- cnx->useAngle = false;
- }
- cnx->angleDecided = true;
-
- return so;
-}
-
static void* load_updated_driver(const char* kind, android_namespace_t* ns) {
ATRACE_CALL();
const android_dlextinfo dlextinfo = {
@@ -597,6 +526,11 @@
Loader::driver_t* Loader::attempt_to_load_angle(egl_connection_t* cnx) {
ATRACE_CALL();
+
+ if (!android::GraphicsEnv::getInstance().shouldUseAngle()) {
+ return nullptr;
+ }
+
android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace();
if (!ns) {
return nullptr;
@@ -606,22 +540,37 @@
driver_t* hnd = nullptr;
// ANGLE doesn't ship with GLES library, and thus we skip GLES driver.
- void* dso = load_angle("EGL", ns, cnx);
+ void* dso = load_angle("EGL", ns);
if (dso) {
initialize_api(dso, cnx, EGL);
hnd = new driver_t(dso);
- dso = load_angle("GLESv1_CM", ns, cnx);
+ dso = load_angle("GLESv1_CM", ns);
initialize_api(dso, cnx, GLESv1_CM);
hnd->set(dso, GLESv1_CM);
- dso = load_angle("GLESv2", ns, cnx);
+ dso = load_angle("GLESv2", ns);
initialize_api(dso, cnx, GLESv2);
hnd->set(dso, GLESv2);
}
return hnd;
}
+void Loader::init_angle_backend(void* dso, egl_connection_t* cnx) {
+ void* eglCreateDeviceANGLE = nullptr;
+
+ ALOGV("dso: %p", dso);
+ eglCreateDeviceANGLE = dlsym(dso, "eglCreateDeviceANGLE");
+ ALOGV("eglCreateDeviceANGLE: %p", eglCreateDeviceANGLE);
+ if (eglCreateDeviceANGLE) {
+ ALOGV("ANGLE GLES library in use");
+ cnx->useAngle = true;
+ } else {
+ ALOGV("Native GLES library in use");
+ cnx->useAngle = false;
+ }
+}
+
Loader::driver_t* Loader::attempt_to_load_updated_driver(egl_connection_t* cnx) {
ATRACE_CALL();
#ifndef __ANDROID_VNDK__
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
index 6f31ab4..7b2d7c9 100644
--- a/opengl/libs/EGL/Loader.h
+++ b/opengl/libs/EGL/Loader.h
@@ -60,6 +60,7 @@
driver_t* attempt_to_load_system_driver(egl_connection_t* cnx, const char* suffix, const bool exact);
void unload_system_driver(egl_connection_t* cnx);
void initialize_api(void* dso, egl_connection_t* cnx, uint32_t mask);
+ void init_angle_backend(void* dso, egl_connection_t* cnx);
static __attribute__((noinline))
void init_api(void* dso,
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 0581708..d5d57d7 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -16,8 +16,6 @@
#include <stdlib.h>
-#include <hardware/gralloc.h>
-
#include <EGL/egl.h>
#include <cutils/properties.h>
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index a58e87c..6af7cd2 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -31,6 +31,7 @@
#include "egl_object.h"
#include "egl_tls.h"
+#include <SurfaceFlingerProperties.h>
#include <android/dlext.h>
#include <dlfcn.h>
#include <graphicsenv/GraphicsEnv.h>
@@ -133,45 +134,6 @@
return sDisplay[uintptr_t(disp)].getPlatformDisplay(disp, attrib_list);
}
-static bool addAnglePlatformAttributes(egl_connection_t* const cnx,
- std::vector<EGLAttrib>& attrs) {
- intptr_t vendorEGL = (intptr_t)cnx->vendorEGL;
-
- attrs.reserve(4 * 2);
-
- attrs.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
- attrs.push_back(cnx->angleBackend);
-
- switch (cnx->angleBackend) {
- case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
- ALOGV("%s: Requesting Vulkan ANGLE back-end", __FUNCTION__);
- char prop[PROPERTY_VALUE_MAX];
- property_get("debug.angle.validation", prop, "0");
- attrs.push_back(EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE);
- attrs.push_back(atoi(prop));
- break;
- case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE:
- ALOGV("%s: Requesting Default ANGLE back-end", __FUNCTION__);
- break;
- case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
- ALOGV("%s: Requesting OpenGL ES ANGLE back-end", __FUNCTION__);
- // NOTE: This is only valid if the backend is OpenGL
- attrs.push_back(EGL_PLATFORM_ANGLE_EGL_HANDLE_ANGLE);
- attrs.push_back(vendorEGL);
-
- // Context virtualization is only available on GL back-end.
- // Needed to support threading with GL back-end
- attrs.push_back(EGL_PLATFORM_ANGLE_CONTEXT_VIRTUALIZATION_ANGLE);
- attrs.push_back(EGL_FALSE);
- break;
- default:
- ALOGE("%s: Requesting Unknown (%d) ANGLE back-end", __FUNCTION__, cnx->angleBackend);
- break;
- }
-
- return true;
-}
-
static EGLDisplay getPlatformDisplayAngle(EGLNativeDisplayType display, egl_connection_t* const cnx,
const EGLAttrib* attrib_list, EGLint* error) {
EGLDisplay dpy = EGL_NO_DISPLAY;
@@ -186,11 +148,14 @@
}
}
- if (!addAnglePlatformAttributes(cnx, attrs)) {
- ALOGE("eglGetDisplay(%p) failed: Mismatch display request", display);
- *error = EGL_BAD_PARAMETER;
- return EGL_NO_DISPLAY;
- }
+ attrs.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
+ attrs.push_back(EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE);
+
+ char prop[PROPERTY_VALUE_MAX];
+ property_get("debug.angle.validation", prop, "0");
+ attrs.push_back(EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE);
+ attrs.push_back(atoi(prop));
+
attrs.push_back(EGL_NONE);
dpy = cnx->egl.eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE,
@@ -361,9 +326,7 @@
// Note: CDD requires that devices supporting wide color and/or HDR color also support
// the EGL_KHR_gl_colorspace extension.
- bool wideColorBoardConfig =
- getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(
- false);
+ bool wideColorBoardConfig = android::sysprop::has_wide_color_display(false);
// Add wide-color extensions if device can support wide-color
if (wideColorBoardConfig && hasColorSpaceSupport) {
@@ -373,8 +336,7 @@
"EGL_EXT_gl_colorspace_display_p3_passthrough ");
}
- bool hasHdrBoardConfig =
- getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasHDRDisplay>(false);
+ bool hasHdrBoardConfig = android::sysprop::has_HDR_display(false);
if (hasHdrBoardConfig && hasColorSpaceSupport) {
// hasHDRBoardConfig indicates the system is capable of supporting HDR content.
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index c8840f9..c976c60 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -23,8 +23,6 @@
#include <stdlib.h>
#include <string.h>
-#include <hardware/gralloc1.h>
-
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <EGL/eglext_angle.h>
@@ -721,7 +719,7 @@
// NOTE: When using Vulkan backend, the Vulkan runtime makes all the
// native_window_* calls, so don't do them here.
- if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
+ if (!cnx->useAngle) {
int result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
if (result < 0) {
ALOGE("eglCreateWindowSurface: native_window_api_connect (win=%p) "
@@ -740,14 +738,14 @@
std::vector<AttrType> strippedAttribList;
if (!processAttributes<AttrType>(dp, window, attrib_list, &colorSpace, &strippedAttribList)) {
ALOGE("error invalid colorspace: %d", colorSpace);
- if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
+ if (!cnx->useAngle) {
native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
}
return EGL_NO_SURFACE;
}
attrib_list = strippedAttribList.data();
- if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
+ if (!cnx->useAngle) {
int err = native_window_set_buffers_format(window, format);
if (err != 0) {
ALOGE("error setting native window pixel format: %s (%d)", strerror(-err), err);
@@ -779,7 +777,7 @@
}
// EGLSurface creation failed
- if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
+ if (!cnx->useAngle) {
native_window_set_buffers_format(window, 0);
native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
}
@@ -1419,7 +1417,7 @@
}
}
- if (s->cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
+ if (!s->cnx->useAngle) {
if (!sendSurfaceMetadata(s)) {
native_window_api_disconnect(s->getNativeWindow(), NATIVE_WINDOW_API_EGL);
return setError(EGL_BAD_NATIVE_WINDOW, (EGLBoolean)EGL_FALSE);
@@ -1444,7 +1442,7 @@
androidRect.bottom = y;
androidRects.push_back(androidRect);
}
- if (s->cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
+ if (!s->cnx->useAngle) {
native_window_set_surface_damage(s->getNativeWindow(), androidRects.data(),
androidRects.size());
}
diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h
index 7bb9b59..5fbffbd 100644
--- a/opengl/libs/EGL/egldefs.h
+++ b/opengl/libs/EGL/egldefs.h
@@ -81,11 +81,7 @@
void* libGles2;
bool systemDriverUnloaded;
- bool shouldUseAngle; // Should we attempt to load ANGLE
- bool angleDecided; // Have we tried to load ANGLE
bool useAngle; // Was ANGLE successfully loaded
- EGLint angleBackend;
- void* vendorEGL;
};
// clang-format on
diff --git a/opengl/tests/EGLTest/Android.bp b/opengl/tests/EGLTest/Android.bp
index 8bfe517..e3912a8 100644
--- a/opengl/tests/EGLTest/Android.bp
+++ b/opengl/tests/EGLTest/Android.bp
@@ -25,6 +25,7 @@
"liblog",
"libutils",
"libnativewindow",
+ "libSurfaceFlingerProp",
],
include_dirs: [
@@ -34,5 +35,6 @@
header_libs: [
"bionic_libc_platform_headers",
+ "libsurfaceflinger_headers",
],
}
diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp
index cca91c3..510226d 100644
--- a/opengl/tests/EGLTest/EGL_test.cpp
+++ b/opengl/tests/EGLTest/EGL_test.cpp
@@ -16,6 +16,7 @@
#include <gtest/gtest.h>
+#include <SurfaceFlingerProperties.h>
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <configstore/Utils.h>
@@ -52,11 +53,9 @@
#define METADATA_SCALE(x) (static_cast<EGLint>(x * EGL_METADATA_SCALING_EXT))
-static bool hasWideColorDisplay =
- getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
+static bool hasWideColorDisplay = android::sysprop::has_wide_color_display(false);
-static bool hasHdrDisplay =
- getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasHDRDisplay>(false);
+static bool hasHdrDisplay = android::sysprop::has_HDR_display(false);
class EGLTest : public ::testing::Test {
public:
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 6a45d58..baf2f2b 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -352,18 +352,16 @@
break;
}
}
- std::vector<uint8_t> data;
const uint8_t* start = reinterpret_cast<const uint8_t*>(&event);
- data.assign(start, start + size);
- return sign(data);
+ return sign(start, size);
}
-std::array<uint8_t, 32> HmacKeyManager::sign(const std::vector<uint8_t>& data) const {
+std::array<uint8_t, 32> HmacKeyManager::sign(const uint8_t* data, size_t size) const {
// SHA256 always generates 32-bytes result
std::array<uint8_t, 32> hash;
unsigned int hashLen = 0;
- uint8_t* result = HMAC(EVP_sha256(), mHmacKey.data(), mHmacKey.size(), data.data(), data.size(),
- hash.data(), &hashLen);
+ uint8_t* result =
+ HMAC(EVP_sha256(), mHmacKey.data(), mHmacKey.size(), data, size, hash.data(), &hashLen);
if (result == nullptr) {
ALOGE("Could not sign the data using HMAC");
return INVALID_HMAC;
@@ -1988,18 +1986,49 @@
return true;
}
+/**
+ * Indicate whether one window handle should be considered as obscuring
+ * another window handle. We only check a few preconditions. Actually
+ * checking the bounds is left to the caller.
+ */
+static bool canBeObscuredBy(const sp<InputWindowHandle>& windowHandle,
+ const sp<InputWindowHandle>& otherHandle) {
+ // Compare by token so cloned layers aren't counted
+ if (haveSameToken(windowHandle, otherHandle)) {
+ return false;
+ }
+ auto info = windowHandle->getInfo();
+ auto otherInfo = otherHandle->getInfo();
+ if (!otherInfo->visible) {
+ return false;
+ } else if (info->ownerPid == otherInfo->ownerPid && otherHandle->getToken() == nullptr) {
+ // In general, if ownerPid is the same we don't want to generate occlusion
+ // events. This line is now necessary since we are including all Surfaces
+ // in occlusion calculation, so if we didn't check PID like this SurfaceView
+ // would occlude their parents. On the other hand before we started including
+ // all surfaces in occlusion calculation and had this line, we would count
+ // windows with an input channel from the same PID as occluding, and so we
+ // preserve this behavior with the getToken() == null check.
+ return false;
+ } else if (otherInfo->isTrustedOverlay()) {
+ return false;
+ } else if (otherInfo->displayId != info->displayId) {
+ return false;
+ }
+ return true;
+}
+
bool InputDispatcher::isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle,
int32_t x, int32_t y) const {
int32_t displayId = windowHandle->getInfo()->displayId;
const std::vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
for (const sp<InputWindowHandle>& otherHandle : windowHandles) {
- if (otherHandle == windowHandle) {
- break;
+ if (windowHandle == otherHandle) {
+ break; // All future windows are below us. Exit early.
}
-
const InputWindowInfo* otherInfo = otherHandle->getInfo();
- if (otherInfo->displayId == displayId && otherInfo->visible &&
- !otherInfo->isTrustedOverlay() && otherInfo->frameContainsPoint(x, y)) {
+ if (canBeObscuredBy(windowHandle, otherHandle) &&
+ otherInfo->frameContainsPoint(x, y)) {
return true;
}
}
@@ -2011,13 +2040,13 @@
const std::vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
const InputWindowInfo* windowInfo = windowHandle->getInfo();
for (const sp<InputWindowHandle>& otherHandle : windowHandles) {
- if (otherHandle == windowHandle) {
- break;
+ if (windowHandle == otherHandle) {
+ break; // All future windows are below us. Exit early.
}
const InputWindowInfo* otherInfo = otherHandle->getInfo();
- if (otherInfo->displayId == displayId && otherInfo->visible &&
- !otherInfo->isTrustedOverlay() && otherInfo->overlaps(windowInfo)) {
+ if (canBeObscuredBy(windowHandle, otherHandle) &&
+ otherInfo->overlaps(windowInfo)) {
return true;
}
}
@@ -2451,11 +2480,8 @@
EventEntry* eventEntry = dispatchEntry->eventEntry;
switch (eventEntry->type) {
case EventEntry::Type::KEY: {
- KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
- VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEntry(*keyEntry);
- verifiedEvent.flags = dispatchEntry->resolvedFlags & VERIFIED_KEY_EVENT_FLAGS;
- verifiedEvent.action = dispatchEntry->resolvedAction;
- std::array<uint8_t, 32> hmac = mHmacKeyManager.sign(verifiedEvent);
+ const KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
+ std::array<uint8_t, 32> hmac = getSignature(*keyEntry, *dispatchEntry);
// Publish the key event.
status =
@@ -2507,12 +2533,8 @@
usingCoords = scaledCoords;
}
}
- VerifiedMotionEvent verifiedEvent =
- verifiedMotionEventFromMotionEntry(*motionEntry);
- verifiedEvent.actionMasked =
- dispatchEntry->resolvedAction & AMOTION_EVENT_ACTION_MASK;
- verifiedEvent.flags = dispatchEntry->resolvedFlags & VERIFIED_MOTION_EVENT_FLAGS;
- std::array<uint8_t, 32> hmac = mHmacKeyManager.sign(verifiedEvent);
+
+ std::array<uint8_t, 32> hmac = getSignature(*motionEntry, *dispatchEntry);
// Publish the motion event.
status = connection->inputPublisher
@@ -2592,6 +2614,28 @@
}
}
+const std::array<uint8_t, 32> InputDispatcher::getSignature(
+ const MotionEntry& motionEntry, const DispatchEntry& dispatchEntry) const {
+ int32_t actionMasked = dispatchEntry.resolvedAction & AMOTION_EVENT_ACTION_MASK;
+ if ((actionMasked == AMOTION_EVENT_ACTION_UP) || (actionMasked == AMOTION_EVENT_ACTION_DOWN)) {
+ // Only sign events up and down events as the purely move events
+ // are tied to their up/down counterparts so signing would be redundant.
+ VerifiedMotionEvent verifiedEvent = verifiedMotionEventFromMotionEntry(motionEntry);
+ verifiedEvent.actionMasked = actionMasked;
+ verifiedEvent.flags = dispatchEntry.resolvedFlags & VERIFIED_MOTION_EVENT_FLAGS;
+ return mHmacKeyManager.sign(verifiedEvent);
+ }
+ return INVALID_HMAC;
+}
+
+const std::array<uint8_t, 32> InputDispatcher::getSignature(
+ const KeyEntry& keyEntry, const DispatchEntry& dispatchEntry) const {
+ VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEntry(keyEntry);
+ verifiedEvent.flags = dispatchEntry.resolvedFlags & VERIFIED_KEY_EVENT_FLAGS;
+ verifiedEvent.action = dispatchEntry.resolvedAction;
+ return mHmacKeyManager.sign(verifiedEvent);
+}
+
void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection, uint32_t seq,
bool handled) {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index cbba7e1..2b9cbce 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -62,7 +62,7 @@
std::array<uint8_t, 32> sign(const VerifiedInputEvent& event) const;
private:
- std::array<uint8_t, 32> sign(const std::vector<uint8_t>& data) const;
+ std::array<uint8_t, 32> sign(const uint8_t* data, size_t size) const;
const std::array<uint8_t, 128> mHmacKey;
};
@@ -219,7 +219,11 @@
// the pointer stream in order to claim it for a system gesture.
std::unordered_map<int32_t, std::vector<Monitor>> mGestureMonitorsByDisplay GUARDED_BY(mLock);
- HmacKeyManager mHmacKeyManager;
+ const HmacKeyManager mHmacKeyManager;
+ const std::array<uint8_t, 32> getSignature(const MotionEntry& motionEntry,
+ const DispatchEntry& dispatchEntry) const;
+ const std::array<uint8_t, 32> getSignature(const KeyEntry& keyEntry,
+ const DispatchEntry& dispatchEntry) const;
// Event injection and synchronization.
std::condition_variable mInjectionResultAvailable;
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
index d77c8c8..43bd9f1 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
@@ -255,6 +255,7 @@
getDeviceName().c_str());
cancelTouch(when);
}
+ continue;
}
if (outCount >= MAX_POINTERS) {
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 675b77b..109edfe 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -7082,6 +7082,76 @@
ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
}
+/**
+ * Test multi-touch should be canceled when received the MT_TOOL_PALM event from some finger,
+ * and could be allowed again after all non-MT_TOOL_PALM is release and the new point is
+ * MT_TOOL_FINGER.
+ */
+TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType2) {
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareAxes(POSITION | ID | SLOT | TOOL_TYPE);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+
+ NotifyMotionArgs motionArgs;
+
+ // default tool type is finger
+ constexpr int32_t x1 = 100, y1 = 200, x2 = 120, y2 = 220, x3 = 140, y3 = 240;
+ processId(mapper, 1);
+ processPosition(mapper, x1, y1);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+ ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+
+ // Second finger down.
+ processSlot(mapper, 1);
+ processPosition(mapper, x2, y2);
+ processId(mapper, 2);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ motionArgs.action);
+ ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+
+ // If the tool type of the first pointer changes to MT_TOOL_PALM,
+ // the entire gesture should be aborted, so we expect to receive ACTION_CANCEL.
+ processSlot(mapper, 0);
+ processId(mapper, 1);
+ processToolType(mapper, MT_TOOL_PALM);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionArgs.action);
+
+ // Ignore the following MOVE and UP events if had detect a palm event.
+ processSlot(mapper, 1);
+ processId(mapper, 2);
+ processPosition(mapper, x3, y3);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+
+ // second finger up.
+ processId(mapper, -1);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+
+ // first finger move, but still in palm
+ processSlot(mapper, 0);
+ processId(mapper, 1);
+ processPosition(mapper, x1 - 1, y1 - 1);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+
+ // second finger down, expect as new finger down.
+ processSlot(mapper, 1);
+ processId(mapper, 2);
+ processPosition(mapper, x2, y2);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+ ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+}
+
// --- MultiTouchInputMapperTest_ExternalDevice ---
class MultiTouchInputMapperTest_ExternalDevice : public MultiTouchInputMapperTest {
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index fce0971..0182937 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -286,6 +286,7 @@
export_shared_lib_headers: [
"android.hardware.graphics.common@1.2",
"libhidlbase",
+ "libui",
],
export_static_lib_headers: [
"SurfaceFlingerProperties",
diff --git a/services/surfaceflinger/Barrier.h b/services/surfaceflinger/Barrier.h
deleted file mode 100644
index 97028a8..0000000
--- a/services/surfaceflinger/Barrier.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_BARRIER_H
-#define ANDROID_BARRIER_H
-
-#include <stdint.h>
-#include <condition_variable>
-#include <mutex>
-
-namespace android {
-
-class Barrier
-{
-public:
- // Release any threads waiting at the Barrier.
- // Provides release semantics: preceding loads and stores will be visible
- // to other threads before they wake up.
- void open() {
- std::lock_guard<std::mutex> lock(mMutex);
- mIsOpen = true;
- mCondition.notify_all();
- }
-
- // Reset the Barrier, so wait() will block until open() has been called.
- void close() {
- std::lock_guard<std::mutex> lock(mMutex);
- mIsOpen = false;
- }
-
- // Wait until the Barrier is OPEN.
- // Provides acquire semantics: no subsequent loads or stores will occur
- // until wait() returns.
- void wait() const {
- std::unique_lock<std::mutex> lock(mMutex);
- mCondition.wait(lock, [this]() NO_THREAD_SAFETY_ANALYSIS { return mIsOpen; });
- }
-private:
- mutable std::mutex mMutex;
- mutable std::condition_variable mCondition;
- int mIsOpen GUARDED_BY(mMutex){false};
-};
-
-}; // namespace android
-
-#endif // ANDROID_BARRIER_H
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index e50a909..648d129 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -407,8 +407,17 @@
}
Rect BufferLayerConsumer::getCurrentCropLocked() const {
+ uint32_t width = mDefaultWidth;
+ uint32_t height = mDefaultHeight;
+ // If the buffer comes with a rotated bit for 90 (or 270) degrees, switch width/height in order
+ // to scale and crop correctly.
+ if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+ width = mDefaultHeight;
+ height = mDefaultWidth;
+ }
+
return (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP)
- ? GLConsumer::scaleDownCrop(mCurrentCrop, mDefaultWidth, mDefaultHeight)
+ ? GLConsumer::scaleDownCrop(mCurrentCrop, width, height)
: mCurrentCrop;
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 27266b7..75a4fec 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -74,7 +74,7 @@
MOCK_METHOD4(setDisplayContentSamplingEnabled, status_t(DisplayId, bool, uint8_t, uint64_t));
MOCK_METHOD4(getDisplayedContentSample,
status_t(DisplayId, uint64_t, uint64_t, DisplayedFrameStats*));
- MOCK_METHOD2(setDisplayBrightness, status_t(DisplayId, float));
+ MOCK_METHOD2(setDisplayBrightness, std::future<status_t>(DisplayId, float));
MOCK_METHOD2(getDisplayBrightnessSupport, status_t(DisplayId, bool*));
MOCK_METHOD2(onHotplug,
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index d6dbd57..0ea3340 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -25,7 +25,6 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include "HWC2.h"
-#include "ComposerHal.h"
#include <ui/Fence.h>
#include <ui/FloatRect.h>
@@ -38,6 +37,9 @@
#include <iterator>
#include <set>
+#include "../Promise.h"
+#include "ComposerHal.h"
+
namespace android {
using android::Fence;
@@ -640,12 +642,14 @@
return error;
}
-Error Display::setDisplayBrightness(float brightness) const {
- const auto intError = mComposer.setDisplayBrightness(mId, brightness);
- return static_cast<Error>(intError);
+std::future<Error> Display::setDisplayBrightness(float brightness) {
+ return promise::defer([composer = &mComposer, id = mId, brightness] {
+ const auto intError = composer->setDisplayBrightness(id, brightness);
+ return static_cast<Error>(intError);
+ });
}
-Error Display::setAutoLowLatencyMode(bool on) const {
+Error Display::setAutoLowLatencyMode(bool on) {
auto intError = mComposer.setAutoLowLatencyMode(mId, on);
return static_cast<Error>(intError);
}
@@ -659,7 +663,7 @@
return static_cast<Error>(intError);
}
-Error Display::setContentType(ContentType contentType) const {
+Error Display::setContentType(ContentType contentType) {
auto intError = mComposer.setContentType(mId, contentType);
return static_cast<Error>(intError);
}
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index af31df8..f4c7fdd 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -27,6 +27,7 @@
#include <utils/Timers.h>
#include <functional>
+#include <future>
#include <string>
#include <unordered_map>
#include <unordered_set>
@@ -221,18 +222,18 @@
[[clang::warn_unused_result]] virtual hal::Error presentOrValidate(
uint32_t* outNumTypes, uint32_t* outNumRequests,
android::sp<android::Fence>* outPresentFence, uint32_t* state) = 0;
- [[clang::warn_unused_result]] virtual hal::Error setDisplayBrightness(
- float brightness) const = 0;
+ [[clang::warn_unused_result]] virtual std::future<hal::Error> setDisplayBrightness(
+ float brightness) = 0;
[[clang::warn_unused_result]] virtual hal::Error getDisplayVsyncPeriod(
nsecs_t* outVsyncPeriod) const = 0;
[[clang::warn_unused_result]] virtual hal::Error setActiveConfigWithConstraints(
const std::shared_ptr<const HWC2::Display::Config>& config,
const hal::VsyncPeriodChangeConstraints& constraints,
hal::VsyncPeriodChangeTimeline* outTimeline) = 0;
- [[clang::warn_unused_result]] virtual hal::Error setAutoLowLatencyMode(bool on) const = 0;
+ [[clang::warn_unused_result]] virtual hal::Error setAutoLowLatencyMode(bool on) = 0;
[[clang::warn_unused_result]] virtual hal::Error getSupportedContentTypes(
std::vector<hal::ContentType>*) const = 0;
- [[clang::warn_unused_result]] virtual hal::Error setContentType(hal::ContentType) const = 0;
+ [[clang::warn_unused_result]] virtual hal::Error setContentType(hal::ContentType) = 0;
};
namespace impl {
@@ -294,16 +295,16 @@
hal::Error presentOrValidate(uint32_t* outNumTypes, uint32_t* outNumRequests,
android::sp<android::Fence>* outPresentFence,
uint32_t* state) override;
- hal::Error setDisplayBrightness(float brightness) const override;
+ std::future<hal::Error> setDisplayBrightness(float brightness) override;
hal::Error getDisplayVsyncPeriod(nsecs_t* outVsyncPeriod) const override;
hal::Error setActiveConfigWithConstraints(
const std::shared_ptr<const HWC2::Display::Config>& config,
const hal::VsyncPeriodChangeConstraints& constraints,
hal::VsyncPeriodChangeTimeline* outTimeline) override;
- hal::Error setAutoLowLatencyMode(bool on) const override;
+ hal::Error setAutoLowLatencyMode(bool on) override;
hal::Error getSupportedContentTypes(
std::vector<hal::ContentType>* outSupportedContentTypes) const override;
- hal::Error setContentType(hal::ContentType contentType) const override;
+ hal::Error setContentType(hal::ContentType) override;
// Other Display methods
hal::HWDisplayId getId() const override { return mId; }
bool isConnected() const override { return mIsConnected; }
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 4344a8d..038cec4 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -36,6 +36,7 @@
#include <utils/Trace.h>
#include "../Layer.h" // needed only for debugging
+#include "../Promise.h"
#include "../SurfaceFlinger.h"
#include "ComposerHal.h"
#include "HWC2.h"
@@ -794,17 +795,21 @@
return NO_ERROR;
}
-status_t HWComposer::setDisplayBrightness(DisplayId displayId, float brightness) {
- RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
- const auto error = mDisplayData[displayId].hwcDisplay->setDisplayBrightness(brightness);
- if (error == hal::Error::UNSUPPORTED) {
- RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION);
- }
- if (error == hal::Error::BAD_PARAMETER) {
- RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE);
- }
- RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
- return NO_ERROR;
+std::future<status_t> HWComposer::setDisplayBrightness(DisplayId displayId, float brightness) {
+ RETURN_IF_INVALID_DISPLAY(displayId, promise::yield<status_t>(BAD_INDEX));
+ auto& display = mDisplayData[displayId].hwcDisplay;
+
+ return promise::chain(display->setDisplayBrightness(brightness))
+ .then([displayId](hal::Error error) -> status_t {
+ if (error == hal::Error::UNSUPPORTED) {
+ RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION);
+ }
+ if (error == hal::Error::BAD_PARAMETER) {
+ RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE);
+ }
+ RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
+ return NO_ERROR;
+ });
}
bool HWComposer::isUsingVrComposer() const {
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index cfa2193..b7e9f3a 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -18,6 +18,7 @@
#define ANDROID_SF_HWCOMPOSER_H
#include <cstdint>
+#include <future>
#include <memory>
#include <mutex>
#include <optional>
@@ -163,7 +164,7 @@
DisplayedFrameStats* outStats) = 0;
// Sets the brightness of a display.
- virtual status_t setDisplayBrightness(DisplayId displayId, float brightness) = 0;
+ virtual std::future<status_t> setDisplayBrightness(DisplayId displayId, float brightness) = 0;
// Events handling ---------------------------------------------------------
@@ -305,7 +306,7 @@
uint8_t componentMask, uint64_t maxFrames) override;
status_t getDisplayedContentSample(DisplayId displayId, uint64_t maxFrames, uint64_t timestamp,
DisplayedFrameStats* outStats) override;
- status_t setDisplayBrightness(DisplayId displayId, float brightness) override;
+ std::future<status_t> setDisplayBrightness(DisplayId displayId, float brightness) override;
// Events handling ---------------------------------------------------------
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 8452957..752407a 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1532,17 +1532,33 @@
void Layer::miniDumpHeader(std::string& result) {
result.append("-------------------------------");
result.append("-------------------------------");
- result.append("-----------------------------\n");
+ result.append("-------------------------------");
+ result.append("-------------------------------");
+ result.append("---------\n");
result.append(" Layer name\n");
result.append(" Z | ");
result.append(" Window Type | ");
result.append(" Comp Type | ");
result.append(" Transform | ");
result.append(" Disp Frame (LTRB) | ");
- result.append(" Source Crop (LTRB)\n");
+ result.append(" Source Crop (LTRB) | ");
+ result.append(" Frame Rate (Explicit)\n");
result.append("-------------------------------");
result.append("-------------------------------");
- result.append("-----------------------------\n");
+ result.append("-------------------------------");
+ result.append("-------------------------------");
+ result.append("---------\n");
+}
+
+std::string Layer::frameRateCompatibilityString(Layer::FrameRateCompatibility compatibility) {
+ switch (compatibility) {
+ case FrameRateCompatibility::Default:
+ return "Default";
+ case FrameRateCompatibility::ExactOrMultiple:
+ return "ExactOrMultiple";
+ case FrameRateCompatibility::NoVote:
+ return "NoVote";
+ }
}
void Layer::miniDump(std::string& result, const sp<DisplayDevice>& displayDevice) const {
@@ -1578,12 +1594,21 @@
const Rect& frame = outputLayerState.displayFrame;
StringAppendF(&result, "%4d %4d %4d %4d | ", frame.left, frame.top, frame.right, frame.bottom);
const FloatRect& crop = outputLayerState.sourceCrop;
- StringAppendF(&result, "%6.1f %6.1f %6.1f %6.1f\n", crop.left, crop.top, crop.right,
+ StringAppendF(&result, "%6.1f %6.1f %6.1f %6.1f | ", crop.left, crop.top, crop.right,
crop.bottom);
+ if (layerState.frameRate.rate != 0 ||
+ layerState.frameRate.type != FrameRateCompatibility::Default) {
+ StringAppendF(&result, "% 6.2ffps %15s\n", layerState.frameRate.rate,
+ frameRateCompatibilityString(layerState.frameRate.type).c_str());
+ } else {
+ StringAppendF(&result, "\n");
+ }
- result.append("- - - - - - - - - - - - - - - -");
- result.append("- - - - - - - - - - - - - - - -");
- result.append("- - - - - - - - - - - - - - -\n");
+ result.append("- - - - - - - - - - - - - - - - ");
+ result.append("- - - - - - - - - - - - - - - - ");
+ result.append("- - - - - - - - - - - - - - - - ");
+ result.append("- - - - - - - - - - - - - - - - ");
+ result.append("- - -\n");
}
void Layer::dumpFrameStats(std::string& result) const {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 6636b5e..b630333 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -819,6 +819,7 @@
bool setFrameRate(FrameRate frameRate);
virtual FrameRate getFrameRateForLayerTree() const;
+ static std::string frameRateCompatibilityString(FrameRateCompatibility compatibility);
protected:
// constant
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index 5009e10..18a2891 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -38,13 +38,7 @@
// because we don't know where this destructor is called from. It could be
// called with the mStateLock held, leading to a dead-lock (it actually
// happens).
- sp<LambdaMessage> cleanUpListMessage =
- new LambdaMessage([flinger = mFlinger, asBinder = wp<IBinder>(onAsBinder())]() {
- Mutex::Autolock lock(flinger->mStateLock);
- flinger->mGraphicBufferProducerList.erase(asBinder);
- });
-
- mFlinger->postMessageAsync(cleanUpListMessage);
+ mFlinger->removeGraphicBufferProducerAsync(onAsBinder());
}
status_t MonitoredProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
diff --git a/services/surfaceflinger/Promise.h b/services/surfaceflinger/Promise.h
new file mode 100644
index 0000000..a80d441
--- /dev/null
+++ b/services/surfaceflinger/Promise.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <future>
+#include <type_traits>
+#include <utility>
+
+namespace android::promise {
+namespace impl {
+
+template <typename T>
+struct FutureResult {
+ using Type = T;
+};
+
+template <typename T>
+struct FutureResult<std::future<T>> {
+ using Type = T;
+};
+
+} // namespace impl
+
+template <typename T>
+using FutureResult = typename impl::FutureResult<T>::Type;
+
+template <typename... Args>
+inline auto defer(Args... args) {
+ return std::async(std::launch::deferred, std::forward<Args>(args)...);
+}
+
+template <typename T>
+inline std::future<T> yield(T&& v) {
+ return defer([](T&& v) { return std::forward<T>(v); }, std::forward<T>(v));
+}
+
+template <typename T>
+struct Chain {
+ Chain(std::future<T>&& f) : future(std::move(f)) {}
+ operator std::future<T>&&() && { return std::move(future); }
+
+ T get() && { return future.get(); }
+
+ template <typename F, typename R = std::invoke_result_t<F, T>>
+ auto then(F&& op) && -> Chain<FutureResult<R>> {
+ return defer(
+ [](auto&& f, F&& op) {
+ R r = op(f.get());
+ if constexpr (std::is_same_v<R, FutureResult<R>>) {
+ return r;
+ } else {
+ return r.get();
+ }
+ },
+ std::move(future), std::forward<F>(op));
+ }
+
+ std::future<T> future;
+};
+
+template <typename T>
+inline Chain<T> chain(std::future<T>&& f) {
+ return std::move(f);
+}
+
+} // namespace android::promise
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index 9d6e1d8..6067e69 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -18,10 +18,6 @@
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
-#include <errno.h>
-#include <stdint.h>
-#include <sys/types.h>
-
#include <binder/IPCThreadState.h>
#include <utils/Log.h>
@@ -35,26 +31,7 @@
#include "MessageQueue.h"
#include "SurfaceFlinger.h"
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-MessageBase::MessageBase() : MessageHandler() {}
-
-MessageBase::~MessageBase() {}
-
-void MessageBase::handleMessage(const Message&) {
- this->handler();
- barrier.open();
-};
-
-// ---------------------------------------------------------------------------
-
-MessageQueue::~MessageQueue() = default;
-
-// ---------------------------------------------------------------------------
-
-namespace impl {
+namespace android::impl {
void MessageQueue::Handler::dispatchRefresh() {
if ((android_atomic_or(eventMaskRefresh, &mEventMask) & eventMaskRefresh) == 0) {
@@ -123,14 +100,8 @@
} while (true);
}
-status_t MessageQueue::postMessage(const sp<MessageBase>& messageHandler, nsecs_t relTime) {
- const Message dummyMessage;
- if (relTime > 0) {
- mLooper->sendMessageDelayed(relTime, messageHandler, dummyMessage);
- } else {
- mLooper->sendMessage(messageHandler, dummyMessage);
- }
- return NO_ERROR;
+void MessageQueue::postMessage(sp<MessageHandler>&& handler) {
+ mLooper->sendMessage(handler, Message());
}
void MessageQueue::invalidate() {
@@ -160,10 +131,7 @@
return 1;
}
-// ---------------------------------------------------------------------------
-
-} // namespace impl
-} // namespace android
+} // namespace android::impl
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h
index ebc4315..132b416 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.h
+++ b/services/surfaceflinger/Scheduler/MessageQueue.h
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-#ifndef ANDROID_MESSAGE_QUEUE_H
-#define ANDROID_MESSAGE_QUEUE_H
+#pragma once
-#include <errno.h>
-#include <stdint.h>
-#include <sys/types.h>
+#include <cstdint>
+#include <future>
+#include <type_traits>
+#include <utility>
#include <utils/Looper.h>
#include <utils/Timers.h>
@@ -28,52 +28,30 @@
#include <gui/IDisplayEventConnection.h>
#include <private/gui/BitTube.h>
-#include "Barrier.h"
#include "EventThread.h"
-#include <functional>
-
namespace android {
class SurfaceFlinger;
-// ---------------------------------------------------------------------------
+template <typename F>
+class Task : public MessageHandler {
+ template <typename G>
+ friend auto makeTask(G&&);
-class MessageBase : public MessageHandler {
-public:
- MessageBase();
+ explicit Task(F&& f) : mTask(std::move(f)) {}
- // return true if message has a handler
- virtual bool handler() = 0;
+ void handleMessage(const Message&) override { mTask(); }
- // waits for the handler to be processed
- void wait() const { barrier.wait(); }
-
-protected:
- virtual ~MessageBase();
-
-private:
- virtual void handleMessage(const Message& message);
-
- mutable Barrier barrier;
+ using T = std::invoke_result_t<F>;
+ std::packaged_task<T()> mTask;
};
-class LambdaMessage : public MessageBase {
-public:
- explicit LambdaMessage(std::function<void()> handler)
- : MessageBase(), mHandler(std::move(handler)) {}
-
- bool handler() override {
- mHandler();
- // This return value is no longer checked, so it's always safe to return true
- return true;
- }
-
-private:
- const std::function<void()> mHandler;
-};
-
-// ---------------------------------------------------------------------------
+template <typename F>
+inline auto makeTask(F&& f) {
+ sp<Task<F>> task = new Task<F>(std::move(f));
+ return std::make_pair(task, task->mTask.get_future());
+}
class MessageQueue {
public:
@@ -82,12 +60,12 @@
REFRESH = 1,
};
- virtual ~MessageQueue();
+ virtual ~MessageQueue() = default;
virtual void init(const sp<SurfaceFlinger>& flinger) = 0;
virtual void setEventConnection(const sp<EventThreadConnection>& connection) = 0;
virtual void waitMessage() = 0;
- virtual status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime = 0) = 0;
+ virtual void postMessage(sp<MessageHandler>&&) = 0;
virtual void invalidate() = 0;
virtual void refresh() = 0;
};
@@ -127,7 +105,7 @@
void setEventConnection(const sp<EventThreadConnection>& connection) override;
void waitMessage() override;
- status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime = 0) override;
+ void postMessage(sp<MessageHandler>&&) override;
// sends INVALIDATE message at next VSYNC
void invalidate() override;
@@ -136,9 +114,5 @@
void refresh() override;
};
-// ---------------------------------------------------------------------------
-
} // namespace impl
} // namespace android
-
-#endif /* ANDROID_MESSAGE_QUEUE_H */
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
index d9aaa05..fe2e406 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
@@ -60,6 +60,12 @@
PhaseOffsets::PhaseOffsets(const scheduler::RefreshRateConfigs& refreshRateConfigs)
: PhaseOffsets(getRefreshRatesFromConfigs(refreshRateConfigs),
refreshRateConfigs.getCurrentRefreshRate().getFps(),
+ sysprop::vsync_event_phase_offset_ns(1000000),
+ sysprop::vsync_sf_event_phase_offset_ns(1000000),
+ getProperty("debug.sf.early_phase_offset_ns"),
+ getProperty("debug.sf.early_gl_phase_offset_ns"),
+ getProperty("debug.sf.early_app_phase_offset_ns"),
+ getProperty("debug.sf.early_gl_app_phase_offset_ns"),
// Below defines the threshold when an offset is considered to be negative,
// i.e. targeting for the N+2 vsync instead of N+1. This means that: For offset
// < threshold, SF wake up (vsync_duration - offset) before HW vsync. For
@@ -69,8 +75,18 @@
.value_or(std::numeric_limits<nsecs_t>::max())) {}
PhaseOffsets::PhaseOffsets(const std::vector<float>& refreshRates, float currentFps,
- nsecs_t thresholdForNextVsync)
- : mThresholdForNextVsync(thresholdForNextVsync),
+ nsecs_t vsyncPhaseOffsetNs, nsecs_t sfVSyncPhaseOffsetNs,
+ std::optional<nsecs_t> earlySfOffsetNs,
+ std::optional<nsecs_t> earlyGlSfOffsetNs,
+ std::optional<nsecs_t> earlyAppOffsetNs,
+ std::optional<nsecs_t> earlyGlAppOffsetNs, nsecs_t thresholdForNextVsync)
+ : mVSyncPhaseOffsetNs(vsyncPhaseOffsetNs),
+ mSfVSyncPhaseOffsetNs(sfVSyncPhaseOffsetNs),
+ mEarlySfOffsetNs(earlySfOffsetNs),
+ mEarlyGlSfOffsetNs(earlyGlSfOffsetNs),
+ mEarlyAppOffsetNs(earlyAppOffsetNs),
+ mEarlyGlAppOffsetNs(earlyGlAppOffsetNs),
+ mThresholdForNextVsync(thresholdForNextVsync),
mOffsets(initializeOffsets(refreshRates)),
mRefreshRateFps(currentFps) {}
@@ -106,35 +122,27 @@
}
PhaseOffsets::Offsets PhaseOffsets::getDefaultOffsets(nsecs_t vsyncDuration) const {
- const int64_t vsyncPhaseOffsetNs = sysprop::vsync_event_phase_offset_ns(1000000);
- const int64_t sfVsyncPhaseOffsetNs = sysprop::vsync_sf_event_phase_offset_ns(1000000);
-
- const auto earlySfOffsetNs = getProperty("debug.sf.early_phase_offset_ns");
- const auto earlyGlSfOffsetNs = getProperty("debug.sf.early_gl_phase_offset_ns");
- const auto earlyAppOffsetNs = getProperty("debug.sf.early_app_phase_offset_ns");
- const auto earlyGlAppOffsetNs = getProperty("debug.sf.early_gl_app_phase_offset_ns");
-
return {
{
- earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs) < mThresholdForNextVsync
- ? earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs)
- : earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs) - vsyncDuration,
+ mEarlySfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) < mThresholdForNextVsync
+ ? mEarlySfOffsetNs.value_or(mSfVSyncPhaseOffsetNs)
+ : mEarlySfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) - vsyncDuration,
- earlyAppOffsetNs.value_or(vsyncPhaseOffsetNs),
+ mEarlyAppOffsetNs.value_or(mVSyncPhaseOffsetNs),
},
{
- earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs) < mThresholdForNextVsync
- ? earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs)
- : earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs) - vsyncDuration,
+ mEarlyGlSfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) < mThresholdForNextVsync
+ ? mEarlyGlSfOffsetNs.value_or(mSfVSyncPhaseOffsetNs)
+ : mEarlyGlSfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) - vsyncDuration,
- earlyGlAppOffsetNs.value_or(vsyncPhaseOffsetNs),
+ mEarlyGlAppOffsetNs.value_or(mVSyncPhaseOffsetNs),
},
{
- sfVsyncPhaseOffsetNs < mThresholdForNextVsync
- ? sfVsyncPhaseOffsetNs
- : sfVsyncPhaseOffsetNs - vsyncDuration,
+ mSfVSyncPhaseOffsetNs < mThresholdForNextVsync
+ ? mSfVSyncPhaseOffsetNs
+ : mSfVSyncPhaseOffsetNs - vsyncDuration,
- vsyncPhaseOffsetNs,
+ mVSyncPhaseOffsetNs,
},
};
}
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.h b/services/surfaceflinger/Scheduler/PhaseOffsets.h
index fa8011d..9ec6d56 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.h
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.h
@@ -69,6 +69,9 @@
protected:
// Used for unit tests
PhaseOffsets(const std::vector<float>& refreshRates, float currentFps,
+ nsecs_t vsyncPhaseOffsetNs, nsecs_t sfVSyncPhaseOffsetNs,
+ std::optional<nsecs_t> earlySfOffsetNs, std::optional<nsecs_t> earlyGlSfOffsetNs,
+ std::optional<nsecs_t> earlyAppOffsetNs, std::optional<nsecs_t> earlyGlAppOffsetNs,
nsecs_t thresholdForNextVsync);
std::unordered_map<float, Offsets> initializeOffsets(
const std::vector<float>& refreshRates) const;
@@ -76,6 +79,12 @@
Offsets getHighFpsOffsets(nsecs_t vsyncPeriod) const;
Offsets getPhaseOffsets(float fps, nsecs_t vsyncPeriod) const;
+ const nsecs_t mVSyncPhaseOffsetNs;
+ const nsecs_t mSfVSyncPhaseOffsetNs;
+ const std::optional<nsecs_t> mEarlySfOffsetNs;
+ const std::optional<nsecs_t> mEarlyGlSfOffsetNs;
+ const std::optional<nsecs_t> mEarlyAppOffsetNs;
+ const std::optional<nsecs_t> mEarlyGlAppOffsetNs;
const nsecs_t mThresholdForNextVsync;
const std::unordered_map<float, Offsets> mOffsets;
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 5634adb..8d958df 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -58,7 +58,7 @@
ATRACE_INT("ContentFPS", contentFramerate);
// Find the appropriate refresh rate with minimal error
- auto iter = min_element(mAvailableRefreshRates.cbegin(), mAvailableRefreshRates.cend(),
+ auto iter = min_element(mPrimaryRefreshRates.cbegin(), mPrimaryRefreshRates.cend(),
[contentFramerate](const auto& lhs, const auto& rhs) -> bool {
return std::abs(lhs->fps - contentFramerate) <
std::abs(rhs->fps - contentFramerate);
@@ -71,7 +71,7 @@
constexpr float MARGIN = 0.05f;
float ratio = (*iter)->fps / contentFramerate;
if (std::abs(std::round(ratio) - ratio) > MARGIN) {
- while (iter != mAvailableRefreshRates.cend()) {
+ while (iter != mPrimaryRefreshRates.cend()) {
ratio = (*iter)->fps / contentFramerate;
if (std::abs(std::round(ratio) - ratio) <= MARGIN) {
@@ -97,8 +97,8 @@
return {displayFramesQuot, displayFramesRem};
}
-const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2(
- const std::vector<LayerRequirement>& layers, bool touchActive,
+const RefreshRate& RefreshRateConfigs::getBestRefreshRate(
+ const std::vector<LayerRequirement>& layers, bool touchActive, bool idle,
bool* touchConsidered) const {
ATRACE_CALL();
ALOGV("getRefreshRateForContent %zu layers", layers.size());
@@ -106,13 +106,6 @@
*touchConsidered = false;
std::lock_guard lock(mLock);
- // If there are not layers, there is not content detection, so return the current
- // refresh rate.
- if (layers.empty()) {
- *touchConsidered = touchActive;
- return touchActive ? *mAvailableRefreshRates.back() : getCurrentRefreshRateByPolicyLocked();
- }
-
int noVoteLayers = 0;
int minVoteLayers = 0;
int maxVoteLayers = 0;
@@ -135,25 +128,33 @@
}
}
- // Consider the touch event if there are no ExplicitDefault layers.
- // ExplicitDefault are mostly interactive (as opposed to ExplicitExactOrMultiple)
- // and therefore if those posted an explicit vote we should not change it
- // if get get a touch event.
- if (touchActive && explicitDefaultVoteLayers == 0) {
+ // Consider the touch event if there are no Explicit* layers. Otherwise wait until after we've
+ // selected a refresh rate to see if we should apply touch boost.
+ if (touchActive && explicitDefaultVoteLayers == 0 && explicitExactOrMultipleVoteLayers == 0) {
*touchConsidered = true;
- return *mAvailableRefreshRates.back();
+ return getMaxRefreshRateByPolicyLocked();
+ }
+
+ if (!touchActive && idle) {
+ return getMinRefreshRateByPolicyLocked();
+ }
+
+ if (layers.empty()) {
+ return getCurrentRefreshRateByPolicyLocked();
}
// Only if all layers want Min we should return Min
if (noVoteLayers + minVoteLayers == layers.size()) {
- return *mAvailableRefreshRates.front();
+ return getMinRefreshRateByPolicyLocked();
}
+ const Policy* policy = getCurrentPolicyLocked();
+
// Find the best refresh rate based on score
std::vector<std::pair<const RefreshRate*, float>> scores;
- scores.reserve(mAvailableRefreshRates.size());
+ scores.reserve(mAppRequestRefreshRates.size());
- for (const auto refreshRate : mAvailableRefreshRates) {
+ for (const auto refreshRate : mAppRequestRefreshRates) {
scores.emplace_back(refreshRate, 0.0f);
}
@@ -166,6 +167,15 @@
auto weight = layer.weight;
for (auto i = 0u; i < scores.size(); i++) {
+ bool inPrimaryRange =
+ scores[i].first->inPolicy(policy->primaryRange.min, policy->primaryRange.max);
+ if (!inPrimaryRange && layer.vote != LayerVoteType::ExplicitDefault &&
+ layer.vote != LayerVoteType::ExplicitExactOrMultiple) {
+ // Only layers with explicit frame rate settings are allowed to score refresh rates
+ // outside the primary range.
+ continue;
+ }
+
// If the layer wants Max, give higher score to the higher refresh rate
if (layer.vote == LayerVoteType::Max) {
const auto ratio = scores[i].first->fps / scores.back().first->fps;
@@ -249,6 +259,17 @@
? getBestRefreshRate(scores.rbegin(), scores.rend())
: getBestRefreshRate(scores.begin(), scores.end());
+ // Consider the touch event if there are no ExplicitDefault layers. ExplicitDefault are mostly
+ // interactive (as opposed to ExplicitExactOrMultiple) and therefore if those posted an explicit
+ // vote we should not change it if we get a touch event. Only apply touch boost if it will
+ // actually increase the refresh rate over the normal selection.
+ const RefreshRate& touchRefreshRate = getMaxRefreshRateByPolicyLocked();
+ if (touchActive && explicitDefaultVoteLayers == 0 &&
+ bestRefreshRate->fps < touchRefreshRate.fps) {
+ *touchConsidered = true;
+ return touchRefreshRate;
+ }
+
return *bestRefreshRate;
}
@@ -278,12 +299,20 @@
const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicy() const {
std::lock_guard lock(mLock);
- return *mAvailableRefreshRates.front();
+ return getMinRefreshRateByPolicyLocked();
+}
+
+const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicyLocked() const {
+ return *mPrimaryRefreshRates.front();
}
const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicy() const {
std::lock_guard lock(mLock);
- return *mAvailableRefreshRates.back();
+ return getMaxRefreshRateByPolicyLocked();
+}
+
+const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked() const {
+ return *mPrimaryRefreshRates.back();
}
const RefreshRate& RefreshRateConfigs::getCurrentRefreshRate() const {
@@ -297,8 +326,8 @@
}
const RefreshRate& RefreshRateConfigs::getCurrentRefreshRateByPolicyLocked() const {
- if (std::find(mAvailableRefreshRates.begin(), mAvailableRefreshRates.end(),
- mCurrentRefreshRate) != mAvailableRefreshRates.end()) {
+ if (std::find(mAppRequestRefreshRates.begin(), mAppRequestRefreshRates.end(),
+ mCurrentRefreshRate) != mAppRequestRefreshRates.end()) {
return *mCurrentRefreshRate;
}
return *mRefreshRates.at(getCurrentPolicyLocked()->defaultConfig);
@@ -320,7 +349,7 @@
const float fps = 1e9f / config->getVsyncPeriod();
mRefreshRates.emplace(configId,
std::make_unique<RefreshRate>(configId, config,
- base::StringPrintf("%2.ffps", fps), fps,
+ base::StringPrintf("%.0ffps", fps), fps,
RefreshRate::ConstructorTag(0)));
if (configId == currentConfigId) {
mCurrentRefreshRate = mRefreshRates.at(configId).get();
@@ -342,10 +371,11 @@
return false;
}
const RefreshRate& refreshRate = *iter->second;
- if (!refreshRate.inPolicy(policy.minRefreshRate, policy.maxRefreshRate)) {
+ if (!refreshRate.inPolicy(policy.primaryRange.min, policy.primaryRange.max)) {
return false;
}
- return true;
+ return policy.appRequestRange.min <= policy.primaryRange.min &&
+ policy.appRequestRange.max >= policy.primaryRange.max;
}
status_t RefreshRateConfigs::setDisplayManagerPolicy(const Policy& policy) {
@@ -392,7 +422,7 @@
bool RefreshRateConfigs::isConfigAllowed(HwcConfigIndexType config) const {
std::lock_guard lock(mLock);
- for (const RefreshRate* refreshRate : mAvailableRefreshRates) {
+ for (const RefreshRate* refreshRate : mAppRequestRefreshRates) {
if (refreshRate->configId == config) {
return true;
}
@@ -430,33 +460,44 @@
// Filter configs based on current policy and sort based on vsync period
const Policy* policy = getCurrentPolicyLocked();
const auto& defaultConfig = mRefreshRates.at(policy->defaultConfig)->hwcConfig;
- ALOGV("constructAvailableRefreshRates: default %d group %d min %.2f max %.2f",
- policy->defaultConfig.value(), defaultConfig->getConfigGroup(), policy->minRefreshRate,
- policy->maxRefreshRate);
- getSortedRefreshRateList(
- [&](const RefreshRate& refreshRate) REQUIRES(mLock) {
- const auto& hwcConfig = refreshRate.hwcConfig;
+ ALOGV("constructAvailableRefreshRates: default %d group %d primaryRange=[%.2f %.2f]"
+ " appRequestRange=[%.2f %.2f]",
+ policy->defaultConfig.value(), defaultConfig->getConfigGroup(), policy->primaryRange.min,
+ policy->primaryRange.max, policy->appRequestRange.min, policy->appRequestRange.max);
- return hwcConfig->getHeight() == defaultConfig->getHeight() &&
- hwcConfig->getWidth() == defaultConfig->getWidth() &&
- hwcConfig->getDpiX() == defaultConfig->getDpiX() &&
- hwcConfig->getDpiY() == defaultConfig->getDpiY() &&
- (policy->allowGroupSwitching ||
- hwcConfig->getConfigGroup() == defaultConfig->getConfigGroup()) &&
- refreshRate.inPolicy(policy->minRefreshRate, policy->maxRefreshRate);
- },
- &mAvailableRefreshRates);
+ auto filterRefreshRates = [&](float min, float max, const char* listName,
+ std::vector<const RefreshRate*>* outRefreshRates) {
+ getSortedRefreshRateList(
+ [&](const RefreshRate& refreshRate) REQUIRES(mLock) {
+ const auto& hwcConfig = refreshRate.hwcConfig;
- std::string availableRefreshRates;
- for (const auto& refreshRate : mAvailableRefreshRates) {
- base::StringAppendF(&availableRefreshRates, "%s ", refreshRate->name.c_str());
- }
+ return hwcConfig->getHeight() == defaultConfig->getHeight() &&
+ hwcConfig->getWidth() == defaultConfig->getWidth() &&
+ hwcConfig->getDpiX() == defaultConfig->getDpiX() &&
+ hwcConfig->getDpiY() == defaultConfig->getDpiY() &&
+ (policy->allowGroupSwitching ||
+ hwcConfig->getConfigGroup() == defaultConfig->getConfigGroup()) &&
+ refreshRate.inPolicy(min, max);
+ },
+ outRefreshRates);
- ALOGV("Available refresh rates: %s", availableRefreshRates.c_str());
- LOG_ALWAYS_FATAL_IF(mAvailableRefreshRates.empty(),
- "No compatible display configs for default=%d min=%.0f max=%.0f",
- policy->defaultConfig.value(), policy->minRefreshRate,
- policy->maxRefreshRate);
+ LOG_ALWAYS_FATAL_IF(outRefreshRates->empty(),
+ "No matching configs for %s range: min=%.0f max=%.0f", listName, min,
+ max);
+ auto stringifyRefreshRates = [&]() -> std::string {
+ std::string str;
+ for (auto refreshRate : *outRefreshRates) {
+ base::StringAppendF(&str, "%s ", refreshRate->name.c_str());
+ }
+ return str;
+ };
+ ALOGV("%s refresh rates: %s", listName, stringifyRefreshRates().c_str());
+ };
+
+ filterRefreshRates(policy->primaryRange.min, policy->primaryRange.max, "primary",
+ &mPrimaryRefreshRates);
+ filterRefreshRates(policy->appRequestRange.min, policy->appRequestRange.max, "app request",
+ &mAppRequestRefreshRates);
}
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index dea7e90..2657dee 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -107,18 +107,46 @@
std::unordered_map<HwcConfigIndexType, std::unique_ptr<const RefreshRate>>;
struct Policy {
+ struct Range {
+ float min = 0;
+ float max = std::numeric_limits<float>::max();
+
+ bool operator==(const Range& other) const {
+ return min == other.min && max == other.max;
+ }
+
+ bool operator!=(const Range& other) const { return !(*this == other); }
+ };
+
// The default config, used to ensure we only initiate display config switches within the
// same config group as defaultConfigId's group.
HwcConfigIndexType defaultConfig;
- // The min and max FPS allowed by the policy.
- float minRefreshRate = 0;
- float maxRefreshRate = std::numeric_limits<float>::max();
+ // The primary refresh rate range represents display manager's general guidance on the
+ // display configs we'll consider when switching refresh rates. Unless we get an explicit
+ // signal from an app, we should stay within this range.
+ Range primaryRange;
+ // The app request refresh rate range allows us to consider more display configs when
+ // switching refresh rates. Although we should generally stay within the primary range,
+ // specific considerations, such as layer frame rate settings specified via the
+ // setFrameRate() api, may cause us to go outside the primary range. We never go outside the
+ // app request range. The app request range will be greater than or equal to the primary
+ // refresh rate range, never smaller.
+ Range appRequestRange;
// Whether or not we switch config groups to get the best frame rate. Only used by tests.
bool allowGroupSwitching = false;
+ Policy() = default;
+ Policy(HwcConfigIndexType defaultConfig, const Range& range)
+ : Policy(defaultConfig, range, range) {}
+ Policy(HwcConfigIndexType defaultConfig, const Range& primaryRange,
+ const Range& appRequestRange)
+ : defaultConfig(defaultConfig),
+ primaryRange(primaryRange),
+ appRequestRange(appRequestRange) {}
+
bool operator==(const Policy& other) const {
- return defaultConfig == other.defaultConfig && minRefreshRate == other.minRefreshRate &&
- maxRefreshRate == other.maxRefreshRate &&
+ return defaultConfig == other.defaultConfig && primaryRange == other.primaryRange &&
+ appRequestRange == other.appRequestRange &&
allowGroupSwitching == other.allowGroupSwitching;
}
@@ -184,12 +212,14 @@
const RefreshRate& getRefreshRateForContent(const std::vector<LayerRequirement>& layers) const
EXCLUDES(mLock);
- // Returns the refresh rate that fits best to the given layers. This function also gets a
- // boolean flag that indicates whether user touched the screen recently to be factored in when
- // choosing the refresh rate and returns whether the refresh rate was chosen as a result of
- // a touch event.
- const RefreshRate& getRefreshRateForContentV2(const std::vector<LayerRequirement>& layers,
- bool touchActive, bool* touchConsidered) const
+ // Returns the refresh rate that fits best to the given layers.
+ // layers - The layer requirements to consider.
+ // touchActive - Whether the user touched the screen recently. Used to apply touch boost.
+ // idle - True if the system hasn't seen any buffers posted to layers recently.
+ // touchConsidered - An output param that tells the caller whether the refresh rate was chosen
+ // based on touch boost.
+ const RefreshRate& getBestRefreshRate(const std::vector<LayerRequirement>& layers,
+ bool touchActive, bool idle, bool* touchConsidered) const
EXCLUDES(mLock);
// Returns all the refresh rates supported by the device. This won't change at runtime.
@@ -198,13 +228,15 @@
// Returns the lowest refresh rate supported by the device. This won't change at runtime.
const RefreshRate& getMinRefreshRate() const { return *mMinSupportedRefreshRate; }
- // Returns the lowest refresh rate according to the current policy. May change in runtime.
+ // Returns the lowest refresh rate according to the current policy. May change at runtime. Only
+ // uses the primary range, not the app request range.
const RefreshRate& getMinRefreshRateByPolicy() const EXCLUDES(mLock);
// Returns the highest refresh rate supported by the device. This won't change at runtime.
const RefreshRate& getMaxRefreshRate() const { return *mMaxSupportedRefreshRate; }
- // Returns the highest refresh rate according to the current policy. May change in runtime.
+ // Returns the highest refresh rate according to the current policy. May change at runtime. Only
+ // uses the primary range, not the app request range.
const RefreshRate& getMaxRefreshRateByPolicy() const EXCLUDES(mLock);
// Returns the current refresh rate
@@ -243,6 +275,14 @@
// display refresh period.
std::pair<nsecs_t, nsecs_t> getDisplayFrames(nsecs_t layerPeriod, nsecs_t displayPeriod) const;
+ // Returns the lowest refresh rate according to the current policy. May change at runtime. Only
+ // uses the primary range, not the app request range.
+ const RefreshRate& getMinRefreshRateByPolicyLocked() const REQUIRES(mLock);
+
+ // Returns the highest refresh rate according to the current policy. May change at runtime. Only
+ // uses the primary range, not the app request range.
+ const RefreshRate& getMaxRefreshRateByPolicyLocked() const REQUIRES(mLock);
+
// Returns the current refresh rate, if allowed. Otherwise the default that is allowed by
// the policy.
const RefreshRate& getCurrentRefreshRateByPolicyLocked() const REQUIRES(mLock);
@@ -254,9 +294,13 @@
// object is initialized.
AllRefreshRatesMapType mRefreshRates;
- // The list of refresh rates which are available in the current policy, ordered by vsyncPeriod
- // (the first element is the lowest refresh rate)
- std::vector<const RefreshRate*> mAvailableRefreshRates GUARDED_BY(mLock);
+ // The list of refresh rates in the primary range of the current policy, ordered by vsyncPeriod
+ // (the first element is the lowest refresh rate).
+ std::vector<const RefreshRate*> mPrimaryRefreshRates GUARDED_BY(mLock);
+
+ // The list of refresh rates in the app request range of the current policy, ordered by
+ // vsyncPeriod (the first element is the lowest refresh rate).
+ std::vector<const RefreshRate*> mAppRequestRefreshRates GUARDED_BY(mLock);
// The current config. This will change at runtime. This is set by SurfaceFlinger on
// the main thread, and read by the Scheduler (and other objects) on other threads.
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 86bb6eb..d73fd8b 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -469,7 +469,7 @@
// that is currently on top. b/142507166 will give us this capability.
std::lock_guard<std::mutex> lock(mFeatureStateLock);
if (mLayerHistory) {
- // Layer History will be cleared based on RefreshRateConfigs::getRefreshRateForContentV2
+ // Layer History will be cleared based on RefreshRateConfigs::getBestRefreshRate
mTouchTimer->reset();
@@ -574,29 +574,28 @@
HwcConfigIndexType Scheduler::calculateRefreshRateConfigIndexType() {
ATRACE_CALL();
- // NOTE: If we remove the kernel idle timer, and use our internal idle timer, this
- // code will have to be refactored. If Display Power is not in normal operation we want to be in
- // performance mode. When coming back to normal mode, a grace period is given with
- // DisplayPowerTimer.
+ // If Display Power is not in normal operation we want to be in performance mode. When coming
+ // back to normal mode, a grace period is given with DisplayPowerTimer.
if (mDisplayPowerTimer &&
(!mFeatures.isDisplayPowerStateNormal ||
mFeatures.displayPowerTimer == TimerState::Reset)) {
return mRefreshRateConfigs.getMaxRefreshRateByPolicy().getConfigId();
}
+ const bool touchActive = mTouchTimer && mFeatures.touch == TouchState::Active;
+ const bool idle = mIdleTimer && mFeatures.idleTimer == TimerState::Expired;
+
if (!mUseContentDetectionV2) {
// As long as touch is active we want to be in performance mode.
- if (mTouchTimer && mFeatures.touch == TouchState::Active) {
+ if (touchActive) {
return mRefreshRateConfigs.getMaxRefreshRateByPolicy().getConfigId();
}
- }
- // If timer has expired as it means there is no new content on the screen.
- if (mIdleTimer && mFeatures.idleTimer == TimerState::Expired) {
- return mRefreshRateConfigs.getMinRefreshRateByPolicy().getConfigId();
- }
+ // If timer has expired as it means there is no new content on the screen.
+ if (idle) {
+ return mRefreshRateConfigs.getMinRefreshRateByPolicy().getConfigId();
+ }
- if (!mUseContentDetectionV2) {
// If content detection is off we choose performance as we don't know the content fps.
if (mFeatures.contentDetectionV1 == ContentDetectionState::Off) {
// NOTE: V1 always calls this, but this is not a default behavior for V2.
@@ -609,13 +608,10 @@
}
bool touchConsidered;
- const auto& ret =
- mRefreshRateConfigs
- .getRefreshRateForContentV2(mFeatures.contentRequirements,
- mTouchTimer &&
- mFeatures.touch == TouchState::Active,
- &touchConsidered)
- .getConfigId();
+ const auto& ret = mRefreshRateConfigs
+ .getBestRefreshRate(mFeatures.contentRequirements, touchActive, idle,
+ &touchConsidered)
+ .getConfigId();
if (touchConsidered) {
// Clear layer history if refresh rate was selected based on touch to allow
// the hueristic to pick up with the new rate.
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 3806343..4ca2074 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -108,6 +108,7 @@
#include "LayerVector.h"
#include "MonitoredProducer.h"
#include "NativeWindowSurface.h"
+#include "Promise.h"
#include "RefreshRateOverlay.h"
#include "RegionSamplingThread.h"
#include "Scheduler/DispSync.h"
@@ -410,15 +411,13 @@
useFrameRateApi = use_frame_rate_api(true);
}
-void SurfaceFlinger::onFirstRef()
-{
+SurfaceFlinger::~SurfaceFlinger() = default;
+
+void SurfaceFlinger::onFirstRef() {
mEventQueue->init(this);
}
-SurfaceFlinger::~SurfaceFlinger() = default;
-
-void SurfaceFlinger::binderDied(const wp<IBinder>& /* who */)
-{
+void SurfaceFlinger::binderDied(const wp<IBinder>&) {
// the window manager died on us. prepare its eulogy.
mBootFinished = false;
@@ -429,21 +428,25 @@
startBootAnim();
}
-static sp<ISurfaceComposerClient> initClient(const sp<Client>& client) {
- status_t err = client->initCheck();
- if (err == NO_ERROR) {
- return client;
+void SurfaceFlinger::run() {
+ while (true) {
+ mEventQueue->waitMessage();
}
- return nullptr;
+}
+
+template <typename F, typename T>
+inline std::future<T> SurfaceFlinger::schedule(F&& f) {
+ auto [task, future] = makeTask(std::move(f));
+ mEventQueue->postMessage(std::move(task));
+ return std::move(future);
}
sp<ISurfaceComposerClient> SurfaceFlinger::createConnection() {
- return initClient(new Client(this));
+ const sp<Client> client = new Client(this);
+ return client->initCheck() == NO_ERROR ? client : nullptr;
}
-sp<IBinder> SurfaceFlinger::createDisplay(const String8& displayName,
- bool secure)
-{
+sp<IBinder> SurfaceFlinger::createDisplay(const String8& displayName, bool secure) {
class DisplayToken : public BBinder {
sp<SurfaceFlinger> flinger;
virtual ~DisplayToken() {
@@ -579,7 +582,7 @@
LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM,
ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
- postMessageAsync(new LambdaMessage([this]() NO_THREAD_SAFETY_ANALYSIS {
+ static_cast<void>(schedule([this]() NO_THREAD_SAFETY_ANALYSIS {
readPersistentProperties();
mPowerAdvisor.onBootFinished();
mBootStage = BootStage::FINISHED;
@@ -607,9 +610,12 @@
// The pool was empty, so we need to get a new texture name directly using a
// blocking call to the main thread
- uint32_t name = 0;
- postMessageSync(new LambdaMessage([&]() { getRenderEngine().genTextures(1, &name); }));
- return name;
+ return schedule([this] {
+ uint32_t name = 0;
+ getRenderEngine().genTextures(1, &name);
+ return name;
+ })
+ .get();
}
void SurfaceFlinger::deleteTextureAsync(uint32_t texture) {
@@ -663,7 +669,7 @@
// mStateLock from the vr flinger dispatch thread might trigger a
// deadlock in surface flinger (see b/66916578), so post a message
// to be handled on the main thread instead.
- postMessageAsync(new LambdaMessage([=] {
+ static_cast<void>(schedule([=] {
ALOGI("VR request display mode: requestDisplay=%d", requestDisplay);
mVrFlingerRequestsDisplay = requestDisplay;
signalTransaction();
@@ -985,29 +991,26 @@
return BAD_VALUE;
}
- status_t result = NAME_NOT_FOUND;
-
- postMessageSync(new LambdaMessage([&]() {
+ auto future = schedule([=]() -> status_t {
const auto display = getDisplayDeviceLocked(displayToken);
if (!display) {
ALOGE("Attempt to set allowed display configs for invalid display token %p",
displayToken.get());
+ return NAME_NOT_FOUND;
} else if (display->isVirtual()) {
ALOGW("Attempt to set allowed display configs for virtual display");
- result = INVALID_OPERATION;
+ return INVALID_OPERATION;
} else {
- HwcConfigIndexType config(mode);
- const auto& refreshRate = mRefreshRateConfigs->getRefreshRateFromConfigId(config);
- result = setDesiredDisplayConfigSpecsInternal(display,
- scheduler::RefreshRateConfigs::
- Policy{config,
- refreshRate.getFps(),
- refreshRate.getFps()},
- /*overridePolicy=*/false);
- }
- }));
+ const HwcConfigIndexType config(mode);
+ const float fps = mRefreshRateConfigs->getRefreshRateFromConfigId(config).getFps();
+ const scheduler::RefreshRateConfigs::Policy policy{config, {fps, fps}};
+ constexpr bool kOverridePolicy = false;
- return result;
+ return setDesiredDisplayConfigSpecsInternal(display, policy, kOverridePolicy);
+ }
+ });
+
+ return future.get();
}
void SurfaceFlinger::setActiveConfigInternal() {
@@ -1181,7 +1184,7 @@
}
status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& displayToken, ColorMode mode) {
- postMessageSync(new LambdaMessage([&] {
+ schedule([=] {
Vector<ColorMode> modes;
getDisplayColorModes(displayToken, &modes);
bool exists = std::find(std::begin(modes), std::end(modes), mode) != std::end(modes);
@@ -1203,7 +1206,7 @@
RenderIntent::COLORIMETRIC,
Dataspace::UNKNOWN});
}
- }));
+ }).wait();
return NO_ERROR;
}
@@ -1227,7 +1230,7 @@
}
void SurfaceFlinger::setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on) {
- postMessageAsync(new LambdaMessage([=] {
+ static_cast<void>(schedule([=] {
if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
getHwComposer().setAutoLowLatencyMode(*displayId, on);
} else {
@@ -1258,7 +1261,7 @@
}
void SurfaceFlinger::setGameContentType(const sp<IBinder>& displayToken, bool on) {
- postMessageAsync(new LambdaMessage([=] {
+ static_cast<void>(schedule([=] {
if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
const auto type = on ? hal::ContentType::GAME : hal::ContentType::NONE;
getHwComposer().setContentType(*displayId, type);
@@ -1348,18 +1351,17 @@
status_t SurfaceFlinger::setDisplayContentSamplingEnabled(const sp<IBinder>& displayToken,
bool enable, uint8_t componentMask,
uint64_t maxFrames) {
- status_t result = NAME_NOT_FOUND;
-
- postMessageSync(new LambdaMessage([&] {
- if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
- result = getHwComposer().setDisplayContentSamplingEnabled(*displayId, enable,
- componentMask, maxFrames);
- } else {
- ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get());
- }
- }));
-
- return result;
+ return schedule([=]() -> status_t {
+ if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
+ return getHwComposer().setDisplayContentSamplingEnabled(*displayId, enable,
+ componentMask,
+ maxFrames);
+ } else {
+ ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get());
+ return NAME_NOT_FOUND;
+ }
+ })
+ .get();
}
status_t SurfaceFlinger::getDisplayedContentSample(const sp<IBinder>& displayToken,
@@ -1401,14 +1403,14 @@
}
status_t SurfaceFlinger::enableVSyncInjections(bool enable) {
- postMessageSync(new LambdaMessage([&] {
+ schedule([=] {
Mutex::Autolock lock(mStateLock);
if (const auto handle = mScheduler->enableVSyncInjection(enable)) {
mEventQueue->setEventConnection(
mScheduler->getEventConnection(enable ? handle : mSfConnectionHandle));
}
- }));
+ }).wait();
return NO_ERROR;
}
@@ -1490,17 +1492,16 @@
return BAD_VALUE;
}
- status_t result = NAME_NOT_FOUND;
-
- postMessageSync(new LambdaMessage([&] {
- if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
- result = getHwComposer().setDisplayBrightness(*displayId, brightness);
- } else {
- ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get());
- }
- }));
-
- return result;
+ return promise::chain(schedule([=] {
+ if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
+ return getHwComposer().setDisplayBrightness(*displayId, brightness);
+ } else {
+ ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get());
+ return promise::yield<status_t>(NAME_NOT_FOUND);
+ }
+ }))
+ .then([](std::future<status_t> task) { return task; })
+ .get();
}
status_t SurfaceFlinger::notifyPowerHint(int32_t hintId) {
@@ -1523,12 +1524,6 @@
return mScheduler->createDisplayEventConnection(handle, configChanged);
}
-// ----------------------------------------------------------------------------
-
-void SurfaceFlinger::waitForEvent() {
- mEventQueue->waitMessage();
-}
-
void SurfaceFlinger::signalTransaction() {
mScheduler->resetIdleTimer();
mPowerAdvisor.notifyDisplayUpdateImminent();
@@ -1546,26 +1541,6 @@
mEventQueue->refresh();
}
-status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg,
- nsecs_t reltime, uint32_t /* flags */) {
- return mEventQueue->postMessage(msg, reltime);
-}
-
-status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg,
- nsecs_t reltime, uint32_t /* flags */) {
- status_t res = mEventQueue->postMessage(msg, reltime);
- if (res == NO_ERROR) {
- msg->wait();
- }
- return res;
-}
-
-void SurfaceFlinger::run() {
- do {
- waitForEvent();
- } while (true);
-}
-
nsecs_t SurfaceFlinger::getVsyncPeriod() const {
const auto displayId = getInternalDisplayIdLocked();
if (!displayId || !getHwComposer().isConnected(*displayId)) {
@@ -1683,8 +1658,8 @@
// Enable / Disable HWVsync from the main thread to avoid race conditions with
// display power state.
- postMessageAsync(new LambdaMessage(
- [=]() NO_THREAD_SAFETY_ANALYSIS { setPrimaryVsyncEnabledInternal(enabled); }));
+ static_cast<void>(
+ schedule([=]() NO_THREAD_SAFETY_ANALYSIS { setPrimaryVsyncEnabledInternal(enabled); }));
}
void SurfaceFlinger::setPrimaryVsyncEnabledInternal(bool enabled) {
@@ -1809,11 +1784,10 @@
return false;
}
- if (graceTimeMs > 0 && fence->getStatus() == Fence::Status::Unsignaled) {
- fence->wait(graceTimeMs);
- }
-
- return (fence->getStatus() == Fence::Status::Unsignaled);
+ const status_t status = fence->wait(graceTimeMs);
+ // This is the same as Fence::Status::Unsignaled, but it saves a getStatus() call,
+ // which calls wait(0) again internally
+ return status == -ETIME;
}
nsecs_t SurfaceFlinger::previousFramePresentTime() NO_THREAD_SAFETY_ANALYSIS {
@@ -1839,184 +1813,188 @@
ATRACE_CALL();
switch (what) {
case MessageQueue::INVALIDATE: {
- const nsecs_t frameStart = systemTime();
- // calculate the expected present time once and use the cached
- // value throughout this frame to make sure all layers are
- // seeing this same value.
- const nsecs_t lastExpectedPresentTime = mExpectedPresentTime.load();
- mExpectedPresentTime = expectedVSyncTime;
-
- // When Backpressure propagation is enabled we want to give a small grace period
- // for the present fence to fire instead of just giving up on this frame to handle cases
- // where present fence is just about to get signaled.
- const int graceTimeForPresentFenceMs =
- (mPropagateBackpressure &&
- (mPropagateBackpressureClientComposition || !mHadClientComposition))
- ? 1
- : 0;
-
- // Pending frames may trigger backpressure propagation.
- const TracedOrdinal<bool> framePending = {"PrevFramePending",
- previousFramePending(
- graceTimeForPresentFenceMs)};
-
- // Frame missed counts for metrics tracking.
- // A frame is missed if the prior frame is still pending. If no longer pending,
- // then we still count the frame as missed if the predicted present time
- // was further in the past than when the fence actually fired.
-
- // Add some slop to correct for drift. This should generally be
- // smaller than a typical frame duration, but should not be so small
- // that it reports reasonable drift as a missed frame.
- DisplayStatInfo stats;
- mScheduler->getDisplayStatInfo(&stats);
- const nsecs_t frameMissedSlop = stats.vsyncPeriod / 2;
- const nsecs_t previousPresentTime = previousFramePresentTime();
- const TracedOrdinal<bool> frameMissed =
- {"PrevFrameMissed",
- framePending ||
- (previousPresentTime >= 0 &&
- (lastExpectedPresentTime < previousPresentTime - frameMissedSlop))};
- const TracedOrdinal<bool> hwcFrameMissed = {"PrevHwcFrameMissed",
- mHadDeviceComposition && frameMissed};
- const TracedOrdinal<bool> gpuFrameMissed = {"PrevGpuFrameMissed",
- mHadClientComposition && frameMissed};
-
- if (frameMissed) {
- mFrameMissedCount++;
- mTimeStats->incrementMissedFrames();
- if (mMissedFrameJankCount == 0) {
- mMissedFrameJankStart = systemTime();
- }
- mMissedFrameJankCount++;
- }
-
- if (hwcFrameMissed) {
- mHwcFrameMissedCount++;
- }
-
- if (gpuFrameMissed) {
- mGpuFrameMissedCount++;
- }
-
- // If we are in the middle of a config change and the fence hasn't
- // fired yet just wait for the next invalidate
- if (mSetActiveConfigPending) {
- if (framePending) {
- mEventQueue->invalidate();
- break;
- }
-
- // We received the present fence from the HWC, so we assume it successfully updated
- // the config, hence we update SF.
- mSetActiveConfigPending = false;
- setActiveConfigInternal();
- }
-
- if (framePending && mPropagateBackpressure) {
- if ((hwcFrameMissed && !gpuFrameMissed) ||
- mPropagateBackpressureClientComposition) {
- signalLayerUpdate();
- break;
- }
- }
-
- // Our jank window is always at least 100ms since we missed a
- // frame...
- static constexpr nsecs_t kMinJankyDuration =
- std::chrono::duration_cast<std::chrono::nanoseconds>(100ms).count();
- // ...but if it's larger than 1s then we missed the trace cutoff.
- static constexpr nsecs_t kMaxJankyDuration =
- std::chrono::duration_cast<std::chrono::nanoseconds>(1s).count();
- // If we're in a user build then don't push any atoms
- if (!mIsUserBuild && mMissedFrameJankCount > 0) {
- const auto displayDevice = getDefaultDisplayDeviceLocked();
- // Only report jank when the display is on, as displays in DOZE
- // power mode may operate at a different frame rate than is
- // reported in their config, which causes noticeable (but less
- // severe) jank.
- if (displayDevice && displayDevice->getPowerMode() == hal::PowerMode::ON) {
- const nsecs_t currentTime = systemTime();
- const nsecs_t jankDuration = currentTime - mMissedFrameJankStart;
- if (jankDuration > kMinJankyDuration && jankDuration < kMaxJankyDuration) {
- ATRACE_NAME("Jank detected");
- ALOGD("Detected janky event. Missed frames: %d", mMissedFrameJankCount);
- const int32_t jankyDurationMillis = jankDuration / (1000 * 1000);
- android::util::stats_write(android::util::DISPLAY_JANK_REPORTED,
- jankyDurationMillis, mMissedFrameJankCount);
- }
-
- // We either reported a jank event or we missed the trace
- // window, so clear counters here.
- if (jankDuration > kMinJankyDuration) {
- mMissedFrameJankCount = 0;
- mMissedFrameJankStart = 0;
- }
- }
- }
-
- // Now that we're going to make it to the handleMessageTransaction()
- // call below it's safe to call updateVrFlinger(), which will
- // potentially trigger a display handoff.
- updateVrFlinger();
-
- if (mTracingEnabledChanged) {
- mTracingEnabled = mTracing.isEnabled();
- mTracingEnabledChanged = false;
- }
-
- bool refreshNeeded;
- {
- ConditionalLockGuard<std::mutex> lock(mTracingLock, mTracingEnabled);
-
- refreshNeeded = handleMessageTransaction();
- refreshNeeded |= handleMessageInvalidate();
- if (mTracingEnabled) {
- mAddCompositionStateToTrace =
- mTracing.flagIsSetLocked(SurfaceTracing::TRACE_COMPOSITION);
- if (mVisibleRegionsDirty && !mAddCompositionStateToTrace) {
- mTracing.notifyLocked("visibleRegionsDirty");
- }
- }
- }
-
- // Layers need to get updated (in the previous line) before we can use them for
- // choosing the refresh rate.
- // Hold mStateLock as chooseRefreshRateForContent promotes wp<Layer> to sp<Layer>
- // and may eventually call to ~Layer() if it holds the last reference
- {
- Mutex::Autolock _l(mStateLock);
- mScheduler->chooseRefreshRateForContent();
- }
-
- performSetActiveConfig();
-
- updateCursorAsync();
- updateInputFlinger();
-
- refreshNeeded |= mRepaintEverything;
- if (refreshNeeded && CC_LIKELY(mBootStage != BootStage::BOOTLOADER)) {
- // Signal a refresh if a transaction modified the window state,
- // a new buffer was latched, or if HWC has requested a full
- // repaint
- if (mFrameStartTime <= 0) {
- // We should only use the time of the first invalidate
- // message that signals a refresh as the beginning of the
- // frame. Otherwise the real frame time will be
- // underestimated.
- mFrameStartTime = frameStart;
- }
- signalRefresh();
- }
+ onMessageInvalidate(expectedVSyncTime);
break;
}
case MessageQueue::REFRESH: {
- handleMessageRefresh();
+ onMessageRefresh();
break;
}
}
}
+void SurfaceFlinger::onMessageInvalidate(nsecs_t expectedVSyncTime) NO_THREAD_SAFETY_ANALYSIS {
+ ATRACE_CALL();
+
+ const nsecs_t frameStart = systemTime();
+ // calculate the expected present time once and use the cached
+ // value throughout this frame to make sure all layers are
+ // seeing this same value.
+ const nsecs_t lastExpectedPresentTime = mExpectedPresentTime.load();
+ mExpectedPresentTime = expectedVSyncTime;
+
+ // When Backpressure propagation is enabled we want to give a small grace period
+ // for the present fence to fire instead of just giving up on this frame to handle cases
+ // where present fence is just about to get signaled.
+ const int graceTimeForPresentFenceMs =
+ (mPropagateBackpressure &&
+ (mPropagateBackpressureClientComposition || !mHadClientComposition))
+ ? 1
+ : 0;
+
+ // Pending frames may trigger backpressure propagation.
+ const TracedOrdinal<bool> framePending = {"PrevFramePending",
+ previousFramePending(graceTimeForPresentFenceMs)};
+
+ // Frame missed counts for metrics tracking.
+ // A frame is missed if the prior frame is still pending. If no longer pending,
+ // then we still count the frame as missed if the predicted present time
+ // was further in the past than when the fence actually fired.
+
+ // Add some slop to correct for drift. This should generally be
+ // smaller than a typical frame duration, but should not be so small
+ // that it reports reasonable drift as a missed frame.
+ DisplayStatInfo stats;
+ mScheduler->getDisplayStatInfo(&stats);
+ const nsecs_t frameMissedSlop = stats.vsyncPeriod / 2;
+ const nsecs_t previousPresentTime = previousFramePresentTime();
+ const TracedOrdinal<bool> frameMissed = {"PrevFrameMissed",
+ framePending ||
+ (previousPresentTime >= 0 &&
+ (lastExpectedPresentTime <
+ previousPresentTime - frameMissedSlop))};
+ const TracedOrdinal<bool> hwcFrameMissed = {"PrevHwcFrameMissed",
+ mHadDeviceComposition && frameMissed};
+ const TracedOrdinal<bool> gpuFrameMissed = {"PrevGpuFrameMissed",
+ mHadClientComposition && frameMissed};
+
+ if (frameMissed) {
+ mFrameMissedCount++;
+ mTimeStats->incrementMissedFrames();
+ if (mMissedFrameJankCount == 0) {
+ mMissedFrameJankStart = systemTime();
+ }
+ mMissedFrameJankCount++;
+ }
+
+ if (hwcFrameMissed) {
+ mHwcFrameMissedCount++;
+ }
+
+ if (gpuFrameMissed) {
+ mGpuFrameMissedCount++;
+ }
+
+ // If we are in the middle of a config change and the fence hasn't
+ // fired yet just wait for the next invalidate
+ if (mSetActiveConfigPending) {
+ if (framePending) {
+ mEventQueue->invalidate();
+ return;
+ }
+
+ // We received the present fence from the HWC, so we assume it successfully updated
+ // the config, hence we update SF.
+ mSetActiveConfigPending = false;
+ setActiveConfigInternal();
+ }
+
+ if (framePending && mPropagateBackpressure) {
+ if ((hwcFrameMissed && !gpuFrameMissed) || mPropagateBackpressureClientComposition) {
+ signalLayerUpdate();
+ return;
+ }
+ }
+
+ // Our jank window is always at least 100ms since we missed a
+ // frame...
+ static constexpr nsecs_t kMinJankyDuration =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(100ms).count();
+ // ...but if it's larger than 1s then we missed the trace cutoff.
+ static constexpr nsecs_t kMaxJankyDuration =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(1s).count();
+ // If we're in a user build then don't push any atoms
+ if (!mIsUserBuild && mMissedFrameJankCount > 0) {
+ const auto displayDevice = getDefaultDisplayDeviceLocked();
+ // Only report jank when the display is on, as displays in DOZE
+ // power mode may operate at a different frame rate than is
+ // reported in their config, which causes noticeable (but less
+ // severe) jank.
+ if (displayDevice && displayDevice->getPowerMode() == hal::PowerMode::ON) {
+ const nsecs_t currentTime = systemTime();
+ const nsecs_t jankDuration = currentTime - mMissedFrameJankStart;
+ if (jankDuration > kMinJankyDuration && jankDuration < kMaxJankyDuration) {
+ ATRACE_NAME("Jank detected");
+ ALOGD("Detected janky event. Missed frames: %d", mMissedFrameJankCount);
+ const int32_t jankyDurationMillis = jankDuration / (1000 * 1000);
+ android::util::stats_write(android::util::DISPLAY_JANK_REPORTED,
+ jankyDurationMillis, mMissedFrameJankCount);
+ }
+
+ // We either reported a jank event or we missed the trace
+ // window, so clear counters here.
+ if (jankDuration > kMinJankyDuration) {
+ mMissedFrameJankCount = 0;
+ mMissedFrameJankStart = 0;
+ }
+ }
+ }
+
+ // Now that we're going to make it to the handleMessageTransaction()
+ // call below it's safe to call updateVrFlinger(), which will
+ // potentially trigger a display handoff.
+ updateVrFlinger();
+
+ if (mTracingEnabledChanged) {
+ mTracingEnabled = mTracing.isEnabled();
+ mTracingEnabledChanged = false;
+ }
+
+ bool refreshNeeded;
+ {
+ ConditionalLockGuard<std::mutex> lock(mTracingLock, mTracingEnabled);
+
+ refreshNeeded = handleMessageTransaction();
+ refreshNeeded |= handleMessageInvalidate();
+ if (mTracingEnabled) {
+ mAddCompositionStateToTrace =
+ mTracing.flagIsSetLocked(SurfaceTracing::TRACE_COMPOSITION);
+ if (mVisibleRegionsDirty && !mAddCompositionStateToTrace) {
+ mTracing.notifyLocked("visibleRegionsDirty");
+ }
+ }
+ }
+
+ // Layers need to get updated (in the previous line) before we can use them for
+ // choosing the refresh rate.
+ // Hold mStateLock as chooseRefreshRateForContent promotes wp<Layer> to sp<Layer>
+ // and may eventually call to ~Layer() if it holds the last reference
+ {
+ Mutex::Autolock _l(mStateLock);
+ mScheduler->chooseRefreshRateForContent();
+ }
+
+ performSetActiveConfig();
+
+ updateCursorAsync();
+ updateInputFlinger();
+
+ refreshNeeded |= mRepaintEverything;
+ if (refreshNeeded && CC_LIKELY(mBootStage != BootStage::BOOTLOADER)) {
+ // Signal a refresh if a transaction modified the window state,
+ // a new buffer was latched, or if HWC has requested a full
+ // repaint
+ if (mFrameStartTime <= 0) {
+ // We should only use the time of the first invalidate
+ // message that signals a refresh as the beginning of the
+ // frame. Otherwise the real frame time will be
+ // underestimated.
+ mFrameStartTime = frameStart;
+ }
+ signalRefresh();
+ }
+}
+
bool SurfaceFlinger::handleMessageTransaction() {
ATRACE_CALL();
uint32_t transactionFlags = peekTransactionFlags();
@@ -2039,7 +2017,7 @@
return runHandleTransaction;
}
-void SurfaceFlinger::handleMessageRefresh() {
+void SurfaceFlinger::onMessageRefresh() {
ATRACE_CALL();
mRefreshPending = false;
@@ -2137,7 +2115,6 @@
}
}
-
bool SurfaceFlinger::handleMessageInvalidate() {
ATRACE_CALL();
bool refreshNeeded = handlePageFlip();
@@ -3210,6 +3187,13 @@
return NO_ERROR;
}
+void SurfaceFlinger::removeGraphicBufferProducerAsync(const wp<IBinder>& binder) {
+ static_cast<void>(schedule([=] {
+ Mutex::Autolock lock(mStateLock);
+ mGraphicBufferProducerList.erase(binder);
+ }));
+}
+
uint32_t SurfaceFlinger::peekTransactionFlags() {
return mTransactionFlags;
}
@@ -3436,18 +3420,26 @@
: Scheduler::TransactionStart::NORMAL;
setTransactionFlags(transactionFlags, start);
- // if this is a synchronous transaction, wait for it to take effect
- // before returning.
- if (flags & eSynchronous) {
- mTransactionPending = true;
- }
if (flags & eAnimation) {
mAnimTransactionPending = true;
}
- if (mPendingInputWindowCommands.syncInputWindows) {
+
+ // if this is a synchronous transaction, wait for it to take effect
+ // before returning.
+ const bool synchronous = flags & eSynchronous;
+ const bool syncInput = inputWindowCommands.syncInputWindows;
+ if (!synchronous && !syncInput) {
+ return;
+ }
+
+ if (synchronous) {
+ mTransactionPending = true;
+ }
+ if (syncInput) {
mPendingSyncInputWindows = true;
}
+
// applyTransactionState can be called by either the main SF thread or by
// another process through setTransactionState. While a given process may wish
// to wait on synchronous transactions, the main SF thread should never
@@ -4133,8 +4125,7 @@
void SurfaceFlinger::initializeDisplays() {
// Async since we may be called from the main thread.
- postMessageAsync(
- new LambdaMessage([this]() NO_THREAD_SAFETY_ANALYSIS { onInitializeDisplays(); }));
+ static_cast<void>(schedule([this]() NO_THREAD_SAFETY_ANALYSIS { onInitializeDisplays(); }));
}
void SurfaceFlinger::setVsyncEnabledInHWC(DisplayId displayId, hal::Vsync enabled) {
@@ -4225,7 +4216,7 @@
}
void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) {
- postMessageSync(new LambdaMessage([&]() NO_THREAD_SAFETY_ANALYSIS {
+ schedule([=]() NO_THREAD_SAFETY_ANALYSIS {
const auto display = getDisplayDeviceLocked(displayToken);
if (!display) {
ALOGE("Attempt to set power mode %d for invalid display token %p", mode,
@@ -4235,11 +4226,9 @@
} else {
setPowerModeInternal(display, static_cast<hal::PowerMode>(mode));
}
- }));
+ }).wait();
}
-// ---------------------------------------------------------------------------
-
status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args,
bool asProto) NO_THREAD_SAFETY_ANALYSIS {
std::string result;
@@ -4394,17 +4383,19 @@
scheduler::RefreshRateConfigs::Policy policy = mRefreshRateConfigs->getDisplayManagerPolicy();
StringAppendF(&result,
"DesiredDisplayConfigSpecs (DisplayManager): default config ID: %d"
- ", min: %.2f Hz, max: %.2f Hz",
- policy.defaultConfig.value(), policy.minRefreshRate, policy.maxRefreshRate);
+ ", primary range: [%.2f %.2f], app request range: [%.2f %.2f]\n\n",
+ policy.defaultConfig.value(), policy.primaryRange.min, policy.primaryRange.max,
+ policy.appRequestRange.min, policy.appRequestRange.max);
StringAppendF(&result, "(config override by backdoor: %s)\n\n",
mDebugDisplayConfigSetByBackdoor ? "yes" : "no");
scheduler::RefreshRateConfigs::Policy currentPolicy = mRefreshRateConfigs->getCurrentPolicy();
if (currentPolicy != policy) {
StringAppendF(&result,
"DesiredDisplayConfigSpecs (Override): default config ID: %d"
- ", min: %.2f Hz, max: %.2f Hz\n\n",
- currentPolicy.defaultConfig.value(), currentPolicy.minRefreshRate,
- currentPolicy.maxRefreshRate);
+ ", primary range: [%.2f %.2f], app request range: [%.2f %.2f]\n\n",
+ currentPolicy.defaultConfig.value(), currentPolicy.primaryRange.min,
+ currentPolicy.primaryRange.max, currentPolicy.appRequestRange.min,
+ currentPolicy.appRequestRange.max);
}
mScheduler->dump(mAppConnectionHandle, result);
@@ -4600,20 +4591,21 @@
}
LayersProto SurfaceFlinger::dumpProtoFromMainThread(uint32_t traceFlags) {
- LayersProto layersProto;
- postMessageSync(new LambdaMessage([&] { layersProto = dumpDrawingStateProto(traceFlags); }));
- return layersProto;
+ return schedule([=] { return dumpDrawingStateProto(traceFlags); }).get();
}
void SurfaceFlinger::dumpOffscreenLayers(std::string& result) {
result.append("Offscreen Layers:\n");
- postMessageSync(new LambdaMessage([&]() {
- for (Layer* offscreenLayer : mOffscreenLayers) {
- offscreenLayer->traverse(LayerVector::StateSet::Drawing, [&](Layer* layer) {
- layer->dumpCallingUidPid(result);
- });
- }
- }));
+ result.append(schedule([this] {
+ std::string result;
+ for (Layer* offscreenLayer : mOffscreenLayers) {
+ offscreenLayer->traverse(LayerVector::StateSet::Drawing,
+ [&](Layer* layer) {
+ layer->dumpCallingUidPid(result);
+ });
+ }
+ return result;
+ }).get());
}
void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) const {
@@ -5296,7 +5288,7 @@
// Update the overlay on the main thread to avoid race conditions with
// mRefreshRateConfigs->getCurrentRefreshRate()
- postMessageAsync(new LambdaMessage([this, expired]() NO_THREAD_SAFETY_ANALYSIS {
+ static_cast<void>(schedule([=]() NO_THREAD_SAFETY_ANALYSIS {
if (mRefreshRateOverlay) {
const auto kernelTimerEnabled = property_get_bool(KERNEL_IDLE_TIMER_PROP, false);
const bool timerExpired = kernelTimerEnabled && expired;
@@ -5680,60 +5672,33 @@
const sp<GraphicBuffer>& buffer,
bool useIdentityTransform, bool regionSampling,
bool& outCapturedSecureLayers) {
- // This mutex protects syncFd and captureResult for communication of the return values from the
- // main thread back to this Binder thread
- std::mutex captureMutex;
- std::condition_variable captureCondition;
- std::unique_lock<std::mutex> captureLock(captureMutex);
- int syncFd = -1;
- std::optional<status_t> captureResult;
-
const int uid = IPCThreadState::self()->getCallingUid();
const bool forSystem = uid == AID_GRAPHICS || uid == AID_SYSTEM;
- sp<LambdaMessage> message = new LambdaMessage([&] {
- // If there is a refresh pending, bug out early and tell the binder thread to try again
- // after the refresh.
- if (mRefreshPending) {
- ATRACE_NAME("Skipping screenshot for now");
- std::unique_lock<std::mutex> captureLock(captureMutex);
- captureResult = std::make_optional<status_t>(EAGAIN);
- captureCondition.notify_one();
- return;
- }
+ status_t result;
+ int syncFd;
- status_t result = NO_ERROR;
- int fd = -1;
- {
- Mutex::Autolock _l(mStateLock);
- renderArea.render([&] {
- result = captureScreenImplLocked(renderArea, traverseLayers, buffer.get(),
- useIdentityTransform, forSystem, &fd,
- regionSampling, outCapturedSecureLayers);
- });
- }
+ do {
+ std::tie(result, syncFd) =
+ schedule([&] {
+ if (mRefreshPending) {
+ ATRACE_NAME("Skipping screenshot for now");
+ return std::make_pair(EAGAIN, -1);
+ }
- {
- std::unique_lock<std::mutex> captureLock(captureMutex);
- syncFd = fd;
- captureResult = std::make_optional<status_t>(result);
- captureCondition.notify_one();
- }
- });
+ status_t result = NO_ERROR;
+ int fd = -1;
- status_t result = postMessageAsync(message);
- if (result == NO_ERROR) {
- captureCondition.wait(captureLock, [&] { return captureResult; });
- while (*captureResult == EAGAIN) {
- captureResult.reset();
- result = postMessageAsync(message);
- if (result != NO_ERROR) {
- return result;
- }
- captureCondition.wait(captureLock, [&] { return captureResult; });
- }
- result = *captureResult;
- }
+ Mutex::Autolock lock(mStateLock);
+ renderArea.render([&] {
+ result = captureScreenImplLocked(renderArea, traverseLayers, buffer.get(),
+ useIdentityTransform, forSystem, &fd,
+ regionSampling, outCapturedSecureLayers);
+ });
+
+ return std::make_pair(result, fd);
+ }).get();
+ } while (result == EAGAIN);
if (result == NO_ERROR) {
sync_wait(syncFd, -1);
@@ -5965,9 +5930,11 @@
}
scheduler::RefreshRateConfigs::Policy currentPolicy = mRefreshRateConfigs->getCurrentPolicy();
- ALOGV("Setting desired display config specs: defaultConfig: %d min: %.f max: %.f",
- currentPolicy.defaultConfig.value(), currentPolicy.minRefreshRate,
- currentPolicy.maxRefreshRate);
+ ALOGV("Setting desired display config specs: defaultConfig: %d primaryRange: [%.0f %.0f]"
+ " expandedRange: [%.0f %.0f]",
+ currentPolicy.defaultConfig.value(), currentPolicy.primaryRange.min,
+ currentPolicy.primaryRange.max, currentPolicy.appRequestRange.min,
+ currentPolicy.appRequestRange.max);
// TODO(b/140204874): This hack triggers a notification that something has changed, so
// that listeners that care about a change in allowed configs can get the notification.
@@ -6000,45 +5967,50 @@
}
status_t SurfaceFlinger::setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t defaultConfig, float minRefreshRate,
- float maxRefreshRate) {
+ int32_t defaultConfig,
+ float primaryRefreshRateMin,
+ float primaryRefreshRateMax,
+ float appRequestRefreshRateMin,
+ float appRequestRefreshRateMax) {
ATRACE_CALL();
if (!displayToken) {
return BAD_VALUE;
}
- status_t result = NAME_NOT_FOUND;
-
- postMessageSync(new LambdaMessage([&]() {
+ auto future = schedule([=]() -> status_t {
const auto display = getDisplayDeviceLocked(displayToken);
if (!display) {
ALOGE("Attempt to set desired display configs for invalid display token %p",
displayToken.get());
+ return NAME_NOT_FOUND;
} else if (display->isVirtual()) {
ALOGW("Attempt to set desired display configs for virtual display");
- result = INVALID_OPERATION;
+ return INVALID_OPERATION;
} else {
- result = setDesiredDisplayConfigSpecsInternal(display,
- scheduler::RefreshRateConfigs::
- Policy{HwcConfigIndexType(
- defaultConfig),
- minRefreshRate,
- maxRefreshRate},
- /*overridePolicy=*/false);
- }
- }));
+ using Policy = scheduler::RefreshRateConfigs::Policy;
+ const Policy policy{HwcConfigIndexType(defaultConfig),
+ {primaryRefreshRateMin, primaryRefreshRateMax},
+ {appRequestRefreshRateMin, appRequestRefreshRateMax}};
+ constexpr bool kOverridePolicy = false;
- return result;
+ return setDesiredDisplayConfigSpecsInternal(display, policy, kOverridePolicy);
+ }
+ });
+
+ return future.get();
}
status_t SurfaceFlinger::getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
int32_t* outDefaultConfig,
- float* outMinRefreshRate,
- float* outMaxRefreshRate) {
+ float* outPrimaryRefreshRateMin,
+ float* outPrimaryRefreshRateMax,
+ float* outAppRequestRefreshRateMin,
+ float* outAppRequestRefreshRateMax) {
ATRACE_CALL();
- if (!displayToken || !outDefaultConfig || !outMinRefreshRate || !outMaxRefreshRate) {
+ if (!displayToken || !outDefaultConfig || !outPrimaryRefreshRateMin ||
+ !outPrimaryRefreshRateMax || !outAppRequestRefreshRateMin || !outAppRequestRefreshRateMax) {
return BAD_VALUE;
}
@@ -6052,8 +6024,10 @@
scheduler::RefreshRateConfigs::Policy policy =
mRefreshRateConfigs->getDisplayManagerPolicy();
*outDefaultConfig = policy.defaultConfig.value();
- *outMinRefreshRate = policy.minRefreshRate;
- *outMaxRefreshRate = policy.maxRefreshRate;
+ *outPrimaryRefreshRateMin = policy.primaryRange.min;
+ *outPrimaryRefreshRateMax = policy.primaryRange.max;
+ *outAppRequestRefreshRateMin = policy.appRequestRange.min;
+ *outAppRequestRefreshRateMax = policy.appRequestRange.max;
return NO_ERROR;
} else if (display->isVirtual()) {
return INVALID_OPERATION;
@@ -6063,8 +6037,10 @@
*outDefaultConfig = getHwComposer().getActiveConfigIndex(*displayId);
auto vsyncPeriod = getHwComposer().getActiveConfig(*displayId)->getVsyncPeriod();
- *outMinRefreshRate = 1e9f / vsyncPeriod;
- *outMaxRefreshRate = 1e9f / vsyncPeriod;
+ *outPrimaryRefreshRateMin = 1e9f / vsyncPeriod;
+ *outPrimaryRefreshRateMax = 1e9f / vsyncPeriod;
+ *outAppRequestRefreshRateMin = 1e9f / vsyncPeriod;
+ *outAppRequestRefreshRateMax = 1e9f / vsyncPeriod;
return NO_ERROR;
}
}
@@ -6158,7 +6134,7 @@
return BAD_VALUE;
}
- postMessageAsync(new LambdaMessage([=]() NO_THREAD_SAFETY_ANALYSIS {
+ static_cast<void>(schedule([=]() NO_THREAD_SAFETY_ANALYSIS {
Mutex::Autolock lock(mStateLock);
if (authenticateSurfaceTextureLocked(surface)) {
sp<Layer> layer = (static_cast<MonitoredProducer*>(surface.get()))->getLayer();
@@ -6181,8 +6157,11 @@
if (!outToken) {
return BAD_VALUE;
}
- status_t result = NO_ERROR;
- postMessageSync(new LambdaMessage([&]() {
+
+ auto future = schedule([this] {
+ status_t result = NO_ERROR;
+ sp<IBinder> token;
+
if (mFrameRateFlexibilityTokenCount == 0) {
// |mStateLock| not needed as we are on the main thread
const auto display = getDefaultDisplayDeviceLocked();
@@ -6196,8 +6175,8 @@
overridePolicy.defaultConfig =
mRefreshRateConfigs->getDisplayManagerPolicy().defaultConfig;
overridePolicy.allowGroupSwitching = true;
- result = setDesiredDisplayConfigSpecsInternal(display, overridePolicy,
- /*overridePolicy=*/true);
+ constexpr bool kOverridePolicy = true;
+ result = setDesiredDisplayConfigSpecsInternal(display, overridePolicy, kOverridePolicy);
}
if (result == NO_ERROR) {
@@ -6214,17 +6193,22 @@
// 2. The frame rate flexibility token is acquired/released only by CTS tests, so even
// if condition 1 were changed, the problem would only show up when running CTS tests,
// not on end user devices, so we could spot it and fix it without serious impact.
- *outToken = new FrameRateFlexibilityToken(
+ token = new FrameRateFlexibilityToken(
[this]() { onFrameRateFlexibilityTokenReleased(); });
ALOGD("Frame rate flexibility token acquired. count=%d",
mFrameRateFlexibilityTokenCount);
}
- }));
+
+ return std::make_pair(result, token);
+ });
+
+ status_t result;
+ std::tie(result, *outToken) = future.get();
return result;
}
void SurfaceFlinger::onFrameRateFlexibilityTokenReleased() {
- postMessageAsync(new LambdaMessage([&]() {
+ static_cast<void>(schedule([this] {
LOG_ALWAYS_FATAL_IF(mFrameRateFlexibilityTokenCount == 0,
"Failed tracking frame rate flexibility tokens");
mFrameRateFlexibilityTokenCount--;
@@ -6232,8 +6216,8 @@
if (mFrameRateFlexibilityTokenCount == 0) {
// |mStateLock| not needed as we are on the main thread
const auto display = getDefaultDisplayDeviceLocked();
- status_t result =
- setDesiredDisplayConfigSpecsInternal(display, {}, /*overridePolicy=*/true);
+ constexpr bool kOverridePolicy = true;
+ status_t result = setDesiredDisplayConfigSpecsInternal(display, {}, kOverridePolicy);
LOG_ALWAYS_FATAL_IF(result < 0, "Failed releasing frame rate flexibility token");
}
}));
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index eb269b4..f3984ed 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -68,6 +68,7 @@
#include <atomic>
#include <cstdint>
#include <functional>
+#include <future>
#include <map>
#include <memory>
#include <mutex>
@@ -276,12 +277,9 @@
// starts SurfaceFlinger main loop in the current thread
void run() ANDROID_API;
- // post an asynchronous message to the main thread
- status_t postMessageAsync(const sp<MessageBase>& msg, nsecs_t reltime = 0, uint32_t flags = 0);
-
- // post a synchronous message to the main thread
- status_t postMessageSync(const sp<MessageBase>& msg, nsecs_t reltime = 0, uint32_t flags = 0)
- EXCLUDES(mStateLock);
+ // Schedule an asynchronous or synchronous task on the main thread.
+ template <typename F, typename T = std::invoke_result_t<F>>
+ [[nodiscard]] std::future<T> schedule(F&&);
// force full composition on all displays
void repaintEverything();
@@ -495,10 +493,15 @@
const sp<IRegionSamplingListener>& listener) override;
status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) override;
status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken, int32_t displayModeId,
- float minRefreshRate, float maxRefreshRate) override;
+ float primaryRefreshRateMin, float primaryRefreshRateMax,
+ float appRequestRefreshRateMin,
+ float appRequestRefreshRateMax) override;
status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t* outDefaultConfig, float* outMinRefreshRate,
- float* outMaxRefreshRate) override;
+ int32_t* outDefaultConfig,
+ float* outPrimaryRefreshRateMin,
+ float* outPrimaryRefreshRateMax,
+ float* outAppRequestRefreshRateMin,
+ float* outAppRequestRefreshRateMax) override;
status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
bool* outSupport) const override;
status_t setDisplayBrightness(const sp<IBinder>& displayToken, float brightness) override;
@@ -542,7 +545,6 @@
/* ------------------------------------------------------------------------
* Message handling
*/
- void waitForEvent();
// Can only be called from the main thread or with mStateLock held
void signalTransaction();
// Can only be called from the main thread or with mStateLock held
@@ -583,14 +585,20 @@
const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy)
EXCLUDES(mStateLock);
+ // Handle the INVALIDATE message queue event, latching new buffers and applying
+ // incoming transactions
+ void onMessageInvalidate(nsecs_t expectedVSyncTime);
+
// Returns whether the transaction actually modified any state
bool handleMessageTransaction();
+ // Handle the REFRESH message queue event, sending the current frame down to RenderEngine and
+ // the Composer HAL for presentation
+ void onMessageRefresh();
+
// Returns whether a new buffer has been latched (see handlePageFlip())
bool handleMessageInvalidate();
- void handleMessageRefresh();
-
void handleTransaction(uint32_t transactionFlags);
void handleTransactionLocked(uint32_t transactionFlags) REQUIRES(mStateLock);
@@ -999,6 +1007,8 @@
std::set<wp<IBinder>> mGraphicBufferProducerList;
size_t mMaxGraphicBufferProducerListSize = ISurfaceComposer::MAX_LAYERS;
+ void removeGraphicBufferProducerAsync(const wp<IBinder>&);
+
// protected by mStateLock (but we could use another lock)
bool mLayersRemoved = false;
bool mLayersAdded = false;
diff --git a/services/surfaceflinger/TracedOrdinal.h b/services/surfaceflinger/TracedOrdinal.h
index c145a39..4e7f67d 100644
--- a/services/surfaceflinger/TracedOrdinal.h
+++ b/services/surfaceflinger/TracedOrdinal.h
@@ -16,10 +16,13 @@
#pragma once
#include <android-base/stringprintf.h>
+#include <cutils/compiler.h>
#include <utils/Trace.h>
#include <cmath>
#include <string>
+namespace android {
+
template <typename T>
class TracedOrdinal {
public:
@@ -27,9 +30,8 @@
"Type is not supported. Please test it with systrace before adding "
"it to the list.");
- TracedOrdinal(const std::string& name, T initialValue)
- : mName(name),
- mNameNegative(android::base::StringPrintf("%sNegative", name.c_str())),
+ TracedOrdinal(std::string name, T initialValue)
+ : mName(std::move(name)),
mHasGoneNegative(std::signbit(initialValue)),
mData(initialValue) {
trace();
@@ -46,6 +48,14 @@
private:
void trace() {
+ if (CC_LIKELY(!ATRACE_ENABLED())) {
+ return;
+ }
+
+ if (mNameNegative.empty()) {
+ mNameNegative = base::StringPrintf("%sNegative", mName.c_str());
+ }
+
if (!std::signbit(mData)) {
ATRACE_INT64(mName.c_str(), int64_t(mData));
if (mHasGoneNegative) {
@@ -58,7 +68,9 @@
}
const std::string mName;
- const std::string mNameNegative;
+ std::string mNameNegative;
bool mHasGoneNegative;
T mData;
};
+
+} // namespace android
diff --git a/services/surfaceflinger/surfaceflinger.rc b/services/surfaceflinger/surfaceflinger.rc
index d3942e8..575e70d 100644
--- a/services/surfaceflinger/surfaceflinger.rc
+++ b/services/surfaceflinger/surfaceflinger.rc
@@ -4,7 +4,7 @@
group graphics drmrpc readproc
capabilities SYS_NICE
onrestart restart zygote
- writepid /dev/stune/foreground/tasks
+ task_profiles HighPerformance
socket pdx/system/vr/display/client stream 0666 system graphics u:object_r:pdx_display_client_endpoint_socket:s0
socket pdx/system/vr/display/manager stream 0666 system graphics u:object_r:pdx_display_manager_endpoint_socket:s0
socket pdx/system/vr/display/vsync stream 0666 system graphics u:object_r:pdx_display_vsync_endpoint_socket:s0
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index 507d28b..c136708 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -215,14 +215,21 @@
TEST_F(CredentialsTest, SetDesiredDisplayConfigsTest) {
const auto display = SurfaceComposerClient::getInternalDisplayToken();
int32_t defaultConfig;
- float minFps;
- float maxFps;
- status_t res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(display, &defaultConfig,
- &minFps, &maxFps);
+ float primaryFpsMin;
+ float primaryFpsMax;
+ float appRequestFpsMin;
+ float appRequestFpsMax;
+ status_t res =
+ SurfaceComposerClient::getDesiredDisplayConfigSpecs(display, &defaultConfig,
+ &primaryFpsMin, &primaryFpsMax,
+ &appRequestFpsMin,
+ &appRequestFpsMax);
ASSERT_EQ(res, NO_ERROR);
std::function<status_t()> condition = [=]() {
- return SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, defaultConfig, minFps,
- maxFps);
+ return SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, defaultConfig,
+ primaryFpsMin, primaryFpsMax,
+ appRequestFpsMin,
+ appRequestFpsMax);
};
ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
}
diff --git a/services/surfaceflinger/tests/DisplayConfigs_test.cpp b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
index 0ed2ffb..debfe83 100644
--- a/services/surfaceflinger/tests/DisplayConfigs_test.cpp
+++ b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
@@ -39,11 +39,16 @@
TEST_F(RefreshRateRangeTest, setAllConfigs) {
int32_t initialDefaultConfig;
- float initialMin;
- float initialMax;
+ float initialPrimaryMin;
+ float initialPrimaryMax;
+ float initialAppRequestMin;
+ float initialAppRequestMax;
status_t res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken,
&initialDefaultConfig,
- &initialMin, &initialMax);
+ &initialPrimaryMin,
+ &initialPrimaryMax,
+ &initialAppRequestMin,
+ &initialAppRequestMax);
ASSERT_EQ(res, NO_ERROR);
Vector<DisplayConfig> configs;
@@ -53,22 +58,33 @@
for (size_t i = 0; i < configs.size(); i++) {
res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, i,
configs[i].refreshRate,
+ configs[i].refreshRate,
+ configs[i].refreshRate,
configs[i].refreshRate);
ASSERT_EQ(res, NO_ERROR);
int defaultConfig;
- float minRefreshRate;
- float maxRefreshRate;
+ float primaryRefreshRateMin;
+ float primaryRefreshRateMax;
+ float appRequestRefreshRateMin;
+ float appRequestRefreshRateMax;
res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken, &defaultConfig,
- &minRefreshRate, &maxRefreshRate);
+ &primaryRefreshRateMin,
+ &primaryRefreshRateMax,
+ &appRequestRefreshRateMin,
+ &appRequestRefreshRateMax);
ASSERT_EQ(res, NO_ERROR);
ASSERT_EQ(defaultConfig, i);
- ASSERT_EQ(minRefreshRate, configs[i].refreshRate);
- ASSERT_EQ(maxRefreshRate, configs[i].refreshRate);
+ ASSERT_EQ(primaryRefreshRateMin, configs[i].refreshRate);
+ ASSERT_EQ(primaryRefreshRateMax, configs[i].refreshRate);
+ ASSERT_EQ(appRequestRefreshRateMin, configs[i].refreshRate);
+ ASSERT_EQ(appRequestRefreshRateMax, configs[i].refreshRate);
}
res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, initialDefaultConfig,
- initialMin, initialMax);
+ initialPrimaryMin, initialPrimaryMax,
+ initialAppRequestMin,
+ initialAppRequestMax);
ASSERT_EQ(res, NO_ERROR);
}
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 32c58ad..a03fd89 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -443,6 +443,8 @@
EXPECT_EQ(NO_ERROR,
SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
config.refreshRate,
+ config.refreshRate,
+ config.refreshRate,
config.refreshRate));
waitForDisplayTransaction();
EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
@@ -547,6 +549,8 @@
EXPECT_EQ(NO_ERROR,
SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
config.refreshRate,
+ config.refreshRate,
+ config.refreshRate,
config.refreshRate));
waitForDisplayTransaction();
EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
@@ -659,9 +663,11 @@
const auto& config = configs[i];
if (config.resolution.getWidth() == 800 && config.refreshRate == 1e9f / 11'111'111) {
EXPECT_EQ(NO_ERROR,
- SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
- configs[i].refreshRate,
- configs[i].refreshRate));
+ SurfaceComposerClient::
+ setDesiredDisplayConfigSpecs(display, i, configs[i].refreshRate,
+ configs[i].refreshRate,
+ configs[i].refreshRate,
+ configs[i].refreshRate));
waitForDisplayTransaction();
EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
break;
@@ -706,6 +712,8 @@
EXPECT_EQ(NO_ERROR,
SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
config.refreshRate,
+ config.refreshRate,
+ config.refreshRate,
config.refreshRate));
waitForDisplayTransaction();
EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
@@ -751,6 +759,8 @@
EXPECT_EQ(NO_ERROR,
SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
config.refreshRate,
+ config.refreshRate,
+ config.refreshRate,
config.refreshRate));
waitForDisplayTransaction();
EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 2f2fb20..7574ff1 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -48,6 +48,7 @@
"LayerHistoryTestV2.cpp",
"LayerMetadataTest.cpp",
"PhaseOffsetsTest.cpp",
+ "PromiseTest.cpp",
"SchedulerTest.cpp",
"SchedulerUtilsTest.cpp",
"SetFrameRateTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index e0dd0d9..8713b2b 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -542,7 +542,7 @@
EXPECT_CALL(*test->mMessageQueue, invalidate()).Times(1);
enqueueBuffer(test, layer);
- Mock::VerifyAndClear(test->mMessageQueue);
+ Mock::VerifyAndClearExpectations(test->mMessageQueue);
EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
bool ignoredRecomputeVisibleRegions;
@@ -834,7 +834,7 @@
struct BaseLayerVariant {
template <typename L, typename F>
static sp<L> createLayerWithFactory(CompositionTest* test, F factory) {
- EXPECT_CALL(*test->mMessageQueue, postMessage(_, 0)).Times(0);
+ EXPECT_CALL(*test->mMessageQueue, postMessage(_)).Times(0);
sp<L> layer = factory();
@@ -843,7 +843,7 @@
Mock::VerifyAndClear(test->mComposer);
Mock::VerifyAndClear(test->mRenderEngine);
- Mock::VerifyAndClear(test->mMessageQueue);
+ Mock::VerifyAndClearExpectations(test->mMessageQueue);
auto& layerDrawingState = test->mFlinger.mutableLayerDrawingState(layer);
layerDrawingState.layerStack = DEFAULT_LAYER_STACK;
@@ -944,7 +944,7 @@
}
static void cleanupInjectedLayers(CompositionTest* test) {
- EXPECT_CALL(*test->mMessageQueue, postMessage(_, 0)).Times(1);
+ EXPECT_CALL(*test->mMessageQueue, postMessage(_)).Times(1);
Base::cleanupInjectedLayers(test);
}
diff --git a/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp b/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp
index ce5993a..0b74682 100644
--- a/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp
@@ -145,7 +145,9 @@
class TestablePhaseOffsets : public impl::PhaseOffsets {
public:
- TestablePhaseOffsets() : impl::PhaseOffsets({60.0f, 90.0f}, 60.0f, 10'000'000) {}
+ TestablePhaseOffsets()
+ : impl::PhaseOffsets({60.0f, 90.0f}, 60.0f, 1'000'000, 1'000'000, {}, {}, {}, {},
+ 10'000'000) {}
};
class PhaseOffsetsTest : public testing::Test {
diff --git a/services/surfaceflinger/tests/unittests/PromiseTest.cpp b/services/surfaceflinger/tests/unittests/PromiseTest.cpp
new file mode 100644
index 0000000..e4dc1fe
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/PromiseTest.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <algorithm>
+#include <future>
+#include <string>
+#include <thread>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "Promise.h"
+
+namespace android {
+namespace {
+
+using Bytes = std::vector<uint8_t>;
+
+Bytes decrement(Bytes bytes) {
+ std::transform(bytes.begin(), bytes.end(), bytes.begin(), [](auto b) { return b - 1; });
+ return bytes;
+}
+
+} // namespace
+
+TEST(PromiseTest, yield) {
+ EXPECT_EQ(42, promise::yield(42).get());
+
+ auto ptr = std::make_unique<char>('!');
+ auto future = promise::yield(std::move(ptr));
+ EXPECT_EQ('!', *future.get());
+}
+
+TEST(PromiseTest, chain) {
+ std::packaged_task<const char*()> fetchString([] { return "ifmmp-"; });
+
+ std::packaged_task<Bytes(std::string)> appendString([](std::string str) {
+ str += "!xpsme";
+ return Bytes{str.begin(), str.end()};
+ });
+
+ std::packaged_task<std::future<Bytes>(Bytes)> decrementBytes(
+ [](Bytes bytes) { return promise::defer(decrement, std::move(bytes)); });
+
+ auto fetch = fetchString.get_future();
+ std::thread fetchThread(std::move(fetchString));
+
+ std::thread appendThread, decrementThread;
+
+ EXPECT_EQ("hello, world",
+ promise::chain(std::move(fetch))
+ .then([](const char* str) { return std::string(str); })
+ .then([&](std::string str) {
+ auto append = appendString.get_future();
+ appendThread = std::thread(std::move(appendString), std::move(str));
+ return append;
+ })
+ .then([&](Bytes bytes) {
+ auto decrement = decrementBytes.get_future();
+ decrementThread = std::thread(std::move(decrementBytes),
+ std::move(bytes));
+ return decrement;
+ })
+ .then([](std::future<Bytes> bytes) { return bytes; })
+ .then([](const Bytes& bytes) {
+ return std::string(bytes.begin(), bytes.end());
+ })
+ .get());
+
+ fetchThread.join();
+ appendThread.join();
+ decrementThread.join();
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 2ceb89c..2b168b2 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -166,8 +166,8 @@
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m60OnlyConfigDevice,
/*currentConfigId=*/HWC_CONFIG_ID_60);
- ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HwcConfigIndexType(10), 60, 60}), 0);
- ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 20, 40}), 0);
+ ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HwcConfigIndexType(10), {60, 60}}), 0);
+ ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {20, 40}}), 0);
}
TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap) {
@@ -201,7 +201,7 @@
ASSERT_EQ(mExpected60Config, minRate60);
ASSERT_EQ(mExpected60Config, performanceRate60);
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 60, 90}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {60, 90}}), 0);
refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
const auto& minRate90 = refreshRateConfigs->getMinRefreshRateByPolicy();
@@ -226,7 +226,7 @@
ASSERT_EQ(mExpected60Config, minRate60);
ASSERT_EQ(mExpected60Config, performanceRate60);
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 60, 90}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {60, 90}}), 0);
refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
const auto& minRate90 = refreshRateConfigs->getMinRefreshRateByPolicy();
@@ -248,7 +248,7 @@
ASSERT_EQ(mExpected60Config, minRate);
ASSERT_EQ(mExpected90Config, performanceRate);
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 60, 60}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 60}}), 0);
auto& minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy();
auto& performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy();
@@ -271,7 +271,7 @@
EXPECT_EQ(current.getConfigId(), HWC_CONFIG_ID_90);
}
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 90, 90}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90, 90}}), 0);
{
auto& current = refreshRateConfigs->getCurrentRefreshRate();
EXPECT_EQ(current.getConfigId(), HWC_CONFIG_ID_90);
@@ -298,7 +298,7 @@
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f)));
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 60, 60}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 60}}), 0);
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f)));
EXPECT_EQ(mExpected60Config,
@@ -310,7 +310,7 @@
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f)));
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 90, 90}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90, 90}}), 0);
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f)));
EXPECT_EQ(mExpected90Config,
@@ -321,7 +321,7 @@
refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(30.0f)));
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f)));
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 0, 120}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {0, 120}}), 0);
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f)));
EXPECT_EQ(mExpected60Config,
@@ -334,7 +334,7 @@
refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f)));
}
-TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_noLayers) {
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_noLayers) {
bool ignored;
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m60_72_90Device, /*currentConfigId=*/
@@ -344,17 +344,17 @@
// refresh rate.
auto layers = std::vector<LayerRequirement>{};
EXPECT_EQ(mExpected72Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/
- false, &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/
+ false, /*idle*/ false, &ignored));
// Current refresh rate can always be changed.
refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_60);
EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/
- false, &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/
+ false, /*idle*/ false, &ignored));
}
-TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_60_90) {
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_60_90) {
bool ignored;
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m60_90Device,
@@ -366,162 +366,162 @@
lr.vote = LayerVoteType::Min;
lr.name = "Min";
EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.vote = LayerVoteType::Max;
lr.name = "Max";
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 90.0f;
lr.vote = LayerVoteType::Heuristic;
lr.name = "90Hz Heuristic";
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 60.0f;
lr.name = "60Hz Heuristic";
EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 45.0f;
lr.name = "45Hz Heuristic";
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 30.0f;
lr.name = "30Hz Heuristic";
EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 24.0f;
lr.name = "24Hz Heuristic";
EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.name = "";
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 60, 60}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 60}}), 0);
lr.vote = LayerVoteType::Min;
EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.vote = LayerVoteType::Max;
EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 90.0f;
lr.vote = LayerVoteType::Heuristic;
EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 60.0f;
EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 45.0f;
EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 30.0f;
EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 24.0f;
EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 90, 90}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90, 90}}), 0);
lr.vote = LayerVoteType::Min;
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.vote = LayerVoteType::Max;
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 90.0f;
lr.vote = LayerVoteType::Heuristic;
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 60.0f;
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 45.0f;
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 30.0f;
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 24.0f;
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 0, 120}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {0, 120}}), 0);
lr.vote = LayerVoteType::Min;
EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.vote = LayerVoteType::Max;
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 90.0f;
lr.vote = LayerVoteType::Heuristic;
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 60.0f;
EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 45.0f;
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 30.0f;
EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 24.0f;
EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
}
-TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_60_72_90) {
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_60_72_90) {
bool ignored;
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m60_72_90Device,
@@ -532,42 +532,42 @@
lr.vote = LayerVoteType::Min;
EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.vote = LayerVoteType::Max;
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 90.0f;
lr.vote = LayerVoteType::Heuristic;
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 60.0f;
EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 45.0f;
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 30.0f;
EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 24.0f;
EXPECT_EQ(mExpected72Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
}
-TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60_72_90_120) {
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_72_90_120) {
bool ignored;
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device,
@@ -583,27 +583,27 @@
lr2.desiredRefreshRate = 60.0f;
lr2.vote = LayerVoteType::Heuristic;
EXPECT_EQ(mExpected120Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr1.desiredRefreshRate = 24.0f;
lr1.vote = LayerVoteType::Heuristic;
lr2.desiredRefreshRate = 48.0f;
lr2.vote = LayerVoteType::Heuristic;
EXPECT_EQ(mExpected72Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr1.desiredRefreshRate = 24.0f;
lr1.vote = LayerVoteType::Heuristic;
lr2.desiredRefreshRate = 48.0f;
lr2.vote = LayerVoteType::Heuristic;
EXPECT_EQ(mExpected72Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
}
-TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60_90_120_DifferentTypes) {
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes) {
bool ignored;
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device,
@@ -621,8 +621,8 @@
lr2.vote = LayerVoteType::Heuristic;
lr2.name = "60Hz Heuristic";
EXPECT_EQ(mExpected120Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr1.desiredRefreshRate = 24.0f;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -631,8 +631,8 @@
lr2.vote = LayerVoteType::Heuristic;
lr2.name = "60Hz Heuristic";
EXPECT_EQ(mExpected120Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr1.desiredRefreshRate = 24.0f;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -641,8 +641,8 @@
lr2.vote = LayerVoteType::ExplicitDefault;
lr2.name = "60Hz ExplicitDefault";
EXPECT_EQ(mExpected120Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr1.desiredRefreshRate = 24.0f;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -651,8 +651,8 @@
lr2.vote = LayerVoteType::Heuristic;
lr2.name = "90Hz Heuristic";
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr1.desiredRefreshRate = 24.0f;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -661,8 +661,8 @@
lr2.vote = LayerVoteType::ExplicitDefault;
lr2.name = "90Hz Heuristic";
EXPECT_EQ(mExpected72Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr1.desiredRefreshRate = 24.0f;
lr1.vote = LayerVoteType::ExplicitDefault;
@@ -671,8 +671,8 @@
lr2.vote = LayerVoteType::Heuristic;
lr2.name = "90Hz Heuristic";
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr1.desiredRefreshRate = 24.0f;
lr1.vote = LayerVoteType::Heuristic;
@@ -681,8 +681,8 @@
lr2.vote = LayerVoteType::ExplicitDefault;
lr2.name = "90Hz ExplicitDefault";
EXPECT_EQ(mExpected72Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr1.desiredRefreshRate = 24.0f;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -691,8 +691,8 @@
lr2.vote = LayerVoteType::ExplicitDefault;
lr2.name = "90Hz ExplicitDefault";
EXPECT_EQ(mExpected72Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr1.desiredRefreshRate = 24.0f;
lr1.vote = LayerVoteType::ExplicitDefault;
@@ -701,11 +701,11 @@
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.name = "90Hz ExplicitExactOrMultiple";
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
}
-TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60) {
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60) {
bool ignored;
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m30_60Device,
@@ -716,42 +716,42 @@
lr.vote = LayerVoteType::Min;
EXPECT_EQ(mExpected30Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.vote = LayerVoteType::Max;
EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 90.0f;
lr.vote = LayerVoteType::Heuristic;
EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 60.0f;
EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 45.0f;
EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 30.0f;
EXPECT_EQ(mExpected30Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 24.0f;
EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
}
-TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60_72_90) {
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_72_90) {
bool ignored;
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m30_60_72_90Device,
@@ -763,70 +763,70 @@
lr.vote = LayerVoteType::Min;
lr.name = "Min";
EXPECT_EQ(mExpected30Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.vote = LayerVoteType::Max;
lr.name = "Max";
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 90.0f;
lr.vote = LayerVoteType::Heuristic;
lr.name = "90Hz Heuristic";
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 60.0f;
lr.name = "60Hz Heuristic";
EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ true,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 45.0f;
lr.name = "45Hz Heuristic";
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ true,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 30.0f;
lr.name = "30Hz Heuristic";
EXPECT_EQ(mExpected30Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ true,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 24.0f;
lr.name = "24Hz Heuristic";
EXPECT_EQ(mExpected72Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ true,
+ /*idle*/ false, &ignored));
lr.desiredRefreshRate = 24.0f;
lr.vote = LayerVoteType::ExplicitExactOrMultiple;
lr.name = "24Hz ExplicitExactOrMultiple";
EXPECT_EQ(mExpected72Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ true,
+ /*idle*/ false, &ignored));
}
-TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_PriorityTest) {
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_PriorityTest) {
bool ignored;
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m30_60_90Device,
@@ -840,55 +840,55 @@
lr1.vote = LayerVoteType::Min;
lr2.vote = LayerVoteType::Max;
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr1.vote = LayerVoteType::Min;
lr2.vote = LayerVoteType::Heuristic;
lr2.desiredRefreshRate = 24.0f;
EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr1.vote = LayerVoteType::Min;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 24.0f;
EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr1.vote = LayerVoteType::Max;
lr2.vote = LayerVoteType::Heuristic;
lr2.desiredRefreshRate = 60.0f;
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr1.vote = LayerVoteType::Max;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 60.0f;
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr1.vote = LayerVoteType::Heuristic;
lr1.desiredRefreshRate = 15.0f;
lr2.vote = LayerVoteType::Heuristic;
lr2.desiredRefreshRate = 45.0f;
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr1.vote = LayerVoteType::Heuristic;
lr1.desiredRefreshRate = 30.0f;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 45.0f;
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
}
-TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_24FpsVideo) {
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_24FpsVideo) {
bool ignored;
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m60_90Device,
@@ -901,8 +901,8 @@
for (float fps = 23.0f; fps < 25.0f; fps += 0.1f) {
lr.desiredRefreshRate = fps;
const auto& refreshRate =
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored);
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored);
printf("%.2fHz chooses %s\n", fps, refreshRate.getName().c_str());
EXPECT_EQ(mExpected60Config, refreshRate);
}
@@ -931,7 +931,7 @@
EXPECT_EQ(mExpected60Config, refreshRateConfigs->getRefreshRateForContent(layers));
}
-TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_Explicit) {
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getBestRefreshRate_Explicit) {
bool ignored;
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m60_90Device,
@@ -947,24 +947,24 @@
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 90.0f;
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr1.vote = LayerVoteType::ExplicitDefault;
lr1.desiredRefreshRate = 90.0f;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 60.0f;
EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr1.vote = LayerVoteType::Heuristic;
lr1.desiredRefreshRate = 90.0f;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 60.0f;
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
}
TEST_F(RefreshRateConfigsTest, testInPolicy) {
@@ -975,7 +975,7 @@
ASSERT_FALSE(mExpectedAlmost60Config.inPolicy(50.0f, 59.998f));
}
-TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_75HzContent) {
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_75HzContent) {
bool ignored;
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m60_90Device,
@@ -988,14 +988,14 @@
for (float fps = 75.0f; fps < 100.0f; fps += 0.1f) {
lr.desiredRefreshRate = fps;
const auto& refreshRate =
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored);
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored);
printf("%.2fHz chooses %s\n", fps, refreshRate.getName().c_str());
EXPECT_EQ(mExpected90Config, refreshRate);
}
}
-TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_Multiples) {
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_Multiples) {
bool ignored;
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m60_90Device,
@@ -1013,8 +1013,8 @@
lr2.desiredRefreshRate = 90.0f;
lr2.name = "90Hz Heuristic";
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.desiredRefreshRate = 60.0f;
@@ -1023,8 +1023,8 @@
lr2.desiredRefreshRate = 90.0f;
lr2.name = "90Hz ExplicitDefault";
EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.desiredRefreshRate = 60.0f;
@@ -1032,8 +1032,8 @@
lr2.vote = LayerVoteType::Max;
lr2.name = "Max";
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.desiredRefreshRate = 30.0f;
@@ -1042,8 +1042,8 @@
lr2.desiredRefreshRate = 90.0f;
lr2.name = "90Hz Heuristic";
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.desiredRefreshRate = 30.0f;
@@ -1051,8 +1051,8 @@
lr2.vote = LayerVoteType::Max;
lr2.name = "Max";
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
- &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, /*touchActive*/ false,
+ /*idle*/ false, &ignored));
}
TEST_F(RefreshRateConfigsTest, scrollWhileWatching60fps_60_90) {
@@ -1072,7 +1072,7 @@
lr2.vote = LayerVoteType::NoVote;
lr2.name = "NoVote";
EXPECT_EQ(mExpected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, false, &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, false, /*idle*/ false, &ignored));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.desiredRefreshRate = 60.0f;
@@ -1080,7 +1080,7 @@
lr2.vote = LayerVoteType::NoVote;
lr2.name = "NoVote";
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, true, &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, true, /*idle*/ false, &ignored));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.desiredRefreshRate = 60.0f;
@@ -1088,7 +1088,7 @@
lr2.vote = LayerVoteType::Max;
lr2.name = "Max";
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, true, &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, true, /*idle*/ false, &ignored));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.desiredRefreshRate = 60.0f;
@@ -1096,7 +1096,7 @@
lr2.vote = LayerVoteType::Max;
lr2.name = "Max";
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, false, &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, false, /*idle*/ false, &ignored));
// The other layer starts to provide buffers
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -1106,7 +1106,7 @@
lr2.desiredRefreshRate = 90.0f;
lr2.name = "90Hz Heuristic";
EXPECT_EQ(mExpected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, false, &ignored));
+ refreshRateConfigs->getBestRefreshRate(layers, false, /*idle*/ false, &ignored));
}
TEST_F(RefreshRateConfigsTest, touchConsidered) {
@@ -1115,10 +1115,10 @@
std::make_unique<RefreshRateConfigs>(m60_90Device,
/*currentConfigId=*/HWC_CONFIG_ID_60);
- refreshRateConfigs->getRefreshRateForContentV2({}, false, &touchConsidered);
+ refreshRateConfigs->getBestRefreshRate({}, false, /*idle*/ false, &touchConsidered);
EXPECT_EQ(false, touchConsidered);
- refreshRateConfigs->getRefreshRateForContentV2({}, true, &touchConsidered);
+ refreshRateConfigs->getBestRefreshRate({}, true, /*idle*/ false, &touchConsidered);
EXPECT_EQ(true, touchConsidered);
auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
@@ -1130,36 +1130,40 @@
lr1.desiredRefreshRate = 60.0f;
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Heuristic;
- lr2.name = "NoVote";
- refreshRateConfigs->getRefreshRateForContentV2(layers, true, &touchConsidered);
+ lr2.desiredRefreshRate = 60.0f;
+ lr2.name = "60Hz Heuristic";
+ refreshRateConfigs->getBestRefreshRate(layers, true, /*idle*/ false, &touchConsidered);
EXPECT_EQ(true, touchConsidered);
lr1.vote = LayerVoteType::ExplicitDefault;
lr1.desiredRefreshRate = 60.0f;
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Heuristic;
- lr2.name = "NoVote";
- refreshRateConfigs->getRefreshRateForContentV2(layers, true, &touchConsidered);
+ lr2.desiredRefreshRate = 60.0f;
+ lr2.name = "60Hz Heuristic";
+ refreshRateConfigs->getBestRefreshRate(layers, true, /*idle*/ false, &touchConsidered);
EXPECT_EQ(false, touchConsidered);
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.desiredRefreshRate = 60.0f;
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Heuristic;
- lr2.name = "NoVote";
- refreshRateConfigs->getRefreshRateForContentV2(layers, true, &touchConsidered);
+ lr2.desiredRefreshRate = 60.0f;
+ lr2.name = "60Hz Heuristic";
+ refreshRateConfigs->getBestRefreshRate(layers, true, /*idle*/ false, &touchConsidered);
EXPECT_EQ(true, touchConsidered);
lr1.vote = LayerVoteType::ExplicitDefault;
lr1.desiredRefreshRate = 60.0f;
- lr1.name = "60Hz ExplicitExactrMultiple";
+ lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Heuristic;
- lr2.name = "NoVote";
- refreshRateConfigs->getRefreshRateForContentV2(layers, true, &touchConsidered);
+ lr2.desiredRefreshRate = 60.0f;
+ lr2.name = "60Hz Heuristic";
+ refreshRateConfigs->getBestRefreshRate(layers, true, /*idle*/ false, &touchConsidered);
EXPECT_EQ(false, touchConsidered);
}
-TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_ExplicitDefault) {
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitDefault) {
bool ignored;
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m60_90_72_120Device, /*currentConfigId=*/
@@ -1196,7 +1200,7 @@
lr.name = ss.str();
const auto& refreshRate =
- refreshRateConfigs->getRefreshRateForContentV2(layers, false, &ignored);
+ refreshRateConfigs->getBestRefreshRate(layers, false, /*idle*/ false, &ignored);
EXPECT_FLOAT_EQ(refreshRate.getFps(), test.second)
<< "Expecting " << test.first << "fps => " << test.second << "Hz";
}
@@ -1215,7 +1219,8 @@
bool touchConsidered;
ASSERT_EQ(HWC_CONFIG_ID_60,
- refreshRateConfigs->getRefreshRateForContentV2(layers, false, &touchConsidered)
+ refreshRateConfigs
+ ->getBestRefreshRate(layers, false, /*idle*/ false, &touchConsidered)
.getConfigId());
RefreshRateConfigs::Policy policy;
@@ -1223,7 +1228,117 @@
policy.allowGroupSwitching = true;
ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(policy), 0);
ASSERT_EQ(HWC_CONFIG_ID_90,
- refreshRateConfigs->getRefreshRateForContentV2(layers, false, &touchConsidered)
+ refreshRateConfigs
+ ->getBestRefreshRate(layers, false, /*idle*/ false, &touchConsidered)
+ .getConfigId());
+}
+
+TEST_F(RefreshRateConfigsTest, primaryVsAppRequestPolicy) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_90Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ layers[0].name = "Test layer";
+
+ // Return the config ID from calling getBestRefreshRate() for a single layer with the
+ // given voteType and fps.
+ auto getFrameRate = [&](LayerVoteType voteType, float fps,
+ bool touchActive = false) -> HwcConfigIndexType {
+ layers[0].vote = voteType;
+ layers[0].desiredRefreshRate = fps;
+ bool touchConsidered;
+ return refreshRateConfigs
+ ->getBestRefreshRate(layers, touchActive, /*idle*/ false, &touchConsidered)
+ .getConfigId();
+ };
+
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
+ {HWC_CONFIG_ID_60, {60.f, 60.f}, {60.f, 90.f}}),
+ 0);
+ bool touchConsidered;
+ EXPECT_EQ(HWC_CONFIG_ID_60,
+ refreshRateConfigs
+ ->getBestRefreshRate({}, /*touchActive=*/false, /*idle*/ false,
+ &touchConsidered)
+ .getConfigId());
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Min, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Heuristic, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitDefault, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90.f));
+
+ // Touch boost should be restricted to the primary range.
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90.f, /*touch=*/true));
+ // When we're higher than the primary range max due to a layer frame rate setting, touch boost
+ // shouldn't drag us back down to the primary range max.
+ EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitDefault, 90.f, /*touch=*/true));
+ EXPECT_EQ(HWC_CONFIG_ID_90,
+ getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90.f, /*touch=*/true));
+
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
+ {HWC_CONFIG_ID_60, {60.f, 60.f}, {60.f, 60.f}}),
+ 0);
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Min, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Heuristic, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitDefault, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90.f));
+}
+
+TEST_F(RefreshRateConfigsTest, idle) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_90Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ layers[0].name = "Test layer";
+
+ auto getIdleFrameRate = [&](LayerVoteType voteType, bool touchActive) -> HwcConfigIndexType {
+ layers[0].vote = voteType;
+ layers[0].desiredRefreshRate = 90.f;
+ bool touchConsidered;
+ return refreshRateConfigs
+ ->getBestRefreshRate(layers, touchActive, /*idle=*/true, &touchConsidered)
+ .getConfigId();
+ };
+
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
+ {HWC_CONFIG_ID_60, {60.f, 90.f}, {60.f, 90.f}}),
+ 0);
+
+ // Idle should be lower priority than touch boost.
+ EXPECT_EQ(HWC_CONFIG_ID_90, getIdleFrameRate(LayerVoteType::NoVote, true));
+ EXPECT_EQ(HWC_CONFIG_ID_90, getIdleFrameRate(LayerVoteType::Min, true));
+ EXPECT_EQ(HWC_CONFIG_ID_90, getIdleFrameRate(LayerVoteType::Max, true));
+ EXPECT_EQ(HWC_CONFIG_ID_90, getIdleFrameRate(LayerVoteType::Heuristic, true));
+ EXPECT_EQ(HWC_CONFIG_ID_90, getIdleFrameRate(LayerVoteType::ExplicitDefault, true));
+ EXPECT_EQ(HWC_CONFIG_ID_90, getIdleFrameRate(LayerVoteType::ExplicitExactOrMultiple, true));
+
+ // With no layers, idle should still be lower priority than touch boost.
+ bool touchConsidered;
+ EXPECT_EQ(HWC_CONFIG_ID_90,
+ refreshRateConfigs
+ ->getBestRefreshRate({}, /*touchActive=*/true, /*idle=*/true,
+ &touchConsidered)
+ .getConfigId());
+
+ // Idle should be higher precedence than other layer frame rate considerations.
+ refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
+ EXPECT_EQ(HWC_CONFIG_ID_60, getIdleFrameRate(LayerVoteType::NoVote, false));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getIdleFrameRate(LayerVoteType::Min, false));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getIdleFrameRate(LayerVoteType::Max, false));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getIdleFrameRate(LayerVoteType::Heuristic, false));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getIdleFrameRate(LayerVoteType::ExplicitDefault, false));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getIdleFrameRate(LayerVoteType::ExplicitExactOrMultiple, false));
+
+ // Idle should be applied rather than the current config when there are no layers.
+ EXPECT_EQ(HWC_CONFIG_ID_60,
+ refreshRateConfigs
+ ->getBestRefreshRate({}, /*touchActive=*/false, /*idle=*/true,
+ &touchConsidered)
.getConfigId());
}
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h
index 67d3e1c..dade9fc 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h
@@ -84,15 +84,15 @@
MOCK_METHOD2(validate, hal::Error(uint32_t*, uint32_t*));
MOCK_METHOD4(presentOrValidate,
hal::Error(uint32_t*, uint32_t*, android::sp<android::Fence>*, uint32_t*));
- MOCK_CONST_METHOD1(setDisplayBrightness, hal::Error(float));
+ MOCK_METHOD1(setDisplayBrightness, std::future<hal::Error>(float));
MOCK_CONST_METHOD1(getDisplayVsyncPeriod, hal::Error(nsecs_t*));
MOCK_METHOD3(setActiveConfigWithConstraints,
hal::Error(const std::shared_ptr<const HWC2::Display::Config>&,
const hal::VsyncPeriodChangeConstraints&,
hal::VsyncPeriodChangeTimeline*));
- MOCK_CONST_METHOD1(setAutoLowLatencyMode, hal::Error(bool on));
+ MOCK_METHOD1(setAutoLowLatencyMode, hal::Error(bool on));
MOCK_CONST_METHOD1(getSupportedContentTypes, hal::Error(std::vector<hal::ContentType>*));
- MOCK_CONST_METHOD1(setContentType, hal::Error(hal::ContentType));
+ MOCK_METHOD1(setContentType, hal::Error(hal::ContentType));
MOCK_CONST_METHOD1(getConnectionType, hal::Error(android::DisplayConnectionType*));
MOCK_CONST_METHOD0(isVsyncPeriodSwitchSupported, bool());
};
diff --git a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.cpp b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.cpp
index 97a13e4..5fb06fd 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.cpp
@@ -16,12 +16,15 @@
#include "mock/MockMessageQueue.h"
-namespace android {
-namespace mock {
+namespace android::mock {
-// Explicit default instantiation is recommended.
-MessageQueue::MessageQueue() = default;
+MessageQueue::MessageQueue() {
+ ON_CALL(*this, postMessage).WillByDefault([](sp<MessageHandler>&& handler) {
+ // Execute task to prevent broken promise exception on destruction.
+ handler->handleMessage(Message());
+ });
+}
+
MessageQueue::~MessageQueue() = default;
-} // namespace mock
-} // namespace android
\ No newline at end of file
+} // namespace android::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
index e781c0a..a82b583 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
@@ -21,8 +21,7 @@
#include "Scheduler/EventThread.h"
#include "Scheduler/MessageQueue.h"
-namespace android {
-namespace mock {
+namespace android::mock {
class MessageQueue : public android::MessageQueue {
public:
@@ -32,10 +31,9 @@
MOCK_METHOD1(init, void(const sp<SurfaceFlinger>&));
MOCK_METHOD1(setEventConnection, void(const sp<EventThreadConnection>& connection));
MOCK_METHOD0(waitMessage, void());
- MOCK_METHOD2(postMessage, status_t(const sp<MessageBase>&, nsecs_t));
+ MOCK_METHOD1(postMessage, void(sp<MessageHandler>&&));
MOCK_METHOD0(invalidate, void());
MOCK_METHOD0(refresh, void());
};
-} // namespace mock
-} // namespace android
+} // namespace android::mock
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index 018f200..f69de1f 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -79,6 +79,7 @@
"hwvulkan_headers",
"libnativeloader-headers",
"vulkan_headers",
+ "libsurfaceflinger_headers",
],
export_header_lib_headers: ["vulkan_headers"],
shared_libs: [
@@ -100,6 +101,7 @@
"libnativeloader_lazy",
"libnativewindow",
"android.hardware.graphics.common@1.0",
+ "libSurfaceFlingerProp",
],
static_libs: ["libgrallocusage"],
}
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index a7ec4ae..a5f0c9f 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -23,9 +23,10 @@
#include <stdlib.h>
#include <string.h>
+#include <SurfaceFlingerProperties.h>
+#include <android-base/properties.h>
#include <android/dlext.h>
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
-#include <android-base/properties.h>
#include <configstore/Utils.h>
#include <cutils/properties.h>
#include <graphicsenv/GraphicsEnv.h>
@@ -959,9 +960,7 @@
VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME,
VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION});
- bool hdrBoardConfig =
- getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasHDRDisplay>(
- false);
+ bool hdrBoardConfig = android::sysprop::has_HDR_display(false);
if (hdrBoardConfig) {
loader_extensions.push_back({VK_EXT_HDR_METADATA_EXTENSION_NAME,
VK_EXT_HDR_METADATA_SPEC_VERSION});
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index a44b9e7..d3ed88d 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -1478,7 +1478,7 @@
ANativeWindowBuffer* buffer;
int fence_fd;
err = window->dequeueBuffer(window, &buffer, &fence_fd);
- if (err == android::TIMED_OUT) {
+ if (err == android::TIMED_OUT || err == android::INVALID_OPERATION) {
ALOGW("dequeueBuffer timed out: %s (%d)", strerror(-err), err);
return timeout ? VK_TIMEOUT : VK_NOT_READY;
} else if (err != android::OK) {