Merge "Check if /dev/input exists before accessing the path"
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 25e6dc9..2d11b90 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -176,6 +176,7 @@
#define LINKERCONFIG_DIR "/linkerconfig"
#define PACKAGE_DEX_USE_LIST "/data/system/package-dex-usage.list"
#define SYSTEM_TRACE_SNAPSHOT "/data/misc/perfetto-traces/bugreport/systrace.pftrace"
+#define CGROUPFS_DIR "/sys/fs/cgroup"
// TODO(narayan): Since this information has to be kept in sync
// with tombstoned, we should just put it in a common header.
@@ -1240,8 +1241,15 @@
if (status == OK) {
dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
std::chrono::duration<double> elapsed_seconds;
- status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
- /* as_proto = */ false, elapsed_seconds, bytes_written);
+ if (priority == IServiceManager::DUMP_FLAG_PRIORITY_HIGH &&
+ service == String16("meminfo")) {
+ // Use a longer timeout for meminfo, since 30s is not always enough.
+ status = dumpsys.writeDump(STDOUT_FILENO, service, 60s,
+ /* as_proto = */ false, elapsed_seconds, bytes_written);
+ } else {
+ status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
+ /* as_proto = */ false, elapsed_seconds, bytes_written);
+ }
dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds);
bool dump_complete = (status == OK);
dumpsys.stopDumpThread(dump_complete);
@@ -1785,6 +1793,9 @@
// Add linker configuration directory
ds.AddDir(LINKERCONFIG_DIR, true);
+ /* Dump cgroupfs */
+ ds.AddDir(CGROUPFS_DIR, true);
+
if (ds.dump_pool_) {
WAIT_TASK_WITH_CONSENT_CHECK(DUMP_INCIDENT_REPORT_TASK, ds.dump_pool_);
} else {
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 15f0c5b..9128542 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -1231,6 +1231,14 @@
}
}
+ // On-device signing related. odsign sets the system property odsign.verification.success if
+ // AOT artifacts have the expected signatures.
+ const bool trust_art_apex_data_files =
+ ::android::base::GetBoolProperty("odsign.verification.success", false);
+ if (!trust_art_apex_data_files) {
+ AddRuntimeArg("-Xdeny-art-apex-data-files");
+ }
+
PrepareArgs(dexoptanalyzer_bin);
}
diff --git a/cmds/installd/run_dex2oat.cpp b/cmds/installd/run_dex2oat.cpp
index e847626..b661684 100644
--- a/cmds/installd/run_dex2oat.cpp
+++ b/cmds/installd/run_dex2oat.cpp
@@ -283,6 +283,13 @@
}
}
+ // On-device signing related. odsign sets the system property odsign.verification.success if
+ // AOT artifacts have the expected signatures.
+ const bool trust_art_apex_data_files = GetBoolProperty("odsign.verification.success", false);
+ if (!trust_art_apex_data_files) {
+ AddRuntimeArg("-Xdeny-art-apex-data-files");
+ }
+
if (target_sdk_version != 0) {
AddRuntimeArg(StringPrintf("-Xtarget-sdk-version:%d", target_sdk_version));
}
diff --git a/include/input/Input.h b/include/input/Input.h
index 3bac763..b09ff48 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -43,6 +43,13 @@
* Additional private constants not defined in ndk/ui/input.h.
*/
enum {
+#ifdef __linux__
+ /* This event was generated or modified by accessibility service. */
+ AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT =
+ android::os::IInputConstants::INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT, // 0x800,
+#else
+ AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT = 0x800,
+#endif
/* Signifies that the key is being predispatched */
AKEY_EVENT_FLAG_PREDISPATCH = 0x20000000,
@@ -81,6 +88,16 @@
*/
AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE = 0x40,
+#ifdef __linux__
+ /**
+ * This event was generated or modified by accessibility service.
+ */
+ AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT =
+ android::os::IInputConstants::INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT, // 0x800,
+#else
+ AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT = 0x800,
+#endif
+
/* Motion event is inconsistent with previously sent motion events. */
AMOTION_EVENT_FLAG_TAINTED = 0x80000000,
};
@@ -89,14 +106,15 @@
* Allowed VerifiedKeyEvent flags. All other flags from KeyEvent do not get verified.
* These values must be kept in sync with VerifiedKeyEvent.java
*/
-constexpr int32_t VERIFIED_KEY_EVENT_FLAGS = AKEY_EVENT_FLAG_CANCELED;
+constexpr int32_t VERIFIED_KEY_EVENT_FLAGS =
+ AKEY_EVENT_FLAG_CANCELED | AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT;
/**
* Allowed VerifiedMotionEventFlags. All other flags from MotionEvent do not get verified.
* These values must be kept in sync with VerifiedMotionEvent.java
*/
-constexpr int32_t VERIFIED_MOTION_EVENT_FLAGS =
- AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
+constexpr int32_t VERIFIED_MOTION_EVENT_FLAGS = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED |
+ AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED | AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT;
/**
* This flag indicates that the point up event has been canceled.
@@ -213,16 +231,14 @@
POLICY_FLAG_GESTURE = 0x00000008,
POLICY_FLAG_RAW_MASK = 0x0000ffff,
-#ifdef __linux__
- POLICY_FLAG_INPUTFILTER_TRUSTED = android::os::IInputConstants::POLICY_FLAG_INPUTFILTER_TRUSTED,
+#ifdef __linux__
POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY =
android::os::IInputConstants::POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY,
#else
- POLICY_FLAG_INPUTFILTER_TRUSTED = 0x10000,
-
POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY = 0x20000,
#endif
+
/* These flags are set by the input dispatcher. */
// Indicates that the input event was injected.
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index 1955104..7f0324a 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -318,8 +318,6 @@
const std::string& name, InputDeviceConfigurationFileType type);
enum ReservedInputDeviceId : int32_t {
- // Device id assigned to input events generated inside accessibility service
- ACCESSIBILITY_DEVICE_ID = -2,
// Device id of a special "virtual" keyboard that is always present.
VIRTUAL_KEYBOARD_ID = -1,
// Device id of the "built-in" keyboard if there is one.
diff --git a/libs/binder/ServiceManagerHost.cpp b/libs/binder/ServiceManagerHost.cpp
index 07f5778..1c2f9b4 100644
--- a/libs/binder/ServiceManagerHost.cpp
+++ b/libs/binder/ServiceManagerHost.cpp
@@ -167,9 +167,12 @@
ALOGE("RpcSession::getRootObject returns nullptr");
return nullptr;
}
- binder->attachObject(kDeviceServiceExtraId,
- static_cast<void*>(new CommandResult(std::move(*result))), nullptr,
- &cleanupCommandResult);
+
+ LOG_ALWAYS_FATAL_IF(
+ nullptr !=
+ binder->attachObject(kDeviceServiceExtraId,
+ static_cast<void*>(new CommandResult(std::move(*result))), nullptr,
+ &cleanupCommandResult));
return binder;
}
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 748fa72..9c5ce67 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -16,6 +16,9 @@
"name": "binderDriverInterfaceTest"
},
{
+ "name": "binderHostDeviceTest"
+ },
+ {
"name": "binderTextOutputTest"
},
{
@@ -55,6 +58,9 @@
"name": "CtsOsTestCases",
"options": [
{
+ "exclude-annotation": "android.platform.test.annotations.LargeTest"
+ },
+ {
"exclude-filter": "android.os.cts.BuildTest#testSdkInt"
},
{
diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h
index c484d83..43fc5ff 100644
--- a/libs/binder/include/binder/IBinder.h
+++ b/libs/binder/include/binder/IBinder.h
@@ -259,21 +259,20 @@
* but calls from different threads are allowed to be interleaved.
*
* This returns the object which is already attached. If this returns a
- * non-null value, it means that attachObject failed. TODO(b/192023359):
- * remove logs and add [[nodiscard]]
+ * non-null value, it means that attachObject failed (a given objectID can
+ * only be used once).
*/
- virtual void* attachObject(const void* objectID, void* object, void* cleanupCookie,
- object_cleanup_func func) = 0;
+ [[nodiscard]] virtual void* attachObject(const void* objectID, void* object,
+ void* cleanupCookie, object_cleanup_func func) = 0;
/**
* Returns object attached with attachObject.
*/
- virtual void* findObject(const void* objectID) const = 0;
+ [[nodiscard]] virtual void* findObject(const void* objectID) const = 0;
/**
* Returns object attached with attachObject, and detaches it. This does not
- * delete the object. This is equivalent to using attachObject to attach a null
- * object.
+ * delete the object.
*/
- virtual void* detachObject(const void* objectID) = 0;
+ [[nodiscard]] virtual void* detachObject(const void* objectID) = 0;
/**
* Use the lock that this binder contains internally. For instance, this can
diff --git a/libs/binder/include/binder/ParcelableHolder.h b/libs/binder/include/binder/ParcelableHolder.h
index 9e4475c..42c85f9 100644
--- a/libs/binder/include/binder/ParcelableHolder.h
+++ b/libs/binder/include/binder/ParcelableHolder.h
@@ -42,6 +42,7 @@
}
mStability = other.mStability;
}
+ ParcelableHolder(ParcelableHolder&& other) = default;
status_t writeToParcel(Parcel* parcel) const override;
status_t readFromParcel(const Parcel* parcel) override;
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 953b2be..785e032 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -47,7 +47,8 @@
void clean(const void* /*id*/, void* /*obj*/, void* /*cookie*/){/* do nothing */};
static void attach(const sp<IBinder>& binder) {
- binder->attachObject(kId, kValue, nullptr /*cookie*/, clean);
+ // can only attach once
+ CHECK_EQ(nullptr, binder->attachObject(kId, kValue, nullptr /*cookie*/, clean));
}
static bool has(const sp<IBinder>& binder) {
return binder != nullptr && binder->findObject(kId) == kValue;
@@ -232,13 +233,15 @@
void ABpBinder::onLastStrongRef(const void* id) {
// Since ABpBinder is OBJECT_LIFETIME_WEAK, we must remove this weak reference in order for
- // the ABpBinder to be deleted. Since a strong reference to this ABpBinder object should no
- // longer be able to exist at the time of this method call, there is no longer a need to
- // recover it.
+ // the ABpBinder to be deleted. Even though we have no more references on the ABpBinder
+ // (BpRefBase), the remote object may still exist (for instance, if we
+ // receive it from another process, before the ABpBinder is attached).
ABpBinderTag::Value* value =
- static_cast<ABpBinderTag::Value*>(remote()->detachObject(ABpBinderTag::kId));
- if (value) ABpBinderTag::clean(ABpBinderTag::kId, value, nullptr /*cookie*/);
+ static_cast<ABpBinderTag::Value*>(remote()->findObject(ABpBinderTag::kId));
+ CHECK_NE(nullptr, value) << "ABpBinder must always be attached";
+
+ remote()->withLock([&]() { value->binder = nullptr; });
BpRefBase::onLastStrongRef(id);
}
@@ -251,6 +254,9 @@
return static_cast<ABBinder*>(binder.get());
}
+ // The following code ensures that for a given binder object (remote or local), if it is not an
+ // ABBinder then at most one ABpBinder object exists in a given process representing it.
+
auto* value = static_cast<ABpBinderTag::Value*>(binder->findObject(ABpBinderTag::kId));
if (value == nullptr) {
value = new ABpBinderTag::Value;
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
index 2277148..aa3b978 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
@@ -46,7 +46,7 @@
AParcelableHolder() = delete;
explicit AParcelableHolder(parcelable_stability_t stability)
: mParcel(AParcel_create()), mStability(stability) {}
-
+ AParcelableHolder(AParcelableHolder&& other) = default;
virtual ~AParcelableHolder() = default;
binder_status_t writeToParcel(AParcel* parcel) const {
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index 62db3cf..ce12ccf 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -39,6 +39,7 @@
#include <condition_variable>
#include <iostream>
#include <mutex>
+#include <thread>
#include "android/binder_ibinder.h"
using namespace android;
@@ -270,6 +271,27 @@
EXPECT_EQ(2, out);
}
+TEST(NdkBinder, GetTestServiceStressTest) {
+ // libbinder has some complicated logic to make sure only one instance of
+ // ABpBinder is associated with each binder.
+
+ constexpr size_t kNumThreads = 10;
+ constexpr size_t kNumCalls = 1000;
+ std::vector<std::thread> threads;
+
+ for (size_t i = 0; i < kNumThreads; i++) {
+ threads.push_back(std::thread([&]() {
+ for (size_t j = 0; j < kNumCalls; j++) {
+ auto binder =
+ ndk::SpAIBinder(AServiceManager_checkService(IFoo::kSomeInstanceName));
+ EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get()));
+ }
+ }));
+ }
+
+ for (auto& thread : threads) thread.join();
+}
+
void defaultInstanceCounter(const char* instance, void* context) {
if (strcmp(instance, "default") == 0) {
++*(size_t*)(context);
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 565f88e..24afcf6 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -348,3 +348,49 @@
},
},
}
+
+cc_test_host {
+ name: "binderHostDeviceTest",
+ defaults: ["binder_test_defaults"],
+ srcs: ["binderHostDeviceTest.cpp"],
+ test_config: "binderHostDeviceTest.xml",
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "liblog",
+ "libutils",
+ ],
+ static_libs: [
+ "libgmock",
+ ],
+ target_required: [
+ "binderHostDeviceTestService",
+ ],
+ test_suites: ["general-tests"],
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+ test_options: {
+ unit_test: false,
+ },
+}
+
+cc_test {
+ name: "binderHostDeviceTestService",
+ // The binary is named differently from the module so that PushFilePreparer pushes the binary
+ // directly, not the test module directory.
+ stem: "binderHostDeviceTest-service",
+ defaults: ["binder_test_defaults"],
+ gtest: false,
+ auto_gen_config: false,
+ srcs: ["binderHostDeviceTestService.cpp"],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "liblog",
+ "libutils",
+ ],
+ test_suites: ["general-tests"],
+}
diff --git a/libs/binder/tests/binderHostDeviceTest.cpp b/libs/binder/tests/binderHostDeviceTest.cpp
new file mode 100644
index 0000000..5dd9212
--- /dev/null
+++ b/libs/binder/tests/binderHostDeviceTest.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Integration test for servicedispatcher + adb forward. Requires ADB.
+
+#include <stdlib.h>
+
+#include <vector>
+
+#include <android-base/parsebool.h>
+#include <android-base/result-gmock.h>
+#include <android-base/strings.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <binder/IServiceManager.h>
+#include <binder/RpcSession.h>
+
+#include "../UtilsHost.h"
+
+using ::android::setDefaultServiceManager;
+using ::android::base::EndsWith;
+using ::android::base::Join;
+using ::android::base::ParseBool;
+using ::android::base::ParseBoolResult;
+using ::android::base::Split;
+using ::android::base::StartsWith;
+using ::android::base::StringReplace;
+using ::android::base::Trim;
+using ::android::base::testing::Ok;
+using ::std::chrono_literals::operator""ms;
+using ::std::string_literals::operator""s;
+using ::testing::AllOf;
+using ::testing::Contains;
+using ::testing::ContainsRegex;
+using ::testing::ExplainMatchResult;
+using ::testing::InitGoogleMock;
+
+namespace android {
+
+namespace {
+
+constexpr const char* kServiceBinary = "/data/local/tmp/binderHostDeviceTest-service";
+constexpr const char* kServiceName = "binderHostDeviceTestService";
+constexpr const char* kDescriptor = "android.binderHostDeviceTestService";
+
+// e.g. EXPECT_THAT(expr, StatusEq(OK)) << "additional message";
+MATCHER_P(StatusEq, expected, (negation ? "not " : "") + statusToString(expected)) {
+ *result_listener << statusToString(arg);
+ return expected == arg;
+}
+
+void initHostRpcServiceManagerOnce() {
+ static std::once_flag gSmOnce;
+ std::call_once(gSmOnce, [] { setDefaultServiceManager(createRpcDelegateServiceManager()); });
+}
+
+// Test for host service manager.
+class HostDeviceTest : public ::testing::Test {
+public:
+ void SetUp() override {
+ auto debuggableResult = execute(Split("adb shell getprop ro.debuggable", " "), nullptr);
+ ASSERT_THAT(debuggableResult, Ok());
+ ASSERT_EQ(0, debuggableResult->exitCode) << *debuggableResult;
+ auto debuggableBool = ParseBool(Trim(debuggableResult->stdout));
+ ASSERT_NE(ParseBoolResult::kError, debuggableBool) << Trim(debuggableResult->stdout);
+ if (debuggableBool == ParseBoolResult::kFalse) {
+ GTEST_SKIP() << "ro.debuggable=" << Trim(debuggableResult->stdout);
+ }
+
+ auto lsResult = execute(Split("adb shell which servicedispatcher", " "), nullptr);
+ ASSERT_THAT(lsResult, Ok());
+ if (lsResult->exitCode != 0) {
+ GTEST_SKIP() << "b/182914638: until feature is fully enabled, skip test on devices "
+ "without servicedispatcher";
+ }
+
+ initHostRpcServiceManagerOnce();
+ ASSERT_NE(nullptr, defaultServiceManager()) << "No defaultServiceManager() over RPC";
+
+ auto service = execute({"adb", "shell", kServiceBinary, kServiceName, kDescriptor},
+ &CommandResult::stdoutEndsWithNewLine);
+ ASSERT_THAT(service, Ok());
+ ASSERT_EQ(std::nullopt, service->exitCode) << *service;
+ mService = std::move(*service);
+ }
+ void TearDown() override { mService.reset(); }
+
+ [[nodiscard]] static sp<IBinder> get(unsigned int hostPort) {
+ auto rpcSession = RpcSession::make();
+ if (!rpcSession->setupInetClient("127.0.0.1", hostPort)) {
+ ADD_FAILURE() << "Failed to setupInetClient on " << hostPort;
+ return nullptr;
+ }
+ return rpcSession->getRootObject();
+ }
+
+private:
+ std::optional<CommandResult> mService;
+};
+
+TEST_F(HostDeviceTest, List) {
+ auto sm = defaultServiceManager();
+
+ auto services = sm->listServices();
+ ASSERT_THAT(services, Contains(String16(kServiceName)));
+}
+
+TEST_F(HostDeviceTest, CheckService) {
+ auto sm = defaultServiceManager();
+
+ auto rpcBinder = sm->checkService(String16(kServiceName));
+ ASSERT_NE(nullptr, rpcBinder);
+
+ EXPECT_THAT(rpcBinder->pingBinder(), StatusEq(OK));
+ EXPECT_EQ(String16(kDescriptor), rpcBinder->getInterfaceDescriptor());
+}
+
+TEST_F(HostDeviceTest, GetService) {
+ auto sm = defaultServiceManager();
+
+ auto rpcBinder = sm->getService(String16(kServiceName));
+ ASSERT_NE(nullptr, rpcBinder);
+
+ EXPECT_THAT(rpcBinder->pingBinder(), StatusEq(OK));
+ EXPECT_EQ(String16(kDescriptor), rpcBinder->getInterfaceDescriptor());
+}
+
+TEST_F(HostDeviceTest, WaitForService) {
+ auto sm = defaultServiceManager();
+
+ auto rpcBinder = sm->waitForService(String16(kServiceName));
+ ASSERT_NE(nullptr, rpcBinder);
+
+ EXPECT_THAT(rpcBinder->pingBinder(), StatusEq(OK));
+ EXPECT_EQ(String16(kDescriptor), rpcBinder->getInterfaceDescriptor());
+}
+
+TEST_F(HostDeviceTest, TenClients) {
+ auto sm = defaultServiceManager();
+
+ auto threadFn = [&] {
+ auto rpcBinder = sm->checkService(String16(kServiceName));
+ ASSERT_NE(nullptr, rpcBinder);
+
+ EXPECT_THAT(rpcBinder->pingBinder(), StatusEq(OK));
+ EXPECT_EQ(String16(kDescriptor), rpcBinder->getInterfaceDescriptor());
+ };
+
+ std::vector<std::thread> threads;
+ for (size_t i = 0; i < 10; ++i) threads.emplace_back(threadFn);
+ for (auto& thread : threads) thread.join();
+}
+
+} // namespace
+
+} // namespace android
diff --git a/libs/binder/tests/binderHostDeviceTest.xml b/libs/binder/tests/binderHostDeviceTest.xml
new file mode 100644
index 0000000..250ed3a
--- /dev/null
+++ b/libs/binder/tests/binderHostDeviceTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs binderHostDeviceTest.">
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push-file" key="binderHostDeviceTest-service"
+ value="/data/local/tmp/binderHostDeviceTest-service"/>
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.binary.ExecutableHostTest">
+ <option name="binary" value="binderHostDeviceTest"/>
+ </test>
+</configuration>
diff --git a/libs/binder/tests/binderHostDeviceTestService.cpp b/libs/binder/tests/binderHostDeviceTestService.cpp
new file mode 100644
index 0000000..6ddd2e7
--- /dev/null
+++ b/libs/binder/tests/binderHostDeviceTestService.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sysexits.h>
+
+#include <android-base/logging.h>
+#include <binder/IBinder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+namespace {
+class Service : public android::BBinder {
+public:
+ Service(std::string_view descriptor) : mDescriptor(descriptor.data(), descriptor.size()) {}
+ const android::String16& getInterfaceDescriptor() const override { return mDescriptor; }
+
+private:
+ android::String16 mDescriptor;
+};
+} // namespace
+
+int main(int argc, char** argv) {
+ if (argc != 3) {
+ std::cerr << "usage: " << argv[0] << " <service-name> <interface-descriptor>" << std::endl;
+ return EX_USAGE;
+ }
+ auto name = argv[1];
+ auto descriptor = argv[2];
+
+ auto sm = android::defaultServiceManager();
+ CHECK(sm != nullptr);
+ auto service = android::sp<Service>::make(descriptor);
+ auto status = sm->addService(android::String16(name), service);
+ CHECK_EQ(android::OK, status) << android::statusToString(status);
+ std::cout << "running..." << std::endl;
+ android::ProcessState::self()->startThreadPool();
+ android::IPCThreadState::self()->joinThreadPool();
+ LOG(ERROR) << "joinThreadPool exits";
+ return EX_SOFTWARE;
+}
diff --git a/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h b/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h
index 626b758..4a0aeba 100644
--- a/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h
+++ b/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h
@@ -62,20 +62,22 @@
object = fdp->ConsumeIntegral<uint32_t>();
cleanup_cookie = fdp->ConsumeIntegral<uint32_t>();
IBinder::object_cleanup_func func = IBinder::object_cleanup_func();
- ibinder->attachObject(fdp->ConsumeBool() ? reinterpret_cast<void*>(&objectID)
- : nullptr,
- fdp->ConsumeBool() ? reinterpret_cast<void*>(&object) : nullptr,
- fdp->ConsumeBool() ? reinterpret_cast<void*>(&cleanup_cookie)
- : nullptr,
- func);
+ (void)ibinder->attachObject(fdp->ConsumeBool() ? reinterpret_cast<void*>(&objectID)
+ : nullptr,
+ fdp->ConsumeBool() ? reinterpret_cast<void*>(&object)
+ : nullptr,
+ fdp->ConsumeBool()
+ ? reinterpret_cast<void*>(&cleanup_cookie)
+ : nullptr,
+ func);
},
[](FuzzedDataProvider* fdp, IBinder* ibinder) -> void {
uint32_t id = fdp->ConsumeIntegral<uint32_t>();
- ibinder->findObject(reinterpret_cast<void*>(&id));
+ (void)ibinder->findObject(reinterpret_cast<void*>(&id));
},
[](FuzzedDataProvider* fdp, IBinder* ibinder) -> void {
uint32_t id = fdp->ConsumeIntegral<uint32_t>();
- ibinder->detachObject(reinterpret_cast<void*>(&id));
+ (void)ibinder->detachObject(reinterpret_cast<void*>(&id));
},
[](FuzzedDataProvider* fdp, IBinder* ibinder) -> void {
uint32_t code = fdp->ConsumeIntegral<uint32_t>();
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 2d8fff9..b0dc27f 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -94,6 +94,12 @@
include_dirs: [
"frameworks/native/include",
],
+
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
}
filegroup {
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index dbb1cb0..d9024fa 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -171,6 +171,8 @@
.apply();
mNumAcquired = 0;
mNumFrameAvailable = 0;
+ BQA_LOGV("BLASTBufferQueue created width=%d height=%d format=%d mTransformHint=%d", width,
+ height, format, mTransformHint);
}
BLASTBufferQueue::~BLASTBufferQueue() {
@@ -190,25 +192,29 @@
void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height,
int32_t format) {
std::unique_lock _lock{mMutex};
- BQA_LOGV("update width=%d height=%d format=%d", width, height, format);
if (mFormat != format) {
mFormat = format;
mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format));
}
SurfaceComposerClient::Transaction t;
+ const bool setBackpressureFlag = !SurfaceControl::isSameSurface(mSurfaceControl, surface);
bool applyTransaction = false;
- if (!SurfaceControl::isSameSurface(mSurfaceControl, surface)) {
- mSurfaceControl = surface;
- t.setFlags(mSurfaceControl, layer_state_t::eEnableBackpressure,
- layer_state_t::eEnableBackpressure);
- applyTransaction = true;
- }
+ // Always update the native object even though they might have the same layer handle, so we can
+ // get the updated transform hint from WM.
+ mSurfaceControl = surface;
if (mSurfaceControl != nullptr) {
+ if (setBackpressureFlag) {
+ t.setFlags(mSurfaceControl, layer_state_t::eEnableBackpressure,
+ layer_state_t::eEnableBackpressure);
+ applyTransaction = true;
+ }
mTransformHint = mSurfaceControl->getTransformHint();
mBufferItemConsumer->setTransformHint(mTransformHint);
}
+ BQA_LOGV("update width=%d height=%d format=%d mTransformHint=%d", width, height, format,
+ mTransformHint);
ui::Size newSize(width, height);
if (mRequestedSize != newSize) {
@@ -221,7 +227,7 @@
// We only need to update the scale if we've received at least one buffer. The reason
// for this is the scale is calculated based on the requested size and buffer size.
// If there's no buffer, the scale will always be 1.
- if (mLastBufferInfo.hasBuffer) {
+ if (mSurfaceControl != nullptr && mLastBufferInfo.hasBuffer) {
t.setDestinationFrame(mSurfaceControl,
Rect(0, 0, newSize.getWidth(), newSize.getHeight()));
}
@@ -264,6 +270,7 @@
mTransformHint = stat.transformHint;
mBufferItemConsumer->setTransformHint(mTransformHint);
+ BQA_LOGV("updated mTransformHint=%d", mTransformHint);
// Update frametime stamps if the frame was latched and presented, indicated by a
// valid latch time.
if (stat.latchTime > 0) {
@@ -336,6 +343,7 @@
mTransformHint = transformHint;
mSurfaceControl->setTransformHint(transformHint);
mBufferItemConsumer->setTransformHint(mTransformHint);
+ BQA_LOGV("updated mTransformHint=%d", mTransformHint);
}
// Calculate how many buffers we need to hold before we release them back
@@ -419,7 +427,7 @@
}
if (rejectBuffer(bufferItem)) {
- BQA_LOGE("rejecting buffer:active_size=%dx%d, requested_size=%dx%d"
+ BQA_LOGE("rejecting buffer:active_size=%dx%d, requested_size=%dx%d "
"buffer{size=%dx%d transform=%d}",
mSize.width, mSize.height, mRequestedSize.width, mRequestedSize.height,
buffer->getWidth(), buffer->getHeight(), bufferItem.mTransform);
@@ -512,11 +520,11 @@
BQA_LOGV("processNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64
" applyTransaction=%s mTimestamp=%" PRId64 "%s mPendingTransactions.size=%d"
- " graphicBufferId=%" PRIu64 "%s",
+ " graphicBufferId=%" PRIu64 "%s transform=%d",
mSize.width, mSize.height, bufferItem.mFrameNumber, boolToString(applyTransaction),
bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp ? "(auto)" : "",
static_cast<uint32_t>(mPendingTransactions.size()), bufferItem.mGraphicBuffer->getId(),
- bufferItem.mAutoRefresh ? " mAutoRefresh" : "");
+ bufferItem.mAutoRefresh ? " mAutoRefresh" : "", bufferItem.mTransform);
}
Rect BLASTBufferQueue::computeCrop(const BufferItem& item) {
@@ -643,14 +651,6 @@
status_t setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo) override {
return mBbq->setFrameTimelineInfo(frameTimelineInfo);
}
- protected:
- uint32_t getTransformHint() const override {
- if (mStickyTransform == 0 && !transformToDisplayInverse()) {
- return mBbq->getLastTransformHint();
- } else {
- return 0;
- }
- }
};
// TODO: Can we coalesce this with frame updates? Need to confirm
diff --git a/libs/gui/bufferqueue/1.0/Conversion.cpp b/libs/gui/bufferqueue/1.0/Conversion.cpp
index 3e20a37..55462c3 100644
--- a/libs/gui/bufferqueue/1.0/Conversion.cpp
+++ b/libs/gui/bufferqueue/1.0/Conversion.cpp
@@ -1187,14 +1187,15 @@
*/
constexpr size_t minFlattenedSize(
HGraphicBufferProducer::QueueBufferInput const& /* t */) {
- return sizeof(int64_t) + // timestamp
- sizeof(int) + // isAutoTimestamp
+ return sizeof(int64_t) + // timestamp
+ sizeof(int) + // isAutoTimestamp
sizeof(android_dataspace) + // dataSpace
- sizeof(::android::Rect) + // crop
- sizeof(int) + // scalingMode
- sizeof(uint32_t) + // transform
- sizeof(uint32_t) + // stickyTransform
- sizeof(bool); // getFrameTimestamps
+ sizeof(::android::Rect) + // crop
+ sizeof(int) + // scalingMode
+ sizeof(uint32_t) + // transform
+ sizeof(uint32_t) + // stickyTransform
+ sizeof(bool) + // getFrameTimestamps
+ sizeof(int); // slot
}
/**
@@ -1267,6 +1268,7 @@
return status;
}
FlattenableUtils::write(buffer, size, decltype(HdrMetadata::validTypes)(0));
+ FlattenableUtils::write(buffer, size, -1 /*slot*/);
return NO_ERROR;
}
@@ -1319,7 +1321,7 @@
if (status != NO_ERROR) {
return status;
}
- // HdrMetadata ignored
+ // HdrMetadata and slot ignored
return unflatten(&(t->surfaceDamage), buffer, size);
}
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 6ff67aa..9082d27 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -71,6 +71,10 @@
return mBlastBufferQueueAdapter->mSurfaceControl;
}
+ sp<Surface> getSurface() {
+ return mBlastBufferQueueAdapter->getSurface(false /* includeSurfaceControlHandle */);
+ }
+
void waitForCallbacks() {
std::unique_lock lock{mBlastBufferQueueAdapter->mMutex};
// Wait until all but one of the submitted buffers have been released.
@@ -758,6 +762,48 @@
{0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight / 2}));
}
+TEST_F(BLASTBufferQueueTest, TransformHint) {
+ // Transform hint is provided to BBQ via the surface control passed by WM
+ mSurfaceControl->setTransformHint(ui::Transform::ROT_90);
+
+ BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+ sp<IGraphicBufferProducer> igbProducer = adapter.getIGraphicBufferProducer();
+ ASSERT_NE(nullptr, igbProducer.get());
+ ASSERT_EQ(NO_ERROR, igbProducer->setMaxDequeuedBufferCount(2));
+ sp<Surface> surface = adapter.getSurface();
+
+ // Before connecting to the surface, we do not get a valid transform hint
+ int transformHint;
+ surface->query(NATIVE_WINDOW_TRANSFORM_HINT, &transformHint);
+ ASSERT_EQ(ui::Transform::ROT_0, transformHint);
+
+ ASSERT_EQ(NO_ERROR,
+ surface->connect(NATIVE_WINDOW_API_CPU, new TestProducerListener(igbProducer)));
+
+ // After connecting to the surface, we should get the correct hint.
+ surface->query(NATIVE_WINDOW_TRANSFORM_HINT, &transformHint);
+ ASSERT_EQ(ui::Transform::ROT_90, transformHint);
+
+ ANativeWindow_Buffer buffer;
+ surface->lock(&buffer, nullptr /* inOutDirtyBounds */);
+
+ // Transform hint is updated via callbacks or surface control updates
+ mSurfaceControl->setTransformHint(ui::Transform::ROT_0);
+ adapter.update(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+
+ // The hint does not change and matches the value used when dequeueing the buffer.
+ surface->query(NATIVE_WINDOW_TRANSFORM_HINT, &transformHint);
+ ASSERT_EQ(ui::Transform::ROT_90, transformHint);
+
+ surface->unlockAndPost();
+
+ // After queuing the buffer, we get the updated transform hint
+ surface->query(NATIVE_WINDOW_TRANSFORM_HINT, &transformHint);
+ ASSERT_EQ(ui::Transform::ROT_0, transformHint);
+
+ adapter.waitForCallbacks();
+}
+
class BLASTBufferQueueTransformTest : public BLASTBufferQueueTest {
public:
void test(uint32_t tr) {
diff --git a/libs/input/android/os/IInputConstants.aidl b/libs/input/android/os/IInputConstants.aidl
index 3038d9d..474a1e4 100644
--- a/libs/input/android/os/IInputConstants.aidl
+++ b/libs/input/android/os/IInputConstants.aidl
@@ -42,16 +42,15 @@
const int INVALID_INPUT_EVENT_ID = 0;
/**
- * The injected event was originally sent from InputDispatcher. Most likely, the journey of the
- * event looked as follows:
- * InputDispatcherPolicyInterface::filterInputEvent -> InputFilter.java::onInputEvent ->
- * InputFilter.java::sendInputEvent -> InputDispatcher::injectInputEvent, without being modified
- * along the way.
- */
- const int POLICY_FLAG_INPUTFILTER_TRUSTED = 0x10000;
-
- /**
- * The input event was injected from accessibility
+ * The input event was injected from accessibility. Used in policyFlags for input event
+ * injection.
*/
const int POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY = 0x20000;
+
+ /**
+ * The input event was generated or modified by accessibility service.
+ * Shared by both KeyEvent and MotionEvent flags, so this value should not overlap with either
+ * set of flags, including in input/Input.h and in android/input.h.
+ */
+ const int INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT = 0x800;
}
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index b5dd8ac..467f848 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -1028,20 +1028,17 @@
return mProtectedEGLContext != EGL_NO_CONTEXT;
}
-bool GLESRenderEngine::useProtectedContext(bool useProtectedContext) {
- if (useProtectedContext == mInProtectedContext) {
- return true;
+void GLESRenderEngine::useProtectedContext(bool useProtectedContext) {
+ if (useProtectedContext == mInProtectedContext ||
+ (useProtectedContext && !supportsProtectedContent())) {
+ return;
}
- if (useProtectedContext && mProtectedEGLContext == EGL_NO_CONTEXT) {
- return false;
- }
+
const EGLSurface surface = useProtectedContext ? mProtectedStubSurface : mStubSurface;
const EGLContext context = useProtectedContext ? mProtectedEGLContext : mEGLContext;
- const bool success = eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE;
- if (success) {
+ if (eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE) {
mInProtectedContext = useProtectedContext;
}
- return success;
}
EGLImageKHR GLESRenderEngine::createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer,
bool isProtected,
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 915dba3..14627ce 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -62,7 +62,7 @@
void deleteTextures(size_t count, uint32_t const* names) override;
bool isProtected() const override { return mInProtectedContext; }
bool supportsProtectedContent() const override;
- bool useProtectedContext(bool useProtectedContext) override;
+ void useProtectedContext(bool useProtectedContext) override;
status_t drawLayers(const DisplaySettings& display,
const std::vector<const LayerSettings*>& layers,
const std::shared_ptr<ExternalTexture>& buffer,
@@ -71,7 +71,7 @@
void cleanupPostRender() override;
int getContextPriority() override;
bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; }
- void onPrimaryDisplaySizeChanged(ui::Size size) override {}
+ void onActiveDisplaySizeChanged(ui::Size size) override {}
EGLDisplay getEGLDisplay() const { return mEGLDisplay; }
// Creates an output image for rendering to
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index ac0affb..967cf5d 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -127,11 +127,11 @@
virtual bool supportsProtectedContent() const = 0;
// Attempt to switch RenderEngine into and out of protectedContext mode
- virtual bool useProtectedContext(bool useProtectedContext) = 0;
+ virtual void useProtectedContext(bool useProtectedContext) = 0;
- // Notify RenderEngine of changes to the dimensions of the primary display
+ // Notify RenderEngine of changes to the dimensions of the active display
// so that it can configure its internal caches accordingly.
- virtual void onPrimaryDisplaySizeChanged(ui::Size size) = 0;
+ virtual void onActiveDisplaySizeChanged(ui::Size size) = 0;
// Renders layers for a particular display via GPU composition. This method
// should be called for every display that needs to be rendered via the GPU.
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index 0175af3..0be3ba6 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -44,7 +44,7 @@
MOCK_CONST_METHOD0(getMaxViewportDims, size_t());
MOCK_CONST_METHOD0(isProtected, bool());
MOCK_CONST_METHOD0(supportsProtectedContent, bool());
- MOCK_METHOD1(useProtectedContext, bool(bool));
+ MOCK_METHOD1(useProtectedContext, void(bool));
MOCK_METHOD0(cleanupPostRender, void());
MOCK_CONST_METHOD0(canSkipPostRenderCleanup, bool());
MOCK_METHOD6(drawLayers,
@@ -54,7 +54,7 @@
MOCK_METHOD0(cleanFramebufferCache, void());
MOCK_METHOD0(getContextPriority, int());
MOCK_METHOD0(supportsBackgroundBlur, bool());
- MOCK_METHOD1(onPrimaryDisplaySizeChanged, void(ui::Size));
+ MOCK_METHOD1(onActiveDisplaySizeChanged, void(ui::Size));
protected:
// mock renderengine still needs to implement these, but callers should never need to call them.
diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp
index 725f57b..ae8f238 100644
--- a/libs/renderengine/skia/Cache.cpp
+++ b/libs/renderengine/skia/Cache.cpp
@@ -41,6 +41,10 @@
0.f, 1.1f, 0.f, 0.f,
0.f, 0.f, 1.f, 0.f,
0.f, 0.f, 0.f, 1.f);
+const auto kFlip = mat4(1.1f, -0.1f, 0.f, 0.f,
+ 0.1f, 1.1f, 0.f, 0.f,
+ 0.f, 0.f, 1.f, 0.f,
+ 2.f, 2.f, 0.f, 1.f);
// clang-format on
// When setting layer.sourceDataspace, whether it matches the destination or not determines whether
// a color correction effect is added to the shader.
@@ -52,42 +56,64 @@
const std::shared_ptr<ExternalTexture>& dstTexture) {
// Somewhat arbitrary dimensions, but on screen and slightly shorter, based
// on actual use.
- FloatRect rect(0, 0, display.physicalDisplay.width(), display.physicalDisplay.height() - 30);
+ const Rect& displayRect = display.physicalDisplay;
+ FloatRect rect(0, 0, displayRect.width(), displayRect.height());
+ FloatRect smallerRect(20, 20, displayRect.width()-20, displayRect.height()-20);
+
LayerSettings layer{
.geometry =
Geometry{
.boundaries = rect,
.roundedCornersCrop = rect,
+ .roundedCornersRadius = 50.f,
},
// drawShadow ignores alpha
.shadow =
ShadowSettings{
+ .boundaries = rect,
.ambientColor = vec4(0, 0, 0, 0.00935997f),
.spotColor = vec4(0, 0, 0, 0.0455841f),
- .lightPos = vec3(370.508f, -1527.03f, 1650.f),
- .lightRadius = 2200.0f,
- .length = 0.955342f,
+ .lightPos = vec3(500.f, -1500.f, 1500.f),
+ .lightRadius = 2500.0f,
+ .length = 15.f,
},
- // important that this matches dest so the general shadow fragment shader doesn't
- // have color correction added, and important that it be srgb, so the *vertex* shader
- // doesn't have color correction added.
- .sourceDataspace = kDestDataSpace,
// setting this is mandatory for shadows and blurs
.skipContentDraw = true,
+ .alpha = 1,
+ };
+ LayerSettings caster{
+ .geometry =
+ Geometry{
+ .boundaries = smallerRect,
+ .roundedCornersCrop = rect,
+ .roundedCornersRadius = 50.f,
+ },
+ .source =
+ PixelSource{
+ .solidColor = half3(0.f, 0.f, 0.f),
+ },
+ .alpha = 1,
};
- auto layers = std::vector<const LayerSettings*>{&layer};
- // The identity matrix will generate the fast shader
- renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd(),
- nullptr);
- // This matrix, which has different scales for x and y, will
- // generate the slower (more general case) version, which has variants for translucent
- // casters and rounded rects.
- layer.geometry.positionTransform = kScaleAsymmetric;
- for (auto translucent : {false, true}) {
- layer.shadow.casterIsTranslucent = translucent;
- renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
- base::unique_fd(), nullptr);
+ auto layers = std::vector<const LayerSettings*>{&layer, &caster};
+ // When sourceDataspace matches dest, the general shadow fragment shader doesn't
+ // have color correction added.
+ // independently, when it is not srgb, the *vertex* shader has color correction added.
+ // This may be a bug, but the shader still needs to be cached as it is triggered
+ // during youtube pip.
+ for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) {
+ layer.sourceDataspace = dataspace;
+ // The 2nd matrix, which has different scales for x and y, will
+ // generate the slower (more general case) shadow shader
+ for (auto transform : {mat4(), kScaleAndTranslate, kFlip}) {
+ layer.geometry.positionTransform = transform;
+ caster.geometry.positionTransform = transform;
+ for (bool translucent : {false, true}){
+ layer.shadow.casterIsTranslucent = translucent;
+ renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
+ base::unique_fd(), nullptr);
+ }
+ }
}
}
@@ -99,6 +125,9 @@
LayerSettings layer{
.geometry =
Geometry{
+ // The position transform doesn't matter when the reduced shader mode
+ // in in effect. A matrix transform stage is always included.
+ .positionTransform = mat4(),
.boundaries = rect,
.roundedCornersCrop = rect,
},
@@ -109,29 +138,20 @@
}},
};
- auto threeCornerRadii = {0.0f, 0.05f, 50.f};
- auto oneCornerRadius = {50.f};
-
- // Test both drawRect and drawRRect
auto layers = std::vector<const LayerSettings*>{&layer};
for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) {
layer.sourceDataspace = dataspace;
- for (bool identity : {true, false}) {
- layer.geometry.positionTransform = identity ? mat4() : kScaleAndTranslate;
- // Corner radii less than 0.5 creates a special shader. This likely occurs in real usage
- // due to animating corner radius.
- // For the non-idenity matrix, only the large corner radius will create a new shader.
- for (float roundedCornersRadius : identity ? threeCornerRadii : oneCornerRadius) {
- // roundedCornersCrop is always set, but it is this radius that triggers the
- // behavior
- layer.geometry.roundedCornersRadius = roundedCornersRadius;
- for (bool isOpaque : {true, false}) {
- layer.source.buffer.isOpaque = isOpaque;
- for (auto alpha : {half(.23999f), half(1.0f)}) {
- layer.alpha = alpha;
- renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
- base::unique_fd(), nullptr);
- }
+ // Cache shaders for both rects and round rects.
+ // In reduced shader mode, all non-zero round rect radii get the same code path.
+ for (float roundedCornersRadius : {0.0f, 50.0f}) {
+ // roundedCornersCrop is always set, but the radius triggers the behavior
+ layer.geometry.roundedCornersRadius = roundedCornersRadius;
+ for (bool isOpaque : {true, false}) {
+ layer.source.buffer.isOpaque = isOpaque;
+ for (auto alpha : {half(.2f), half(1.0f)}) {
+ layer.alpha = alpha;
+ renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
+ base::unique_fd(), nullptr);
}
}
}
@@ -157,7 +177,7 @@
auto layers = std::vector<const LayerSettings*>{&layer};
for (auto transform : {mat4(), kScaleAndTranslate}) {
layer.geometry.positionTransform = transform;
- for (float roundedCornersRadius : {0.0f, 0.05f, 50.f}) {
+ for (float roundedCornersRadius : {0.0f, 50.f}) {
layer.geometry.roundedCornersRadius = roundedCornersRadius;
renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
base::unique_fd(), nullptr);
@@ -225,11 +245,9 @@
layer.source = pixelSource;
for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) {
layer.sourceDataspace = dataspace;
- // Produce a CircularRRect clip and an EllipticalRRect clip
+ // Produce a CircularRRect clip and an EllipticalRRect clip.
for (auto transform : {kScaleAndTranslate, kScaleAsymmetric}) {
layer.geometry.positionTransform = transform;
- // In real use, I saw alpha of 1.0 and 0.999, probably a mistake, but cache both
- // shaders.
for (float alpha : {0.5f, 1.f}) {
layer.alpha = alpha,
renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
@@ -240,6 +258,69 @@
}
}
+static void drawPIPImageLayer(SkiaRenderEngine* renderengine, const DisplaySettings& display,
+ const std::shared_ptr<ExternalTexture>& dstTexture,
+ const std::shared_ptr<ExternalTexture>& srcTexture) {
+ const Rect& displayRect = display.physicalDisplay;
+ FloatRect rect(0, 0, displayRect.width(), displayRect.height());
+ LayerSettings layer{
+ .geometry =
+ Geometry{
+ // Note that this flip matrix only makes a difference when clipping,
+ // which happens in this layer because the roundrect crop is just a bit
+ // larger than the layer bounds.
+ .positionTransform = kFlip,
+ .boundaries = rect,
+ .roundedCornersRadius = 94.2551,
+ .roundedCornersCrop = FloatRect(
+ -93.75, 0, displayRect.width() + 93.75, displayRect.height()),
+ },
+ .source = PixelSource{.buffer =
+ Buffer{
+ .buffer = srcTexture,
+ .maxLuminanceNits = 1000.f,
+ .isOpaque = 0,
+ .usePremultipliedAlpha = 1,
+ }},
+ .sourceDataspace = kOtherDataSpace,
+ .alpha = 1,
+
+ };
+
+ auto layers = std::vector<const LayerSettings*>{&layer};
+ renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
+ base::unique_fd(), nullptr);
+}
+
+static void drawHolePunchLayer(SkiaRenderEngine* renderengine, const DisplaySettings& display,
+ const std::shared_ptr<ExternalTexture>& dstTexture) {
+ const Rect& displayRect = display.physicalDisplay;
+ FloatRect rect(0, 0, displayRect.width(), displayRect.height());
+ FloatRect small(0, 0, displayRect.width()-20, displayRect.height()+20);
+ LayerSettings layer{
+ .geometry =
+ Geometry{
+ .positionTransform = kScaleAndTranslate,
+ // the boundaries have to be smaller than the rounded crop so that
+ // clipRRect is used instead of drawRRect
+ .boundaries = small,
+ .roundedCornersRadius = 50.f,
+ .roundedCornersCrop = rect,
+ },
+ .source = PixelSource{
+ .solidColor = half3(0.f, 0.f, 0.f),
+ },
+ .sourceDataspace = kDestDataSpace,
+ .alpha = 0,
+ .disableBlending = true,
+
+ };
+
+ auto layers = std::vector<const LayerSettings*>{&layer};
+ renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
+ base::unique_fd(), nullptr);
+}
+
//
// The collection of shaders cached here were found by using perfetto to record shader compiles
// during actions that involve RenderEngine, logging the layer settings, and the shader code
@@ -251,8 +332,6 @@
// kFlushAfterEveryLayer = true
// in external/skia/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp
// gPrintSKSL = true
-//
-// TODO(b/184631553) cache the shader involved in youtube pip return.
void Cache::primeShaderCache(SkiaRenderEngine* renderengine) {
const int previousCount = renderengine->reportShadersCompiled();
if (previousCount) {
@@ -272,6 +351,12 @@
.maxLuminance = 500,
.outputDataspace = kDestDataSpace,
};
+ DisplaySettings p3Display{
+ .physicalDisplay = displayRect,
+ .clip = displayRect,
+ .maxLuminance = 500,
+ .outputDataspace = kOtherDataSpace,
+ };
const int64_t usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
@@ -294,35 +379,47 @@
std::make_shared<ExternalTexture>(srcBuffer, *renderengine,
ExternalTexture::Usage::READABLE |
ExternalTexture::Usage::WRITEABLE);
-
- // 6 shaders
+ drawHolePunchLayer(renderengine, display, dstTexture);
drawSolidLayers(renderengine, display, dstTexture);
- // 8 shaders
drawShadowLayers(renderengine, display, srcTexture);
+ drawShadowLayers(renderengine, p3Display, srcTexture);
if (renderengine->supportsBackgroundBlur()) {
- // 2 shaders
drawBlurLayers(renderengine, display, dstTexture);
}
- // The majority of shaders are related to sampling images.
- drawImageLayers(renderengine, display, dstTexture, srcTexture);
-
// should be the same as AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
const int64_t usageExternal = GRALLOC_USAGE_HW_TEXTURE;
-
sp<GraphicBuffer> externalBuffer =
new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888,
1, usageExternal, "primeShaderCache_external");
const auto externalTexture =
std::make_shared<ExternalTexture>(externalBuffer, *renderengine,
ExternalTexture::Usage::READABLE);
- // TODO(b/184665179) doubles number of image shader compilations, but only somewhere
- // between 6 and 8 will occur in real uses.
- drawImageLayers(renderengine, display, dstTexture, externalTexture);
- // Draw layers for b/185569240.
- drawClippedLayers(renderengine, display, dstTexture, externalTexture);
+ // Another external texture with a different pixel format triggers useIsOpaqueWorkaround
+ sp<GraphicBuffer> f16ExternalBuffer =
+ new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_FP16,
+ 1, usageExternal, "primeShaderCache_external_f16");
+ const auto f16ExternalTexture =
+ std::make_shared<ExternalTexture>(f16ExternalBuffer, *renderengine,
+ ExternalTexture::Usage::READABLE);
+
+ // The majority of shaders are related to sampling images.
+ // These need to be generated with various source textures
+ // The F16 texture may not be usable on all devices, so check first that it was created with
+ // the requested usage bit.
+ auto textures = {srcTexture, externalTexture};
+ auto texturesWithF16 = {srcTexture, externalTexture, f16ExternalTexture};
+ bool canUsef16 = f16ExternalBuffer->getUsage() & GRALLOC_USAGE_HW_TEXTURE;
+
+ for (auto texture : canUsef16 ? texturesWithF16 : textures) {
+ drawImageLayers(renderengine, display, dstTexture, texture);
+ // Draw layers for b/185569240.
+ drawClippedLayers(renderengine, display, dstTexture, texture);
+ }
+
+ drawPIPImageLayer(renderengine, display, dstTexture, externalTexture);
const nsecs_t timeAfter = systemTime();
const float compileTimeMs = static_cast<float>(timeAfter - timeBefore) / 1.0E6;
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index c7356ea..f4b07d0 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -320,7 +320,8 @@
options.fReducedShaderVariations = true;
options.fPersistentCache = &mSkSLCacheMonitor;
mGrContext = GrDirectContext::MakeGL(glInterface, options);
- if (useProtectedContext(true)) {
+ if (supportsProtectedContent()) {
+ useProtectedContext(true);
mProtectedGrContext = GrDirectContext::MakeGL(glInterface, options);
useProtectedContext(false);
}
@@ -373,12 +374,10 @@
return mInProtectedContext ? mProtectedGrContext.get() : mGrContext.get();
}
-bool SkiaGLRenderEngine::useProtectedContext(bool useProtectedContext) {
- if (useProtectedContext == mInProtectedContext) {
- return true;
- }
- if (useProtectedContext && !supportsProtectedContent()) {
- return false;
+void SkiaGLRenderEngine::useProtectedContext(bool useProtectedContext) {
+ if (useProtectedContext == mInProtectedContext ||
+ (useProtectedContext && !supportsProtectedContent())) {
+ return;
}
// release any scratch resources before switching into a new mode
@@ -389,9 +388,8 @@
const EGLSurface surface =
useProtectedContext ? mProtectedPlaceholderSurface : mPlaceholderSurface;
const EGLContext context = useProtectedContext ? mProtectedEGLContext : mEGLContext;
- const bool success = eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE;
- if (success) {
+ if (eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE) {
mInProtectedContext = useProtectedContext;
// given that we are sharing the same thread between two GrContexts we need to
// make sure that the thread state is reset when switching between the two.
@@ -399,7 +397,6 @@
getActiveGrContext()->resetContext();
}
}
- return success;
}
base::unique_fd SkiaGLRenderEngine::flush() {
@@ -1401,7 +1398,7 @@
return value;
}
-void SkiaGLRenderEngine::onPrimaryDisplaySizeChanged(ui::Size size) {
+void SkiaGLRenderEngine::onActiveDisplaySizeChanged(ui::Size size) {
// This cache multiplier was selected based on review of cache sizes relative
// to the screen resolution. Looking at the worst case memory needed by blur (~1.5x),
// shadows (~1x), and general data structures (e.g. vertex buffers) we selected this as a
@@ -1413,10 +1410,12 @@
getActiveGrContext()->setResourceCacheLimit(maxResourceBytes);
// if it is possible to switch contexts then we will resize the other context
- if (useProtectedContext(!mInProtectedContext)) {
+ const bool originalProtectedState = mInProtectedContext;
+ useProtectedContext(!mInProtectedContext);
+ if (mInProtectedContext != originalProtectedState) {
getActiveGrContext()->setResourceCacheLimit(maxResourceBytes);
// reset back to the initial context that was active when this method was called
- useProtectedContext(!mInProtectedContext);
+ useProtectedContext(originalProtectedState);
}
}
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index b30355b..cc91948 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -64,10 +64,10 @@
int getContextPriority() override;
bool isProtected() const override { return mInProtectedContext; }
bool supportsProtectedContent() const override;
- bool useProtectedContext(bool useProtectedContext) override;
+ void useProtectedContext(bool useProtectedContext) override;
bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; }
void assertShadersCompiled(int numShaders) override;
- void onPrimaryDisplaySizeChanged(ui::Size size) override;
+ void onActiveDisplaySizeChanged(ui::Size size) override;
int reportShadersCompiled() override;
protected:
diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h
index 31ad63e..7cd9eca 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.h
+++ b/libs/renderengine/skia/SkiaRenderEngine.h
@@ -44,7 +44,6 @@
virtual void deleteTextures(size_t /*count*/, uint32_t const* /*names*/) override{};
virtual bool isProtected() const override { return false; } // mInProtectedContext; }
virtual bool supportsProtectedContent() const override { return false; };
- virtual bool useProtectedContext(bool /*useProtectedContext*/) override { return false; };
virtual status_t drawLayers(const DisplaySettings& /*display*/,
const std::vector<const LayerSettings*>& /*layers*/,
const std::shared_ptr<ExternalTexture>& /*buffer*/,
diff --git a/libs/renderengine/skia/filters/LinearEffect.cpp b/libs/renderengine/skia/filters/LinearEffect.cpp
index 9b044e1..fc45af9 100644
--- a/libs/renderengine/skia/filters/LinearEffect.cpp
+++ b/libs/renderengine/skia/filters/LinearEffect.cpp
@@ -167,13 +167,12 @@
float nits = xyz.y;
- // clamp to max input luminance
- nits = clamp(nits, 0.0, maxInLumi);
-
- // scale [0.0, maxInLumi] to [0.0, maxOutLumi]
+ // if the max input luminance is less than what we can output then
+ // no tone mapping is needed as all color values will be in range.
if (maxInLumi <= maxOutLumi) {
- return xyz * (maxOutLumi / maxInLumi);
+ return xyz;
} else {
+
// three control points
const float x0 = 10.0;
const float y0 = 17.0;
diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
index c65e731..830f463 100644
--- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp
+++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
@@ -118,16 +118,26 @@
ASSERT_EQ(true, result);
}
-TEST_F(RenderEngineThreadedTest, useProtectedContext_returnsFalse) {
- EXPECT_CALL(*mRenderEngine, useProtectedContext(false)).WillOnce(Return(false));
- status_t result = mThreadedRE->useProtectedContext(false);
- ASSERT_EQ(false, result);
+TEST_F(RenderEngineThreadedTest, useProtectedContext) {
+ EXPECT_CALL(*mRenderEngine, useProtectedContext(true));
+ auto& ipExpect = EXPECT_CALL(*mRenderEngine, isProtected()).WillOnce(Return(false));
+ EXPECT_CALL(*mRenderEngine, supportsProtectedContent()).WillOnce(Return(true));
+ EXPECT_CALL(*mRenderEngine, isProtected()).After(ipExpect).WillOnce(Return(true));
+
+ mThreadedRE->useProtectedContext(true);
+ ASSERT_EQ(true, mThreadedRE->isProtected());
+
+ // call ANY synchronous function to ensure that useProtectedContext has completed.
+ mThreadedRE->getContextPriority();
+ ASSERT_EQ(true, mThreadedRE->isProtected());
}
-TEST_F(RenderEngineThreadedTest, useProtectedContext_returnsTrue) {
- EXPECT_CALL(*mRenderEngine, useProtectedContext(false)).WillOnce(Return(true));
- status_t result = mThreadedRE->useProtectedContext(false);
- ASSERT_EQ(true, result);
+TEST_F(RenderEngineThreadedTest, useProtectedContext_quickReject) {
+ EXPECT_CALL(*mRenderEngine, useProtectedContext(false)).Times(0);
+ EXPECT_CALL(*mRenderEngine, isProtected()).WillOnce(Return(false));
+ mThreadedRE->useProtectedContext(false);
+ // call ANY synchronous function to ensure that useProtectedContext has completed.
+ mThreadedRE->getContextPriority();
}
TEST_F(RenderEngineThreadedTest, PostRenderCleanup_skipped) {
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp
index ea3871f..8e666d5 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.cpp
+++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp
@@ -90,6 +90,7 @@
}
mRenderEngine = factory();
+ mIsProtected = mRenderEngine->isProtected();
pthread_setname_np(pthread_self(), mThreadName);
@@ -248,10 +249,8 @@
bool RenderEngineThreaded::isProtected() const {
waitUntilInitialized();
- // ensure that useProtectedContext is not currently being changed by some
- // other thread.
std::lock_guard lock(mThreadMutex);
- return mRenderEngine->isProtected();
+ return mIsProtected;
}
bool RenderEngineThreaded::supportsProtectedContent() const {
@@ -259,20 +258,28 @@
return mRenderEngine->supportsProtectedContent();
}
-bool RenderEngineThreaded::useProtectedContext(bool useProtectedContext) {
- std::promise<bool> resultPromise;
- std::future<bool> resultFuture = resultPromise.get_future();
+void RenderEngineThreaded::useProtectedContext(bool useProtectedContext) {
+ if (isProtected() == useProtectedContext ||
+ (useProtectedContext && !supportsProtectedContent())) {
+ return;
+ }
+
{
std::lock_guard lock(mThreadMutex);
- mFunctionCalls.push(
- [&resultPromise, useProtectedContext](renderengine::RenderEngine& instance) {
- ATRACE_NAME("REThreaded::useProtectedContext");
- bool returnValue = instance.useProtectedContext(useProtectedContext);
- resultPromise.set_value(returnValue);
- });
+ mFunctionCalls.push([useProtectedContext, this](renderengine::RenderEngine& instance) {
+ ATRACE_NAME("REThreaded::useProtectedContext");
+ instance.useProtectedContext(useProtectedContext);
+ if (instance.isProtected() != useProtectedContext) {
+ ALOGE("Failed to switch RenderEngine context.");
+ // reset the cached mIsProtected value to a good state, but this does not
+ // prevent other callers of this method and isProtected from reading the
+ // invalid cached value.
+ mIsProtected = instance.isProtected();
+ }
+ });
+ mIsProtected = useProtectedContext;
}
mCondition.notify_one();
- return resultFuture.get();
}
void RenderEngineThreaded::cleanupPostRender() {
@@ -354,14 +361,14 @@
return mRenderEngine->supportsBackgroundBlur();
}
-void RenderEngineThreaded::onPrimaryDisplaySizeChanged(ui::Size size) {
+void RenderEngineThreaded::onActiveDisplaySizeChanged(ui::Size size) {
// This function is designed so it can run asynchronously, so we do not need to wait
// for the futures.
{
std::lock_guard lock(mThreadMutex);
mFunctionCalls.push([size](renderengine::RenderEngine& instance) {
- ATRACE_NAME("REThreaded::onPrimaryDisplaySizeChanged");
- instance.onPrimaryDisplaySizeChanged(size);
+ ATRACE_NAME("REThreaded::onActiveDisplaySizeChanged");
+ instance.onActiveDisplaySizeChanged(size);
});
}
mCondition.notify_one();
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h
index 9b523b2..b197df7 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.h
+++ b/libs/renderengine/threaded/RenderEngineThreaded.h
@@ -53,7 +53,7 @@
bool isProtected() const override;
bool supportsProtectedContent() const override;
- bool useProtectedContext(bool useProtectedContext) override;
+ void useProtectedContext(bool useProtectedContext) override;
void cleanupPostRender() override;
status_t drawLayers(const DisplaySettings& display,
@@ -65,7 +65,7 @@
void cleanFramebufferCache() override;
int getContextPriority() override;
bool supportsBackgroundBlur() override;
- void onPrimaryDisplaySizeChanged(ui::Size size) override;
+ void onActiveDisplaySizeChanged(ui::Size size) override;
protected:
void mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, bool isRenderable) override;
@@ -100,6 +100,7 @@
* Render Engine
*/
std::unique_ptr<renderengine::RenderEngine> mRenderEngine;
+ std::atomic<bool> mIsProtected = false;
};
} // namespace threaded
} // namespace renderengine
diff --git a/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl
index f91f5b9..9564cba 100644
--- a/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl
+++ b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl
@@ -36,7 +36,7 @@
void setSensorPrivacy(boolean enable);
- void setIndividualSensorPrivacy(int userId, int sensor, boolean enable);
+ void setIndividualSensorPrivacy(int userId, int source, int sensor, boolean enable);
- void setIndividualSensorPrivacyForProfileGroup(int userId, int sensor, boolean enable);
+ void setIndividualSensorPrivacyForProfileGroup(int userId, int source, int sensor, boolean enable);
}
diff --git a/libs/ui/include/ui/Transform.h b/libs/ui/include/ui/Transform.h
index a197b3b..33fbe05 100644
--- a/libs/ui/include/ui/Transform.h
+++ b/libs/ui/include/ui/Transform.h
@@ -112,6 +112,7 @@
void dump(const char* name, const char* prefix = "") const;
static constexpr RotationFlags toRotationFlags(Rotation);
+ static constexpr Rotation toRotation(RotationFlags);
private:
struct mat33 {
@@ -151,5 +152,20 @@
}
}
+inline constexpr Rotation Transform::toRotation(Transform::RotationFlags rotationFlags) {
+ switch (rotationFlags) {
+ case ROT_0:
+ return ROTATION_0;
+ case ROT_90:
+ return ROTATION_90;
+ case ROT_180:
+ return ROTATION_180;
+ case ROT_270:
+ return ROTATION_270;
+ default:
+ return ROTATION_0;
+ }
+}
+
} // namespace ui
} // namespace android
diff --git a/services/gpuservice/bpfprogs/gpu_mem.c b/services/gpuservice/bpfprogs/gpu_mem.c
index c75213b..16e1e8a 100644
--- a/services/gpuservice/bpfprogs/gpu_mem.c
+++ b/services/gpuservice/bpfprogs/gpu_mem.c
@@ -72,4 +72,4 @@
return 0;
}
-char _license[] SEC("license") = "Apache 2.0";
+LICENSE("Apache 2.0");
diff --git a/services/inputflinger/TEST_MAPPING b/services/inputflinger/TEST_MAPPING
index dc0e60c..3d85bef 100644
--- a/services/inputflinger/TEST_MAPPING
+++ b/services/inputflinger/TEST_MAPPING
@@ -27,7 +27,17 @@
"name": "CtsViewTestCases",
"options": [
{
- "include-filter": "android.view.cts.MotionEventTest"
+ "include-filter": "android.view.cts.MotionEventTest",
+ "include-filter": "android.view.cts.VerifyInputEventTest"
+ }
+ ]
+ },
+ {
+ "name": "FrameworksCoreTests",
+ "options": [
+ {
+ "include-filter": "android.view.VerifiedKeyEventTest",
+ "include-filter": "android.view.VerifiedMotionEventTest"
}
]
},
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index cecfb33..d8af48e 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -3756,7 +3756,7 @@
if (shouldSendKeyToInputFilterLocked(args)) {
mLock.unlock();
- policyFlags |= POLICY_FLAG_FILTERED | POLICY_FLAG_INPUTFILTER_TRUSTED;
+ policyFlags |= POLICY_FLAG_FILTERED;
if (!mPolicy->filterInputEvent(&event, policyFlags)) {
return; // event was consumed by the filter
}
@@ -3979,16 +3979,14 @@
}
// For all injected events, set device id = VIRTUAL_KEYBOARD_ID. The only exception is events
- // that have gone through the InputFilter. If the event passed through the InputFilter,
- // but did not get modified, assign the provided device id. If the InputFilter modifies the
- // events in any way, it is responsible for removing this flag.
- // If the injected event originated from accessibility, assign the accessibility device id,
- // so that it can be distinguished from regular injected events.
+ // that have gone through the InputFilter. If the event passed through the InputFilter, assign
+ // the provided device id. If the InputFilter is accessibility, and it modifies or synthesizes
+ // the injected event, it is responsible for setting POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY.
+ // For those events, we will set FLAG_IS_ACCESSIBILITY_EVENT to allow apps to distinguish them
+ // from events that originate from actual hardware.
int32_t resolvedDeviceId = VIRTUAL_KEYBOARD_ID;
- if (policyFlags & POLICY_FLAG_INPUTFILTER_TRUSTED) {
+ if (policyFlags & POLICY_FLAG_FILTERED) {
resolvedDeviceId = event->getDeviceId();
- } else if (policyFlags & POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY) {
- resolvedDeviceId = ACCESSIBILITY_DEVICE_ID;
}
std::queue<std::unique_ptr<EventEntry>> injectedEntries;
@@ -4001,6 +3999,9 @@
}
int32_t flags = incomingKey.getFlags();
+ if (policyFlags & POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY) {
+ flags |= AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT;
+ }
int32_t keyCode = incomingKey.getKeyCode();
int32_t metaState = incomingKey.getMetaState();
accelerateMetaShortcuts(resolvedDeviceId, action,
@@ -4042,6 +4043,7 @@
size_t pointerCount = motionEvent.getPointerCount();
const PointerProperties* pointerProperties = motionEvent.getPointerProperties();
int32_t actionButton = motionEvent.getActionButton();
+ int32_t flags = motionEvent.getFlags();
int32_t displayId = motionEvent.getDisplayId();
if (!validateMotionEvent(action, actionButton, pointerCount, pointerProperties)) {
return InputEventInjectionResult::FAILED;
@@ -4057,6 +4059,10 @@
}
}
+ if (policyFlags & POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY) {
+ flags |= AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT;
+ }
+
mLock.lock();
const nsecs_t* sampleEventTimes = motionEvent.getSampleEventTimes();
const PointerCoords* samplePointerCoords = motionEvent.getSamplePointerCoords();
@@ -4064,8 +4070,7 @@
std::make_unique<MotionEntry>(motionEvent.getId(), *sampleEventTimes,
resolvedDeviceId, motionEvent.getSource(),
motionEvent.getDisplayId(), policyFlags, action,
- actionButton, motionEvent.getFlags(),
- motionEvent.getMetaState(),
+ actionButton, flags, motionEvent.getMetaState(),
motionEvent.getButtonState(),
motionEvent.getClassification(),
motionEvent.getEdgeFlags(),
@@ -4085,7 +4090,7 @@
std::make_unique<MotionEntry>(motionEvent.getId(), *sampleEventTimes,
resolvedDeviceId, motionEvent.getSource(),
motionEvent.getDisplayId(), policyFlags,
- action, actionButton, motionEvent.getFlags(),
+ action, actionButton, flags,
motionEvent.getMetaState(),
motionEvent.getButtonState(),
motionEvent.getClassification(),
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
index ca43123..fab7f4c 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
@@ -104,36 +104,37 @@
#endif
} else {
Slot* slot = &mSlots[mCurrentSlot];
+ // If mUsingSlotsProtocol is true, it means the raw pointer has axis info of
+ // ABS_MT_TRACKING_ID and ABS_MT_SLOT, so driver should send a valid trackingId while
+ // updating the slot.
+ if (!mUsingSlotsProtocol) {
+ slot->mInUse = true;
+ }
switch (rawEvent->code) {
case ABS_MT_POSITION_X:
- slot->mInUse = true;
slot->mAbsMTPositionX = rawEvent->value;
+ warnIfNotInUse(*rawEvent, *slot);
break;
case ABS_MT_POSITION_Y:
- slot->mInUse = true;
slot->mAbsMTPositionY = rawEvent->value;
+ warnIfNotInUse(*rawEvent, *slot);
break;
case ABS_MT_TOUCH_MAJOR:
- slot->mInUse = true;
slot->mAbsMTTouchMajor = rawEvent->value;
break;
case ABS_MT_TOUCH_MINOR:
- slot->mInUse = true;
slot->mAbsMTTouchMinor = rawEvent->value;
slot->mHaveAbsMTTouchMinor = true;
break;
case ABS_MT_WIDTH_MAJOR:
- slot->mInUse = true;
slot->mAbsMTWidthMajor = rawEvent->value;
break;
case ABS_MT_WIDTH_MINOR:
- slot->mInUse = true;
slot->mAbsMTWidthMinor = rawEvent->value;
slot->mHaveAbsMTWidthMinor = true;
break;
case ABS_MT_ORIENTATION:
- slot->mInUse = true;
slot->mAbsMTOrientation = rawEvent->value;
break;
case ABS_MT_TRACKING_ID:
@@ -147,15 +148,12 @@
}
break;
case ABS_MT_PRESSURE:
- slot->mInUse = true;
slot->mAbsMTPressure = rawEvent->value;
break;
case ABS_MT_DISTANCE:
- slot->mInUse = true;
slot->mAbsMTDistance = rawEvent->value;
break;
case ABS_MT_TOOL_TYPE:
- slot->mInUse = true;
slot->mAbsMTToolType = rawEvent->value;
slot->mHaveAbsMTToolType = true;
break;
@@ -177,6 +175,13 @@
return mHaveStylus;
}
+void MultiTouchMotionAccumulator::warnIfNotInUse(const RawEvent& event, const Slot& slot) {
+ if (!slot.mInUse) {
+ ALOGW("Received unexpected event (0x%0x, 0x%0x) for slot %i with tracking id %i",
+ event.code, event.value, mCurrentSlot, slot.mAbsMTTrackingId);
+ }
+}
+
// --- MultiTouchMotionAccumulator::Slot ---
MultiTouchMotionAccumulator::Slot::Slot() {
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
index ea6f207..225ad49 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
@@ -87,6 +87,7 @@
bool mHaveStylus;
void clearSlots(int32_t initialSlot);
+ void warnIfNotInUse(const RawEvent& event, const Slot& slot);
};
class MultiTouchInputMapper : public TouchInputMapper {
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index fbb4db0..af02844 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -1471,6 +1471,13 @@
next.rawPointerData.canceledIdBits.value);
#endif
+ if (!next.rawPointerData.touchingIdBits.isEmpty() &&
+ !next.rawPointerData.hoveringIdBits.isEmpty() &&
+ last.rawPointerData.hoveringIdBits != next.rawPointerData.hoveringIdBits) {
+ ALOGI("Multi-touch contains some hovering ids 0x%08x",
+ next.rawPointerData.hoveringIdBits.value);
+ }
+
processRawTouches(false /*timeout*/);
}
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index e268843..1a70e54 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -3170,7 +3170,8 @@
mWindow->consumeFocusEvent(true);
}
- void testInjectedKey(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId) {
+ void testInjectedKey(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId,
+ int32_t flags) {
KeyEvent event;
const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
@@ -3187,6 +3188,45 @@
InputEvent* received = mWindow->consume();
ASSERT_NE(nullptr, received);
ASSERT_EQ(resolvedDeviceId, received->getDeviceId());
+ ASSERT_EQ(received->getType(), AINPUT_EVENT_TYPE_KEY);
+ KeyEvent& keyEvent = static_cast<KeyEvent&>(*received);
+ ASSERT_EQ(flags, keyEvent.getFlags());
+ }
+
+ void testInjectedMotion(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId,
+ int32_t flags) {
+ MotionEvent event;
+ PointerProperties pointerProperties[1];
+ PointerCoords pointerCoords[1];
+ pointerProperties[0].clear();
+ pointerProperties[0].id = 0;
+ pointerCoords[0].clear();
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 300);
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 400);
+
+ ui::Transform identityTransform;
+ const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ event.initialize(InputEvent::nextId(), injectedDeviceId, AINPUT_SOURCE_TOUCHSCREEN,
+ DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0,
+ AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, MotionClassification::NONE,
+ identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ 0 /*AMOTION_EVENT_INVALID_DISPLAY_SIZE*/,
+ 0 /*AMOTION_EVENT_INVALID_DISPLAY_SIZE*/, eventTime, eventTime,
+ /*pointerCount*/ 1, pointerProperties, pointerCoords);
+
+ const int32_t additionalPolicyFlags = POLICY_FLAG_PASS_TO_USER;
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ InputEventInjectionSync::WAIT_FOR_RESULT, 10ms,
+ policyFlags | additionalPolicyFlags));
+
+ InputEvent* received = mWindow->consume();
+ ASSERT_NE(nullptr, received);
+ ASSERT_EQ(resolvedDeviceId, received->getDeviceId());
+ ASSERT_EQ(received->getType(), AINPUT_EVENT_TYPE_MOTION);
+ MotionEvent& motionEvent = static_cast<MotionEvent&>(*received);
+ ASSERT_EQ(flags, motionEvent.getFlags());
}
private:
@@ -3194,20 +3234,29 @@
};
TEST_F(InputFilterInjectionPolicyTest, TrustedFilteredEvents_KeepOriginalDeviceId) {
- // We don't need POLICY_FLAG_FILTERED here, but it will be set in practice, so keep it to make
- // the test more closely resemble the real usage
- testInjectedKey(POLICY_FLAG_FILTERED | POLICY_FLAG_INPUTFILTER_TRUSTED, 3 /*injectedDeviceId*/,
- 3 /*resolvedDeviceId*/);
+ // Must have POLICY_FLAG_FILTERED here to indicate that the event has gone through the input
+ // filter. Without it, the event will no different from a regularly injected event, and the
+ // injected device id will be overwritten.
+ testInjectedKey(POLICY_FLAG_FILTERED, 3 /*injectedDeviceId*/, 3 /*resolvedDeviceId*/,
+ 0 /*flags*/);
}
-TEST_F(InputFilterInjectionPolicyTest, EventsInjectedFromAccessibility_HaveAccessibilityDeviceId) {
+TEST_F(InputFilterInjectionPolicyTest, KeyEventsInjectedFromAccessibility_HaveAccessibilityFlag) {
testInjectedKey(POLICY_FLAG_FILTERED | POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY,
- 3 /*injectedDeviceId*/, ACCESSIBILITY_DEVICE_ID /*resolvedDeviceId*/);
+ 3 /*injectedDeviceId*/, 3 /*resolvedDeviceId*/,
+ AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
+}
+
+TEST_F(InputFilterInjectionPolicyTest,
+ MotionEventsInjectedFromAccessibility_HaveAccessibilityFlag) {
+ testInjectedMotion(POLICY_FLAG_FILTERED | POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY,
+ 3 /*injectedDeviceId*/, 3 /*resolvedDeviceId*/,
+ AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
}
TEST_F(InputFilterInjectionPolicyTest, RegularInjectedEvents_ReceiveVirtualDeviceId) {
testInjectedKey(0 /*policyFlags*/, 3 /*injectedDeviceId*/,
- VIRTUAL_KEYBOARD_ID /*resolvedDeviceId*/);
+ VIRTUAL_KEYBOARD_ID /*resolvedDeviceId*/, 0 /*flags*/);
}
class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest {
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 02423c4..778f6e6 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -2277,6 +2277,7 @@
const Point centerPoint = mDevice->getCenterPoint();
// ACTION_DOWN
+ mDevice->sendTrackingId(FIRST_TRACKING_ID);
mDevice->sendDown(centerPoint);
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action);
@@ -2297,6 +2298,8 @@
const Point centerPoint = mDevice->getCenterPoint();
// ACTION_DOWN
+ mDevice->sendSlot(FIRST_SLOT);
+ mDevice->sendTrackingId(FIRST_TRACKING_ID);
mDevice->sendDown(centerPoint);
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action);
@@ -8218,6 +8221,70 @@
ASSERT_NE(AMOTION_EVENT_FLAG_CANCELED, motionArgs.flags);
}
+/**
+ * Test multi-touch should sent ACTION_POINTER_UP/ACTION_UP when received the INVALID_TRACKING_ID,
+ * to prevent the driver side may send unexpected data after set tracking id as INVALID_TRACKING_ID
+ * cause slot be valid again.
+ */
+TEST_F(MultiTouchInputMapperTest, Process_MultiTouch_WithInvalidTrackingId) {
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareAxes(POSITION | ID | SLOT | PRESSURE);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+
+ NotifyMotionArgs motionArgs;
+
+ constexpr int32_t x1 = 100, y1 = 200, x2 = 0, y2 = 0;
+ // First finger down.
+ processId(mapper, FIRST_TRACKING_ID);
+ processPosition(mapper, x1, y1);
+ processPressure(mapper, RAW_PRESSURE_MAX);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+ ASSERT_EQ(uint32_t(1), motionArgs.pointerCount);
+
+ // First finger move.
+ processId(mapper, FIRST_TRACKING_ID);
+ processPosition(mapper, x1 + 1, y1 + 1);
+ processPressure(mapper, RAW_PRESSURE_MAX);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+ ASSERT_EQ(uint32_t(1), motionArgs.pointerCount);
+
+ // Second finger down.
+ processSlot(mapper, SECOND_SLOT);
+ processId(mapper, SECOND_TRACKING_ID);
+ processPosition(mapper, x2, y2);
+ processPressure(mapper, RAW_PRESSURE_MAX);
+ 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(uint32_t(2), motionArgs.pointerCount);
+
+ // second finger up with some unexpected data.
+ processSlot(mapper, SECOND_SLOT);
+ processId(mapper, INVALID_TRACKING_ID);
+ processPosition(mapper, x2, y2);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ motionArgs.action);
+ ASSERT_EQ(uint32_t(2), motionArgs.pointerCount);
+
+ // first finger up with some unexpected data.
+ processSlot(mapper, FIRST_SLOT);
+ processId(mapper, INVALID_TRACKING_ID);
+ processPosition(mapper, x2, y2);
+ processPressure(mapper, RAW_PRESSURE_MAX);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action);
+ ASSERT_EQ(uint32_t(1), motionArgs.pointerCount);
+}
+
// --- MultiTouchInputMapperTest_ExternalDevice ---
class MultiTouchInputMapperTest_ExternalDevice : public MultiTouchInputMapperTest {
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 3cb7e9c..6a78b53 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -421,7 +421,7 @@
mFrameTracker.setFrameReadyTime(desiredPresentTime);
}
- const Fps refreshRate = mFlinger->mRefreshRateConfigs->getCurrentRefreshRate().getFps();
+ const Fps refreshRate = display->refreshRateConfigs().getCurrentRefreshRate().getFps();
const std::optional<Fps> renderRate = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid());
if (presentFence->isValid()) {
mFlinger->mTimeStats->setPresentFence(layerId, mCurrentFrameNumber, presentFence,
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
index 2bf931c..2e7a377 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
@@ -65,7 +65,9 @@
size_t getLayerCount() const { return mLayers.size(); }
const Layer& getFirstLayer() const { return mLayers[0]; }
const Rect& getBounds() const { return mBounds; }
- Rect getTextureBounds() const { return mOutputSpace.content; }
+ Rect getTextureBounds() const {
+ return mTexture ? mTexture->get()->getBuffer()->getBounds() : Rect::INVALID_RECT;
+ }
const Region& getVisibleRegion() const { return mVisibleRegion; }
size_t getAge() const { return mAge; }
std::shared_ptr<renderengine::ExternalTexture> getBuffer() const {
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 742b155..ee73cfc 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -3487,7 +3487,7 @@
mLayer2.mLayerFEState.hasProtectedContent = true;
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(true));
EXPECT_CALL(mRenderEngine, isProtected).WillOnce(Return(true));
- EXPECT_CALL(mRenderEngine, useProtectedContext(false)).WillOnce(Return(true));
+ EXPECT_CALL(mRenderEngine, useProtectedContext(false));
mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
index 7f0e186..b05a594 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
@@ -355,7 +355,7 @@
expectReadyBuffer(cachedSet);
EXPECT_EQ(mOutputState.framebufferSpace, cachedSet.getOutputSpace());
- EXPECT_EQ(mOutputState.framebufferSpace.content, cachedSet.getTextureBounds());
+ EXPECT_EQ(Rect(kOutputSize.width, kOutputSize.height), cachedSet.getTextureBounds());
// Now check that appending a new cached set properly cleans up RenderEngine resources.
CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get();
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index c391901..4445eea 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -22,6 +22,8 @@
#undef LOG_TAG
#define LOG_TAG "DisplayDevice"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
#include <android-base/stringprintf.h>
#include <compositionengine/CompositionEngine.h>
#include <compositionengine/Display.h>
@@ -40,6 +42,7 @@
#include "DisplayDevice.h"
#include "Layer.h"
+#include "RefreshRateOverlay.h"
#include "SurfaceFlinger.h"
namespace android {
@@ -65,9 +68,12 @@
mSequenceId(args.sequenceId),
mConnectionType(args.connectionType),
mCompositionDisplay{args.compositionDisplay},
+ mActiveModeFPSTrace("ActiveModeFPS -" + to_string(getId())),
+ mActiveModeFPSHwcTrace("ActiveModeFPS_HWC -" + to_string(getId())),
mPhysicalOrientation(args.physicalOrientation),
mSupportedModes(std::move(args.supportedModes)),
- mIsPrimary(args.isPrimary) {
+ mIsPrimary(args.isPrimary),
+ mRefreshRateConfigs(std::move(args.refreshRateConfigs)) {
mCompositionDisplay->editState().isSecure = args.isSecure;
mCompositionDisplay->createRenderSurface(
compositionengine::RenderSurfaceCreationArgsBuilder()
@@ -154,20 +160,29 @@
void DisplayDevice::setActiveMode(DisplayModeId id) {
const auto mode = getMode(id);
LOG_FATAL_IF(!mode, "Cannot set active mode which is not supported.");
+ ATRACE_INT(mActiveModeFPSTrace.c_str(), mode->getFps().getIntValue());
mActiveMode = mode;
+ if (mRefreshRateConfigs) {
+ mRefreshRateConfigs->setCurrentModeId(mActiveMode->getId());
+ }
+ if (mRefreshRateOverlay) {
+ mRefreshRateOverlay->changeRefreshRate(mActiveMode->getFps());
+ }
}
-status_t DisplayDevice::initiateModeChange(DisplayModeId modeId,
+status_t DisplayDevice::initiateModeChange(const ActiveModeInfo& info,
const hal::VsyncPeriodChangeConstraints& constraints,
- hal::VsyncPeriodChangeTimeline* outTimeline) const {
- const auto mode = getMode(modeId);
- if (!mode) {
+ hal::VsyncPeriodChangeTimeline* outTimeline) {
+ if (!info.mode || info.mode->getPhysicalDisplayId() != getPhysicalId()) {
ALOGE("Trying to initiate a mode change to invalid mode %s on display %s",
- std::to_string(modeId.value()).c_str(), to_string(getId()).c_str());
+ info.mode ? std::to_string(info.mode->getId().value()).c_str() : "null",
+ to_string(getId()).c_str());
return BAD_VALUE;
}
- return mHwComposer.setActiveModeWithConstraints(getPhysicalId(), mode->getHwcId(), constraints,
- outTimeline);
+ mUpcomingActiveMode = info;
+ ATRACE_INT(mActiveModeFPSHwcTrace.c_str(), info.mode->getFps().getIntValue());
+ return mHwComposer.setActiveModeWithConstraints(getPhysicalId(), info.mode->getHwcId(),
+ constraints, outTimeline);
}
const DisplayModePtr& DisplayDevice::getActiveMode() const {
@@ -217,7 +232,10 @@
}
void DisplayDevice::setLayerStack(ui::LayerStack stack) {
- mCompositionDisplay->setLayerStackFilter(stack, isPrimary());
+ mCompositionDisplay->setLayerStackFilter(stack, isInternal());
+ if (mRefreshRateOverlay) {
+ mRefreshRateOverlay->setLayerStack(stack);
+ }
}
void DisplayDevice::setFlags(uint32_t flags) {
@@ -226,7 +244,11 @@
void DisplayDevice::setDisplaySize(int width, int height) {
LOG_FATAL_IF(!isVirtual(), "Changing the display size is supported only for virtual displays.");
- mCompositionDisplay->setDisplaySize(ui::Size(width, height));
+ const auto size = ui::Size(width, height);
+ mCompositionDisplay->setDisplaySize(size);
+ if (mRefreshRateOverlay) {
+ mRefreshRateOverlay->setViewport(size);
+ }
}
void DisplayDevice::setProjection(ui::Rotation orientation, Rect layerStackSpaceRect,
@@ -266,7 +288,7 @@
std::string DisplayDevice::getDebugName() const {
const char* type = "virtual";
if (mConnectionType) {
- type = *mConnectionType == ui::DisplayConnectionType::Internal ? "internal" : "external";
+ type = isInternal() ? "internal" : "external";
}
return base::StringPrintf("DisplayDevice{%s, %s%s, \"%s\"}", to_string(getId()).c_str(), type,
@@ -296,6 +318,10 @@
}
result.append("\n");
getCompositionDisplay()->dump(result);
+
+ if (mRefreshRateConfigs) {
+ mRefreshRateConfigs->dump(result);
+ }
}
bool DisplayDevice::hasRenderIntent(ui::RenderIntent intent) const {
@@ -382,6 +408,80 @@
capabilities.getDesiredMinLuminance());
}
+void DisplayDevice::enableRefreshRateOverlay(bool enable, bool showSpinnner) {
+ if (!enable) {
+ mRefreshRateOverlay.reset();
+ return;
+ }
+
+ const auto [lowFps, highFps] = mRefreshRateConfigs->getSupportedRefreshRateRange();
+ mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(*mFlinger, lowFps.getIntValue(),
+ highFps.getIntValue(), showSpinnner);
+ mRefreshRateOverlay->setLayerStack(getLayerStack());
+ mRefreshRateOverlay->setViewport(getSize());
+ mRefreshRateOverlay->changeRefreshRate(getActiveMode()->getFps());
+}
+
+bool DisplayDevice::onKernelTimerChanged(std::optional<DisplayModeId> desiredModeId,
+ bool timerExpired) {
+ if (mRefreshRateConfigs && mRefreshRateOverlay) {
+ const auto newRefreshRate =
+ mRefreshRateConfigs->onKernelTimerChanged(desiredModeId, timerExpired);
+ if (newRefreshRate) {
+ mRefreshRateOverlay->changeRefreshRate(*newRefreshRate);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void DisplayDevice::onInvalidate() {
+ if (mRefreshRateOverlay) {
+ mRefreshRateOverlay->onInvalidate();
+ }
+}
+
+bool DisplayDevice::setDesiredActiveMode(const ActiveModeInfo& info) {
+ ATRACE_CALL();
+
+ LOG_ALWAYS_FATAL_IF(!info.mode, "desired mode not provided");
+ LOG_ALWAYS_FATAL_IF(getPhysicalId() != info.mode->getPhysicalDisplayId(), "DisplayId mismatch");
+
+ ALOGV("%s(%s)", __func__, to_string(*info.mode).c_str());
+
+ std::scoped_lock lock(mActiveModeLock);
+ if (mDesiredActiveModeChanged) {
+ // If a mode change is pending, just cache the latest request in mDesiredActiveMode
+ const Scheduler::ModeEvent prevConfig = mDesiredActiveMode.event;
+ mDesiredActiveMode = info;
+ mDesiredActiveMode.event = mDesiredActiveMode.event | prevConfig;
+ return false;
+ }
+
+ // Check if we are already at the desired mode
+ if (getActiveMode()->getId() == info.mode->getId()) {
+ return false;
+ }
+
+ // Initiate a mode change.
+ mDesiredActiveModeChanged = true;
+ mDesiredActiveMode = info;
+ return true;
+}
+
+std::optional<DisplayDevice::ActiveModeInfo> DisplayDevice::getDesiredActiveMode() const {
+ std::scoped_lock lock(mActiveModeLock);
+ if (mDesiredActiveModeChanged) return mDesiredActiveMode;
+ return std::nullopt;
+}
+
+void DisplayDevice::clearDesiredActiveModeState() {
+ std::scoped_lock lock(mActiveModeLock);
+ mDesiredActiveMode.event = Scheduler::ModeEvent::None;
+ mDesiredActiveModeChanged = false;
+}
+
std::atomic<int32_t> DisplayDeviceState::sNextSequenceId(1);
} // namespace android
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index b068daf..afd12b5 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -39,17 +39,24 @@
#include <utils/RefBase.h>
#include <utils/Timers.h>
+#include "MainThreadGuard.h"
+
#include "DisplayHardware/DisplayIdentification.h"
#include "DisplayHardware/DisplayMode.h"
#include "DisplayHardware/Hal.h"
#include "DisplayHardware/PowerAdvisor.h"
+#include "Scheduler/RefreshRateConfigs.h"
+
+#include "TracedOrdinal.h"
+
namespace android {
class Fence;
class HWComposer;
class IGraphicBufferProducer;
class Layer;
+class RefreshRateOverlay;
class SurfaceFlinger;
struct CompositionInfo;
@@ -79,6 +86,9 @@
bool isVirtual() const { return !mConnectionType; }
bool isPrimary() const { return mIsPrimary; }
+ bool isInternal() const {
+ return !isVirtual() && mConnectionType == ui::DisplayConnectionType::Internal;
+ }
// isSecure indicates whether this display can be trusted to display
// secure surfaces.
@@ -175,10 +185,28 @@
* Display mode management.
*/
const DisplayModePtr& getActiveMode() const;
- void setActiveMode(DisplayModeId);
- status_t initiateModeChange(DisplayModeId modeId,
+
+ struct ActiveModeInfo {
+ DisplayModePtr mode;
+ scheduler::RefreshRateConfigEvent event = scheduler::RefreshRateConfigEvent::None;
+
+ bool operator!=(const ActiveModeInfo& other) const {
+ return mode != other.mode || event != other.event;
+ }
+ };
+
+ bool setDesiredActiveMode(const ActiveModeInfo&) EXCLUDES(mActiveModeLock);
+ std::optional<ActiveModeInfo> getDesiredActiveMode() const EXCLUDES(mActiveModeLock);
+ void clearDesiredActiveModeState() EXCLUDES(mActiveModeLock);
+ ActiveModeInfo getUpcomingActiveMode() const REQUIRES(SF_MAIN_THREAD) {
+ return mUpcomingActiveMode;
+ }
+
+ void setActiveMode(DisplayModeId) REQUIRES(SF_MAIN_THREAD);
+ status_t initiateModeChange(const ActiveModeInfo&,
const hal::VsyncPeriodChangeConstraints& constraints,
- hal::VsyncPeriodChangeTimeline* outTimeline) const;
+ hal::VsyncPeriodChangeTimeline* outTimeline)
+ REQUIRES(SF_MAIN_THREAD);
// Return the immutable list of supported display modes. The HWC may report different modes
// after a hotplug reconnect event, in which case the DisplayDevice object will be recreated.
@@ -190,6 +218,22 @@
// set-top boxes after a hotplug reconnect.
DisplayModePtr getMode(DisplayModeId) const;
+ // Returns the refresh rate configs for this display.
+ scheduler::RefreshRateConfigs& refreshRateConfigs() const { return *mRefreshRateConfigs; }
+
+ // Returns a shared pointer to the refresh rate configs for this display.
+ // Clients can store this refresh rate configs and use it even if the DisplayDevice
+ // is destroyed.
+ std::shared_ptr<scheduler::RefreshRateConfigs> holdRefreshRateConfigs() const {
+ return mRefreshRateConfigs;
+ }
+
+ // Enables an overlay to be displayed with the current refresh rate
+ void enableRefreshRateOverlay(bool enable, bool showSpinner);
+ bool isRefreshRateOverlayEnabled() const { return mRefreshRateOverlay != nullptr; }
+ bool onKernelTimerChanged(std::optional<DisplayModeId>, bool timerExpired);
+ void onInvalidate();
+
void onVsync(nsecs_t timestamp);
nsecs_t getVsyncPeriodFromHWC() const;
nsecs_t getRefreshTimestamp() const;
@@ -214,6 +258,8 @@
const std::shared_ptr<compositionengine::Display> mCompositionDisplay;
std::string mDisplayName;
+ std::string mActiveModeFPSTrace;
+ std::string mActiveModeFPSHwcTrace;
const ui::Rotation mPhysicalOrientation;
ui::Rotation mOrientation = ui::ROTATION_0;
@@ -235,6 +281,15 @@
std::optional<DeviceProductInfo> mDeviceProductInfo;
std::vector<ui::Hdr> mOverrideHdrTypes;
+
+ std::shared_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs;
+ std::unique_ptr<RefreshRateOverlay> mRefreshRateOverlay;
+
+ mutable std::mutex mActiveModeLock;
+ ActiveModeInfo mDesiredActiveMode GUARDED_BY(mActiveModeLock);
+ TracedOrdinal<bool> mDesiredActiveModeChanged
+ GUARDED_BY(mActiveModeLock) = {"DesiredActiveModeChanged", false};
+ ActiveModeInfo mUpcomingActiveMode GUARDED_BY(SF_MAIN_THREAD);
};
struct DisplayDeviceState {
@@ -280,6 +335,7 @@
HWComposer& hwComposer;
const wp<IBinder> displayToken;
const std::shared_ptr<compositionengine::Display> compositionDisplay;
+ std::shared_ptr<scheduler::RefreshRateConfigs> refreshRateConfigs;
int32_t sequenceId{0};
std::optional<ui::DisplayConnectionType> connectionType;
@@ -295,6 +351,7 @@
hardware::graphics::composer::hal::PowerMode::ON};
bool isPrimary{false};
DisplayModes supportedModes;
+ DisplayModeId activeModeId;
};
} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/DisplayMode.h b/services/surfaceflinger/DisplayHardware/DisplayMode.h
index 85cc993..5de622b 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayMode.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayMode.h
@@ -22,6 +22,7 @@
#include <android-base/stringprintf.h>
#include <android/configuration.h>
+#include <ui/DisplayId.h>
#include <ui/DisplayMode.h>
#include <ui/Size.h>
#include <utils/Timers.h>
@@ -54,6 +55,11 @@
return *this;
}
+ Builder& setPhysicalDisplayId(PhysicalDisplayId id) {
+ mDisplayMode->mPhysicalDisplayId = id;
+ return *this;
+ }
+
Builder& setWidth(int32_t width) {
mDisplayMode->mWidth = width;
return *this;
@@ -112,6 +118,7 @@
DisplayModeId getId() const { return mId; }
hal::HWConfigId getHwcId() const { return mHwcId; }
+ PhysicalDisplayId getPhysicalDisplayId() const { return mPhysicalDisplayId; }
int32_t getWidth() const { return mWidth; }
int32_t getHeight() const { return mHeight; }
@@ -136,6 +143,7 @@
hal::HWConfigId mHwcId;
DisplayModeId mId;
+ PhysicalDisplayId mPhysicalDisplayId;
int32_t mWidth = -1;
int32_t mHeight = -1;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index f1bfebc..2976937 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -177,6 +177,9 @@
if (mDrawingState.sidebandStream != nullptr) {
mFlinger->mTunnelModeEnabledReporter->decrementTunnelModeCount();
}
+ if (mHadClonedChild) {
+ mFlinger->mNumClones--;
+ }
}
LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, sp<Client> client, std::string name,
@@ -254,6 +257,7 @@
if (mRemovedFromDrawingState) {
mRemovedFromDrawingState = false;
mFlinger->mScheduler->registerLayer(this);
+ mFlinger->removeFromOffscreenLayers(this);
}
for (const auto& child : mCurrentChildren) {
@@ -2535,6 +2539,12 @@
return parent == nullptr ? false : parent->getPrimaryDisplayOnly();
}
+void Layer::setClonedChild(const sp<Layer>& clonedChild) {
+ mClonedChild = clonedChild;
+ mHadClonedChild = true;
+ mFlinger->mNumClones++;
+}
+
// ---------------------------------------------------------------------------
std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 82d0fc3..24789cf 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -863,6 +863,8 @@
// The layers in the cloned hierarchy will match the lifetime of the real layers. That is
// if the real layer is destroyed, then the clone layer will also be destroyed.
sp<Layer> mClonedChild;
+ bool mHadClonedChild = false;
+ void setClonedChild(const sp<Layer>& mClonedChild);
mutable bool contentDirty{false};
Region surfaceDamageRegion;
diff --git a/services/surfaceflinger/MainThreadGuard.h b/services/surfaceflinger/MainThreadGuard.h
new file mode 100644
index 0000000..c1aa118
--- /dev/null
+++ b/services/surfaceflinger/MainThreadGuard.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <utils/Mutex.h>
+
+namespace android {
+namespace {
+
+// Helps to ensure that some functions runs on SF's main thread by using the
+// clang thread safety annotations.
+class CAPABILITY("mutex") MainThreadGuard {
+} SF_MAIN_THREAD;
+
+struct SCOPED_CAPABILITY MainThreadScopedGuard {
+public:
+ explicit MainThreadScopedGuard(MainThreadGuard& mutex) ACQUIRE(mutex) {}
+ ~MainThreadScopedGuard() RELEASE() {}
+};
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index 5c85bf0..2a33ad8 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -179,10 +179,14 @@
return buffers;
}
-RefreshRateOverlay::RefreshRateOverlay(SurfaceFlinger& flinger, bool showSpinner)
- : mFlinger(flinger), mClient(new Client(&mFlinger)), mShowSpinner(showSpinner) {
+RefreshRateOverlay::RefreshRateOverlay(SurfaceFlinger& flinger, uint32_t lowFps, uint32_t highFps,
+ bool showSpinner)
+ : mFlinger(flinger),
+ mClient(new Client(&mFlinger)),
+ mShowSpinner(showSpinner),
+ mLowFps(lowFps),
+ mHighFps(highFps) {
createLayer();
- reset();
}
bool RefreshRateOverlay::createLayer() {
@@ -198,7 +202,6 @@
return false;
}
- Mutex::Autolock _l(mFlinger.mStateLock);
mLayer = mClient->getLayerUser(mIBinder);
mLayer->setFrameRate(Layer::FrameRate(Fps(0.0f), Layer::FrameRateCompatibility::NoVote));
@@ -261,8 +264,11 @@
}
void RefreshRateOverlay::setViewport(ui::Size viewport) {
- Rect frame((3 * viewport.width) >> 4, viewport.height >> 5);
- frame.offsetBy(viewport.width >> 5, viewport.height >> 4);
+ constexpr int32_t kMaxWidth = 1000;
+ const auto width = std::min(kMaxWidth, std::min(viewport.width, viewport.height));
+ const auto height = 2 * width;
+ Rect frame((3 * width) >> 4, height >> 5);
+ frame.offsetBy(width >> 5, height >> 4);
layer_state_t::matrix22_t matrix;
matrix.dsdx = frame.getWidth() / static_cast<float>(SevenSegmentDrawer::getWidth());
@@ -274,6 +280,11 @@
mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
}
+void RefreshRateOverlay::setLayerStack(uint32_t stack) {
+ mLayer->setLayerStack(stack);
+ mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
+}
+
void RefreshRateOverlay::changeRefreshRate(const Fps& fps) {
mCurrentFps = fps.getIntValue();
auto buffer = getOrCreateBuffers(*mCurrentFps)[mFrame];
@@ -299,13 +310,6 @@
mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
}
-void RefreshRateOverlay::reset() {
- mBufferCache.clear();
- const auto range = mFlinger.mRefreshRateConfigs->getSupportedRefreshRateRange();
- mLowFps = range.min.getIntValue();
- mHighFps = range.max.getIntValue();
-}
-
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h
index cb8b227..fd1e2df 100644
--- a/services/surfaceflinger/RefreshRateOverlay.h
+++ b/services/surfaceflinger/RefreshRateOverlay.h
@@ -39,12 +39,12 @@
class RefreshRateOverlay {
public:
- RefreshRateOverlay(SurfaceFlinger&, bool showSpinner);
+ RefreshRateOverlay(SurfaceFlinger&, uint32_t lowFps, uint32_t highFps, bool showSpinner);
+ void setLayerStack(uint32_t stack);
void setViewport(ui::Size);
void changeRefreshRate(const Fps&);
void onInvalidate();
- void reset();
private:
class SevenSegmentDrawer {
@@ -91,8 +91,8 @@
const bool mShowSpinner;
// Interpolate the colors between these values.
- uint32_t mLowFps;
- uint32_t mHighFps;
+ const uint32_t mLowFps;
+ const uint32_t mHighFps;
};
} // namespace android
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 653aca6..aa2fec5 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -287,33 +287,12 @@
descriptors.emplace_back(descriptor);
}
- auto dx = 0;
- auto dy = 0;
- switch (orientation) {
- case ui::Transform::ROT_90:
- dx = displaySize.getWidth();
- break;
- case ui::Transform::ROT_180:
- dx = displaySize.getWidth();
- dy = displaySize.getHeight();
- break;
- case ui::Transform::ROT_270:
- dy = displaySize.getHeight();
- break;
- default:
- break;
- }
-
- ui::Transform t(orientation);
- auto screencapRegion = t.transform(sampleRegion);
- screencapRegion = screencapRegion.translate(dx, dy);
-
const Rect sampledBounds = sampleRegion.bounds();
+ constexpr bool kUseIdentityTransform = false;
SurfaceFlinger::RenderAreaFuture renderAreaFuture = ftl::defer([=] {
- return DisplayRenderArea::create(displayWeak, screencapRegion.bounds(),
- sampledBounds.getSize(), ui::Dataspace::V0_SRGB,
- orientation);
+ return DisplayRenderArea::create(displayWeak, sampledBounds, sampledBounds.getSize(),
+ ui::Dataspace::V0_SRGB, kUseIdentityTransform);
});
std::unordered_set<sp<IRegionSamplingListener>, SpHash<IRegionSamplingListener>> listeners;
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 2321e2d..2bdcaf6 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -118,12 +118,12 @@
return event;
}
-DisplayEventReceiver::Event makeModeChanged(PhysicalDisplayId displayId, DisplayModeId modeId,
- nsecs_t vsyncPeriod) {
+DisplayEventReceiver::Event makeModeChanged(DisplayModePtr mode) {
DisplayEventReceiver::Event event;
- event.header = {DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE, displayId, systemTime()};
- event.modeChange.modeId = modeId.value();
- event.modeChange.vsyncPeriod = vsyncPeriod;
+ event.header = {DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE, mode->getPhysicalDisplayId(),
+ systemTime()};
+ event.modeChange.modeId = mode->getId().value();
+ event.modeChange.vsyncPeriod = mode->getVsyncPeriod();
return event;
}
@@ -375,11 +375,10 @@
mCondition.notify_all();
}
-void EventThread::onModeChanged(PhysicalDisplayId displayId, DisplayModeId modeId,
- nsecs_t vsyncPeriod) {
+void EventThread::onModeChanged(DisplayModePtr mode) {
std::lock_guard<std::mutex> lock(mMutex);
- mPendingEvents.push_back(makeModeChanged(displayId, modeId, vsyncPeriod));
+ mPendingEvents.push_back(makeModeChanged(mode));
mCondition.notify_all();
}
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 1e6793f..9265a25 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -124,8 +124,7 @@
virtual void onHotplugReceived(PhysicalDisplayId displayId, bool connected) = 0;
// called when SF changes the active mode and apps needs to be notified about the change
- virtual void onModeChanged(PhysicalDisplayId displayId, DisplayModeId modeId,
- nsecs_t vsyncPeriod) = 0;
+ virtual void onModeChanged(DisplayModePtr) = 0;
// called when SF updates the Frame Rate Override list
virtual void onFrameRateOverridesChanged(PhysicalDisplayId displayId,
@@ -174,8 +173,7 @@
void onHotplugReceived(PhysicalDisplayId displayId, bool connected) override;
- void onModeChanged(PhysicalDisplayId displayId, DisplayModeId modeId,
- nsecs_t vsyncPeriod) override;
+ void onModeChanged(DisplayModePtr) override;
void onFrameRateOverridesChanged(PhysicalDisplayId displayId,
std::vector<FrameRateOverride> overrides) override;
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index 0563795..84e3548 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -75,10 +75,9 @@
}
} // namespace
-LayerHistory::LayerHistory(const RefreshRateConfigs& refreshRateConfigs)
+LayerHistory::LayerHistory()
: mTraceEnabled(traceEnabled()), mUseFrameRatePriority(useFrameRatePriority()) {
LayerInfo::setTraceEnabled(mTraceEnabled);
- LayerInfo::setRefreshRateConfigs(refreshRateConfigs);
}
LayerHistory::~LayerHistory() = default;
@@ -138,7 +137,8 @@
}
}
-LayerHistory::Summary LayerHistory::summarize(nsecs_t now) {
+LayerHistory::Summary LayerHistory::summarize(const RefreshRateConfigs& refreshRateConfigs,
+ nsecs_t now) {
LayerHistory::Summary summary;
std::lock_guard lock(mLock);
@@ -151,7 +151,7 @@
ALOGV("%s has priority: %d %s focused", info->getName().c_str(), frameRateSelectionPriority,
layerFocused ? "" : "not");
- const auto vote = info->getRefreshRateVote(now);
+ const auto vote = info->getRefreshRateVote(refreshRateConfigs, now);
// Skip NoVote layer as those don't have any requirements
if (vote.type == LayerHistory::LayerVoteType::NoVote) {
continue;
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index 82f6c39..92236f5 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -42,7 +42,7 @@
public:
using LayerVoteType = RefreshRateConfigs::LayerVoteType;
- LayerHistory(const RefreshRateConfigs&);
+ LayerHistory();
~LayerHistory();
// Layers are unregistered when the weak reference expires.
@@ -67,7 +67,7 @@
using Summary = std::vector<RefreshRateConfigs::LayerRequirement>;
// Rebuilds sets of active/inactive layers, and accumulates stats for active layers.
- Summary summarize(nsecs_t now);
+ Summary summarize(const RefreshRateConfigs&, nsecs_t now);
void clear();
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp
index 989bf4e..8a45b66 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -34,7 +34,6 @@
namespace android::scheduler {
-const RefreshRateConfigs* LayerInfo::sRefreshRateConfigs = nullptr;
bool LayerInfo::sTraceEnabled = false;
LayerInfo::LayerInfo(const std::string& name, uid_t ownerUid,
@@ -184,7 +183,8 @@
return static_cast<nsecs_t>(averageFrameTime);
}
-std::optional<Fps> LayerInfo::calculateRefreshRateIfPossible(nsecs_t now) {
+std::optional<Fps> LayerInfo::calculateRefreshRateIfPossible(
+ const RefreshRateConfigs& refreshRateConfigs, nsecs_t now) {
static constexpr float MARGIN = 1.0f; // 1Hz
if (!hasEnoughDataForHeuristic()) {
ALOGV("Not enough data");
@@ -196,9 +196,7 @@
const auto refreshRate = Fps::fromPeriodNsecs(*averageFrameTime);
const bool refreshRateConsistent = mRefreshRateHistory.add(refreshRate, now);
if (refreshRateConsistent) {
- const auto knownRefreshRate =
- sRefreshRateConfigs->findClosestKnownFrameRate(refreshRate);
-
+ const auto knownRefreshRate = refreshRateConfigs.findClosestKnownFrameRate(refreshRate);
// To avoid oscillation, use the last calculated refresh rate if it is
// close enough
if (std::abs(mLastRefreshRate.calculated.getValue() - refreshRate.getValue()) >
@@ -220,7 +218,8 @@
: std::nullopt;
}
-LayerInfo::LayerVote LayerInfo::getRefreshRateVote(nsecs_t now) {
+LayerInfo::LayerVote LayerInfo::getRefreshRateVote(const RefreshRateConfigs& refreshRateConfigs,
+ nsecs_t now) {
if (mLayerVote.type != LayerHistory::LayerVoteType::Heuristic) {
ALOGV("%s voted %d ", mName.c_str(), static_cast<int>(mLayerVote.type));
return mLayerVote;
@@ -247,7 +246,7 @@
clearHistory(now);
}
- auto refreshRate = calculateRefreshRateIfPossible(now);
+ auto refreshRate = calculateRefreshRateIfPossible(refreshRateConfigs, now);
if (refreshRate.has_value()) {
ALOGV("%s calculated refresh rate: %s", mName.c_str(), to_string(*refreshRate).c_str());
return {LayerHistory::LayerVoteType::Heuristic, refreshRate.value()};
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h
index 34cc389..ce9783c 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.h
+++ b/services/surfaceflinger/Scheduler/LayerInfo.h
@@ -122,10 +122,6 @@
static void setTraceEnabled(bool enabled) { sTraceEnabled = enabled; }
- static void setRefreshRateConfigs(const RefreshRateConfigs& refreshRateConfigs) {
- sRefreshRateConfigs = &refreshRateConfigs;
- }
-
LayerInfo(const std::string& name, uid_t ownerUid, LayerHistory::LayerVoteType defaultVote);
LayerInfo(const LayerInfo&) = delete;
@@ -161,7 +157,7 @@
uid_t getOwnerUid() const { return mOwnerUid; }
- LayerVote getRefreshRateVote(nsecs_t now);
+ LayerVote getRefreshRateVote(const RefreshRateConfigs&, nsecs_t now);
// Return the last updated time. If the present time is farther in the future than the
// updated time, the updated time is the present time.
@@ -263,7 +259,7 @@
bool isFrequent(nsecs_t now) const;
bool isAnimating(nsecs_t now) const;
bool hasEnoughDataForHeuristic() const;
- std::optional<Fps> calculateRefreshRateIfPossible(nsecs_t now);
+ std::optional<Fps> calculateRefreshRateIfPossible(const RefreshRateConfigs&, nsecs_t now);
std::optional<nsecs_t> calculateAverageFrameTime() const;
bool isFrameTimeValid(const FrameTimeData&) const;
@@ -300,7 +296,6 @@
mutable std::unordered_map<LayerHistory::LayerVoteType, std::string> mTraceTags;
// Shared for all LayerInfo instances
- static const RefreshRateConfigs* sRefreshRateConfigs;
static bool sTraceEnabled;
};
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 0334d70..c38cd68 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -113,7 +113,7 @@
case LayerVoteType::ExplicitExactOrMultiple:
case LayerVoteType::Heuristic:
if (mConfig.frameRateMultipleThreshold != 0 &&
- refreshRate.fps.greaterThanOrEqualWithMargin(
+ refreshRate.getFps().greaterThanOrEqualWithMargin(
Fps(mConfig.frameRateMultipleThreshold)) &&
layer.desiredRefreshRate.lessThanWithMargin(
Fps(mConfig.frameRateMultipleThreshold / 2))) {
@@ -146,8 +146,8 @@
// If the layer wants Max, give higher score to the higher refresh rate
if (layer.vote == LayerVoteType::Max) {
- const auto ratio =
- refreshRate.fps.getValue() / mAppRequestRefreshRates.back()->fps.getValue();
+ const auto ratio = refreshRate.getFps().getValue() /
+ mAppRequestRefreshRates.back()->getFps().getValue();
// use ratio^2 to get a lower score the more we get further from peak
return ratio * ratio;
}
@@ -463,7 +463,7 @@
}
}();
if (globalSignals.touch && explicitDefaultVoteLayers == 0 && touchBoostForExplicitExact &&
- bestRefreshRate->fps.lessThanWithMargin(touchRefreshRate.fps)) {
+ bestRefreshRate->getFps().lessThanWithMargin(touchRefreshRate.getFps())) {
setTouchConsidered();
ALOGV("TouchBoost - choose %s", touchRefreshRate.getName().c_str());
return touchRefreshRate;
@@ -699,8 +699,7 @@
for (const auto& mode : modes) {
const auto modeId = mode->getId();
mRefreshRates.emplace(modeId,
- std::make_unique<RefreshRate>(modeId, mode, mode->getFps(),
- RefreshRate::ConstructorTag(0)));
+ std::make_unique<RefreshRate>(mode, RefreshRate::ConstructorTag(0)));
if (modeId == currentModeId) {
mCurrentRefreshRate = mRefreshRates.at(modeId).get();
}
@@ -793,7 +792,7 @@
bool RefreshRateConfigs::isModeAllowed(DisplayModeId modeId) const {
std::lock_guard lock(mLock);
for (const RefreshRate* refreshRate : mAppRequestRefreshRates) {
- if (refreshRate->modeId == modeId) {
+ if (refreshRate->getModeId() == modeId) {
return true;
}
}
@@ -808,7 +807,7 @@
for (const auto& [type, refreshRate] : mRefreshRates) {
if (shouldAddRefreshRate(*refreshRate)) {
ALOGV("getSortedRefreshRateListLocked: mode %d added to list policy",
- refreshRate->modeId.value());
+ refreshRate->getModeId().value());
outRefreshRates->push_back(refreshRate.get());
}
}
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index dfd1395..4a9a1fd 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -64,25 +64,23 @@
};
public:
- RefreshRate(DisplayModeId modeId, DisplayModePtr mode, Fps fps, ConstructorTag)
- : modeId(modeId), mode(mode), fps(std::move(fps)) {}
+ RefreshRate(DisplayModePtr mode, ConstructorTag) : mode(mode) {}
- DisplayModeId getModeId() const { return modeId; }
+ DisplayModeId getModeId() const { return mode->getId(); }
nsecs_t getVsyncPeriod() const { return mode->getVsyncPeriod(); }
int32_t getModeGroup() const { return mode->getGroup(); }
- std::string getName() const { return to_string(fps); }
- Fps getFps() const { return fps; }
+ std::string getName() const { return to_string(getFps()); }
+ Fps getFps() const { return mode->getFps(); }
+ DisplayModePtr getMode() const { return mode; }
// Checks whether the fps of this RefreshRate struct is within a given min and max refresh
// rate passed in. Margin of error is applied to the boundaries for approximation.
bool inPolicy(Fps minRefreshRate, Fps maxRefreshRate) const {
- return minRefreshRate.lessThanOrEqualWithMargin(fps) &&
- fps.lessThanOrEqualWithMargin(maxRefreshRate);
+ return minRefreshRate.lessThanOrEqualWithMargin(getFps()) &&
+ getFps().lessThanOrEqualWithMargin(maxRefreshRate);
}
- bool operator!=(const RefreshRate& other) const {
- return modeId != other.modeId || mode != other.mode;
- }
+ bool operator!=(const RefreshRate& other) const { return mode != other.mode; }
bool operator<(const RefreshRate& other) const {
return getFps().getValue() < other.getFps().getValue();
@@ -99,10 +97,7 @@
friend RefreshRateConfigs;
friend class RefreshRateConfigsTest;
- const DisplayModeId modeId;
DisplayModePtr mode;
- // Refresh rate in frames per second
- const Fps fps{0.0f};
};
using AllRefreshRatesMapType =
@@ -316,8 +311,6 @@
Config config = {.enableFrameRateOverride = false,
.frameRateMultipleThreshold = 0});
- void updateDisplayModes(const DisplayModes& mode, DisplayModeId currentModeId) EXCLUDES(mLock);
-
// Returns whether switching modes (refresh rate or resolution) is possible.
// TODO(b/158780872): Consider HAL support, and skip frame rate detection if the modes only
// differ in resolution.
@@ -354,6 +347,9 @@
void dump(std::string& result) const EXCLUDES(mLock);
+ RefreshRateConfigs(const RefreshRateConfigs&) = delete;
+ void operator=(const RefreshRateConfigs&) = delete;
+
private:
friend class RefreshRateConfigsTest;
@@ -405,6 +401,8 @@
float calculateLayerScoreLocked(const LayerRequirement&, const RefreshRate&,
bool isSeamlessSwitch) const REQUIRES(mLock);
+ void updateDisplayModes(const DisplayModes& mode, DisplayModeId currentModeId) EXCLUDES(mLock);
+
// The list of refresh rates, indexed by display modes ID. This may change after this
// object is initialized.
AllRefreshRatesMapType mRefreshRates GUARDED_BY(mLock);
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 6d6e3c2..f808981 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -117,16 +117,17 @@
}
};
-Scheduler::Scheduler(const scheduler::RefreshRateConfigs& configs, ISchedulerCallback& callback)
+Scheduler::Scheduler(const std::shared_ptr<scheduler::RefreshRateConfigs>& configs,
+ ISchedulerCallback& callback)
: Scheduler(configs, callback,
{.supportKernelTimer = sysprop::support_kernel_idle_timer(false),
.useContentDetection = sysprop::use_content_detection_for_refresh_rate(false)}) {
}
-Scheduler::Scheduler(const scheduler::RefreshRateConfigs& configs, ISchedulerCallback& callback,
- Options options)
+Scheduler::Scheduler(const std::shared_ptr<scheduler::RefreshRateConfigs>& configs,
+ ISchedulerCallback& callback, Options options)
: Scheduler(createVsyncSchedule(options.supportKernelTimer), configs, callback,
- createLayerHistory(configs), options) {
+ createLayerHistory(), options) {
using namespace sysprop;
const int setIdleTimerMs = base::GetIntProperty("debug.sf.set_idle_timer_ms"s, 0);
@@ -159,7 +160,8 @@
}
}
-Scheduler::Scheduler(VsyncSchedule schedule, const scheduler::RefreshRateConfigs& configs,
+Scheduler::Scheduler(VsyncSchedule schedule,
+ const std::shared_ptr<scheduler::RefreshRateConfigs>& configs,
ISchedulerCallback& schedulerCallback,
std::unique_ptr<LayerHistory> layerHistory, Options options)
: mOptions(options),
@@ -194,9 +196,8 @@
return {std::move(controller), std::move(tracker), std::move(dispatch)};
}
-std::unique_ptr<LayerHistory> Scheduler::createLayerHistory(
- const scheduler::RefreshRateConfigs& configs) {
- return std::make_unique<scheduler::LayerHistory>(configs);
+std::unique_ptr<LayerHistory> Scheduler::createLayerHistory() {
+ return std::make_unique<scheduler::LayerHistory>();
}
std::unique_ptr<VSyncSource> Scheduler::makePrimaryDispSyncSource(
@@ -207,11 +208,14 @@
}
std::optional<Fps> Scheduler::getFrameRateOverride(uid_t uid) const {
- if (!mRefreshRateConfigs.supportsFrameRateOverride()) {
- return std::nullopt;
+ {
+ std::scoped_lock lock(mRefreshRateConfigsLock);
+ if (!mRefreshRateConfigs->supportsFrameRateOverride()) {
+ return std::nullopt;
+ }
}
- std::lock_guard lock(mFrameRateOverridesMutex);
+ std::lock_guard lock(mFrameRateOverridesLock);
{
const auto iter = mFrameRateOverridesFromBackdoor.find(uid);
if (iter != mFrameRateOverridesFromBackdoor.end()) {
@@ -239,7 +243,8 @@
}
impl::EventThread::ThrottleVsyncCallback Scheduler::makeThrottleVsyncCallback() const {
- if (!mRefreshRateConfigs.supportsFrameRateOverride()) {
+ std::scoped_lock lock(mRefreshRateConfigsLock);
+ if (!mRefreshRateConfigs->supportsFrameRateOverride()) {
return {};
}
@@ -250,14 +255,18 @@
impl::EventThread::GetVsyncPeriodFunction Scheduler::makeGetVsyncPeriodFunction() const {
return [this](uid_t uid) {
- nsecs_t basePeriod = mRefreshRateConfigs.getCurrentRefreshRate().getVsyncPeriod();
+ const auto refreshRateConfigs = holdRefreshRateConfigs();
+ nsecs_t basePeriod = refreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
const auto frameRate = getFrameRateOverride(uid);
if (!frameRate.has_value()) {
return basePeriod;
}
- const auto divider = scheduler::RefreshRateConfigs::getFrameRateDivider(
- mRefreshRateConfigs.getCurrentRefreshRate().getFps(), *frameRate);
+ const auto divider =
+ scheduler::RefreshRateConfigs::getFrameRateDivider(refreshRateConfigs
+ ->getCurrentRefreshRate()
+ .getFps(),
+ *frameRate);
if (divider <= 1) {
return basePeriod;
}
@@ -343,7 +352,7 @@
void Scheduler::onFrameRateOverridesChanged(ConnectionHandle handle, PhysicalDisplayId displayId) {
std::vector<FrameRateOverride> overrides;
{
- std::lock_guard lock(mFrameRateOverridesMutex);
+ std::lock_guard lock(mFrameRateOverridesLock);
for (const auto& [uid, frameRate] : mFrameRateOverridesFromBackdoor) {
overrides.emplace_back(FrameRateOverride{uid, frameRate.getValue()});
}
@@ -362,23 +371,22 @@
thread->onFrameRateOverridesChanged(displayId, std::move(overrides));
}
-void Scheduler::onPrimaryDisplayModeChanged(ConnectionHandle handle, PhysicalDisplayId displayId,
- DisplayModeId modeId, nsecs_t vsyncPeriod) {
+void Scheduler::onPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) {
{
std::lock_guard<std::mutex> lock(mFeatureStateLock);
// Cache the last reported modes for primary display.
- mFeatures.cachedModeChangedParams = {handle, displayId, modeId, vsyncPeriod};
+ mFeatures.cachedModeChangedParams = {handle, mode};
// Invalidate content based refresh rate selection so it could be calculated
// again for the new refresh rate.
mFeatures.contentRequirements.clear();
}
- onNonPrimaryDisplayModeChanged(handle, displayId, modeId, vsyncPeriod);
+ onNonPrimaryDisplayModeChanged(handle, mode);
}
void Scheduler::dispatchCachedReportedMode() {
// Check optional fields first.
- if (!mFeatures.modeId.has_value()) {
+ if (!mFeatures.mode) {
ALOGW("No mode ID found, not dispatching cached mode.");
return;
}
@@ -387,32 +395,24 @@
return;
}
- const auto modeId = *mFeatures.modeId;
- const auto vsyncPeriod = mRefreshRateConfigs.getRefreshRateFromModeId(modeId).getVsyncPeriod();
-
// If there is no change from cached mode, there is no need to dispatch an event
- if (modeId == mFeatures.cachedModeChangedParams->modeId &&
- vsyncPeriod == mFeatures.cachedModeChangedParams->vsyncPeriod) {
+ if (mFeatures.mode == mFeatures.cachedModeChangedParams->mode) {
return;
}
- mFeatures.cachedModeChangedParams->modeId = modeId;
- mFeatures.cachedModeChangedParams->vsyncPeriod = vsyncPeriod;
+ mFeatures.cachedModeChangedParams->mode = mFeatures.mode;
onNonPrimaryDisplayModeChanged(mFeatures.cachedModeChangedParams->handle,
- mFeatures.cachedModeChangedParams->displayId,
- mFeatures.cachedModeChangedParams->modeId,
- mFeatures.cachedModeChangedParams->vsyncPeriod);
+ mFeatures.cachedModeChangedParams->mode);
}
-void Scheduler::onNonPrimaryDisplayModeChanged(ConnectionHandle handle, PhysicalDisplayId displayId,
- DisplayModeId modeId, nsecs_t vsyncPeriod) {
+void Scheduler::onNonPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) {
android::EventThread* thread;
{
std::lock_guard<std::mutex> lock(mConnectionsLock);
RETURN_IF_INVALID_HANDLE(handle);
thread = mConnections[handle].thread.get();
}
- thread->onModeChanged(displayId, modeId, vsyncPeriod);
+ thread->onModeChanged(mode);
}
size_t Scheduler::getEventThreadConnectionCount(ConnectionHandle handle) {
@@ -532,7 +532,11 @@
const nsecs_t last = mLastResyncTime.exchange(now);
if (now - last > kIgnoreDelay) {
- resyncToHardwareVsync(false, mRefreshRateConfigs.getCurrentRefreshRate().getVsyncPeriod());
+ const auto vsyncPeriod = [&] {
+ std::scoped_lock lock(mRefreshRateConfigsLock);
+ return mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
+ }();
+ resyncToHardwareVsync(false, vsyncPeriod);
}
}
@@ -602,9 +606,12 @@
void Scheduler::recordLayerHistory(Layer* layer, nsecs_t presentTime,
LayerHistory::LayerUpdateType updateType) {
- if (mRefreshRateConfigs.canSwitch()) {
- mLayerHistory->record(layer, presentTime, systemTime(), updateType);
+ {
+ std::scoped_lock lock(mRefreshRateConfigsLock);
+ if (!mRefreshRateConfigs->canSwitch()) return;
}
+
+ mLayerHistory->record(layer, presentTime, systemTime(), updateType);
}
void Scheduler::setModeChangePending(bool pending) {
@@ -612,25 +619,28 @@
}
void Scheduler::chooseRefreshRateForContent() {
- if (!mRefreshRateConfigs.canSwitch()) return;
+ {
+ std::scoped_lock lock(mRefreshRateConfigsLock);
+ if (!mRefreshRateConfigs->canSwitch()) return;
+ }
ATRACE_CALL();
- scheduler::LayerHistory::Summary summary = mLayerHistory->summarize(systemTime());
+ const auto refreshRateConfigs = holdRefreshRateConfigs();
+ scheduler::LayerHistory::Summary summary =
+ mLayerHistory->summarize(*refreshRateConfigs, systemTime());
scheduler::RefreshRateConfigs::GlobalSignals consideredSignals;
- DisplayModeId newModeId;
+ DisplayModePtr newMode;
bool frameRateChanged;
bool frameRateOverridesChanged;
{
std::lock_guard<std::mutex> lock(mFeatureStateLock);
mFeatures.contentRequirements = summary;
- newModeId = calculateRefreshRateModeId(&consideredSignals);
- auto newRefreshRate = mRefreshRateConfigs.getRefreshRateFromModeId(newModeId);
- frameRateOverridesChanged =
- updateFrameRateOverrides(consideredSignals, newRefreshRate.getFps());
+ newMode = calculateRefreshRateModeId(&consideredSignals);
+ frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps());
- if (mFeatures.modeId == newModeId) {
+ if (mFeatures.mode == newMode) {
// We don't need to change the display mode, but we might need to send an event
// about a mode change, since it was suppressed due to a previous idleConsidered
if (!consideredSignals.idle) {
@@ -638,12 +648,12 @@
}
frameRateChanged = false;
} else {
- mFeatures.modeId = newModeId;
+ mFeatures.mode = newMode;
frameRateChanged = true;
}
}
if (frameRateChanged) {
- auto newRefreshRate = mRefreshRateConfigs.getRefreshRateFromModeId(newModeId);
+ auto newRefreshRate = refreshRateConfigs->getRefreshRateFromModeId(newMode->getId());
mSchedulerCallback.changeRefreshRate(newRefreshRate,
consideredSignals.idle ? ModeEvent::None
: ModeEvent::Changed);
@@ -689,7 +699,11 @@
// TODO(145561154): cleanup the kernel idle timer implementation and the refresh rate
// magic number
- const auto& refreshRate = mRefreshRateConfigs.getCurrentRefreshRate();
+ const auto refreshRate = [&] {
+ std::scoped_lock lock(mRefreshRateConfigsLock);
+ return mRefreshRateConfigs->getCurrentRefreshRate();
+ }();
+
constexpr Fps FPS_THRESHOLD_FOR_KERNEL_TIMER{65.0f};
if (state == TimerState::Reset &&
refreshRate.getFps().greaterThanWithMargin(FPS_THRESHOLD_FOR_KERNEL_TIMER)) {
@@ -741,7 +755,7 @@
mLayerHistory ? mLayerHistory->dump().c_str() : "(no layer history)");
{
- std::lock_guard lock(mFrameRateOverridesMutex);
+ std::lock_guard lock(mFrameRateOverridesLock);
StringAppendF(&result, "Frame Rate Overrides (backdoor): {");
for (const auto& [uid, frameRate] : mFrameRateOverridesFromBackdoor) {
StringAppendF(&result, "[uid: %d frameRate: %s], ", uid, to_string(frameRate).c_str());
@@ -767,16 +781,17 @@
bool Scheduler::updateFrameRateOverrides(
scheduler::RefreshRateConfigs::GlobalSignals consideredSignals, Fps displayRefreshRate) {
- if (!mRefreshRateConfigs.supportsFrameRateOverride()) {
+ const auto refreshRateConfigs = holdRefreshRateConfigs();
+ if (!refreshRateConfigs->supportsFrameRateOverride()) {
return false;
}
if (!consideredSignals.idle) {
const auto frameRateOverrides =
- mRefreshRateConfigs.getFrameRateOverrides(mFeatures.contentRequirements,
+ refreshRateConfigs->getFrameRateOverrides(mFeatures.contentRequirements,
displayRefreshRate,
consideredSignals.touch);
- std::lock_guard lock(mFrameRateOverridesMutex);
+ std::lock_guard lock(mFrameRateOverridesLock);
if (!std::equal(mFrameRateOverridesByContent.begin(), mFrameRateOverridesByContent.end(),
frameRateOverrides.begin(), frameRateOverrides.end(),
[](const std::pair<uid_t, Fps>& a, const std::pair<uid_t, Fps>& b) {
@@ -791,33 +806,33 @@
template <class T>
bool Scheduler::handleTimerStateChanged(T* currentState, T newState) {
- DisplayModeId newModeId;
+ DisplayModePtr newMode;
bool refreshRateChanged = false;
bool frameRateOverridesChanged;
scheduler::RefreshRateConfigs::GlobalSignals consideredSignals;
+ const auto refreshRateConfigs = holdRefreshRateConfigs();
{
std::lock_guard<std::mutex> lock(mFeatureStateLock);
if (*currentState == newState) {
return false;
}
*currentState = newState;
- newModeId = calculateRefreshRateModeId(&consideredSignals);
- const RefreshRate& newRefreshRate = mRefreshRateConfigs.getRefreshRateFromModeId(newModeId);
- frameRateOverridesChanged =
- updateFrameRateOverrides(consideredSignals, newRefreshRate.getFps());
- if (mFeatures.modeId == newModeId) {
+ newMode = calculateRefreshRateModeId(&consideredSignals);
+ frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps());
+ if (mFeatures.mode == newMode) {
// We don't need to change the display mode, but we might need to send an event
// about a mode change, since it was suppressed due to a previous idleConsidered
if (!consideredSignals.idle) {
dispatchCachedReportedMode();
}
} else {
- mFeatures.modeId = newModeId;
+ mFeatures.mode = newMode;
refreshRateChanged = true;
}
}
if (refreshRateChanged) {
- const RefreshRate& newRefreshRate = mRefreshRateConfigs.getRefreshRateFromModeId(newModeId);
+ const RefreshRate& newRefreshRate =
+ refreshRateConfigs->getRefreshRateFromModeId(newMode->getId());
mSchedulerCallback.changeRefreshRate(newRefreshRate,
consideredSignals.idle ? ModeEvent::None
@@ -829,35 +844,36 @@
return consideredSignals.touch;
}
-DisplayModeId Scheduler::calculateRefreshRateModeId(
+DisplayModePtr Scheduler::calculateRefreshRateModeId(
scheduler::RefreshRateConfigs::GlobalSignals* consideredSignals) {
ATRACE_CALL();
if (consideredSignals) *consideredSignals = {};
+ const auto refreshRateConfigs = holdRefreshRateConfigs();
// 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().getModeId();
+ return refreshRateConfigs->getMaxRefreshRateByPolicy().getMode();
}
const bool touchActive = mTouchTimer && mFeatures.touch == TouchState::Active;
const bool idle = mIdleTimer && mFeatures.idleTimer == TimerState::Expired;
- return mRefreshRateConfigs
- .getBestRefreshRate(mFeatures.contentRequirements, {.touch = touchActive, .idle = idle},
- consideredSignals)
- .getModeId();
+ return refreshRateConfigs
+ ->getBestRefreshRate(mFeatures.contentRequirements,
+ {.touch = touchActive, .idle = idle}, consideredSignals)
+ .getMode();
}
-std::optional<DisplayModeId> Scheduler::getPreferredModeId() {
+DisplayModePtr Scheduler::getPreferredDisplayMode() {
std::lock_guard<std::mutex> lock(mFeatureStateLock);
// Make sure that the default mode ID is first updated, before returned.
- if (mFeatures.modeId.has_value()) {
- mFeatures.modeId = calculateRefreshRateModeId();
+ if (mFeatures.mode) {
+ mFeatures.mode = calculateRefreshRateModeId();
}
- return mFeatures.modeId;
+ return mFeatures.mode;
}
void Scheduler::onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline) {
@@ -893,7 +909,7 @@
}
}
-void Scheduler::onPrimaryDisplayAreaChanged(uint32_t displayArea) {
+void Scheduler::onActiveDisplayAreaChanged(uint32_t displayArea) {
mLayerHistory->setDisplayArea(displayArea);
}
@@ -902,7 +918,7 @@
return;
}
- std::lock_guard lock(mFrameRateOverridesMutex);
+ std::lock_guard lock(mFrameRateOverridesLock);
if (frameRateOverride.frameRateHz != 0.f) {
mFrameRateOverridesFromBackdoor[frameRateOverride.uid] = Fps(frameRateOverride.frameRateHz);
} else {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 30a3253..4b6905b 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -72,7 +72,7 @@
using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate;
using ModeEvent = scheduler::RefreshRateConfigEvent;
- Scheduler(const scheduler::RefreshRateConfigs&, ISchedulerCallback&);
+ Scheduler(const std::shared_ptr<scheduler::RefreshRateConfigs>&, ISchedulerCallback&);
~Scheduler();
using ConnectionHandle = scheduler::ConnectionHandle;
@@ -87,15 +87,13 @@
sp<EventThreadConnection> getEventConnection(ConnectionHandle);
void onHotplugReceived(ConnectionHandle, PhysicalDisplayId, bool connected);
- void onPrimaryDisplayModeChanged(ConnectionHandle, PhysicalDisplayId, DisplayModeId,
- nsecs_t vsyncPeriod) EXCLUDES(mFeatureStateLock);
- void onNonPrimaryDisplayModeChanged(ConnectionHandle, PhysicalDisplayId, DisplayModeId,
- nsecs_t vsyncPeriod);
+ void onPrimaryDisplayModeChanged(ConnectionHandle, DisplayModePtr) EXCLUDES(mFeatureStateLock);
+ void onNonPrimaryDisplayModeChanged(ConnectionHandle, DisplayModePtr);
void onScreenAcquired(ConnectionHandle);
void onScreenReleased(ConnectionHandle);
void onFrameRateOverridesChanged(ConnectionHandle, PhysicalDisplayId)
- EXCLUDES(mFrameRateOverridesMutex) EXCLUDES(mConnectionsLock);
+ EXCLUDES(mFrameRateOverridesLock) EXCLUDES(mConnectionsLock);
// Modifies work duration in the event thread.
void setDuration(ConnectionHandle, std::chrono::nanoseconds workDuration,
@@ -116,7 +114,7 @@
// no-op.
// The period is the vsync period from the current display configuration.
void resyncToHardwareVsync(bool makeAvailable, nsecs_t period);
- void resync();
+ void resync() EXCLUDES(mRefreshRateConfigsLock);
// Passes a vsync sample to VsyncController. periodFlushed will be true if
// VsyncController detected that the vsync period changed, and false otherwise.
@@ -127,12 +125,13 @@
// Layers are registered on creation, and unregistered when the weak reference expires.
void registerLayer(Layer*);
- void recordLayerHistory(Layer*, nsecs_t presentTime, LayerHistory::LayerUpdateType updateType);
+ void recordLayerHistory(Layer*, nsecs_t presentTime, LayerHistory::LayerUpdateType updateType)
+ EXCLUDES(mRefreshRateConfigsLock);
void setModeChangePending(bool pending);
void deregisterLayer(Layer*);
// Detects content using layer history, and selects a matching refresh rate.
- void chooseRefreshRateForContent();
+ void chooseRefreshRateForContent() EXCLUDES(mRefreshRateConfigsLock);
bool isIdleTimerEnabled() const { return mIdleTimer.has_value(); }
void resetIdleTimer();
@@ -147,7 +146,7 @@
// Returns true if a given vsync timestamp is considered valid vsync
// for a given uid
bool isVsyncValid(nsecs_t expectedVsyncTimestamp, uid_t uid) const
- EXCLUDES(mFrameRateOverridesMutex);
+ EXCLUDES(mFrameRateOverridesLock);
std::chrono::steady_clock::time_point getPreviousVsyncFrom(nsecs_t expectedPresentTime) const;
@@ -156,7 +155,7 @@
void dumpVsync(std::string&) const;
// Get the appropriate refresh for current conditions.
- std::optional<DisplayModeId> getPreferredModeId();
+ DisplayModePtr getPreferredDisplayMode();
// Notifies the scheduler about a refresh rate timeline change.
void onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline);
@@ -165,7 +164,7 @@
void onDisplayRefreshed(nsecs_t timestamp);
// Notifies the scheduler when the display size has changed. Called from SF's main thread
- void onPrimaryDisplayAreaChanged(uint32_t displayArea);
+ void onActiveDisplayAreaChanged(uint32_t displayArea);
size_t getEventThreadConnectionCount(ConnectionHandle handle);
@@ -176,9 +175,21 @@
// Stores the preferred refresh rate that an app should run at.
// FrameRateOverride.refreshRateHz == 0 means no preference.
- void setPreferredRefreshRateForUid(FrameRateOverride) EXCLUDES(mFrameRateOverridesMutex);
+ void setPreferredRefreshRateForUid(FrameRateOverride) EXCLUDES(mFrameRateOverridesLock);
// Retrieves the overridden refresh rate for a given uid.
- std::optional<Fps> getFrameRateOverride(uid_t uid) const EXCLUDES(mFrameRateOverridesMutex);
+ std::optional<Fps> getFrameRateOverride(uid_t uid) const
+ EXCLUDES(mRefreshRateConfigsLock, mFrameRateOverridesLock);
+
+ void setRefreshRateConfigs(std::shared_ptr<scheduler::RefreshRateConfigs> refreshRateConfigs)
+ EXCLUDES(mRefreshRateConfigsLock) {
+ std::scoped_lock lock(mRefreshRateConfigsLock);
+ mRefreshRateConfigs = std::move(refreshRateConfigs);
+ }
+
+ nsecs_t getVsyncPeriodFromRefreshRateConfigs() const EXCLUDES(mRefreshRateConfigsLock) {
+ std::scoped_lock lock(mRefreshRateConfigsLock);
+ return mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
+ }
private:
friend class TestableScheduler;
@@ -203,14 +214,14 @@
};
// Unlike the testing constructor, this creates the VsyncSchedule, LayerHistory, and timers.
- Scheduler(const scheduler::RefreshRateConfigs&, ISchedulerCallback&, Options);
+ Scheduler(const std::shared_ptr<scheduler::RefreshRateConfigs>&, ISchedulerCallback&, Options);
// Used by tests to inject mocks.
- Scheduler(VsyncSchedule, const scheduler::RefreshRateConfigs&, ISchedulerCallback&,
- std::unique_ptr<LayerHistory>, Options);
+ Scheduler(VsyncSchedule, const std::shared_ptr<scheduler::RefreshRateConfigs>&,
+ ISchedulerCallback&, std::unique_ptr<LayerHistory>, Options);
static VsyncSchedule createVsyncSchedule(bool supportKernelIdleTimer);
- static std::unique_ptr<LayerHistory> createLayerHistory(const scheduler::RefreshRateConfigs&);
+ static std::unique_ptr<LayerHistory> createLayerHistory();
// Create a connection on the given EventThread.
ConnectionHandle createConnection(std::unique_ptr<EventThread>);
@@ -218,7 +229,7 @@
EventThread*, ISurfaceComposer::EventRegistrationFlags eventRegistration = {});
// Update feature state machine to given state when corresponding timer resets or expires.
- void kernelIdleTimerCallback(TimerState);
+ void kernelIdleTimerCallback(TimerState) EXCLUDES(mRefreshRateConfigsLock);
void idleTimerCallback(TimerState);
void touchTimerCallback(TimerState);
void displayPowerTimerCallback(TimerState);
@@ -232,18 +243,25 @@
// This function checks whether individual features that are affecting the refresh rate
// selection were initialized, prioritizes them, and calculates the DisplayModeId
// for the suggested refresh rate.
- DisplayModeId calculateRefreshRateModeId(
+ DisplayModePtr calculateRefreshRateModeId(
scheduler::RefreshRateConfigs::GlobalSignals* consideredSignals = nullptr)
REQUIRES(mFeatureStateLock);
- void dispatchCachedReportedMode() REQUIRES(mFeatureStateLock);
+ void dispatchCachedReportedMode() REQUIRES(mFeatureStateLock) EXCLUDES(mRefreshRateConfigsLock);
bool updateFrameRateOverrides(scheduler::RefreshRateConfigs::GlobalSignals consideredSignals,
Fps displayRefreshRate) REQUIRES(mFeatureStateLock)
- EXCLUDES(mFrameRateOverridesMutex);
+ EXCLUDES(mFrameRateOverridesLock);
- impl::EventThread::ThrottleVsyncCallback makeThrottleVsyncCallback() const;
+ impl::EventThread::ThrottleVsyncCallback makeThrottleVsyncCallback() const
+ EXCLUDES(mRefreshRateConfigsLock);
impl::EventThread::GetVsyncPeriodFunction makeGetVsyncPeriodFunction() const;
+ std::shared_ptr<scheduler::RefreshRateConfigs> holdRefreshRateConfigs() const
+ EXCLUDES(mRefreshRateConfigsLock) {
+ std::scoped_lock lock(mRefreshRateConfigsLock);
+ return mRefreshRateConfigs;
+ }
+
// Stores EventThread associated with a given VSyncSource, and an initial EventThreadConnection.
struct Connection {
sp<EventThreadConnection> connection;
@@ -288,7 +306,7 @@
TouchState touch = TouchState::Inactive;
TimerState displayPowerTimer = TimerState::Expired;
- std::optional<DisplayModeId> modeId;
+ DisplayModePtr mode;
LayerHistory::Summary contentRequirements;
bool isDisplayPowerStateNormal = true;
@@ -296,15 +314,15 @@
// Used to cache the last parameters of onPrimaryDisplayModeChanged
struct ModeChangedParams {
ConnectionHandle handle;
- PhysicalDisplayId displayId;
- DisplayModeId modeId;
- nsecs_t vsyncPeriod;
+ DisplayModePtr mode;
};
std::optional<ModeChangedParams> cachedModeChangedParams;
} mFeatures GUARDED_BY(mFeatureStateLock);
- const scheduler::RefreshRateConfigs& mRefreshRateConfigs;
+ mutable std::mutex mRefreshRateConfigsLock;
+ std::shared_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs
+ GUARDED_BY(mRefreshRateConfigsLock);
std::mutex mVsyncTimelineLock;
std::optional<hal::VsyncPeriodChangeTimeline> mLastVsyncPeriodChangeTimeline
@@ -315,14 +333,14 @@
// The frame rate override lists need their own mutex as they are being read
// by SurfaceFlinger, Scheduler and EventThread (as a callback) to prevent deadlocks
- mutable std::mutex mFrameRateOverridesMutex;
+ mutable std::mutex mFrameRateOverridesLock;
// mappings between a UID and a preferred refresh rate that this app would
// run at.
scheduler::RefreshRateConfigs::UidToFrameRateOverride mFrameRateOverridesByContent
- GUARDED_BY(mFrameRateOverridesMutex);
+ GUARDED_BY(mFrameRateOverridesLock);
scheduler::RefreshRateConfigs::UidToFrameRateOverride mFrameRateOverridesFromBackdoor
- GUARDED_BY(mFrameRateOverridesMutex);
+ GUARDED_BY(mFrameRateOverridesLock);
};
} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 9fecd63..07a67a9 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -145,6 +145,13 @@
return (expr); \
}()
+#define MAIN_THREAD_GUARD(expr) \
+ [&] { \
+ LOG_FATAL_IF(std::this_thread::get_id() != mMainThreadId); \
+ MainThreadScopedGuard lock(SF_MAIN_THREAD); \
+ return (expr); \
+ }()
+
#undef NO_THREAD_SAFETY_ANALYSIS
#define NO_THREAD_SAFETY_ANALYSIS \
_Pragma("GCC error \"Prefer MAIN_THREAD macros or {Conditional,Timed,Unnecessary}Lock.\"")
@@ -632,9 +639,7 @@
mVirtualDisplayIdGenerators.gpu.releaseId(*id);
}
-std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIds() const {
- Mutex::Autolock lock(mStateLock);
-
+std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIdsLocked() const {
const auto internalDisplayId = getInternalDisplayIdLocked();
if (!internalDisplayId) {
return {};
@@ -728,7 +733,7 @@
mBootStage = BootStage::FINISHED;
if (property_get_bool("sf.debug.show_refresh_rate_overlay", false)) {
- enableRefreshRateOverlay(true);
+ ON_MAIN_THREAD(enableRefreshRateOverlay(true));
}
}));
}
@@ -837,7 +842,7 @@
}
}
- getRenderEngine().onPrimaryDisplaySizeChanged(display->getSize());
+ onActiveDisplaySizeChanged(display);
// Inform native graphics APIs whether the present timestamp is supported:
@@ -1075,36 +1080,28 @@
void SurfaceFlinger::setDesiredActiveMode(const ActiveModeInfo& info) {
ATRACE_CALL();
- auto refreshRate = mRefreshRateConfigs->getRefreshRateFromModeId(info.modeId);
- ALOGV("%s(%s)", __func__, refreshRate.getName().c_str());
- std::lock_guard<std::mutex> lock(mActiveModeLock);
- if (mDesiredActiveModeChanged) {
- // If a mode change is pending, just cache the latest request in mDesiredActiveMode
- const Scheduler::ModeEvent prevConfig = mDesiredActiveMode.event;
- mDesiredActiveMode = info;
- mDesiredActiveMode.event = mDesiredActiveMode.event | prevConfig;
- } else {
- // Check if we are already at the desired mode
- const auto display = getDefaultDisplayDeviceLocked();
- if (!display || display->getActiveMode()->getId() == refreshRate.getModeId()) {
- return;
- }
+ if (!info.mode) {
+ ALOGW("requested display mode is null");
+ return;
+ }
+ auto display = getDisplayDeviceLocked(info.mode->getPhysicalDisplayId());
+ if (!display) {
+ ALOGW("%s: display is no longer valid", __func__);
+ return;
+ }
- // Initiate a mode change.
- mDesiredActiveModeChanged = true;
- mDesiredActiveMode = info;
-
+ if (display->setDesiredActiveMode(info)) {
// This will trigger HWC refresh without resetting the idle timer.
repaintEverythingForHWC();
// Start receiving vsync samples now, so that we can detect a period
// switch.
- mScheduler->resyncToHardwareVsync(true, refreshRate.getVsyncPeriod());
+ mScheduler->resyncToHardwareVsync(true, info.mode->getVsyncPeriod());
// As we called to set period, we will call to onRefreshRateChangeCompleted once
// VsyncController model is locked.
modulateVsync(&VsyncModulator::onRefreshRateChangeInitiated);
- updatePhaseConfiguration(refreshRate.getFps());
+ updatePhaseConfiguration(info.mode->getFps());
mScheduler->setModeChangePending(true);
}
}
@@ -1138,7 +1135,7 @@
const auto fps = mode->getFps();
// Keep the old switching type.
const auto allowGroupSwitching =
- mRefreshRateConfigs->getCurrentPolicy().allowGroupSwitching;
+ display->refreshRateConfigs().getCurrentPolicy().allowGroupSwitching;
const scheduler::RefreshRateConfigs::Policy policy{mode->getId(),
allowGroupSwitching,
{fps, fps}};
@@ -1158,59 +1155,43 @@
return;
}
- const auto upcomingMode = display->getMode(mUpcomingActiveMode.modeId);
- if (!upcomingMode) {
- ALOGW("Upcoming active mode is no longer supported. Mode ID = %d",
- mUpcomingActiveMode.modeId.value());
- // TODO(b/159590486) Handle the error better. Some parts of SurfaceFlinger may
- // have been already updated with the upcoming active mode.
- return;
- }
-
- if (display->getActiveMode()->getSize() != upcomingMode->getSize()) {
+ const auto upcomingModeInfo = MAIN_THREAD_GUARD(display->getUpcomingActiveMode());
+ if (display->getActiveMode()->getSize() != upcomingModeInfo.mode->getSize()) {
auto& state = mCurrentState.displays.editValueFor(display->getDisplayToken());
// We need to generate new sequenceId in order to recreate the display (and this
// way the framebuffer).
state.sequenceId = DisplayDeviceState{}.sequenceId;
- state.physical->activeMode = upcomingMode;
+ state.physical->activeMode = upcomingModeInfo.mode;
processDisplayChangesLocked();
// processDisplayChangesLocked will update all necessary components so we're done here.
return;
}
- std::lock_guard<std::mutex> lock(mActiveModeLock);
- mRefreshRateConfigs->setCurrentModeId(mUpcomingActiveMode.modeId);
- display->setActiveMode(mUpcomingActiveMode.modeId);
+ // We just created this display so we can call even if we are not on
+ // the main thread
+ MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD);
+ display->setActiveMode(upcomingModeInfo.mode->getId());
- const Fps refreshRate = upcomingMode->getFps();
-
+ const Fps refreshRate = upcomingModeInfo.mode->getFps();
mRefreshRateStats->setRefreshRate(refreshRate);
-
updatePhaseConfiguration(refreshRate);
- ATRACE_INT("ActiveConfigFPS", refreshRate.getValue());
- if (mUpcomingActiveMode.event != Scheduler::ModeEvent::None) {
- const nsecs_t vsyncPeriod = refreshRate.getPeriodNsecs();
- const auto physicalId = display->getPhysicalId();
- mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, physicalId,
- mUpcomingActiveMode.modeId, vsyncPeriod);
+ if (upcomingModeInfo.event != Scheduler::ModeEvent::None) {
+ mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, upcomingModeInfo.mode);
}
}
-void SurfaceFlinger::clearDesiredActiveModeState() {
- std::lock_guard<std::mutex> lock(mActiveModeLock);
- mDesiredActiveMode.event = Scheduler::ModeEvent::None;
- mDesiredActiveModeChanged = false;
- mScheduler->setModeChangePending(false);
+void SurfaceFlinger::clearDesiredActiveModeState(const sp<DisplayDevice>& display) {
+ display->clearDesiredActiveModeState();
+ if (isDisplayActiveLocked(display)) {
+ mScheduler->setModeChangePending(false);
+ }
}
-void SurfaceFlinger::desiredActiveModeChangeDone() {
- const auto modeId = getDesiredActiveMode()->modeId;
-
- clearDesiredActiveModeState();
-
- const auto refreshRate = getDefaultDisplayDeviceLocked()->getMode(modeId)->getFps();
+void SurfaceFlinger::desiredActiveModeChangeDone(const sp<DisplayDevice>& display) {
+ const auto refreshRate = display->getDesiredActiveMode()->mode->getFps();
+ clearDesiredActiveModeState(display);
mScheduler->resyncToHardwareVsync(true, refreshRate.getPeriodNsecs());
updatePhaseConfiguration(refreshRate);
}
@@ -1218,66 +1199,75 @@
void SurfaceFlinger::performSetActiveMode() {
ATRACE_CALL();
ALOGV("%s", __FUNCTION__);
- // Store the local variable to release the lock.
- const auto desiredActiveMode = getDesiredActiveMode();
- if (!desiredActiveMode) {
- // No desired active mode pending to be applied
- return;
+
+ for (const auto& iter : mDisplays) {
+ const auto& display = iter.second;
+ if (!display || !display->isInternal()) {
+ continue;
+ }
+
+ // Store the local variable to release the lock.
+ const auto desiredActiveMode = display->getDesiredActiveMode();
+ if (!desiredActiveMode) {
+ // No desired active mode pending to be applied
+ continue;
+ }
+
+ if (!isDisplayActiveLocked(display)) {
+ // display is no longer the active display, so abort the mode change
+ clearDesiredActiveModeState(display);
+ continue;
+ }
+
+ const auto desiredMode = display->getMode(desiredActiveMode->mode->getId());
+ if (!desiredMode) {
+ ALOGW("Desired display mode is no longer supported. Mode ID = %d",
+ desiredActiveMode->mode->getId().value());
+ clearDesiredActiveModeState(display);
+ continue;
+ }
+
+ const auto refreshRate = desiredMode->getFps();
+ ALOGV("%s changing active mode to %d(%s) for display %s", __func__,
+ desiredMode->getId().value(), to_string(refreshRate).c_str(),
+ to_string(display->getId()).c_str());
+
+ if (display->getActiveMode()->getId() == desiredActiveMode->mode->getId()) {
+ // display is not valid or we are already in the requested mode
+ // on both cases there is nothing left to do
+ desiredActiveModeChangeDone(display);
+ continue;
+ }
+
+ // Desired active mode was set, it is different than the mode currently in use, however
+ // allowed modes might have changed by the time we process the refresh.
+ // Make sure the desired mode is still allowed
+ const auto displayModeAllowed =
+ display->refreshRateConfigs().isModeAllowed(desiredActiveMode->mode->getId());
+ if (!displayModeAllowed) {
+ desiredActiveModeChangeDone(display);
+ continue;
+ }
+
+ // TODO(b/142753666) use constrains
+ hal::VsyncPeriodChangeConstraints constraints;
+ constraints.desiredTimeNanos = systemTime();
+ constraints.seamlessRequired = false;
+ hal::VsyncPeriodChangeTimeline outTimeline;
+
+ const auto status = MAIN_THREAD_GUARD(
+ display->initiateModeChange(*desiredActiveMode, constraints, &outTimeline));
+ if (status != NO_ERROR) {
+ // initiateModeChange may fail if a hotplug event is just about
+ // to be sent. We just log the error in this case.
+ ALOGW("initiateModeChange failed: %d", status);
+ continue;
+ }
+ mScheduler->onNewVsyncPeriodChangeTimeline(outTimeline);
+
+ // Scheduler will submit an empty frame to HWC if needed.
+ mSetActiveModePending = true;
}
-
- const auto display = getDefaultDisplayDeviceLocked();
- const auto desiredMode = display->getMode(desiredActiveMode->modeId);
- if (!desiredMode) {
- ALOGW("Desired display mode is no longer supported. Mode ID = %d",
- desiredActiveMode->modeId.value());
- clearDesiredActiveModeState();
- return;
- }
- const auto refreshRate = desiredMode->getFps();
- ALOGV("%s changing active mode to %d(%s)", __FUNCTION__, desiredMode->getId().value(),
- to_string(refreshRate).c_str());
-
- if (!display || display->getActiveMode()->getId() == desiredActiveMode->modeId) {
- // display is not valid or we are already in the requested mode
- // on both cases there is nothing left to do
- desiredActiveModeChangeDone();
- return;
- }
-
- // Desired active mode was set, it is different than the mode currently in use, however
- // allowed modes might have changed by the time we process the refresh.
- // Make sure the desired mode is still allowed
- if (!isDisplayModeAllowed(desiredActiveMode->modeId)) {
- desiredActiveModeChangeDone();
- return;
- }
-
- mUpcomingActiveMode = *desiredActiveMode;
-
- ATRACE_INT("ActiveModeFPS_HWC", refreshRate.getValue());
-
- // TODO(b/142753666) use constrains
- hal::VsyncPeriodChangeConstraints constraints;
- constraints.desiredTimeNanos = systemTime();
- constraints.seamlessRequired = false;
-
- hal::VsyncPeriodChangeTimeline outTimeline;
- const auto status =
- display->initiateModeChange(mUpcomingActiveMode.modeId, constraints, &outTimeline);
- if (status != NO_ERROR) {
- // initiateModeChange may fail if a hotplug event is just about
- // to be sent. We just log the error in this case.
- ALOGW("initiateModeChange failed: %d", status);
- return;
- }
-
- mScheduler->onNewVsyncPeriodChangeTimeline(outTimeline);
- if (mRefreshRateOverlay) {
- mRefreshRateOverlay->changeRefreshRate(desiredMode->getFps());
- }
-
- // Scheduler will submit an empty frame to HWC if needed.
- mSetActiveModePending = true;
}
void SurfaceFlinger::disableExpensiveRendering() {
@@ -1744,10 +1734,6 @@
*compositorTiming = getBE().mCompositorTiming;
}
-bool SurfaceFlinger::isDisplayModeAllowed(DisplayModeId modeId) const {
- return mRefreshRateConfigs->isModeAllowed(modeId);
-}
-
void SurfaceFlinger::changeRefreshRateLocked(const RefreshRate& refreshRate,
Scheduler::ModeEvent event) {
const auto display = getDefaultDisplayDeviceLocked();
@@ -1757,13 +1743,13 @@
ATRACE_CALL();
// Don't do any updating if the current fps is the same as the new one.
- if (!isDisplayModeAllowed(refreshRate.getModeId())) {
+ if (!display->refreshRateConfigs().isModeAllowed(refreshRate.getModeId())) {
ALOGV("Skipping mode %d as it is not part of allowed modes",
refreshRate.getModeId().value());
return;
}
- setDesiredActiveMode({refreshRate.getModeId(), event});
+ setDesiredActiveMode({refreshRate.getMode(), event});
}
void SurfaceFlinger::onComposerHalHotplug(hal::HWDisplayId hwcDisplayId,
@@ -1961,8 +1947,13 @@
}
if (mRefreshRateOverlaySpinner) {
- if (Mutex::Autolock lock(mStateLock); mRefreshRateOverlay) {
- mRefreshRateOverlay->onInvalidate();
+ if (Mutex::Autolock lock(mStateLock);
+ const auto display = getDefaultDisplayDeviceLocked()) {
+ if (display) {
+ display->onInvalidate();
+ } else {
+ ALOGW("%s: default display is null", __func__);
+ }
}
}
@@ -2334,7 +2325,7 @@
mTransactionCallbackInvoker.addPresentFence(mPreviousPresentFences[0].fence);
mTransactionCallbackInvoker.sendCallbacks();
- if (display && display->isPrimary() && display->getPowerMode() == hal::PowerMode::ON &&
+ if (display && display->isInternal() && display->getPowerMode() == hal::PowerMode::ON &&
mPreviousPresentFences[0].fenceTime->isValid()) {
mScheduler->addPresentFence(mPreviousPresentFences[0].fenceTime);
}
@@ -2471,7 +2462,6 @@
// We call getTransactionFlags(), which will also clear the flags,
// with mStateLock held to guarantee that mCurrentState won't change
// until the transaction is committed.
-
modulateVsync(&VsyncModulator::onTransactionCommit);
transactionFlags = getTransactionFlags(eTransactionMask);
handleTransactionLocked(transactionFlags);
@@ -2523,6 +2513,7 @@
for (const auto& hwcMode : hwcModes) {
newModes.push_back(DisplayMode::Builder(hwcMode.hwcId)
.setId(DisplayModeId{nextModeId++})
+ .setPhysicalDisplayId(displayId)
.setWidth(hwcMode.width)
.setHeight(hwcMode.height)
.setVsyncPeriod(hwcMode.vsyncPeriod)
@@ -2584,11 +2575,6 @@
sp<IBinder> token = new BBinder();
mCurrentState.displays.add(token, state);
mPhysicalDisplayTokens.emplace(displayId, std::move(token));
-
- if (event.hwcDisplayId == getHwComposer().getInternalHwcDisplayId()) {
- initScheduler(state);
- }
-
mInterceptor->saveDisplayCreation(state);
} else {
ALOGV("Recreating display %s", to_string(displayId).c_str());
@@ -2643,6 +2629,14 @@
if (const auto& physical = state.physical) {
creationArgs.connectionType = physical->type;
creationArgs.supportedModes = physical->supportedModes;
+ creationArgs.activeModeId = physical->activeMode->getId();
+ scheduler::RefreshRateConfigs::Config config =
+ {.enableFrameRateOverride = android::sysprop::enable_frame_rate_override(false),
+ .frameRateMultipleThreshold =
+ base::GetIntProperty("debug.sf.frame_rate_multiple_threshold", 0)};
+ creationArgs.refreshRateConfigs =
+ std::make_shared<scheduler::RefreshRateConfigs>(creationArgs.supportedModes,
+ creationArgs.activeModeId, config);
}
if (const auto id = PhysicalDisplayId::tryCast(compositionDisplay->getId())) {
@@ -2699,7 +2693,7 @@
RenderIntent::COLORIMETRIC,
Dataspace::UNKNOWN});
if (!state.isVirtual()) {
- display->setActiveMode(state.physical->activeMode->getId());
+ MAIN_THREAD_GUARD(display->setActiveMode(state.physical->activeMode->getId()));
display->setDeviceProductInfo(state.physical->deviceProductInfo);
}
@@ -2781,14 +2775,12 @@
const auto display = setupNewDisplayDeviceInternal(displayToken, std::move(compositionDisplay),
state, displaySurface, producer);
mDisplays.emplace(displayToken, display);
+ if (display->isPrimary()) {
+ initScheduler(display);
+ }
if (!state.isVirtual()) {
dispatchDisplayHotplugEvent(display->getPhysicalId(), true);
}
-
- if (display->isPrimary()) {
- mScheduler->onPrimaryDisplayAreaChanged(display->getWidth() * display->getHeight());
- getRenderEngine().onPrimaryDisplaySizeChanged(display->getSize());
- }
}
void SurfaceFlinger::processDisplayRemoved(const wp<IBinder>& displayToken) {
@@ -2853,16 +2845,7 @@
// TODO(b/175678251) Call a listener instead.
if (currentState.physical->hwcDisplayId == getHwComposer().getInternalHwcDisplayId()) {
- mRefreshRateConfigs->updateDisplayModes(currentState.physical->supportedModes,
- currentState.physical->activeMode->getId());
- mVsyncConfiguration->reset();
- const Fps refreshRate = currentState.physical->activeMode->getFps();
- updatePhaseConfiguration(refreshRate);
- mRefreshRateStats->setRefreshRate(refreshRate);
-
- if (mRefreshRateOverlay) {
- mRefreshRateOverlay->reset();
- }
+ updateInternalDisplayVsyncLocked(display);
}
}
return;
@@ -2888,16 +2871,18 @@
currentState.height != drawingState.height) {
display->setDisplaySize(currentState.width, currentState.height);
- if (display->isPrimary()) {
- mScheduler->onPrimaryDisplayAreaChanged(currentState.width * currentState.height);
- }
-
- if (mRefreshRateOverlay) {
- mRefreshRateOverlay->setViewport(display->getSize());
+ if (isDisplayActiveLocked(display)) {
+ onActiveDisplaySizeChanged(display);
}
}
}
}
+void SurfaceFlinger::updateInternalDisplayVsyncLocked(const sp<DisplayDevice>& activeDisplay) {
+ mVsyncConfiguration->reset();
+ const Fps refreshRate = activeDisplay->refreshRateConfigs().getCurrentRefreshRate().getFps();
+ updatePhaseConfiguration(refreshRate);
+ mRefreshRateStats->setRefreshRate(refreshRate);
+}
void SurfaceFlinger::processDisplayChangesLocked() {
// here we take advantage of Vector's copy-on-write semantics to
@@ -3125,24 +3110,14 @@
mScheduler->onFrameRateOverridesChanged(mAppConnectionHandle, displayId);
}
-void SurfaceFlinger::initScheduler(const DisplayDeviceState& displayState) {
+void SurfaceFlinger::initScheduler(const sp<DisplayDevice>& display) {
if (mScheduler) {
// In practice it's not allowed to hotplug in/out the primary display once it's been
// connected during startup, but some tests do it, so just warn and return.
ALOGW("Can't re-init scheduler");
return;
}
- const auto displayId = displayState.physical->id;
- scheduler::RefreshRateConfigs::Config config =
- {.enableFrameRateOverride = android::sysprop::enable_frame_rate_override(false),
- .frameRateMultipleThreshold =
- base::GetIntProperty("debug.sf.frame_rate_multiple_threshold", 0)};
- mRefreshRateConfigs =
- std::make_unique<scheduler::RefreshRateConfigs>(displayState.physical->supportedModes,
- displayState.physical->activeMode
- ->getId(),
- config);
- const auto currRefreshRate = displayState.physical->activeMode->getFps();
+ const auto currRefreshRate = display->getActiveMode()->getFps();
mRefreshRateStats = std::make_unique<scheduler::RefreshRateStats>(*mTimeStats, currRefreshRate,
hal::PowerMode::OFF);
@@ -3150,7 +3125,7 @@
mVsyncModulator.emplace(mVsyncConfiguration->getCurrentConfigs());
// start the EventThread
- mScheduler = getFactory().createScheduler(*mRefreshRateConfigs, *this);
+ mScheduler = getFactory().createScheduler(display->holdRefreshRateConfigs(), *this);
const auto configs = mVsyncConfiguration->getCurrentConfigs();
const nsecs_t vsyncPeriod = currRefreshRate.getPeriodNsecs();
mAppConnectionHandle =
@@ -3179,9 +3154,7 @@
// This is a bit hacky, but this avoids a back-pointer into the main SF
// classes from EventThread, and there should be no run-time binder cost
// anyway since there are no connected apps at this point.
- mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, displayId,
- displayState.physical->activeMode->getId(),
- vsyncPeriod);
+ mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, display->getActiveMode());
static auto ignorePresentFences =
base::GetBoolProperty("debug.sf.vsync_reactor_ignore_present_fences"s, false);
mScheduler->setIgnorePresentFences(
@@ -3248,19 +3221,10 @@
}
}
- // TODO(b/163019109): See if this traversal is needed at all...
- if (!mOffscreenLayers.empty()) {
- mDrawingState.traverse([&](Layer* layer) {
- // If the layer can be reached when traversing mDrawingState, then the layer is no
- // longer offscreen. Remove the layer from the offscreenLayer set.
- if (mOffscreenLayers.count(layer)) {
- mOffscreenLayers.erase(layer);
- }
- });
- }
-
commitOffscreenLayers();
- mDrawingState.traverse([&](Layer* layer) { layer->updateMirrorInfo(); });
+ if (mNumClones > 0) {
+ mDrawingState.traverse([&](Layer* layer) { layer->updateMirrorInfo(); });
+ }
}
void SurfaceFlinger::commitOffscreenLayers() {
@@ -3366,7 +3330,9 @@
mBootStage = BootStage::BOOTANIMATION;
}
- mDrawingState.traverse([&](Layer* layer) { layer->updateCloneBufferInfo(); });
+ if (mNumClones > 0) {
+ mDrawingState.traverse([&](Layer* layer) { layer->updateCloneBufferInfo(); });
+ }
// Only continue with the refresh if there is actually new work to do
return !mLayersWithQueuedFrames.empty() && newDataLatched;
@@ -4257,7 +4223,7 @@
return result;
}
- mirrorLayer->mClonedChild = mirrorFrom->createClone();
+ mirrorLayer->setClonedChild(mirrorFrom->createClone());
}
*outLayerId = mirrorLayer->sequence;
@@ -4499,7 +4465,8 @@
{}, getpid(), getuid(), 0 /* Undefined transactionId */);
setPowerModeInternal(display, hal::PowerMode::ON);
- const nsecs_t vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
+ const nsecs_t vsyncPeriod =
+ display->refreshRateConfigs().getCurrentRefreshRate().getVsyncPeriod();
mAnimFrameTracker.setDisplayRefreshPeriod(vsyncPeriod);
mDefaultDisplayTransformHint = display->getTransformHint();
// Use phase of 0 since phase is not known.
@@ -4552,8 +4519,13 @@
if (mInterceptor->isEnabled()) {
mInterceptor->savePowerModeUpdate(display->getSequenceId(), static_cast<int32_t>(mode));
}
- const auto vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
+ const auto vsyncPeriod = display->refreshRateConfigs().getCurrentRefreshRate().getVsyncPeriod();
if (currentMode == hal::PowerMode::OFF) {
+ const auto activeDisplay = getDisplayDeviceLocked(mActiveDisplayToken);
+ if (display->isInternal() && (!activeDisplay || !activeDisplay->isPoweredOn())) {
+ mActiveDisplayToken = display->getDisplayToken();
+ onActiveDisplayChangedLocked(getDisplayDeviceLocked(mActiveDisplayToken));
+ }
// Keep uclamp in a separate syscall and set it before changing to RT due to b/190237315.
// We can merge the syscall later.
if (SurfaceFlinger::setSchedAttr(true) != NO_ERROR) {
@@ -4563,7 +4535,7 @@
ALOGW("Couldn't set SCHED_FIFO on display on: %s\n", strerror(errno));
}
getHwComposer().setPowerMode(displayId, mode);
- if (display->isPrimary() && mode != hal::PowerMode::DOZE_SUSPEND) {
+ if (display->isInternal() && mode != hal::PowerMode::DOZE_SUSPEND) {
getHwComposer().setVsyncEnabled(displayId, mHWCVsyncPendingState);
mScheduler->onScreenAcquired(mAppConnectionHandle);
mScheduler->resyncToHardwareVsync(true, vsyncPeriod);
@@ -4580,7 +4552,7 @@
if (SurfaceFlinger::setSchedAttr(false) != NO_ERROR) {
ALOGW("Couldn't set uclamp.min on display off: %s\n", strerror(errno));
}
- if (display->isPrimary() && currentMode != hal::PowerMode::DOZE_SUSPEND) {
+ if (display->isInternal() && currentMode != hal::PowerMode::DOZE_SUSPEND) {
mScheduler->disableHardwareVsync(true);
mScheduler->onScreenReleased(mAppConnectionHandle);
}
@@ -4594,13 +4566,13 @@
} else if (mode == hal::PowerMode::DOZE || mode == hal::PowerMode::ON) {
// Update display while dozing
getHwComposer().setPowerMode(displayId, mode);
- if (display->isPrimary() && currentMode == hal::PowerMode::DOZE_SUSPEND) {
+ if (display->isInternal() && currentMode == hal::PowerMode::DOZE_SUSPEND) {
mScheduler->onScreenAcquired(mAppConnectionHandle);
mScheduler->resyncToHardwareVsync(true, vsyncPeriod);
}
} else if (mode == hal::PowerMode::DOZE_SUSPEND) {
// Leave display going to doze
- if (display->isPrimary()) {
+ if (display->isInternal()) {
mScheduler->disableHardwareVsync(true);
mScheduler->onScreenReleased(mAppConnectionHandle);
}
@@ -4610,7 +4582,7 @@
getHwComposer().setPowerMode(displayId, mode);
}
- if (display->isPrimary()) {
+ if (display->isInternal()) {
mTimeStats->setPowerMode(mode);
mRefreshRateStats->setPowerMode(mode);
mScheduler->setDisplayPowerState(mode == hal::PowerMode::ON);
@@ -4779,8 +4751,6 @@
" present offset: %9" PRId64 " ns\t VSYNC period: %9" PRId64 " ns\n\n",
dispSyncPresentTimeOffset, getVsyncPeriodFromHWC());
- mRefreshRateConfigs->dump(result);
-
StringAppendF(&result, "(mode override by backdoor: %s)\n\n",
mDebugDisplayModeSetByBackdoor ? "yes" : "no");
@@ -5656,16 +5626,17 @@
return NO_ERROR;
}
case 1034: {
- switch (n = data.readInt32()) {
- case 0:
- case 1:
- enableRefreshRateOverlay(static_cast<bool>(n));
- break;
- default: {
- Mutex::Autolock lock(mStateLock);
- reply->writeBool(mRefreshRateOverlay != nullptr);
+ schedule([&] {
+ switch (n = data.readInt32()) {
+ case 0:
+ case 1:
+ ON_MAIN_THREAD(enableRefreshRateOverlay(static_cast<bool>(n)));
+ break;
+ default: {
+ reply->writeBool(ON_MAIN_THREAD(isRefreshRateOverlayEnabled()));
+ }
}
- }
+ }).get();
return NO_ERROR;
}
case 1035: {
@@ -5674,7 +5645,7 @@
const auto display = [&]() -> sp<IBinder> {
uint64_t value;
if (data.readUint64(&value) != NO_ERROR) {
- return getInternalDisplayToken();
+ return getDefaultDisplayDevice()->getDisplayToken().promote();
}
if (const auto id = DisplayId::fromValue<PhysicalDisplayId>(value)) {
@@ -5795,22 +5766,25 @@
static bool updateOverlay =
property_get_bool("debug.sf.kernel_idle_timer_update_overlay", true);
if (!updateOverlay) return;
- if (Mutex::Autolock lock(mStateLock); !mRefreshRateOverlay) return;
+ if (Mutex::Autolock lock(mStateLock); !isRefreshRateOverlayEnabled()) return;
// Update the overlay on the main thread to avoid race conditions with
// mRefreshRateConfigs->getCurrentRefreshRate()
static_cast<void>(schedule([=] {
- const auto desiredActiveMode = getDesiredActiveMode();
- const std::optional<DisplayModeId> desiredModeId =
- desiredActiveMode ? std::make_optional(desiredActiveMode->modeId) : std::nullopt;
+ const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
+ if (!display) {
+ ALOGW("%s: default display is null", __func__);
+ return;
+ }
+
+ const auto desiredActiveMode = display->getDesiredActiveMode();
+ const std::optional<DisplayModeId> desiredModeId = desiredActiveMode
+ ? std::make_optional(desiredActiveMode->mode->getId())
+ : std::nullopt;
const bool timerExpired = mKernelIdleTimerEnabled && expired;
- const auto newRefreshRate =
- mRefreshRateConfigs->onKernelTimerChanged(desiredModeId, timerExpired);
- if (newRefreshRate) {
- if (Mutex::Autolock lock(mStateLock); mRefreshRateOverlay) {
- mRefreshRateOverlay->changeRefreshRate(*newRefreshRate);
- }
+
+ if (display->onKernelTimerChanged(desiredModeId, timerExpired)) {
mEventQueue->invalidate();
}
}));
@@ -5823,8 +5797,13 @@
if (!mSupportKernelIdleTimer) {
return;
}
- const KernelIdleTimerAction action = mRefreshRateConfigs->getIdleTimerAction();
+ const auto display = getDefaultDisplayDeviceLocked();
+ if (!display) {
+ ALOGW("%s: default display is null", __func__);
+ return;
+ }
+ const KernelIdleTimerAction action = display->refreshRateConfigs().getIdleTimerAction();
switch (action) {
case KernelIdleTimerAction::TurnOff:
if (mKernelIdleTimerEnabled) {
@@ -6439,78 +6418,55 @@
const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy) {
Mutex::Autolock lock(mStateLock);
- LOG_ALWAYS_FATAL_IF(!display->isPrimary() && overridePolicy,
- "Can only set override policy on the primary display");
- LOG_ALWAYS_FATAL_IF(!policy && !overridePolicy, "Can only clear the override policy");
-
if (mDebugDisplayModeSetByBackdoor) {
// ignore this request as mode is overridden by backdoor
return NO_ERROR;
}
- if (!display->isPrimary()) {
- // TODO(b/144711714): For non-primary displays we should be able to set an active mode
- // as well. For now, just call directly to initiateModeChange but ideally
- // it should go thru setDesiredActiveMode, similar to primary display.
- ALOGV("%s for non-primary display", __func__);
- const auto displayId = display->getPhysicalId();
-
- hal::VsyncPeriodChangeConstraints constraints;
- constraints.desiredTimeNanos = systemTime();
- constraints.seamlessRequired = false;
-
- hal::VsyncPeriodChangeTimeline timeline = {0, 0, 0};
- if (display->initiateModeChange(policy->defaultMode, constraints, &timeline) != NO_ERROR) {
- return BAD_VALUE;
- }
- if (timeline.refreshRequired) {
- repaintEverythingForHWC();
- }
-
- display->setActiveMode(policy->defaultMode);
- const nsecs_t vsyncPeriod = display->getMode(policy->defaultMode)->getVsyncPeriod();
- mScheduler->onNonPrimaryDisplayModeChanged(mAppConnectionHandle, displayId,
- policy->defaultMode, vsyncPeriod);
- return NO_ERROR;
- }
-
status_t setPolicyResult = overridePolicy
- ? mRefreshRateConfigs->setOverridePolicy(policy)
- : mRefreshRateConfigs->setDisplayManagerPolicy(*policy);
+ ? display->refreshRateConfigs().setOverridePolicy(policy)
+ : display->refreshRateConfigs().setDisplayManagerPolicy(*policy);
if (setPolicyResult < 0) {
return BAD_VALUE;
}
if (setPolicyResult == scheduler::RefreshRateConfigs::CURRENT_POLICY_UNCHANGED) {
return NO_ERROR;
}
- scheduler::RefreshRateConfigs::Policy currentPolicy = mRefreshRateConfigs->getCurrentPolicy();
+
+ scheduler::RefreshRateConfigs::Policy currentPolicy =
+ display->refreshRateConfigs().getCurrentPolicy();
ALOGV("Setting desired display mode specs: %s", currentPolicy.toString().c_str());
// TODO(b/140204874): Leave the event in until we do proper testing with all apps that might
// be depending in this callback.
const auto activeMode = display->getActiveMode();
- const nsecs_t vsyncPeriod = activeMode->getVsyncPeriod();
- const auto physicalId = display->getPhysicalId();
- mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, physicalId, activeMode->getId(),
- vsyncPeriod);
- toggleKernelIdleTimer();
+ if (isDisplayActiveLocked(display)) {
+ mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, activeMode);
+ toggleKernelIdleTimer();
+ } else {
+ mScheduler->onNonPrimaryDisplayModeChanged(mAppConnectionHandle, activeMode);
+ }
- auto modeId = mScheduler->getPreferredModeId();
- auto preferredRefreshRate = modeId
- ? mRefreshRateConfigs->getRefreshRateFromModeId(*modeId)
- // NOTE: Choose the default mode ID, if Scheduler doesn't have one in mind.
- : mRefreshRateConfigs->getRefreshRateFromModeId(currentPolicy.defaultMode);
+ const DisplayModePtr preferredDisplayMode = [&] {
+ const auto schedulerMode = mScheduler->getPreferredDisplayMode();
+ if (schedulerMode && schedulerMode->getPhysicalDisplayId() == display->getPhysicalId()) {
+ return schedulerMode;
+ }
+
+ return display->getMode(currentPolicy.defaultMode);
+ }();
+
ALOGV("trying to switch to Scheduler preferred mode %d (%s)",
- preferredRefreshRate.getModeId().value(), preferredRefreshRate.getName().c_str());
+ preferredDisplayMode->getId().value(), to_string(preferredDisplayMode->getFps()).c_str());
- if (isDisplayModeAllowed(preferredRefreshRate.getModeId())) {
+ if (display->refreshRateConfigs().isModeAllowed(preferredDisplayMode->getId())) {
ALOGV("switching to Scheduler preferred display mode %d",
- preferredRefreshRate.getModeId().value());
- setDesiredActiveMode({preferredRefreshRate.getModeId(), Scheduler::ModeEvent::Changed});
+ preferredDisplayMode->getId().value());
+ setDesiredActiveMode({preferredDisplayMode, Scheduler::ModeEvent::Changed});
} else {
LOG_ALWAYS_FATAL("Desired display mode not allowed: %d",
- preferredRefreshRate.getModeId().value());
+ preferredDisplayMode->getId().value());
}
return NO_ERROR;
@@ -6570,29 +6526,19 @@
return NAME_NOT_FOUND;
}
- if (display->isPrimary()) {
- scheduler::RefreshRateConfigs::Policy policy =
- mRefreshRateConfigs->getDisplayManagerPolicy();
- *outDefaultMode = policy.defaultMode.value();
- *outAllowGroupSwitching = policy.allowGroupSwitching;
- *outPrimaryRefreshRateMin = policy.primaryRange.min.getValue();
- *outPrimaryRefreshRateMax = policy.primaryRange.max.getValue();
- *outAppRequestRefreshRateMin = policy.appRequestRange.min.getValue();
- *outAppRequestRefreshRateMax = policy.appRequestRange.max.getValue();
- return NO_ERROR;
- } else if (display->isVirtual()) {
+ if (display->isVirtual()) {
return INVALID_OPERATION;
- } else {
- const auto activeMode = display->getActiveMode();
- *outDefaultMode = activeMode->getId().value();
- *outAllowGroupSwitching = false;
- auto vsyncPeriod = activeMode->getVsyncPeriod();
- *outPrimaryRefreshRateMin = Fps::fromPeriodNsecs(vsyncPeriod).getValue();
- *outPrimaryRefreshRateMax = Fps::fromPeriodNsecs(vsyncPeriod).getValue();
- *outAppRequestRefreshRateMin = Fps::fromPeriodNsecs(vsyncPeriod).getValue();
- *outAppRequestRefreshRateMax = Fps::fromPeriodNsecs(vsyncPeriod).getValue();
- return NO_ERROR;
}
+
+ scheduler::RefreshRateConfigs::Policy policy =
+ display->refreshRateConfigs().getDisplayManagerPolicy();
+ *outDefaultMode = policy.defaultMode.value();
+ *outAllowGroupSwitching = policy.allowGroupSwitching;
+ *outPrimaryRefreshRateMin = policy.primaryRange.min.getValue();
+ *outPrimaryRefreshRateMax = policy.primaryRange.max.getValue();
+ *outAppRequestRefreshRateMin = policy.appRequestRange.min.getValue();
+ *outAppRequestRefreshRateMax = policy.appRequestRange.max.getValue();
+ return NO_ERROR;
}
wp<Layer> SurfaceFlinger::fromHandle(const sp<IBinder>& handle) {
@@ -6624,7 +6570,7 @@
void SurfaceFlinger::onLayerDestroyed(Layer* layer) {
mNumLayers--;
- removeFromOffscreenLayers(layer);
+ removeHierarchyFromOffscreenLayers(layer);
if (!layer->isRemovedFromCurrentState()) {
mScheduler->deregisterLayer(layer);
}
@@ -6637,13 +6583,17 @@
// from dangling children layers such that they are not reachable from the
// Drawing state nor the offscreen layer list
// See b/141111965
-void SurfaceFlinger::removeFromOffscreenLayers(Layer* layer) {
+void SurfaceFlinger::removeHierarchyFromOffscreenLayers(Layer* layer) {
for (auto& child : layer->getCurrentChildren()) {
mOffscreenLayers.emplace(child.get());
}
mOffscreenLayers.erase(layer);
}
+void SurfaceFlinger::removeFromOffscreenLayers(Layer* layer) {
+ mOffscreenLayers.erase(layer);
+}
+
status_t SurfaceFlinger::setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor,
float lightPosY, float lightPosZ,
float lightRadius) {
@@ -6723,7 +6673,8 @@
// matter for the override policy though, since we set allowGroupSwitching to
// true, so it's not a problem.
scheduler::RefreshRateConfigs::Policy overridePolicy;
- overridePolicy.defaultMode = mRefreshRateConfigs->getDisplayManagerPolicy().defaultMode;
+ overridePolicy.defaultMode =
+ display->refreshRateConfigs().getDisplayManagerPolicy().defaultMode;
overridePolicy.allowGroupSwitching = true;
constexpr bool kOverridePolicy = true;
result = setDesiredDisplayModeSpecsInternal(display, overridePolicy, kOverridePolicy);
@@ -6791,25 +6742,11 @@
}
void SurfaceFlinger::enableRefreshRateOverlay(bool enable) {
- static_cast<void>(schedule([=] {
- std::unique_ptr<RefreshRateOverlay> overlay;
- if (enable) {
- overlay = std::make_unique<RefreshRateOverlay>(*this, mRefreshRateOverlaySpinner);
+ for (const auto& [ignored, display] : mDisplays) {
+ if (display->isInternal()) {
+ display->enableRefreshRateOverlay(enable, mRefreshRateOverlaySpinner);
}
-
- {
- Mutex::Autolock lock(mStateLock);
-
- // Destroy the layer of the current overlay, if any, outside the lock.
- mRefreshRateOverlay.swap(overlay);
- if (!mRefreshRateOverlay) return;
-
- if (const auto display = getDefaultDisplayDeviceLocked()) {
- mRefreshRateOverlay->setViewport(display->getSize());
- mRefreshRateOverlay->changeRefreshRate(display->getActiveMode()->getFps());
- }
- }
- }));
+ }
}
status_t SurfaceFlinger::addTransactionTraceListener(
@@ -6837,7 +6774,14 @@
}
status_t SurfaceFlinger::getMaxAcquiredBufferCount(int* buffers) const {
- const auto maxSupportedRefreshRate = mRefreshRateConfigs->getSupportedRefreshRateRange().max;
+ const auto maxSupportedRefreshRate = [&] {
+ const auto display = getDefaultDisplayDevice();
+ if (display) {
+ return display->refreshRateConfigs().getSupportedRefreshRateRange().max;
+ }
+ ALOGW("%s: default display is null", __func__);
+ return Fps(60);
+ }();
*buffers = getMaxAcquiredBufferCountForRefreshRate(maxSupportedRefreshRate);
return NO_ERROR;
}
@@ -6848,7 +6792,14 @@
if (frameRateOverride.has_value()) {
return frameRateOverride.value();
}
- return mRefreshRateConfigs->getCurrentRefreshRate().getFps();
+
+ const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
+ if (display) {
+ return display->refreshRateConfigs().getCurrentRefreshRate().getFps();
+ }
+
+ ALOGW("%s: default display is null", __func__);
+ return Fps(60);
}();
return getMaxAcquiredBufferCountForRefreshRate(refreshRate);
}
@@ -6964,6 +6915,24 @@
mRegionSamplingThread->onCompositionComplete(mEventQueue->nextExpectedInvalidate());
}
+void SurfaceFlinger::onActiveDisplaySizeChanged(const sp<DisplayDevice>& activeDisplay) {
+ mScheduler->onActiveDisplayAreaChanged(activeDisplay->getWidth() * activeDisplay->getHeight());
+ getRenderEngine().onActiveDisplaySizeChanged(activeDisplay->getSize());
+}
+
+void SurfaceFlinger::onActiveDisplayChangedLocked(const sp<DisplayDevice>& activeDisplay) {
+ ATRACE_CALL();
+
+ if (!activeDisplay) {
+ ALOGE("%s: activeDisplay is null", __func__);
+ return;
+ }
+ updateInternalDisplayVsyncLocked(activeDisplay);
+ mScheduler->setModeChangePending(false);
+ mScheduler->setRefreshRateConfigs(activeDisplay->holdRefreshRateConfigs());
+ onActiveDisplaySizeChanged(activeDisplay);
+}
+
} // namespace android
#if defined(__gl_h_)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index b7f3db0..80f3f9c 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -313,8 +313,12 @@
void onLayerFirstRef(Layer*);
void onLayerDestroyed(Layer*);
+ void removeHierarchyFromOffscreenLayers(Layer* layer);
void removeFromOffscreenLayers(Layer* layer);
+ // TODO: Remove atomic if move dtor to main thread CL lands
+ std::atomic<uint32_t> mNumClones;
+
TransactionCallbackInvoker& getTransactionCallbackInvoker() {
return mTransactionCallbackInvoker;
}
@@ -452,14 +456,7 @@
mCounterByLayerHandle GUARDED_BY(mLock);
};
- struct ActiveModeInfo {
- DisplayModeId modeId;
- Scheduler::ModeEvent event = Scheduler::ModeEvent::None;
-
- bool operator!=(const ActiveModeInfo& other) const {
- return modeId != other.modeId || event != other.event;
- }
- };
+ using ActiveModeInfo = DisplayDevice::ActiveModeInfo;
enum class BootStage {
BOOTLOADER,
@@ -590,7 +587,7 @@
typename Handler = VsyncModulator::VsyncConfigOpt (VsyncModulator::*)(Args...)>
void modulateVsync(Handler handler, Args... args) {
if (const auto config = (*mVsyncModulator.*handler)(args...)) {
- const auto vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
+ const auto vsyncPeriod = mScheduler->getVsyncPeriodFromRefreshRateConfigs();
setVsyncConfig(*config, vsyncPeriod);
}
}
@@ -609,7 +606,10 @@
sp<ISurfaceComposerClient> createConnection() override;
sp<IBinder> createDisplay(const String8& displayName, bool secure) override;
void destroyDisplay(const sp<IBinder>& displayToken) override;
- std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override;
+ std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override EXCLUDES(mStateLock) {
+ Mutex::Autolock lock(mStateLock);
+ return getPhysicalDisplayIdsLocked();
+ }
sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const override;
status_t setTransactionState(const FrameTimelineInfo& frameTimelineInfo,
const Vector<ComposerState>& state,
@@ -745,7 +745,7 @@
// Called when the frame rate override list changed to trigger an event.
void triggerOnFrameRateOverridesChanged() override;
// Toggles the kernel idle timer on or off depending the policy decisions around refresh rates.
- void toggleKernelIdleTimer();
+ void toggleKernelIdleTimer() REQUIRES(mStateLock);
// Keeps track of whether the kernel idle timer is currently enabled, so we don't have to
// make calls to sys prop each time.
bool mKernelIdleTimerEnabled = false;
@@ -774,9 +774,9 @@
// Calls to setActiveMode on the main thread if there is a pending mode change
// that needs to be applied.
void performSetActiveMode() REQUIRES(mStateLock);
- void clearDesiredActiveModeState() REQUIRES(mStateLock) EXCLUDES(mActiveModeLock);
+ void clearDesiredActiveModeState(const sp<DisplayDevice>&) REQUIRES(mStateLock);
// Called when active mode is no longer is progress
- void desiredActiveModeChangeDone() REQUIRES(mStateLock);
+ void desiredActiveModeChangeDone(const sp<DisplayDevice>&) REQUIRES(mStateLock);
// Called on the main thread in response to setPowerMode()
void setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode)
REQUIRES(mStateLock);
@@ -809,7 +809,7 @@
void commitInputWindowCommands() REQUIRES(mStateLock);
void updateCursorAsync();
- void initScheduler(const DisplayDeviceState&) REQUIRES(mStateLock);
+ void initScheduler(const sp<DisplayDevice>& display) REQUIRES(mStateLock);
void updatePhaseConfiguration(const Fps&) REQUIRES(mStateLock);
void setVsyncConfig(const VsyncModulator::VsyncConfig&, nsecs_t vsyncPeriod);
@@ -946,18 +946,35 @@
return it == mDisplays.end() ? nullptr : it->second;
}
+ sp<const DisplayDevice> getDisplayDeviceLocked(PhysicalDisplayId id) const
+ REQUIRES(mStateLock) {
+ return const_cast<SurfaceFlinger*>(this)->getDisplayDeviceLocked(id);
+ }
+
+ sp<DisplayDevice> getDisplayDeviceLocked(PhysicalDisplayId id) REQUIRES(mStateLock) {
+ if (const auto token = getPhysicalDisplayTokenLocked(id)) {
+ return getDisplayDeviceLocked(token);
+ }
+ return nullptr;
+ }
+
sp<const DisplayDevice> getDefaultDisplayDeviceLocked() const REQUIRES(mStateLock) {
return const_cast<SurfaceFlinger*>(this)->getDefaultDisplayDeviceLocked();
}
sp<DisplayDevice> getDefaultDisplayDeviceLocked() REQUIRES(mStateLock) {
+ if (const auto display = getDisplayDeviceLocked(mActiveDisplayToken)) {
+ return display;
+ }
+ // The active display is outdated, fall back to the internal display
+ mActiveDisplayToken.clear();
if (const auto token = getInternalDisplayTokenLocked()) {
return getDisplayDeviceLocked(token);
}
return nullptr;
}
- sp<const DisplayDevice> getDefaultDisplayDevice() EXCLUDES(mStateLock) {
+ sp<const DisplayDevice> getDefaultDisplayDevice() const EXCLUDES(mStateLock) {
Mutex::Autolock lock(mStateLock);
return getDefaultDisplayDeviceLocked();
}
@@ -976,12 +993,18 @@
return findDisplay([id](const auto& display) { return display.getId() == id; });
}
+ std::vector<PhysicalDisplayId> getPhysicalDisplayIdsLocked() const REQUIRES(mStateLock);
+
// mark a region of a layer stack dirty. this updates the dirty
// region of all screens presenting this layer stack.
void invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty);
sp<DisplayDevice> getDisplayWithInputByLayer(Layer* layer) const REQUIRES(mStateLock);
+ bool isDisplayActiveLocked(const sp<const DisplayDevice>& display) REQUIRES(mStateLock) {
+ return display->getDisplayToken() == mActiveDisplayToken;
+ }
+
/*
* H/W composer
*/
@@ -1038,8 +1061,6 @@
// the desired refresh rate.
void changeRefreshRateLocked(const RefreshRate&, Scheduler::ModeEvent) REQUIRES(mStateLock);
- bool isDisplayModeAllowed(DisplayModeId) const REQUIRES(mStateLock);
-
struct FenceWithFenceTime {
sp<Fence> fence = Fence::NO_FENCE;
std::shared_ptr<FenceTime> fenceTime = FenceTime::NO_FENCE;
@@ -1104,6 +1125,10 @@
REQUIRES(mStateLock);
void releaseVirtualDisplay(VirtualDisplayId);
+ void onActiveDisplayChangedLocked(const sp<DisplayDevice>& activeDisplay) REQUIRES(mStateLock);
+
+ void onActiveDisplaySizeChanged(const sp<DisplayDevice>& activeDisplay);
+
/*
* Debugging & dumpsys
*/
@@ -1169,13 +1194,6 @@
/*
* Misc
*/
-
- std::optional<ActiveModeInfo> getDesiredActiveMode() EXCLUDES(mActiveModeLock) {
- std::lock_guard<std::mutex> lock(mActiveModeLock);
- if (mDesiredActiveModeChanged) return mDesiredActiveMode;
- return std::nullopt;
- }
-
std::vector<ui::ColorMode> getDisplayColorModes(PhysicalDisplayId displayId)
REQUIRES(mStateLock);
@@ -1183,6 +1201,9 @@
std::chrono::nanoseconds presentLatency);
int getMaxAcquiredBufferCountForRefreshRate(Fps refreshRate) const;
+ void updateInternalDisplayVsyncLocked(const sp<DisplayDevice>& activeDisplay)
+ REQUIRES(mStateLock);
+
sp<StartPropertySetThread> mStartPropertySetThread;
surfaceflinger::Factory& mFactory;
@@ -1379,24 +1400,13 @@
// Optional to defer construction until PhaseConfiguration is created.
std::optional<scheduler::VsyncModulator> mVsyncModulator;
- std::unique_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs;
std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats;
std::atomic<nsecs_t> mExpectedPresentTime = 0;
nsecs_t mScheduledPresentTime = 0;
hal::Vsync mHWCVsyncPendingState = hal::Vsync::DISABLE;
- std::mutex mActiveModeLock;
- // This bit is set once we start setting the mode. We read from this bit during the
- // process. If at the end, this bit is different than mDesiredActiveMode, we restart
- // the process.
- ActiveModeInfo mUpcomingActiveMode; // Always read and written on the main thread.
- // This bit can be set at any point in time when the system wants the new mode.
- ActiveModeInfo mDesiredActiveMode GUARDED_BY(mActiveModeLock);
-
// below flags are set by main thread only
- TracedOrdinal<bool> mDesiredActiveModeChanged
- GUARDED_BY(mActiveModeLock) = {"DesiredActiveModeChanged", false};
bool mSetActiveModePending = false;
bool mLumaSampling = true;
@@ -1419,8 +1429,7 @@
// This should only be accessed on the main thread.
nsecs_t mFrameStartTime = 0;
- void enableRefreshRateOverlay(bool enable);
- std::unique_ptr<RefreshRateOverlay> mRefreshRateOverlay GUARDED_BY(mStateLock);
+ void enableRefreshRateOverlay(bool enable) REQUIRES(mStateLock);
// Flag used to set override desired display mode from backdoor
bool mDebugDisplayModeSetByBackdoor = false;
@@ -1471,6 +1480,15 @@
void scheduleRegionSamplingThread();
void notifyRegionSamplingThread();
+
+ bool isRefreshRateOverlayEnabled() const REQUIRES(mStateLock) {
+ return std::any_of(mDisplays.begin(), mDisplays.end(),
+ [](std::pair<wp<IBinder>, sp<DisplayDevice>> display) {
+ return display.second->isRefreshRateOverlayEnabled();
+ });
+ }
+
+ wp<IBinder> mActiveDisplayToken GUARDED_BY(mStateLock);
};
} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
index 4a75180..89d1c4d 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -65,8 +65,9 @@
}
std::unique_ptr<Scheduler> DefaultFactory::createScheduler(
- const scheduler::RefreshRateConfigs& configs, ISchedulerCallback& callback) {
- return std::make_unique<Scheduler>(configs, callback);
+ const std::shared_ptr<scheduler::RefreshRateConfigs>& refreshRateConfigs,
+ ISchedulerCallback& callback) {
+ return std::make_unique<Scheduler>(std::move(refreshRateConfigs), callback);
}
sp<SurfaceInterceptor> DefaultFactory::createSurfaceInterceptor() {
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
index 24148dd..b8bf2ba 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
@@ -30,8 +30,8 @@
std::unique_ptr<MessageQueue> createMessageQueue() override;
std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration(
Fps currentRefreshRate) override;
- std::unique_ptr<Scheduler> createScheduler(const scheduler::RefreshRateConfigs&,
- ISchedulerCallback&) override;
+ std::unique_ptr<Scheduler> createScheduler(
+ const std::shared_ptr<scheduler::RefreshRateConfigs>&, ISchedulerCallback&) override;
sp<SurfaceInterceptor> createSurfaceInterceptor() override;
sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override;
sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs&) override;
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index 885297f..13c95dd 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -79,8 +79,8 @@
virtual std::unique_ptr<MessageQueue> createMessageQueue() = 0;
virtual std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration(
Fps currentRefreshRate) = 0;
- virtual std::unique_ptr<Scheduler> createScheduler(const scheduler::RefreshRateConfigs&,
- ISchedulerCallback&) = 0;
+ virtual std::unique_ptr<Scheduler> createScheduler(
+ const std::shared_ptr<scheduler::RefreshRateConfigs>&, ISchedulerCallback&) = 0;
virtual sp<SurfaceInterceptor> createSurfaceInterceptor() = 0;
virtual sp<StartPropertySetThread> createStartPropertySetThread(
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index bd6fe1d..8bd6e62 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -54,6 +54,7 @@
"DisplayIdGeneratorTest.cpp",
"DisplayTransactionTest.cpp",
"DisplayDevice_GetBestColorModeTest.cpp",
+ "DisplayDevice_InitiateModeChange.cpp",
"DisplayDevice_SetProjectionTest.cpp",
"EventThreadTest.cpp",
"FpsReporterTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp
new file mode 100644
index 0000000..d4cfbbb
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include "DisplayTransactionTestHelpers.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace {
+
+using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector;
+
+class InitiateModeChangeTest : public DisplayTransactionTest {
+public:
+ using Event = scheduler::RefreshRateConfigEvent;
+
+ void SetUp() override {
+ injectFakeBufferQueueFactory();
+ injectFakeNativeWindowSurfaceFactory();
+
+ PrimaryDisplayVariant::setupHwcHotplugCallExpectations(this);
+ PrimaryDisplayVariant::setupFramebufferConsumerBufferQueueCallExpectations(this);
+ PrimaryDisplayVariant::setupFramebufferProducerBufferQueueCallExpectations(this);
+ PrimaryDisplayVariant::setupNativeWindowSurfaceCreationCallExpectations(this);
+ PrimaryDisplayVariant::setupHwcGetActiveConfigCallExpectations(this);
+
+ mFlinger.onComposerHalHotplug(PrimaryDisplayVariant::HWC_DISPLAY_ID, Connection::CONNECTED);
+
+ mDisplay = PrimaryDisplayVariant::makeFakeExistingDisplayInjector(this)
+ .setSupportedModes({kDisplayMode60, kDisplayMode90, kDisplayMode120})
+ .setActiveMode(kDisplayModeId60)
+ .inject();
+ }
+
+protected:
+ sp<DisplayDevice> mDisplay;
+
+ const DisplayModeId kDisplayModeId60 = DisplayModeId(0);
+ const DisplayModePtr kDisplayMode60 =
+ DisplayMode::Builder(hal::HWConfigId(kDisplayModeId60.value()))
+ .setId(kDisplayModeId60)
+ .setPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get())
+ .setVsyncPeriod(int32_t(16'666'667))
+ .setGroup(0)
+ .setHeight(1000)
+ .setWidth(1000)
+ .build();
+
+ const DisplayModeId kDisplayModeId90 = DisplayModeId(1);
+ const DisplayModePtr kDisplayMode90 =
+ DisplayMode::Builder(hal::HWConfigId(kDisplayModeId90.value()))
+ .setId(kDisplayModeId90)
+ .setPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get())
+ .setVsyncPeriod(int32_t(11'111'111))
+ .setGroup(0)
+ .setHeight(1000)
+ .setWidth(1000)
+ .build();
+
+ const DisplayModeId kDisplayModeId120 = DisplayModeId(2);
+ const DisplayModePtr kDisplayMode120 =
+ DisplayMode::Builder(hal::HWConfigId(kDisplayModeId120.value()))
+ .setId(kDisplayModeId120)
+ .setPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get())
+ .setVsyncPeriod(int32_t(8'333'333))
+ .setGroup(0)
+ .setHeight(1000)
+ .setWidth(1000)
+ .build();
+};
+
+TEST_F(InitiateModeChangeTest, setDesiredActiveMode_setCurrentMode) {
+ EXPECT_FALSE(mDisplay->setDesiredActiveMode({kDisplayMode60, Event::None}));
+ EXPECT_EQ(std::nullopt, mDisplay->getDesiredActiveMode());
+}
+
+TEST_F(InitiateModeChangeTest, setDesiredActiveMode_setNewMode) {
+ EXPECT_TRUE(mDisplay->setDesiredActiveMode({kDisplayMode90, Event::None}));
+ ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode());
+ EXPECT_EQ(kDisplayMode90, mDisplay->getDesiredActiveMode()->mode);
+ EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event);
+
+ // Setting another mode should be cached but return false
+ EXPECT_FALSE(mDisplay->setDesiredActiveMode({kDisplayMode120, Event::None}));
+ ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode());
+ EXPECT_EQ(kDisplayMode120, mDisplay->getDesiredActiveMode()->mode);
+ EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event);
+}
+
+TEST_F(InitiateModeChangeTest, clearDesiredActiveModeState) {
+ EXPECT_TRUE(mDisplay->setDesiredActiveMode({kDisplayMode90, Event::None}));
+ ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode());
+
+ mDisplay->clearDesiredActiveModeState();
+ ASSERT_EQ(std::nullopt, mDisplay->getDesiredActiveMode());
+}
+
+TEST_F(InitiateModeChangeTest, initiateModeChange) NO_THREAD_SAFETY_ANALYSIS {
+ EXPECT_TRUE(mDisplay->setDesiredActiveMode({kDisplayMode90, Event::None}));
+ ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode());
+ EXPECT_EQ(kDisplayMode90, mDisplay->getDesiredActiveMode()->mode);
+ EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event);
+
+ hal::VsyncPeriodChangeConstraints constraints{
+ .desiredTimeNanos = systemTime(),
+ .seamlessRequired = false,
+ };
+ hal::VsyncPeriodChangeTimeline timeline;
+ EXPECT_EQ(OK,
+ mDisplay->initiateModeChange(*mDisplay->getDesiredActiveMode(), constraints,
+ &timeline));
+ EXPECT_EQ(kDisplayMode90, mDisplay->getUpcomingActiveMode().mode);
+ EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event);
+
+ mDisplay->clearDesiredActiveModeState();
+ ASSERT_EQ(std::nullopt, mDisplay->getDesiredActiveMode());
+}
+
+TEST_F(InitiateModeChangeTest, getUpcomingActiveMode_desiredActiveModeChanged)
+NO_THREAD_SAFETY_ANALYSIS {
+ EXPECT_TRUE(mDisplay->setDesiredActiveMode({kDisplayMode90, Event::None}));
+ ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode());
+ EXPECT_EQ(kDisplayMode90, mDisplay->getDesiredActiveMode()->mode);
+ EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event);
+
+ hal::VsyncPeriodChangeConstraints constraints{
+ .desiredTimeNanos = systemTime(),
+ .seamlessRequired = false,
+ };
+ hal::VsyncPeriodChangeTimeline timeline;
+ EXPECT_EQ(OK,
+ mDisplay->initiateModeChange(*mDisplay->getDesiredActiveMode(), constraints,
+ &timeline));
+ EXPECT_EQ(kDisplayMode90, mDisplay->getUpcomingActiveMode().mode);
+ EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event);
+
+ EXPECT_FALSE(mDisplay->setDesiredActiveMode({kDisplayMode120, Event::None}));
+ ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode());
+ EXPECT_EQ(kDisplayMode120, mDisplay->getDesiredActiveMode()->mode);
+ EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event);
+
+ EXPECT_EQ(kDisplayMode90, mDisplay->getUpcomingActiveMode().mode);
+ EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event);
+
+ EXPECT_EQ(OK,
+ mDisplay->initiateModeChange(*mDisplay->getDesiredActiveMode(), constraints,
+ &timeline));
+ EXPECT_EQ(kDisplayMode120, mDisplay->getUpcomingActiveMode().mode);
+ EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event);
+
+ mDisplay->clearDesiredActiveModeState();
+ ASSERT_EQ(std::nullopt, mDisplay->getDesiredActiveMode());
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 62acc6b..28d0222 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -546,17 +546,34 @@
}
TEST_F(EventThreadTest, postConfigChangedPrimary) {
- mThread->onModeChanged(INTERNAL_DISPLAY_ID, DisplayModeId(7), 16666666);
+ const auto mode = DisplayMode::Builder(hal::HWConfigId(0))
+ .setPhysicalDisplayId(INTERNAL_DISPLAY_ID)
+ .setId(DisplayModeId(7))
+ .setVsyncPeriod(16666666)
+ .build();
+
+ mThread->onModeChanged(mode);
expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 7, 16666666);
}
TEST_F(EventThreadTest, postConfigChangedExternal) {
- mThread->onModeChanged(EXTERNAL_DISPLAY_ID, DisplayModeId(5), 16666666);
+ const auto mode = DisplayMode::Builder(hal::HWConfigId(0))
+ .setPhysicalDisplayId(EXTERNAL_DISPLAY_ID)
+ .setId(DisplayModeId(5))
+ .setVsyncPeriod(16666666)
+ .build();
+
+ mThread->onModeChanged(mode);
expectConfigChangedEventReceivedByConnection(EXTERNAL_DISPLAY_ID, 5, 16666666);
}
TEST_F(EventThreadTest, postConfigChangedPrimary64bit) {
- mThread->onModeChanged(DISPLAY_ID_64BIT, DisplayModeId(7), 16666666);
+ const auto mode = DisplayMode::Builder(hal::HWConfigId(0))
+ .setPhysicalDisplayId(DISPLAY_ID_64BIT)
+ .setId(DisplayModeId(7))
+ .setVsyncPeriod(16666666)
+ .build();
+ mThread->onModeChanged(mode);
expectConfigChangedEventReceivedByConnection(DISPLAY_ID_64BIT, 7, 16666666);
}
@@ -565,7 +582,13 @@
sp<MockEventThreadConnection> suppressConnection =
createConnection(suppressConnectionEventRecorder);
- mThread->onModeChanged(INTERNAL_DISPLAY_ID, DisplayModeId(9), 16666666);
+ const auto mode = DisplayMode::Builder(hal::HWConfigId(0))
+ .setPhysicalDisplayId(INTERNAL_DISPLAY_ID)
+ .setId(DisplayModeId(9))
+ .setVsyncPeriod(16666666)
+ .build();
+
+ mThread->onModeChanged(mode);
expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 9, 16666666);
auto args = suppressConnectionEventRecorder.waitForCall();
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index b67ebca..bb21ad6 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -35,6 +35,7 @@
using testing::_;
using testing::Return;
+using testing::ReturnRef;
namespace android {
@@ -62,6 +63,10 @@
LayerHistory& history() { return *mScheduler->mutableLayerHistory(); }
const LayerHistory& history() const { return *mScheduler->mutableLayerHistory(); }
+ LayerHistory::Summary summarizeLayerHistory(nsecs_t now) {
+ return history().summarize(*mScheduler->refreshRateConfigs(), now);
+ }
+
size_t layerCount() const { return mScheduler->layerHistorySize(); }
size_t activeLayerCount() const NO_THREAD_SAFETY_ANALYSIS { return history().mActiveLayersEnd; }
@@ -101,7 +106,7 @@
history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += frameRate.getPeriodNsecs();
- summary = history().summarize(time);
+ summary = summarizeLayerHistory(time);
}
ASSERT_EQ(1, summary.size());
@@ -110,21 +115,26 @@
<< "Frame rate is " << frameRate;
}
- RefreshRateConfigs mConfigs{{DisplayMode::Builder(0)
- .setId(DisplayModeId(0))
- .setVsyncPeriod(int32_t(LO_FPS_PERIOD))
- .setGroup(0)
- .build(),
- DisplayMode::Builder(1)
- .setId(DisplayModeId(1))
- .setVsyncPeriod(int32_t(HI_FPS_PERIOD))
- .setGroup(0)
- .build()},
- DisplayModeId(0)};
+ std::shared_ptr<RefreshRateConfigs> mConfigs = std::make_shared<
+ RefreshRateConfigs>(DisplayModes{DisplayMode::Builder(0)
+ .setId(DisplayModeId(0))
+ .setPhysicalDisplayId(
+ PhysicalDisplayId::fromPort(0))
+ .setVsyncPeriod(int32_t(LO_FPS_PERIOD))
+ .setGroup(0)
+ .build(),
+ DisplayMode::Builder(1)
+ .setId(DisplayModeId(1))
+ .setPhysicalDisplayId(
+ PhysicalDisplayId::fromPort(0))
+ .setVsyncPeriod(int32_t(HI_FPS_PERIOD))
+ .setGroup(0)
+ .build()},
+ DisplayModeId(0));
- mock::NoOpSchedulerCallback mSchedulerCallback;
+ mock::SchedulerCallback mSchedulerCallback;
- TestableScheduler* const mScheduler = new TestableScheduler(mConfigs, mSchedulerCallback);
+ TestableScheduler* mScheduler = new TestableScheduler(mConfigs, mSchedulerCallback);
TestableSurfaceFlinger mFlinger;
};
@@ -142,22 +152,22 @@
const nsecs_t time = systemTime();
// No layers returned if no layers are active.
- EXPECT_TRUE(history().summarize(time).empty());
+ EXPECT_TRUE(summarizeLayerHistory(time).empty());
EXPECT_EQ(0, activeLayerCount());
// Max returned if active layers have insufficient history.
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) {
history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer);
- ASSERT_EQ(1, history().summarize(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
}
// Max is returned since we have enough history but there is no timestamp votes.
for (int i = 0; i < 10; i++) {
history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer);
- ASSERT_EQ(1, history().summarize(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
}
}
@@ -173,17 +183,17 @@
nsecs_t time = systemTime();
history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer);
- auto summary = history().summarize(time);
- ASSERT_EQ(1, history().summarize(time).size());
+ auto summary = summarizeLayerHistory(time);
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
// Layer is still considered inactive so we expect to get Min
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(false));
history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer);
- summary = history().summarize(time);
- EXPECT_TRUE(history().summarize(time).empty());
+ summary = summarizeLayerHistory(time);
+ EXPECT_TRUE(summarizeLayerHistory(time).empty());
EXPECT_EQ(0, activeLayerCount());
}
@@ -201,9 +211,9 @@
time += LO_FPS_PERIOD;
}
- ASSERT_EQ(1, history().summarize(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, history().summarize(time)[0].vote);
- EXPECT_TRUE(LO_FPS.equalsWithMargin(history().summarize(time)[0].desiredRefreshRate));
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summarizeLayerHistory(time)[0].vote);
+ EXPECT_TRUE(LO_FPS.equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate));
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
}
@@ -224,13 +234,13 @@
time += HI_FPS_PERIOD;
}
- ASSERT_TRUE(history().summarize(time).empty());
+ ASSERT_TRUE(summarizeLayerHistory(time).empty());
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
// layer became inactive
time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
- ASSERT_TRUE(history().summarize(time).empty());
+ ASSERT_TRUE(summarizeLayerHistory(time).empty());
EXPECT_EQ(0, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
}
@@ -251,14 +261,14 @@
time += HI_FPS_PERIOD;
}
- ASSERT_EQ(1, history().summarize(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
// layer became inactive
time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
- ASSERT_TRUE(history().summarize(time).empty());
+ ASSERT_TRUE(summarizeLayerHistory(time).empty());
EXPECT_EQ(0, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
}
@@ -279,14 +289,14 @@
time += LO_FPS_PERIOD;
}
- ASSERT_EQ(1, history().summarize(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
// layer became inactive
time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
- ASSERT_TRUE(history().summarize(time).empty());
+ ASSERT_TRUE(summarizeLayerHistory(time).empty());
EXPECT_EQ(0, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
}
@@ -307,18 +317,18 @@
time += HI_FPS_PERIOD;
}
- ASSERT_EQ(1, history().summarize(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, history().summarize(time)[0].vote);
- EXPECT_TRUE(Fps(73.4f).equalsWithMargin(history().summarize(time)[0].desiredRefreshRate));
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summarizeLayerHistory(time)[0].vote);
+ EXPECT_TRUE(Fps(73.4f).equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate));
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
// layer became inactive, but the vote stays
setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic);
time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
- ASSERT_EQ(1, history().summarize(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, history().summarize(time)[0].vote);
- EXPECT_TRUE(Fps(73.4f).equalsWithMargin(history().summarize(time)[0].desiredRefreshRate));
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summarizeLayerHistory(time)[0].vote);
+ EXPECT_TRUE(Fps(73.4f).equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate));
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
}
@@ -339,20 +349,20 @@
time += HI_FPS_PERIOD;
}
- ASSERT_EQ(1, history().summarize(time).size());
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple,
- history().summarize(time)[0].vote);
- EXPECT_TRUE(Fps(73.4f).equalsWithMargin(history().summarize(time)[0].desiredRefreshRate));
+ summarizeLayerHistory(time)[0].vote);
+ EXPECT_TRUE(Fps(73.4f).equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate));
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
// layer became inactive, but the vote stays
setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic);
time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
- ASSERT_EQ(1, history().summarize(time).size());
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple,
- history().summarize(time)[0].vote);
- EXPECT_TRUE(Fps(73.4f).equalsWithMargin(history().summarize(time)[0].desiredRefreshRate));
+ summarizeLayerHistory(time)[0].vote);
+ EXPECT_TRUE(Fps(73.4f).equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate));
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
}
@@ -383,7 +393,7 @@
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer1.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
- summary = history().summarize(time);
+ summary = summarizeLayerHistory(time);
}
ASSERT_EQ(1, summary.size());
@@ -395,7 +405,7 @@
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += HI_FPS_PERIOD;
- summary = history().summarize(time);
+ summary = summarizeLayerHistory(time);
}
// layer1 is still active but infrequent.
@@ -404,7 +414,7 @@
ASSERT_EQ(2, summary.size());
EXPECT_EQ(LayerHistory::LayerVoteType::Min, summary[0].vote);
ASSERT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[1].vote);
- EXPECT_TRUE(HI_FPS.equalsWithMargin(history().summarize(time)[1].desiredRefreshRate));
+ EXPECT_TRUE(HI_FPS.equalsWithMargin(summarizeLayerHistory(time)[1].desiredRefreshRate));
EXPECT_EQ(2, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
@@ -414,7 +424,7 @@
for (int i = 0; i < 2 * PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += LO_FPS_PERIOD;
- summary = history().summarize(time);
+ summary = summarizeLayerHistory(time);
}
ASSERT_EQ(1, summary.size());
@@ -433,7 +443,7 @@
history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += HI_FPS_PERIOD;
- summary = history().summarize(time);
+ summary = summarizeLayerHistory(time);
}
ASSERT_EQ(2, summary.size());
@@ -445,7 +455,7 @@
// layer3 becomes recently active.
history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
- summary = history().summarize(time);
+ summary = summarizeLayerHistory(time);
ASSERT_EQ(2, summary.size());
EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
EXPECT_TRUE(LO_FPS.equalsWithMargin(summary[0].desiredRefreshRate));
@@ -456,7 +466,7 @@
// layer1 expires.
layer1.clear();
- summary = history().summarize(time);
+ summary = summarizeLayerHistory(time);
ASSERT_EQ(2, summary.size());
EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
@@ -472,7 +482,7 @@
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += LO_FPS_PERIOD;
- summary = history().summarize(time);
+ summary = summarizeLayerHistory(time);
}
ASSERT_EQ(1, summary.size());
@@ -483,7 +493,7 @@
// layer2 expires.
layer2.clear();
- summary = history().summarize(time);
+ summary = summarizeLayerHistory(time);
EXPECT_TRUE(summary.empty());
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
@@ -493,7 +503,7 @@
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE + FREQUENT_LAYER_WINDOW_SIZE + 1; i++) {
history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += HI_FPS_PERIOD;
- summary = history().summarize(time);
+ summary = summarizeLayerHistory(time);
}
ASSERT_EQ(1, summary.size());
@@ -505,7 +515,7 @@
// layer3 expires.
layer3.clear();
- summary = history().summarize(time);
+ summary = summarizeLayerHistory(time);
EXPECT_TRUE(summary.empty());
EXPECT_EQ(0, layerCount());
EXPECT_EQ(0, activeLayerCount());
@@ -526,8 +536,8 @@
time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
EXPECT_EQ(1, layerCount());
- ASSERT_EQ(1, history().summarize(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
}
@@ -537,8 +547,8 @@
time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
EXPECT_EQ(1, layerCount());
- ASSERT_EQ(1, history().summarize(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
@@ -551,8 +561,8 @@
time += HI_FPS_PERIOD;
EXPECT_EQ(1, layerCount());
- ASSERT_EQ(1, history().summarize(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
}
@@ -562,8 +572,8 @@
time += HI_FPS_PERIOD;
EXPECT_EQ(1, layerCount());
- ASSERT_EQ(1, history().summarize(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
}
@@ -590,10 +600,10 @@
LayerHistory::LayerUpdateType::Buffer);
EXPECT_EQ(2, layerCount());
- ASSERT_EQ(1, history().summarize(time).size());
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple,
- history().summarize(time)[0].vote);
- EXPECT_TRUE(Fps(60.0f).equalsWithMargin(history().summarize(time)[0].desiredRefreshRate));
+ summarizeLayerHistory(time)[0].vote);
+ EXPECT_TRUE(Fps(60.0f).equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate));
EXPECT_EQ(2, activeLayerCount());
EXPECT_EQ(2, frequentLayerCount(time));
}
@@ -617,8 +627,8 @@
time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
}
- ASSERT_EQ(1, history().summarize(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
EXPECT_EQ(0, animatingLayerCount(time));
@@ -627,8 +637,8 @@
history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
- ASSERT_EQ(1, history().summarize(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
EXPECT_EQ(0, animatingLayerCount(time));
@@ -637,8 +647,8 @@
history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::AnimationTX);
time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
- ASSERT_EQ(1, history().summarize(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+ ASSERT_EQ(1, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
EXPECT_EQ(1, animatingLayerCount(time));
@@ -727,13 +737,13 @@
}
if (time - startTime > PRESENT_TIME_HISTORY_DURATION.count()) {
- ASSERT_NE(0, history().summarize(time).size());
- ASSERT_GE(2, history().summarize(time).size());
+ ASSERT_NE(0, summarizeLayerHistory(time).size());
+ ASSERT_GE(2, summarizeLayerHistory(time).size());
bool max = false;
bool min = false;
Fps heuristic{0.0};
- for (const auto& layer : history().summarize(time)) {
+ for (const auto& layer : summarizeLayerHistory(time)) {
if (layer.vote == LayerHistory::LayerVoteType::Heuristic) {
heuristic = layer.desiredRefreshRate;
} else if (layer.vote == LayerHistory::LayerVoteType::Max) {
@@ -746,7 +756,7 @@
if (infrequentLayerUpdates > FREQUENT_LAYER_WINDOW_SIZE) {
EXPECT_TRUE(Fps(24.0f).equalsWithMargin(heuristic));
EXPECT_FALSE(max);
- if (history().summarize(time).size() == 2) {
+ if (summarizeLayerHistory(time).size() == 2) {
EXPECT_TRUE(min);
}
}
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 3423bd5..c04919f 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -51,8 +51,7 @@
~RefreshRateConfigsTest();
RefreshRate createRefreshRate(DisplayModePtr displayMode) {
- return {displayMode->getId(), displayMode, displayMode->getFps(),
- RefreshRate::ConstructorTag(0)};
+ return {displayMode, RefreshRate::ConstructorTag(0)};
}
Fps findClosestKnownFrameRate(const RefreshRateConfigs& refreshRateConfigs, Fps frameRate) {
@@ -147,24 +146,17 @@
DisplayModes m60_120Device = {mConfig60, mConfig120};
// Expected RefreshRate objects
- RefreshRate mExpected60Config = {HWC_CONFIG_ID_60, mConfig60, Fps(60),
- RefreshRate::ConstructorTag(0)};
- RefreshRate mExpectedAlmost60Config = {HWC_CONFIG_ID_60,
- createDisplayMode(HWC_CONFIG_ID_60, 0, 16666665),
- Fps(60), RefreshRate::ConstructorTag(0)};
- RefreshRate mExpected90Config = {HWC_CONFIG_ID_90, mConfig90, Fps(90),
- RefreshRate::ConstructorTag(0)};
- RefreshRate mExpected90DifferentGroupConfig = {HWC_CONFIG_ID_90, mConfig90DifferentGroup,
- Fps(90), RefreshRate::ConstructorTag(0)};
- RefreshRate mExpected90DifferentResolutionConfig = {HWC_CONFIG_ID_90,
- mConfig90DifferentResolution, Fps(90),
+ RefreshRate mExpected60Config = {mConfig60, RefreshRate::ConstructorTag(0)};
+ RefreshRate mExpectedAlmost60Config = {createDisplayMode(HWC_CONFIG_ID_60, 0, 16666665),
+ RefreshRate::ConstructorTag(0)};
+ RefreshRate mExpected90Config = {mConfig90, RefreshRate::ConstructorTag(0)};
+ RefreshRate mExpected90DifferentGroupConfig = {mConfig90DifferentGroup,
+ RefreshRate::ConstructorTag(0)};
+ RefreshRate mExpected90DifferentResolutionConfig = {mConfig90DifferentResolution,
RefreshRate::ConstructorTag(0)};
- RefreshRate mExpected72Config = {HWC_CONFIG_ID_72, mConfig72, Fps(72.0f),
- RefreshRate::ConstructorTag(0)};
- RefreshRate mExpected30Config = {HWC_CONFIG_ID_30, mConfig30, Fps(30),
- RefreshRate::ConstructorTag(0)};
- RefreshRate mExpected120Config = {HWC_CONFIG_ID_120, mConfig120, Fps(120),
- RefreshRate::ConstructorTag(0)};
+ RefreshRate mExpected72Config = {mConfig72, RefreshRate::ConstructorTag(0)};
+ RefreshRate mExpected30Config = {mConfig30, RefreshRate::ConstructorTag(0)};
+ RefreshRate mExpected120Config = {mConfig120, RefreshRate::ConstructorTag(0)};
private:
DisplayModePtr createDisplayMode(DisplayModeId modeId, int32_t group, int64_t vsyncPeriod,
@@ -189,6 +181,7 @@
int64_t vsyncPeriod, ui::Size resolution) {
return DisplayMode::Builder(hal::HWConfigId(modeId.value()))
.setId(modeId)
+ .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
.setVsyncPeriod(int32_t(vsyncPeriod))
.setGroup(group)
.setHeight(resolution.height)
@@ -2272,26 +2265,6 @@
ASSERT_TRUE(frameRateOverrides.empty());
}
-TEST_F(RefreshRateConfigsTest, updateDisplayModes) {
- auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device,
- /*currentConfigId=*/HWC_CONFIG_ID_30);
- refreshRateConfigs->setDisplayManagerPolicy({DisplayModeId(HWC_CONFIG_ID_30),
- /* allowGroupSwitching */ false,
- /* range */ {Fps(30.0f), Fps(30.0f)}});
-
- refreshRateConfigs->updateDisplayModes(m60_90Device, HWC_CONFIG_ID_60);
-
- const auto currentRefreshRate = refreshRateConfigs->getCurrentRefreshRate();
- EXPECT_TRUE(currentRefreshRate.getFps().equalsWithMargin(Fps(60.0)));
- EXPECT_EQ(currentRefreshRate.getModeId(), HWC_CONFIG_ID_60);
-
- EXPECT_TRUE(
- getMaxSupportedRefreshRate(*refreshRateConfigs).getFps().equalsWithMargin(Fps(90.0)));
- EXPECT_TRUE(
- getMinSupportedRefreshRate(*refreshRateConfigs).getFps().equalsWithMargin(Fps(60.0)));
-}
-
} // namespace
} // namespace scheduler
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
index bf07106..0a8759d 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -81,6 +81,7 @@
int64_t vsyncPeriod) {
return DisplayMode::Builder(static_cast<hal::HWConfigId>(modeId.value()))
.setId(modeId)
+ .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
.setVsyncPeriod(static_cast<int32_t>(vsyncPeriod))
.setGroup(group)
.build();
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 0023aa0..e2b3993 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -53,16 +53,19 @@
const DisplayModePtr mode60 = DisplayMode::Builder(0)
.setId(DisplayModeId(0))
+ .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
.setVsyncPeriod(Fps(60.f).getPeriodNsecs())
.setGroup(0)
.build();
const DisplayModePtr mode120 = DisplayMode::Builder(1)
.setId(DisplayModeId(1))
+ .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
.setVsyncPeriod(Fps(120.f).getPeriodNsecs())
.setGroup(0)
.build();
- scheduler::RefreshRateConfigs mConfigs{{mode60}, mode60->getId()};
+ std::shared_ptr<scheduler::RefreshRateConfigs> mConfigs =
+ std::make_shared<scheduler::RefreshRateConfigs>(DisplayModes{mode60}, mode60->getId());
mock::SchedulerCallback mSchedulerCallback;
@@ -171,7 +174,7 @@
mScheduler->setDisplayPowerState(kPowerStateNormal);
constexpr uint32_t kDisplayArea = 999'999;
- mScheduler->onPrimaryDisplayAreaChanged(kDisplayArea);
+ mScheduler->onActiveDisplayAreaChanged(kDisplayArea);
EXPECT_CALL(mSchedulerCallback, changeRefreshRate(_, _)).Times(0);
mScheduler->chooseRefreshRateForContent();
@@ -182,7 +185,9 @@
sp<mock::MockLayer> layer = sp<mock::MockLayer>::make(mFlinger.flinger());
ASSERT_EQ(static_cast<size_t>(1), mScheduler->layerHistorySize());
- mConfigs.updateDisplayModes({mode60, mode120}, /* activeMode */ mode60->getId());
+ mScheduler->setRefreshRateConfigs(
+ std::make_shared<scheduler::RefreshRateConfigs>(DisplayModes{mode60, mode120},
+ mode60->getId()));
ASSERT_EQ(static_cast<size_t>(0), mScheduler->getNumActiveLayers());
mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer);
@@ -194,20 +199,21 @@
// onModeChange is called.
mScheduler->clearOptionalFieldsInFeatures();
EXPECT_NO_FATAL_FAILURE(mScheduler->dispatchCachedReportedMode());
- EXPECT_CALL(*mEventThread, onModeChanged(_, _, _)).Times(0);
+ EXPECT_CALL(*mEventThread, onModeChanged(_)).Times(0);
}
TEST_F(SchedulerTest, onNonPrimaryDisplayModeChanged_invalidParameters) {
- DisplayModeId modeId = DisplayModeId(111);
- nsecs_t vsyncPeriod = 111111;
+ const auto mode = DisplayMode::Builder(hal::HWConfigId(0))
+ .setId(DisplayModeId(111))
+ .setPhysicalDisplayId(PHYSICAL_DISPLAY_ID)
+ .setVsyncPeriod(111111)
+ .build();
// If the handle is incorrect, the function should return before
// onModeChange is called.
Scheduler::ConnectionHandle invalidHandle = {.id = 123};
- EXPECT_NO_FATAL_FAILURE(mScheduler->onNonPrimaryDisplayModeChanged(invalidHandle,
- PHYSICAL_DISPLAY_ID, modeId,
- vsyncPeriod));
- EXPECT_CALL(*mEventThread, onModeChanged(_, _, _)).Times(0);
+ EXPECT_NO_FATAL_FAILURE(mScheduler->onNonPrimaryDisplayModeChanged(invalidHandle, mode));
+ EXPECT_CALL(*mEventThread, onModeChanged(_)).Times(0);
}
TEST_F(SchedulerTest, calculateMaxAcquiredBufferCount) {
@@ -225,7 +231,9 @@
}
TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) {
- mConfigs.updateDisplayModes({mode60, mode120}, /* activeMode */ mode60->getId());
+ mScheduler->setRefreshRateConfigs(
+ std::make_shared<scheduler::RefreshRateConfigs>(DisplayModes{mode60, mode120},
+ mode60->getId()));
sp<mock::MockLayer> layer = sp<mock::MockLayer>::make(mFlinger.flinger());
@@ -235,7 +243,7 @@
mScheduler->setDisplayPowerState(kPowerStateNormal);
constexpr uint32_t kDisplayArea = 999'999;
- mScheduler->onPrimaryDisplayAreaChanged(kDisplayArea);
+ mScheduler->onActiveDisplayAreaChanged(kDisplayArea);
EXPECT_CALL(mSchedulerCallback, changeRefreshRate(Is120Hz(), _)).Times(1);
mScheduler->chooseRefreshRateForContent();
diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
index 1ed52ea..8e7554b 100644
--- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
@@ -479,7 +479,9 @@
->record(child.get(), 0, 0, LayerHistory::LayerUpdateType::Buffer);
const auto layerHistorySummary =
- mFlinger.mutableScheduler().mutableLayerHistory()->summarize(0);
+ mFlinger.mutableScheduler()
+ .mutableLayerHistory()
+ ->summarize(*mFlinger.mutableScheduler().refreshRateConfigs(), 0);
ASSERT_EQ(2u, layerHistorySummary.size());
EXPECT_TRUE(FRAME_RATE_VOTE1.rate.equalsWithMargin(layerHistorySummary[0].desiredRefreshRate));
EXPECT_TRUE(FRAME_RATE_VOTE1.rate.equalsWithMargin(layerHistorySummary[1].desiredRefreshRate));
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index 41fd6e3..a99dabe 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -32,15 +32,18 @@
class TestableScheduler : public Scheduler {
public:
- TestableScheduler(const scheduler::RefreshRateConfigs& configs, ISchedulerCallback& callback)
+ TestableScheduler(const std::shared_ptr<scheduler::RefreshRateConfigs>& refreshRateConfigs,
+ ISchedulerCallback& callback)
: TestableScheduler(std::make_unique<mock::VsyncController>(),
- std::make_unique<mock::VSyncTracker>(), configs, callback) {}
+ std::make_unique<mock::VSyncTracker>(), refreshRateConfigs,
+ callback) {}
TestableScheduler(std::unique_ptr<scheduler::VsyncController> vsyncController,
std::unique_ptr<scheduler::VSyncTracker> vsyncTracker,
- const scheduler::RefreshRateConfigs& configs, ISchedulerCallback& callback)
- : Scheduler({std::move(vsyncController), std::move(vsyncTracker), nullptr}, configs,
- callback, createLayerHistory(configs),
+ const std::shared_ptr<scheduler::RefreshRateConfigs>& refreshRateConfigs,
+ ISchedulerCallback& callback)
+ : Scheduler({std::move(vsyncController), std::move(vsyncTracker), nullptr},
+ refreshRateConfigs, callback, createLayerHistory(),
{.supportKernelTimer = false, .useContentDetection = true}) {}
// Used to inject mock event thread.
@@ -64,6 +67,8 @@
return mutableLayerHistory()->mLayerInfos.size();
}
+ auto refreshRateConfigs() { return holdRefreshRateConfigs(); }
+
size_t getNumActiveLayers() NO_THREAD_SAFETY_ANALYSIS {
if (!mLayerHistory) return 0;
return mutableLayerHistory()->mActiveLayersEnd;
@@ -95,9 +100,8 @@
mFeatures.cachedModeChangedParams.reset();
}
- void onNonPrimaryDisplayModeChanged(ConnectionHandle handle, PhysicalDisplayId displayId,
- DisplayModeId modeId, nsecs_t vsyncPeriod) {
- return Scheduler::onNonPrimaryDisplayModeChanged(handle, displayId, modeId, vsyncPeriod);
+ void onNonPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) {
+ return Scheduler::onNonPrimaryDisplayModeChanged(handle, mode);
}
~TestableScheduler() {
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 7f6e05e..ad284e3 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -82,8 +82,8 @@
return std::make_unique<scheduler::FakePhaseOffsets>();
}
- std::unique_ptr<Scheduler> createScheduler(const scheduler::RefreshRateConfigs&,
- ISchedulerCallback&) override {
+ std::unique_ptr<Scheduler> createScheduler(
+ const std::shared_ptr<scheduler::RefreshRateConfigs>&, ISchedulerCallback&) override {
return nullptr;
}
@@ -209,6 +209,7 @@
ISchedulerCallback* callback = nullptr, bool hasMultipleModes = false) {
DisplayModes modes{DisplayMode::Builder(0)
.setId(DisplayModeId(0))
+ .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
.setVsyncPeriod(16'666'667)
.setGroup(0)
.build()};
@@ -216,24 +217,23 @@
if (hasMultipleModes) {
modes.emplace_back(DisplayMode::Builder(1)
.setId(DisplayModeId(1))
+ .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
.setVsyncPeriod(11'111'111)
.setGroup(0)
.build());
}
const auto currMode = DisplayModeId(0);
- mFlinger->mRefreshRateConfigs =
- std::make_unique<scheduler::RefreshRateConfigs>(modes, currMode);
- const auto currFps =
- mFlinger->mRefreshRateConfigs->getRefreshRateFromModeId(currMode).getFps();
+ mRefreshRateConfigs = std::make_shared<scheduler::RefreshRateConfigs>(modes, currMode);
+ const auto currFps = mRefreshRateConfigs->getCurrentRefreshRate().getFps();
+ mFlinger->mVsyncConfiguration = mFactory.createVsyncConfiguration(currFps);
+ mFlinger->mVsyncModulator.emplace(mFlinger->mVsyncConfiguration->getCurrentConfigs());
mFlinger->mRefreshRateStats =
std::make_unique<scheduler::RefreshRateStats>(*mFlinger->mTimeStats, currFps,
/*powerMode=*/hal::PowerMode::OFF);
- mFlinger->mVsyncConfiguration = mFactory.createVsyncConfiguration(currFps);
- mFlinger->mVsyncModulator.emplace(mFlinger->mVsyncConfiguration->getCurrentConfigs());
mScheduler = new TestableScheduler(std::move(vsyncController), std::move(vsyncTracker),
- *mFlinger->mRefreshRateConfigs, *(callback ?: this));
+ mRefreshRateConfigs, *(callback ?: this));
mFlinger->mAppConnectionHandle = mScheduler->createConnection(std::move(appEventThread));
mFlinger->mSfConnectionHandle = mScheduler->createConnection(std::move(sfEventThread));
@@ -643,6 +643,7 @@
DisplayModePtr activeMode =
DisplayMode::Builder(FakeHwcDisplayInjector::DEFAULT_ACTIVE_CONFIG)
.setId(mActiveModeId)
+ .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
.setWidth(FakeHwcDisplayInjector::DEFAULT_WIDTH)
.setHeight(FakeHwcDisplayInjector::DEFAULT_HEIGHT)
.setVsyncPeriod(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)
@@ -653,6 +654,7 @@
DisplayModes modes{activeMode};
mCreationArgs.supportedModes = modes;
+ mCreationArgs.refreshRateConfigs = flinger.mRefreshRateConfigs;
}
sp<IBinder> token() const { return mDisplayToken; }
@@ -722,7 +724,7 @@
return *this;
}
- sp<DisplayDevice> inject() {
+ sp<DisplayDevice> inject() NO_THREAD_SAFETY_ANALYSIS {
const auto displayId = mCreationArgs.compositionDisplay->getDisplayId();
DisplayDeviceState state;
@@ -769,6 +771,7 @@
surfaceflinger::test::Factory mFactory;
sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(mFactory, SurfaceFlinger::SkipInitialization);
TestableScheduler* mScheduler = nullptr;
+ std::shared_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs;
};
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index 7c431a0..1a50427 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -74,6 +74,7 @@
EXPECT_CALL(*mVSyncTracker, currentPeriod())
.WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
+ mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>());
mFlinger.setupScheduler(std::unique_ptr<mock::VsyncController>(mVsyncController),
std::unique_ptr<mock::VSyncTracker>(mVSyncTracker),
std::move(eventThread), std::move(sfEventThread));
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index 485b4ac..d25973e 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -33,7 +33,7 @@
MOCK_METHOD0(onScreenReleased, void());
MOCK_METHOD0(onScreenAcquired, void());
MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool));
- MOCK_METHOD3(onModeChanged, void(PhysicalDisplayId, DisplayModeId, nsecs_t));
+ MOCK_METHOD1(onModeChanged, void(DisplayModePtr));
MOCK_METHOD2(onFrameRateOverridesChanged,
void(PhysicalDisplayId, std::vector<FrameRateOverride>));
MOCK_CONST_METHOD1(dump, void(std::string&));
diff --git a/vulkan/README.md b/vulkan/README.md
index 185aa39..144805c 100644
--- a/vulkan/README.md
+++ b/vulkan/README.md
@@ -14,7 +14,7 @@
## Code Generation
-We generate several parts of the loader and tools driectly from the Vulkan Registry (external/vulkan-headers/registry/vk.xml). Code generation must be done manually because the generator is not part of the platform toolchain (yet?). Files named `foo_gen.*` are generated by the code generator.
+We generate several parts of the loader and tools directly from the Vulkan Registry (external/vulkan-headers/registry/vk.xml). Code generation must be done manually because the generator is not part of the platform toolchain (yet?). Files named `foo_gen.*` are generated by the code generator.
### Run The Code Generator
diff --git a/vulkan/libvulkan/api_gen.cpp b/vulkan/libvulkan/api_gen.cpp
index 26052fb..33401d2 100644
--- a/vulkan/libvulkan/api_gen.cpp
+++ b/vulkan/libvulkan/api_gen.cpp
@@ -560,6 +560,7 @@
}
static const char* const known_non_device_names[] = {
+ "vkAcquireDrmDisplayEXT",
"vkCreateAndroidSurfaceKHR",
"vkCreateDebugReportCallbackEXT",
"vkCreateDebugUtilsMessengerEXT",
@@ -581,6 +582,7 @@
"vkEnumeratePhysicalDevices",
"vkGetDisplayModeProperties2KHR",
"vkGetDisplayPlaneCapabilities2KHR",
+ "vkGetDrmDisplayEXT",
"vkGetInstanceProcAddr",
"vkGetPhysicalDeviceCalibrateableTimeDomainsEXT",
"vkGetPhysicalDeviceDisplayPlaneProperties2KHR",
@@ -624,6 +626,8 @@
"vkGetPhysicalDeviceSurfacePresentModesKHR",
"vkGetPhysicalDeviceSurfaceSupportKHR",
"vkGetPhysicalDeviceToolPropertiesEXT",
+ "vkGetPhysicalDeviceVideoCapabilitiesKHR",
+ "vkGetPhysicalDeviceVideoFormatPropertiesKHR",
"vkSubmitDebugUtilsMessageEXT",
};
// clang-format on
diff --git a/vulkan/scripts/generator_common.py b/vulkan/scripts/generator_common.py
index 72fd4fb..4176509 100644
--- a/vulkan/scripts/generator_common.py
+++ b/vulkan/scripts/generator_common.py
@@ -33,6 +33,7 @@
'VK_EXT_metal_surface',
'VK_FUCHSIA_imagepipe_surface',
'VK_GGP_stream_descriptor_surface',
+ 'VK_HUAWEI_subpass_shading',
'VK_KHR_display',
'VK_KHR_display_swapchain',
'VK_KHR_external_fence_win32',
@@ -47,11 +48,13 @@
'VK_MVK_ios_surface',
'VK_MVK_macos_surface',
'VK_NN_vi_surface',
+ 'VK_NV_acquire_winrt_display',
'VK_NV_cooperative_matrix',
'VK_NV_coverage_reduction_mode',
'VK_NV_external_memory_win32',
'VK_NV_win32_keyed_mutex',
'VK_NVX_image_view_handle',
+ 'VK_QNX_screen_surface',
]
# Extensions having functions exported by the loader.