Merge "TouchInputMapper: Use default viewport for PointerController"
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index 09aee89..ba54d13 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -110,29 +110,20 @@
],
required: [
"atrace",
- "df",
- "getprop",
"ip",
"iptables",
- "ip6tables",
- "kill",
"librank",
"logcat",
"lpdump",
"lpdumpd",
- "lsmod",
- "lsof",
- "netstat",
- "printenv",
"procrank",
"screencap",
"showmap",
"ss",
"storaged",
- "top",
- "uptime",
+ "toolbox",
+ "toybox",
"vdc",
- "vril-dump",
],
init_rc: ["dumpstate.rc"],
}
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index c0fb0f8..43c4900 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -1064,6 +1064,7 @@
res = error(rc, "Failed copying " + from_ce + " to " + to_ce);
return res;
}
+ delete_dir_contents_and_dir(from_ce, true /* ignore_if_missing */);
}
if (needs_de_rollback) {
@@ -1080,6 +1081,7 @@
res = error(rc, "Failed copying " + from_de + " to " + to_de);
return res;
}
+ delete_dir_contents_and_dir(from_de, true /* ignore_if_missing */);
}
// Finally, restore the SELinux label on the app data.
@@ -2329,26 +2331,6 @@
return *_aidl_return ? ok() : error("viewcompiler failed");
}
-binder::Status InstalldNativeService::markBootComplete(const std::string& instructionSet) {
- ENFORCE_UID(AID_SYSTEM);
- std::lock_guard<std::recursive_mutex> lock(mLock);
-
- const char* instruction_set = instructionSet.c_str();
-
- char boot_marker_path[PKG_PATH_MAX];
- sprintf(boot_marker_path,
- "%s/%s/%s/.booting",
- android_data_dir.c_str(),
- DALVIK_CACHE,
- instruction_set);
-
- ALOGV("mark_boot_complete : %s", boot_marker_path);
- if (unlink(boot_marker_path) != 0) {
- return error(StringPrintf("Failed to unlink %s", boot_marker_path));
- }
- return ok();
-}
-
binder::Status InstalldNativeService::linkNativeLibraryDirectory(
const std::optional<std::string>& uuid, const std::string& packageName,
const std::string& nativeLibPath32, int32_t userId) {
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 3f44021..372fbc5 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -130,7 +130,6 @@
int32_t uid);
binder::Status removeIdmap(const std::string& overlayApkPath);
binder::Status rmPackageDir(const std::string& packageDir);
- binder::Status markBootComplete(const std::string& instructionSet);
binder::Status freeCache(const std::optional<std::string>& uuid, int64_t targetFreeBytes,
int64_t cacheReservedBytes, int32_t flags);
binder::Status linkNativeLibraryDirectory(const std::optional<std::string>& uuid,
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 1e18a6b..f1a8754 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -78,7 +78,6 @@
void idmap(@utf8InCpp String targetApkPath, @utf8InCpp String overlayApkPath, int uid);
void removeIdmap(@utf8InCpp String overlayApkPath);
void rmPackageDir(@utf8InCpp String packageDir);
- void markBootComplete(@utf8InCpp String instructionSet);
void freeCache(@nullable @utf8InCpp String uuid, long targetFreeBytes,
long cacheReservedBytes, int flags);
void linkNativeLibraryDirectory(@nullable @utf8InCpp String uuid,
diff --git a/cmds/servicemanager/Access.cpp b/cmds/servicemanager/Access.cpp
index 1bbde23..b7e520f 100644
--- a/cmds/servicemanager/Access.cpp
+++ b/cmds/servicemanager/Access.cpp
@@ -31,7 +31,7 @@
#endif
static std::string getPidcon(pid_t pid) {
- if (pid != getpid()) return "";
+ android_errorWriteLog(0x534e4554, "121035042");
char* lookup = nullptr;
if (getpidcon(pid, &lookup) < 0) {
diff --git a/libs/binder/BufferedTextOutput.cpp b/libs/binder/BufferedTextOutput.cpp
index 856a178..8cf6097 100644
--- a/libs/binder/BufferedTextOutput.cpp
+++ b/libs/binder/BufferedTextOutput.cpp
@@ -49,9 +49,10 @@
}
status_t append(const char* txt, size_t len) {
+ if (len > SIZE_MAX - bufferPos) return NO_MEMORY; // overflow
if ((len+bufferPos) > bufferSize) {
+ if ((len + bufferPos) > SIZE_MAX / 3) return NO_MEMORY; // overflow
size_t newSize = ((len+bufferPos)*3)/2;
- if (newSize < (len+bufferPos)) return NO_MEMORY; // overflow
void* b = realloc(buffer, newSize);
if (!b) return NO_MEMORY;
buffer = (char*)b;
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 1d94bd6..660b96a 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -422,8 +422,10 @@
const sp<ProcessState> proc(ProcessState::self());
// grow objects
if (mObjectsCapacity < mObjectsSize + numObjects) {
+ if ((size_t) numObjects > SIZE_MAX - mObjectsSize) return NO_MEMORY; // overflow
+ if (mObjectsSize + numObjects > SIZE_MAX / 3) return NO_MEMORY; // overflow
size_t newSize = ((mObjectsSize + numObjects)*3)/2;
- if (newSize*sizeof(binder_size_t) < mObjectsSize) return NO_MEMORY; // overflow
+ if (newSize > SIZE_MAX / sizeof(binder_size_t)) return NO_MEMORY; // overflow
binder_size_t *objects =
(binder_size_t*)realloc(mObjects, newSize*sizeof(binder_size_t));
if (objects == (binder_size_t*)nullptr) {
@@ -1373,8 +1375,10 @@
if (err != NO_ERROR) return err;
}
if (!enoughObjects) {
+ if (mObjectsSize > SIZE_MAX - 2) return NO_MEMORY; // overflow
+ if ((mObjectsSize + 2) > SIZE_MAX / 3) return NO_MEMORY; // overflow
size_t newSize = ((mObjectsSize+2)*3)/2;
- if (newSize*sizeof(binder_size_t) < mObjectsSize) return NO_MEMORY; // overflow
+ if (newSize > SIZE_MAX / sizeof(binder_size_t)) return NO_MEMORY; // overflow
binder_size_t* objects = (binder_size_t*)realloc(mObjects, newSize*sizeof(binder_size_t));
if (objects == nullptr) return NO_MEMORY;
mObjects = objects;
@@ -2606,10 +2610,12 @@
return BAD_VALUE;
}
+ if (len > SIZE_MAX - mDataSize) return NO_MEMORY; // overflow
+ if (mDataSize + len > SIZE_MAX / 3) return NO_MEMORY; // overflow
size_t newSize = ((mDataSize+len)*3)/2;
return (newSize <= mDataSize)
? (status_t) NO_MEMORY
- : continueWrite(newSize);
+ : continueWrite(std::max(newSize, (size_t) 128));
}
status_t Parcel::restartWrite(size_t desired)
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 9aa7651..c232283 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -7,6 +7,9 @@
"name": "binderVendorDoubleLoadTest"
},
{
+ "name": "binderAllocationLimits"
+ },
+ {
"name": "binderDriverInterfaceTest"
},
{
@@ -29,6 +32,17 @@
},
{
"name": "libbinderthreadstateutils_test"
+ },
+ {
+ "name": "CtsOsTestCases",
+ "options": [
+ {
+ "exclude-filter": "android.os.cts.BuildTest#testSdkInt"
+ },
+ {
+ "exclude-filter": "android.os.cts.StrictModeTest#testNonSdkApiUsage"
+ }
+ ]
}
]
}
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 69fdd7c..9dad969 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -164,3 +164,18 @@
test_suites: ["device-tests"],
require_root: true,
}
+
+cc_test {
+ name: "binderAllocationLimits",
+ defaults: ["binder_test_defaults"],
+ srcs: ["binderAllocationLimits.cpp"],
+ shared_libs: [
+ "libbinder",
+ "liblog",
+ "libutils",
+ "libutilscallstack",
+ "libbase",
+ ],
+ test_suites: ["device-tests"],
+ require_root: true,
+}
diff --git a/libs/binder/tests/binderAllocationLimits.cpp b/libs/binder/tests/binderAllocationLimits.cpp
new file mode 100644
index 0000000..e1f5ed5
--- /dev/null
+++ b/libs/binder/tests/binderAllocationLimits.cpp
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <binder/Parcel.h>
+#include <binder/IServiceManager.h>
+#include <gtest/gtest.h>
+#include <utils/CallStack.h>
+
+#include <malloc.h>
+#include <functional>
+#include <vector>
+
+struct DestructionAction {
+ DestructionAction(std::function<void()> f) : mF(std::move(f)) {}
+ ~DestructionAction() { mF(); };
+private:
+ std::function<void()> mF;
+};
+
+// Group of hooks
+struct MallocHooks {
+ decltype(__malloc_hook) malloc_hook;
+ decltype(__realloc_hook) realloc_hook;
+
+ static MallocHooks save() {
+ return {
+ .malloc_hook = __malloc_hook,
+ .realloc_hook = __realloc_hook,
+ };
+ }
+
+ void overwrite() const {
+ __malloc_hook = malloc_hook;
+ __realloc_hook = realloc_hook;
+ }
+};
+
+static const MallocHooks orig_malloc_hooks = MallocHooks::save();
+
+// When malloc is hit, executes lambda.
+namespace LambdaHooks {
+ using AllocationHook = std::function<void(size_t)>;
+ static std::vector<AllocationHook> lambdas = {};
+
+ static void* lambda_realloc_hook(void* ptr, size_t bytes, const void* arg);
+ static void* lambda_malloc_hook(size_t bytes, const void* arg);
+
+ static const MallocHooks lambda_malloc_hooks = {
+ .malloc_hook = lambda_malloc_hook,
+ .realloc_hook = lambda_realloc_hook,
+ };
+
+ static void* lambda_malloc_hook(size_t bytes, const void* arg) {
+ {
+ orig_malloc_hooks.overwrite();
+ lambdas.at(lambdas.size() - 1)(bytes);
+ lambda_malloc_hooks.overwrite();
+ }
+ return orig_malloc_hooks.malloc_hook(bytes, arg);
+ }
+
+ static void* lambda_realloc_hook(void* ptr, size_t bytes, const void* arg) {
+ {
+ orig_malloc_hooks.overwrite();
+ lambdas.at(lambdas.size() - 1)(bytes);
+ lambda_malloc_hooks.overwrite();
+ }
+ return orig_malloc_hooks.realloc_hook(ptr, bytes, arg);
+ }
+
+}
+
+// Action to execute when malloc is hit. Supports nesting. Malloc is not
+// restricted when the allocation hook is being processed.
+__attribute__((warn_unused_result))
+DestructionAction OnMalloc(LambdaHooks::AllocationHook f) {
+ MallocHooks before = MallocHooks::save();
+ LambdaHooks::lambdas.emplace_back(std::move(f));
+ LambdaHooks::lambda_malloc_hooks.overwrite();
+ return DestructionAction([before]() {
+ before.overwrite();
+ LambdaHooks::lambdas.pop_back();
+ });
+}
+
+// exported symbol, to force compiler not to optimize away pointers we set here
+const void* imaginary_use;
+
+TEST(TestTheTest, OnMalloc) {
+ size_t mallocs = 0;
+ {
+ const auto on_malloc = OnMalloc([&](size_t bytes) {
+ mallocs++;
+ EXPECT_EQ(bytes, 40);
+ });
+
+ imaginary_use = new int[10];
+ }
+ EXPECT_EQ(mallocs, 1);
+}
+
+
+__attribute__((warn_unused_result))
+DestructionAction ScopeDisallowMalloc() {
+ return OnMalloc([&](size_t bytes) {
+ ADD_FAILURE() << "Unexpected allocation: " << bytes;
+ using android::CallStack;
+ std::cout << CallStack::stackToString("UNEXPECTED ALLOCATION", CallStack::getCurrent(4 /*ignoreDepth*/).get())
+ << std::endl;
+ });
+}
+
+using android::IBinder;
+using android::Parcel;
+using android::String16;
+using android::defaultServiceManager;
+using android::sp;
+using android::IServiceManager;
+
+static sp<IBinder> GetRemoteBinder() {
+ // This gets binder representing the service manager
+ // the current IServiceManager API doesn't expose the binder, and
+ // I want to avoid adding usages of the AIDL generated interface it
+ // is using underneath, so to avoid people copying it.
+ sp<IBinder> binder = defaultServiceManager()->checkService(String16("manager"));
+ EXPECT_NE(nullptr, binder);
+ return binder;
+}
+
+TEST(BinderAllocation, ParcelOnStack) {
+ const auto m = ScopeDisallowMalloc();
+ Parcel p;
+ imaginary_use = p.data();
+}
+
+TEST(BinderAllocation, GetServiceManager) {
+ defaultServiceManager(); // first call may alloc
+ const auto m = ScopeDisallowMalloc();
+ defaultServiceManager();
+}
+
+// note, ping does not include interface descriptor
+TEST(BinderAllocation, PingTransaction) {
+ sp<IBinder> a_binder = GetRemoteBinder();
+ const auto m = ScopeDisallowMalloc();
+ a_binder->pingBinder();
+}
+
+TEST(BinderAllocation, SmallTransaction) {
+ String16 empty_descriptor = String16("");
+ sp<IServiceManager> manager = defaultServiceManager();
+
+ size_t mallocs = 0;
+ const auto on_malloc = OnMalloc([&](size_t bytes) {
+ mallocs++;
+ // Parcel should allocate a small amount by default
+ EXPECT_EQ(bytes, 128);
+ });
+ manager->checkService(empty_descriptor);
+
+ EXPECT_EQ(mallocs, 1);
+}
+
+int main(int argc, char** argv) {
+ if (getenv("LIBC_HOOKS_ENABLE") == nullptr) {
+ CHECK(0 == setenv("LIBC_HOOKS_ENABLE", "1", true /*overwrite*/));
+ execv(argv[0], argv);
+ return 1;
+ }
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 5cb2bec..5d51d2b 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -134,12 +134,8 @@
return env;
}
-int GraphicsEnv::getCanLoadSystemLibraries() {
- if (property_get_bool("ro.debuggable", false) && prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) {
- // Return an integer value since this crosses library boundaries
- return 1;
- }
- return 0;
+bool GraphicsEnv::isDebuggable() {
+ return prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) > 0;
}
void GraphicsEnv::setDriverPathAndSphalLibraries(const std::string path,
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 937bcd9..227b458 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -84,7 +84,16 @@
public:
static GraphicsEnv& getInstance();
- int getCanLoadSystemLibraries();
+ // Check if the process is debuggable. It returns false except in any of the
+ // following circumstances:
+ // 1. ro.debuggable=1 (global debuggable enabled).
+ // 2. android:debuggable="true" in the manifest for an individual app.
+ // 3. An app which explicitly calls prctl(PR_SET_DUMPABLE, 1).
+ // 4. GraphicsEnv calls prctl(PR_SET_DUMPABLE, 1) in the presence of
+ // <meta-data android:name="com.android.graphics.injectLayers.enable"
+ // android:value="true"/>
+ // in the application manifest.
+ bool isDebuggable();
// Set a search path for loading graphics drivers. The path is a list of
// directories separated by ':'. A directory can be contained in a zip file
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 2d78811..6132b1c 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -34,6 +34,9 @@
clang: true,
+ header_libs: ["jni_headers"],
+ export_header_lib_headers: ["jni_headers"],
+
shared_libs: [
"libbase",
"liblog",
diff --git a/libs/input/TouchVideoFrame.cpp b/libs/input/TouchVideoFrame.cpp
index 8a4298a..ce76e3f 100644
--- a/libs/input/TouchVideoFrame.cpp
+++ b/libs/input/TouchVideoFrame.cpp
@@ -42,13 +42,13 @@
void TouchVideoFrame::rotate(int32_t orientation) {
switch (orientation) {
case DISPLAY_ORIENTATION_90:
- rotateQuarterTurn(true /*clockwise*/);
+ rotateQuarterTurn(false /*clockwise*/);
break;
case DISPLAY_ORIENTATION_180:
rotate180();
break;
case DISPLAY_ORIENTATION_270:
- rotateQuarterTurn(false /*clockwise*/);
+ rotateQuarterTurn(true /*clockwise*/);
break;
}
}
diff --git a/libs/input/tests/TouchVideoFrame_test.cpp b/libs/input/tests/TouchVideoFrame_test.cpp
index 815424e..fe06cad 100644
--- a/libs/input/tests/TouchVideoFrame_test.cpp
+++ b/libs/input/tests/TouchVideoFrame_test.cpp
@@ -85,14 +85,14 @@
TEST(TouchVideoFrame, Rotate90_2x2) {
TouchVideoFrame frame(2, 2, {1, 2, 3, 4}, TIMESTAMP);
- TouchVideoFrame frameRotated(2, 2, {3, 1, 4, 2}, TIMESTAMP);
+ TouchVideoFrame frameRotated(2, 2, {2, 4, 1, 3}, TIMESTAMP);
frame.rotate(DISPLAY_ORIENTATION_90);
ASSERT_EQ(frame, frameRotated);
}
TEST(TouchVideoFrame, Rotate90_3x2) {
TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP);
- TouchVideoFrame frameRotated(2, 3, {5, 3, 1, 6, 4, 2}, TIMESTAMP);
+ TouchVideoFrame frameRotated(2, 3, {2, 4, 6, 1, 3, 5}, TIMESTAMP);
frame.rotate(DISPLAY_ORIENTATION_90);
ASSERT_EQ(frame, frameRotated);
}
@@ -170,14 +170,14 @@
TEST(TouchVideoFrame, Rotate270_2x2) {
TouchVideoFrame frame(2, 2, {1, 2, 3, 4}, TIMESTAMP);
- TouchVideoFrame frameRotated(2, 2, {2, 4, 1, 3}, TIMESTAMP);
+ TouchVideoFrame frameRotated(2, 2, {3, 1, 4, 2}, TIMESTAMP);
frame.rotate(DISPLAY_ORIENTATION_270);
ASSERT_EQ(frame, frameRotated);
}
TEST(TouchVideoFrame, Rotate270_3x2) {
TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP);
- TouchVideoFrame frameRotated(2, 3, {2, 4, 6, 1, 3, 5}, TIMESTAMP);
+ TouchVideoFrame frameRotated(2, 3, {5, 3, 1, 6, 4, 2}, TIMESTAMP);
frame.rotate(DISPLAY_ORIENTATION_270);
ASSERT_EQ(frame, frameRotated);
}
diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp
index 2fcee7b..37c19d4 100644
--- a/libs/vr/libbufferhub/Android.bp
+++ b/libs/vr/libbufferhub/Android.bp
@@ -16,6 +16,12 @@
name: "libbufferhub_headers",
export_include_dirs: ["include"],
vendor_available: true, // TODO(b/112338314): Does shouldn't be available to vendor.
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media",
+ "com.android.media.swcodec",
+ ],
+ min_sdk_version: "29",
}
sourceFiles = [
diff --git a/libs/vr/libdvr/Android.bp b/libs/vr/libdvr/Android.bp
index 81a9b2d..340d7bf 100644
--- a/libs/vr/libdvr/Android.bp
+++ b/libs/vr/libdvr/Android.bp
@@ -17,6 +17,12 @@
name: "libdvr_headers",
export_include_dirs: ["include"],
vendor_available: true,
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media",
+ "com.android.media.swcodec",
+ ],
+ min_sdk_version: "29",
}
cc_library_headers {
diff --git a/opengl/libs/EGL/egl_layers.cpp b/opengl/libs/EGL/egl_layers.cpp
index 9b1b522..408e76b 100644
--- a/opengl/libs/EGL/egl_layers.cpp
+++ b/opengl/libs/EGL/egl_layers.cpp
@@ -337,7 +337,7 @@
// Only enable the system search path for non-user builds
std::string system_path;
- if (property_get_bool("ro.debuggable", false) && prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) {
+ if (android::GraphicsEnv::getInstance().isDebuggable()) {
system_path = kSystemLayerLibraryDir;
}
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 11578c3..04f6472 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -46,7 +46,6 @@
"liblog",
"libutils",
"libui",
- "server_configurable_flags",
],
static_libs: [
diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp
index 6e51fb2..cda0e0c 100644
--- a/services/inputflinger/InputClassifier.cpp
+++ b/services/inputflinger/InputClassifier.cpp
@@ -27,7 +27,6 @@
#if defined(__linux__)
#include <pthread.h>
#endif
-#include <server_configurable_flags/get_flags.h>
#include <unordered_set>
#include <android/hardware/input/classifier/1.0/IInputClassifier.h>
@@ -46,11 +45,6 @@
namespace android {
-// Category (=namespace) name for the input settings that are applied at boot time
-static const char* INPUT_NATIVE_BOOT = "input_native_boot";
-// Feature flag name for the deep press feature
-static const char* DEEP_PRESS_ENABLED = "deep_press_enabled";
-
//Max number of elements to store in mEvents.
static constexpr size_t MAX_EVENTS = 5;
@@ -77,20 +71,6 @@
return args.source == AINPUT_SOURCE_TOUCHPAD || args.source == AINPUT_SOURCE_TOUCHSCREEN;
}
-// Check if the "deep touch" feature is on.
-static bool deepPressEnabled() {
- std::string flag_value = server_configurable_flags::GetServerConfigurableFlag(
- INPUT_NATIVE_BOOT, DEEP_PRESS_ENABLED, "true");
- std::transform(flag_value.begin(), flag_value.end(), flag_value.begin(), ::tolower);
- if (flag_value == "1" || flag_value == "true") {
- ALOGI("Deep press feature enabled.");
- return true;
- }
- ALOGI("Deep press feature is not enabled.");
- return false;
-}
-
-
// --- ClassifierEvent ---
ClassifierEvent::ClassifierEvent(std::unique_ptr<NotifyMotionArgs> args) :
@@ -157,12 +137,6 @@
std::unique_ptr<MotionClassifierInterface> MotionClassifier::create(
sp<android::hardware::hidl_death_recipient> deathRecipient) {
- if (!deepPressEnabled()) {
- // If feature is not enabled, MotionClassifier should stay null to avoid unnecessary work.
- // When MotionClassifier is null, InputClassifier will forward all events
- // to the next InputListener, unmodified.
- return nullptr;
- }
sp<android::hardware::input::classifier::V1_0::IInputClassifier> service =
classifier::V1_0::IInputClassifier::getService();
if (!service) {
@@ -366,14 +340,25 @@
// --- InputClassifier ---
InputClassifier::InputClassifier(const sp<InputListenerInterface>& listener)
- : mListener(listener), mHalDeathRecipient(new HalDeathRecipient(*this)) {
- mInitializeMotionClassifierThread = std::thread(
- [this] { setMotionClassifier(MotionClassifier::create(mHalDeathRecipient)); });
+ : mListener(listener), mHalDeathRecipient(new HalDeathRecipient(*this)) {}
+
+void InputClassifier::setMotionClassifierEnabled(bool enabled) {
+ if (enabled) {
+ ALOGI("Enabling motion classifier");
+ if (mInitializeMotionClassifierThread.joinable()) {
+ mInitializeMotionClassifierThread.join();
+ }
+ mInitializeMotionClassifierThread = std::thread(
+ [this] { setMotionClassifier(MotionClassifier::create(mHalDeathRecipient)); });
#if defined(__linux__)
- // Set the thread name for debugging
- pthread_setname_np(mInitializeMotionClassifierThread.native_handle(),
- "Create MotionClassifier");
+ // Set the thread name for debugging
+ pthread_setname_np(mInitializeMotionClassifierThread.native_handle(),
+ "Create MotionClassifier");
#endif
+ } else {
+ ALOGI("Disabling motion classifier");
+ setMotionClassifier(nullptr);
+ }
}
void InputClassifier::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) {
@@ -434,7 +419,9 @@
}
InputClassifier::~InputClassifier() {
- mInitializeMotionClassifierThread.join();
+ if (mInitializeMotionClassifierThread.joinable()) {
+ mInitializeMotionClassifierThread.join();
+ }
}
} // namespace android
diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputClassifier.h
index b1769b9..9ac8e2d 100644
--- a/services/inputflinger/InputClassifier.h
+++ b/services/inputflinger/InputClassifier.h
@@ -90,6 +90,7 @@
*/
class InputClassifierInterface : public virtual RefBase, public InputListenerInterface {
public:
+ virtual void setMotionClassifierEnabled(bool enabled) = 0;
/**
* Dump the state of the input classifier.
* This method may be called on any thread (usually by the input manager).
@@ -232,6 +233,9 @@
~InputClassifier();
+ // Called from InputManager
+ virtual void setMotionClassifierEnabled(bool enabled) override;
+
private:
// Protect access to mMotionClassifier, since it may become null via a hidl callback
std::mutex mLock;
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index 7d30672..d6cc603 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -135,4 +135,8 @@
mDispatcher->unregisterInputChannel(channel);
}
+void InputManager::setMotionClassifierEnabled(bool enabled) {
+ mClassifier->setMotionClassifierEnabled(enabled);
+}
+
} // namespace android
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index 40f66d8..5c07706 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -100,6 +100,8 @@
virtual void registerInputChannel(const sp<InputChannel>& channel);
virtual void unregisterInputChannel(const sp<InputChannel>& channel);
+ void setMotionClassifierEnabled(bool enabled);
+
private:
sp<InputReaderInterface> mReader;
sp<InputReaderThread> mReaderThread;
diff --git a/services/inputflinger/host/Android.bp b/services/inputflinger/host/Android.bp
index cbe0190..b56f356 100644
--- a/services/inputflinger/host/Android.bp
+++ b/services/inputflinger/host/Android.bp
@@ -21,6 +21,7 @@
"InputHost.cpp",
],
+ header_libs: ["jni_headers"],
shared_libs: [
"libbinder",
"libcrypto",
@@ -42,6 +43,7 @@
//-fvisibility=hidden
],
+ export_header_lib_headers: ["jni_headers"],
export_include_dirs: ["."],
}
diff --git a/services/inputflinger/tests/InputClassifier_test.cpp b/services/inputflinger/tests/InputClassifier_test.cpp
index 9121d7e..4cddec5 100644
--- a/services/inputflinger/tests/InputClassifier_test.cpp
+++ b/services/inputflinger/tests/InputClassifier_test.cpp
@@ -132,6 +132,28 @@
ASSERT_EQ(args, outArgs);
}
+TEST_F(InputClassifierTest, SetMotionClassifier_Enabled) {
+ mClassifier->setMotionClassifierEnabled(true);
+}
+
+TEST_F(InputClassifierTest, SetMotionClassifier_Disabled) {
+ mClassifier->setMotionClassifierEnabled(false);
+}
+
+/**
+ * Try to break it by calling setMotionClassifierEnabled multiple times.
+ */
+TEST_F(InputClassifierTest, SetMotionClassifier_Multiple) {
+ mClassifier->setMotionClassifierEnabled(true);
+ mClassifier->setMotionClassifierEnabled(true);
+ mClassifier->setMotionClassifierEnabled(true);
+ mClassifier->setMotionClassifierEnabled(false);
+ mClassifier->setMotionClassifierEnabled(false);
+ mClassifier->setMotionClassifierEnabled(true);
+ mClassifier->setMotionClassifierEnabled(true);
+ mClassifier->setMotionClassifierEnabled(true);
+}
+
/**
* A minimal implementation of IInputClassifier.
*/
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 14ed73d..090a0ce 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -208,12 +208,6 @@
registerSensor(new RotationVectorSensor(), !needRotationVector, true);
registerSensor(new OrientationSensor(), !needRotationVector, true);
- bool needLinearAcceleration =
- (virtualSensorsNeeds & (1<<SENSOR_TYPE_LINEAR_ACCELERATION)) != 0;
-
- registerSensor(new LinearAccelerationSensor(list, count),
- !needLinearAcceleration, true);
-
// virtual debugging sensors are not for user
registerSensor( new CorrectedGyroSensor(list, count), true, true);
registerSensor( new GyroDriftSensor(), true, true);
@@ -223,6 +217,11 @@
bool needGravitySensor = (virtualSensorsNeeds & (1<<SENSOR_TYPE_GRAVITY)) != 0;
registerSensor(new GravitySensor(list, count), !needGravitySensor, true);
+ bool needLinearAcceleration =
+ (virtualSensorsNeeds & (1<<SENSOR_TYPE_LINEAR_ACCELERATION)) != 0;
+ registerSensor(new LinearAccelerationSensor(list, count),
+ !needLinearAcceleration, true);
+
bool needGameRotationVector =
(virtualSensorsNeeds & (1<<SENSOR_TYPE_GAME_ROTATION_VECTOR)) != 0;
registerSensor(new GameRotationVectorSensor(), !needGameRotationVector, true);
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index dd79d82..1de7afb 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -458,6 +458,7 @@
status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500));
if (result != NO_ERROR) {
ALOGE("[%s] Timed out waiting on callback", mName.string());
+ break;
}
}
@@ -492,6 +493,7 @@
status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500));
if (result != NO_ERROR) {
ALOGE("[%s] Timed out waiting on callback", mName.string());
+ break;
}
}
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 07fdead..80da154 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -200,9 +200,10 @@
void RegionSamplingThread::addListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
const sp<IRegionSamplingListener>& listener) {
- wp<Layer> stopLayer = stopLayerHandle != nullptr
- ? static_cast<Layer::Handle*>(stopLayerHandle.get())->owner
- : nullptr;
+ wp<Layer> stopLayer;
+ if (stopLayerHandle != nullptr && stopLayerHandle->localBinder() != nullptr) {
+ stopLayer = static_cast<Layer::Handle*>(stopLayerHandle.get())->owner;
+ }
sp<IBinder> asBinder = IInterface::asBinder(listener);
asBinder->linkToDeath(this);
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
index 8a2604f..9fa2bbc 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
@@ -96,7 +96,6 @@
highFpsOffsets.late = {RefreshRateType::PERFORMANCE, highFpsLateSfOffsetNs,
highFpsLateAppOffsetNs};
- mOffsets.insert({RefreshRateType::POWER_SAVING, defaultOffsets});
mOffsets.insert({RefreshRateType::DEFAULT, defaultOffsets});
mOffsets.insert({RefreshRateType::PERFORMANCE, highFpsOffsets});
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index d730058..d813708 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -34,10 +34,9 @@
*/
class RefreshRateConfigs {
public:
- // Enum to indicate which vsync rate to run at. Power saving is intended to be the lowest
- // (eg. when the screen is in AOD mode or off), default is the old 60Hz, and performance
+ // Enum to indicate which vsync rate to run at. Default is the old 60Hz, and performance
// is the new 90Hz. Eventually we want to have a way for vendors to map these in the configs.
- enum class RefreshRateType { POWER_SAVING, DEFAULT, PERFORMANCE };
+ enum class RefreshRateType { DEFAULT, PERFORMANCE };
struct RefreshRate {
// This config ID corresponds to the position of the config in the vector that is stored
@@ -47,26 +46,57 @@
std::string name;
// Refresh rate in frames per second, rounded to the nearest integer.
uint32_t fps = 0;
- // config Id (returned from HWC2::Display::Config::getId())
- hwc2_config_t id;
+ // Vsync period in nanoseconds.
+ nsecs_t vsyncPeriod;
+ // Hwc config Id (returned from HWC2::Display::Config::getId())
+ hwc2_config_t hwcId;
};
+ // Returns true if this device is doing refresh rate switching. This won't change at runtime.
+ bool refreshRateSwitchingSupported() const { return mRefreshRateSwitchingSupported; }
+
+ // Returns the refresh rate map. This map won't be modified at runtime, so it's safe to access
+ // from multiple threads. This can only be called if refreshRateSwitching() returns true.
// TODO(b/122916473): Get this information from configs prepared by vendors, instead of
// baking them in.
- const std::map<RefreshRateType, std::shared_ptr<RefreshRate>>& getRefreshRates() const {
- return mRefreshRates;
- }
- std::shared_ptr<RefreshRate> getRefreshRate(RefreshRateType type) const {
- const auto& refreshRate = mRefreshRates.find(type);
- if (refreshRate != mRefreshRates.end()) {
- return refreshRate->second;
- }
- return nullptr;
+ const std::map<RefreshRateType, RefreshRate>& getRefreshRateMap() const {
+ LOG_ALWAYS_FATAL_IF(!mRefreshRateSwitchingSupported);
+ return mRefreshRateMap;
}
- RefreshRateType getRefreshRateType(hwc2_config_t id) const {
- for (const auto& [type, refreshRate] : mRefreshRates) {
- if (refreshRate->id == id) {
+ const RefreshRate& getRefreshRateFromType(RefreshRateType type) const {
+ if (!mRefreshRateSwitchingSupported) {
+ return getCurrentRefreshRate().second;
+ } else {
+ auto refreshRate = mRefreshRateMap.find(type);
+ LOG_ALWAYS_FATAL_IF(refreshRate == mRefreshRateMap.end());
+ return refreshRate->second;
+ }
+ }
+
+ std::pair<RefreshRateType, const RefreshRate&> getCurrentRefreshRate() const {
+ int currentConfig = mCurrentConfig;
+ if (mRefreshRateSwitchingSupported) {
+ for (const auto& [type, refresh] : mRefreshRateMap) {
+ if (refresh.configId == currentConfig) {
+ return {type, refresh};
+ }
+ }
+ LOG_ALWAYS_FATAL();
+ }
+ return {RefreshRateType::DEFAULT, mRefreshRates[currentConfig]};
+ }
+
+ const RefreshRate& getRefreshRateFromConfigId(int configId) const {
+ LOG_ALWAYS_FATAL_IF(configId >= mRefreshRates.size());
+ return mRefreshRates[configId];
+ }
+
+ RefreshRateType getRefreshRateTypeFromHwcConfigId(hwc2_config_t hwcId) const {
+ if (!mRefreshRateSwitchingSupported) return RefreshRateType::DEFAULT;
+
+ for (const auto& [type, refreshRate] : mRefreshRateMap) {
+ if (refreshRate.hwcId == hwcId) {
return type;
}
}
@@ -74,64 +104,102 @@
return RefreshRateType::DEFAULT;
}
- void populate(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) {
- mRefreshRates.clear();
+ void setCurrentConfig(int config) {
+ LOG_ALWAYS_FATAL_IF(config >= mRefreshRates.size());
+ mCurrentConfig = config;
+ }
- // This is the rate that HWC encapsulates right now when the device is in DOZE mode.
- mRefreshRates.emplace(RefreshRateType::POWER_SAVING,
- std::make_shared<RefreshRate>(
- RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0,
- HWC2_SCREEN_OFF_CONFIG_ID}));
+ struct InputConfig {
+ hwc2_config_t hwcId = 0;
+ nsecs_t vsyncPeriod = 0;
+ };
- if (configs.size() < 1) {
- ALOGE("Device does not have valid configs. Config size is 0.");
- return;
+ RefreshRateConfigs(bool refreshRateSwitching, const std::vector<InputConfig>& configs,
+ int currentConfig) {
+ init(refreshRateSwitching, configs, currentConfig);
+ }
+
+ RefreshRateConfigs(bool refreshRateSwitching,
+ const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
+ int currentConfig) {
+ std::vector<InputConfig> inputConfigs;
+ for (const auto& config : configs) {
+ inputConfigs.push_back({config->getId(), config->getVsyncPeriod()});
}
-
- // Create a map between config index and vsync period. This is all the info we need
- // from the configs.
- std::vector<std::pair<int, nsecs_t>> configIdToVsyncPeriod;
- for (int i = 0; i < configs.size(); ++i) {
- configIdToVsyncPeriod.emplace_back(i, configs.at(i)->getVsyncPeriod());
- }
-
- std::sort(configIdToVsyncPeriod.begin(), configIdToVsyncPeriod.end(),
- [](const std::pair<int, nsecs_t>& a, const std::pair<int, nsecs_t>& b) {
- return a.second > b.second;
- });
-
- // When the configs are ordered by the resync rate. We assume that the first one is DEFAULT.
- nsecs_t vsyncPeriod = configIdToVsyncPeriod[0].second;
- if (vsyncPeriod != 0) {
- const float fps = 1e9 / vsyncPeriod;
- const int configId = configIdToVsyncPeriod[0].first;
- mRefreshRates.emplace(RefreshRateType::DEFAULT,
- std::make_shared<RefreshRate>(
- RefreshRate{configId, base::StringPrintf("%2.ffps", fps),
- static_cast<uint32_t>(fps),
- configs.at(configId)->getId()}));
- }
-
- if (configs.size() < 2) {
- return;
- }
-
- // When the configs are ordered by the resync rate. We assume that the second one is
- // PERFORMANCE, eg. the higher rate.
- vsyncPeriod = configIdToVsyncPeriod[1].second;
- if (vsyncPeriod != 0) {
- const float fps = 1e9 / vsyncPeriod;
- const int configId = configIdToVsyncPeriod[1].first;
- mRefreshRates.emplace(RefreshRateType::PERFORMANCE,
- std::make_shared<RefreshRate>(
- RefreshRate{configId, base::StringPrintf("%2.ffps", fps),
- static_cast<uint32_t>(fps),
- configs.at(configId)->getId()}));
- }
+ init(refreshRateSwitching, inputConfigs, currentConfig);
}
private:
- std::map<RefreshRateType, std::shared_ptr<RefreshRate>> mRefreshRates;
+ void init(bool refreshRateSwitching, const std::vector<InputConfig>& configs,
+ int currentConfig) {
+ mRefreshRateSwitchingSupported = refreshRateSwitching;
+ LOG_ALWAYS_FATAL_IF(configs.empty());
+ LOG_ALWAYS_FATAL_IF(currentConfig >= configs.size());
+ mCurrentConfig = currentConfig;
+
+ auto buildRefreshRate = [&](int configId) -> RefreshRate {
+ const nsecs_t vsyncPeriod = configs[configId].vsyncPeriod;
+ const float fps = 1e9 / vsyncPeriod;
+ return {configId, base::StringPrintf("%2.ffps", fps), static_cast<uint32_t>(fps),
+ vsyncPeriod, configs[configId].hwcId};
+ };
+
+ for (int i = 0; i < configs.size(); ++i) {
+ mRefreshRates.push_back(buildRefreshRate(i));
+ }
+
+ if (!mRefreshRateSwitchingSupported) return;
+
+ auto findDefaultAndPerfConfigs = [&]() -> std::optional<std::pair<int, int>> {
+ if (configs.size() < 2) {
+ return {};
+ }
+
+ std::vector<const RefreshRate*> sortedRefreshRates;
+ for (const auto& refreshRate : mRefreshRates) {
+ sortedRefreshRates.push_back(&refreshRate);
+ }
+ std::sort(sortedRefreshRates.begin(), sortedRefreshRates.end(),
+ [](const RefreshRate* refreshRate1, const RefreshRate* refreshRate2) {
+ return refreshRate1->vsyncPeriod > refreshRate2->vsyncPeriod;
+ });
+
+ // When the configs are ordered by the resync rate, we assume that
+ // the first one is DEFAULT and the second one is PERFORMANCE,
+ // i.e. the higher rate.
+ if (sortedRefreshRates[0]->vsyncPeriod == 0 ||
+ sortedRefreshRates[1]->vsyncPeriod == 0) {
+ return {};
+ }
+
+ return std::pair<int, int>(sortedRefreshRates[0]->configId,
+ sortedRefreshRates[1]->configId);
+ };
+
+ auto defaultAndPerfConfigs = findDefaultAndPerfConfigs();
+ if (!defaultAndPerfConfigs) {
+ mRefreshRateSwitchingSupported = false;
+ return;
+ }
+
+ mRefreshRateMap[RefreshRateType::DEFAULT] = mRefreshRates[defaultAndPerfConfigs->first];
+ mRefreshRateMap[RefreshRateType::PERFORMANCE] =
+ mRefreshRates[defaultAndPerfConfigs->second];
+ }
+
+ // Whether this device is doing refresh rate switching or not. This must not change after this
+ // object is initialized.
+ bool mRefreshRateSwitchingSupported;
+ // The list of refresh rates, indexed by display config ID. This must not change after this
+ // object is initialized.
+ std::vector<RefreshRate> mRefreshRates;
+ // The mapping of refresh rate type to RefreshRate. This must not change after this object is
+ // initialized.
+ std::map<RefreshRateType, RefreshRate> mRefreshRateMap;
+ // The ID of the current config. This will change at runtime. This is set by SurfaceFlinger on
+ // the main thread, and read by the Scheduler (and other objects) on other threads, so it's
+ // atomic.
+ std::atomic<int> mCurrentConfig;
};
} // namespace scheduler
diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h
index 7e7c630..947eb08 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateStats.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h
@@ -41,21 +41,18 @@
static constexpr int64_t MS_PER_DAY = 24 * MS_PER_HOUR;
public:
- RefreshRateStats(const RefreshRateConfigs& refreshRateConfigs, TimeStats& timeStats)
- : mRefreshRateConfigs(refreshRateConfigs), mTimeStats(timeStats) {}
+ RefreshRateStats(const RefreshRateConfigs& refreshRateConfigs, TimeStats& timeStats,
+ int currentConfigMode, int currentPowerMode)
+ : mRefreshRateConfigs(refreshRateConfigs),
+ mTimeStats(timeStats),
+ mCurrentConfigMode(currentConfigMode),
+ mCurrentPowerMode(currentPowerMode) {}
- // Sets power mode. We only collect the information when the power mode is not
- // HWC_POWER_MODE_NORMAL. When power mode is HWC_POWER_MODE_NORMAL, we collect the stats based
- // on config mode.
+ // Sets power mode.
void setPowerMode(int mode) {
if (mCurrentPowerMode == mode) {
return;
}
- // If power mode is normal, the time is going to be recorded under config modes.
- if (mode == HWC_POWER_MODE_NORMAL) {
- mCurrentPowerMode = mode;
- return;
- }
flushTime();
mCurrentPowerMode = mode;
}
@@ -79,16 +76,15 @@
flushTime();
std::unordered_map<std::string, int64_t> totalTime;
- for (const auto& [type, config] : mRefreshRateConfigs.getRefreshRates()) {
- int64_t totalTimeForConfig = 0;
- if (!config) {
- continue;
- }
- if (mConfigModesTotalTime.find(config->configId) != mConfigModesTotalTime.end()) {
- totalTimeForConfig = mConfigModesTotalTime.at(config->configId);
- }
- totalTime[config->name] = totalTimeForConfig;
+ // Multiple configs may map to the same name, e.g. "60fps". Add the
+ // times for such configs together.
+ for (const auto& [config, time] : mConfigModesTotalTime) {
+ totalTime[mRefreshRateConfigs.getRefreshRateFromConfigId(config).name] = 0;
}
+ for (const auto& [config, time] : mConfigModesTotalTime) {
+ totalTime[mRefreshRateConfigs.getRefreshRateFromConfigId(config).name] += time;
+ }
+ totalTime["ScreenOff"] = mScreenOffTime;
return totalTime;
}
@@ -104,32 +100,26 @@
}
private:
- void flushTime() {
- // Normal power mode is counted under different config modes.
- if (mCurrentPowerMode == HWC_POWER_MODE_NORMAL) {
- flushTimeForMode(mCurrentConfigMode);
- } else {
- flushTimeForMode(SCREEN_OFF_CONFIG_ID);
- }
- }
-
// Calculates the time that passed in ms between the last time we recorded time and the time
// this method was called.
- void flushTimeForMode(int mode) {
+ void flushTime() {
nsecs_t currentTime = systemTime();
nsecs_t timeElapsed = currentTime - mPreviousRecordedTime;
int64_t timeElapsedMs = ns2ms(timeElapsed);
mPreviousRecordedTime = currentTime;
- mConfigModesTotalTime[mode] += timeElapsedMs;
- for (const auto& [type, config] : mRefreshRateConfigs.getRefreshRates()) {
- if (!config) {
- continue;
+ uint32_t fps = 0;
+ if (mCurrentPowerMode == HWC_POWER_MODE_NORMAL) {
+ // Normal power mode is counted under different config modes.
+ if (mConfigModesTotalTime.find(mCurrentConfigMode) == mConfigModesTotalTime.end()) {
+ mConfigModesTotalTime[mCurrentConfigMode] = 0;
}
- if (config->configId == mode) {
- mTimeStats.recordRefreshRate(config->fps, timeElapsed);
- }
+ mConfigModesTotalTime[mCurrentConfigMode] += timeElapsedMs;
+ fps = mRefreshRateConfigs.getRefreshRateFromConfigId(mCurrentConfigMode).fps;
+ } else {
+ mScreenOffTime += timeElapsedMs;
}
+ mTimeStats.recordRefreshRate(fps, timeElapsed);
}
// Formats the time in milliseconds into easy to read format.
@@ -149,10 +139,11 @@
// Aggregate refresh rate statistics for telemetry.
TimeStats& mTimeStats;
- int64_t mCurrentConfigMode = SCREEN_OFF_CONFIG_ID;
- int32_t mCurrentPowerMode = HWC_POWER_MODE_OFF;
+ int mCurrentConfigMode;
+ int32_t mCurrentPowerMode;
- std::unordered_map<int /* power mode */, int64_t /* duration in ms */> mConfigModesTotalTime;
+ std::unordered_map<int /* config */, int64_t /* duration in ms */> mConfigModesTotalTime;
+ int64_t mScreenOffTime = 0;
nsecs_t mPreviousRecordedTime = systemTime();
};
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 8da5612..b2c069e 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -133,7 +133,6 @@
sp<Scheduler::ConnectionHandle> Scheduler::createConnection(
const char* connectionName, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync,
- ResyncCallback resyncCallback,
impl::EventThread::InterceptVSyncsCallback interceptCallback) {
const int64_t id = sNextId++;
ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id);
@@ -143,8 +142,7 @@
offsetThresholdForNextVsync, std::move(interceptCallback));
auto eventThreadConnection =
- createConnectionInternal(eventThread.get(), std::move(resyncCallback),
- ISurfaceComposer::eConfigChangedSuppress);
+ createConnectionInternal(eventThread.get(), ISurfaceComposer::eConfigChangedSuppress);
mConnections.emplace(id,
std::make_unique<Connection>(new ConnectionHandle(id),
eventThreadConnection,
@@ -164,17 +162,15 @@
}
sp<EventThreadConnection> Scheduler::createConnectionInternal(
- EventThread* eventThread, ResyncCallback&& resyncCallback,
- ISurfaceComposer::ConfigChanged configChanged) {
- return eventThread->createEventConnection(std::move(resyncCallback), configChanged);
+ EventThread* eventThread, ISurfaceComposer::ConfigChanged configChanged) {
+ return eventThread->createEventConnection([&] { resync(); }, configChanged);
}
sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
- const sp<Scheduler::ConnectionHandle>& handle, ResyncCallback resyncCallback,
+ const sp<Scheduler::ConnectionHandle>& handle,
ISurfaceComposer::ConfigChanged configChanged) {
RETURN_VALUE_IF_INVALID(nullptr);
- return createConnectionInternal(mConnections[handle->id]->thread.get(),
- std::move(resyncCallback), configChanged);
+ return createConnectionInternal(mConnections[handle->id]->thread.get(), configChanged);
}
EventThread* Scheduler::getEventThread(const sp<Scheduler::ConnectionHandle>& handle) {
@@ -264,23 +260,15 @@
setVsyncPeriod(period);
}
-ResyncCallback Scheduler::makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod) {
- std::weak_ptr<VsyncState> ptr = mPrimaryVsyncState;
- return [ptr, getVsyncPeriod = std::move(getVsyncPeriod)]() {
- if (const auto vsync = ptr.lock()) {
- vsync->resync(getVsyncPeriod);
- }
- };
-}
-
-void Scheduler::VsyncState::resync(const GetVsyncPeriod& getVsyncPeriod) {
+void Scheduler::resync() {
static constexpr nsecs_t kIgnoreDelay = ms2ns(750);
const nsecs_t now = systemTime();
- const nsecs_t last = lastResyncTime.exchange(now);
+ const nsecs_t last = mLastResyncTime.exchange(now);
if (now - last > kIgnoreDelay) {
- scheduler.resyncToHardwareVsync(false, getVsyncPeriod());
+ resyncToHardwareVsync(false,
+ mRefreshRateConfigs.getCurrentRefreshRate().second.vsyncPeriod);
}
}
@@ -338,15 +326,19 @@
std::unique_ptr<scheduler::LayerHistory::LayerHandle> Scheduler::registerLayer(
std::string const& name, int windowType) {
- RefreshRateType refreshRateType = (windowType == InputWindowInfo::TYPE_WALLPAPER)
- ? RefreshRateType::DEFAULT
- : RefreshRateType::PERFORMANCE;
-
- const auto refreshRate = mRefreshRateConfigs.getRefreshRate(refreshRateType);
- const uint32_t performanceFps = (refreshRate) ? refreshRate->fps : 0;
-
- const auto defaultRefreshRate = mRefreshRateConfigs.getRefreshRate(RefreshRateType::DEFAULT);
- const uint32_t defaultFps = (defaultRefreshRate) ? defaultRefreshRate->fps : 0;
+ uint32_t defaultFps, performanceFps;
+ if (mRefreshRateConfigs.refreshRateSwitchingSupported()) {
+ defaultFps = mRefreshRateConfigs.getRefreshRateFromType(RefreshRateType::DEFAULT).fps;
+ performanceFps =
+ mRefreshRateConfigs
+ .getRefreshRateFromType((windowType == InputWindowInfo::TYPE_WALLPAPER)
+ ? RefreshRateType::DEFAULT
+ : RefreshRateType::PERFORMANCE)
+ .fps;
+ } else {
+ defaultFps = mRefreshRateConfigs.getCurrentRefreshRate().second.fps;
+ performanceFps = defaultFps;
+ }
return mLayerHistory.createLayer(name, defaultFps, performanceFps);
}
@@ -398,17 +390,6 @@
mChangeRefreshRateCallback = changeRefreshRateCallback;
}
-void Scheduler::setGetCurrentRefreshRateTypeCallback(
- const GetCurrentRefreshRateTypeCallback&& getCurrentRefreshRateTypeCallback) {
- std::lock_guard<std::mutex> lock(mCallbackLock);
- mGetCurrentRefreshRateTypeCallback = getCurrentRefreshRateTypeCallback;
-}
-
-void Scheduler::setGetVsyncPeriodCallback(const GetVsyncPeriod&& getVsyncPeriod) {
- std::lock_guard<std::mutex> lock(mCallbackLock);
- mGetVsyncPeriod = getVsyncPeriod;
-}
-
void Scheduler::updateFrameSkipping(const int64_t skipCount) {
ATRACE_INT("FrameSkipCount", skipCount);
if (mSkipCount != skipCount) {
@@ -460,14 +441,12 @@
void Scheduler::resetKernelTimerCallback() {
ATRACE_INT("ExpiredKernelIdleTimer", 0);
- std::lock_guard<std::mutex> lock(mCallbackLock);
- if (mGetVsyncPeriod && mGetCurrentRefreshRateTypeCallback) {
+ const auto refreshRate = mRefreshRateConfigs.getCurrentRefreshRate();
+ if (refreshRate.first == RefreshRateType::PERFORMANCE) {
// If we're not in performance mode then the kernel timer shouldn't do
// anything, as the refresh rate during DPU power collapse will be the
// same.
- if (mGetCurrentRefreshRateTypeCallback() == Scheduler::RefreshRateType::PERFORMANCE) {
- resyncToHardwareVsync(true, mGetVsyncPeriod());
- }
+ resyncToHardwareVsync(true, refreshRate.second.vsyncPeriod);
}
}
@@ -497,15 +476,13 @@
}
void Scheduler::expiredKernelTimerCallback() {
- std::lock_guard<std::mutex> lock(mCallbackLock);
ATRACE_INT("ExpiredKernelIdleTimer", 1);
- if (mGetCurrentRefreshRateTypeCallback) {
- if (mGetCurrentRefreshRateTypeCallback() != Scheduler::RefreshRateType::PERFORMANCE) {
- // Disable HW Vsync if the timer expired, as we don't need it
- // enabled if we're not pushing frames, and if we're in PERFORMANCE
- // mode then we'll need to re-update the DispSync model anyways.
- disableHardwareVsync(false);
- }
+ const auto refreshRate = mRefreshRateConfigs.getCurrentRefreshRate();
+ if (refreshRate.first != RefreshRateType::PERFORMANCE) {
+ // Disable HW Vsync if the timer expired, as we don't need it
+ // enabled if we're not pushing frames, and if we're in PERFORMANCE
+ // mode then we'll need to re-update the DispSync model anyways.
+ disableHardwareVsync(false);
}
}
@@ -540,6 +517,10 @@
}
Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() {
+ if (!mRefreshRateConfigs.refreshRateSwitchingSupported()) {
+ return RefreshRateType::DEFAULT;
+ }
+
// HDR content is not supported on PERFORMANCE mode
if (mForceHDRContentToDefaultRefreshRate && mIsHDRContent) {
return RefreshRateType::DEFAULT;
@@ -567,16 +548,12 @@
}
// Content detection is on, find the appropriate refresh rate with minimal error
- auto begin = mRefreshRateConfigs.getRefreshRates().cbegin();
+ auto begin = mRefreshRateConfigs.getRefreshRateMap().cbegin();
- // Skip POWER_SAVING config as it is not a real config
- if (begin->first == RefreshRateType::POWER_SAVING) {
- ++begin;
- }
- auto iter = min_element(begin, mRefreshRateConfigs.getRefreshRates().cend(),
+ auto iter = min_element(begin, mRefreshRateConfigs.getRefreshRateMap().cend(),
[rate = mContentRefreshRate](const auto& l, const auto& r) -> bool {
- return std::abs(l.second->fps - static_cast<float>(rate)) <
- std::abs(r.second->fps - static_cast<float>(rate));
+ return std::abs(l.second.fps - static_cast<float>(rate)) <
+ std::abs(r.second.fps - static_cast<float>(rate));
});
RefreshRateType currRefreshRateType = iter->first;
@@ -584,11 +561,11 @@
// 90Hz config. However we should still prefer a lower refresh rate if the content doesn't
// align well with both
constexpr float MARGIN = 0.05f;
- float ratio = mRefreshRateConfigs.getRefreshRate(currRefreshRateType)->fps /
+ float ratio = mRefreshRateConfigs.getRefreshRateFromType(currRefreshRateType).fps /
float(mContentRefreshRate);
if (std::abs(std::round(ratio) - ratio) > MARGIN) {
- while (iter != mRefreshRateConfigs.getRefreshRates().cend()) {
- ratio = iter->second->fps / float(mContentRefreshRate);
+ while (iter != mRefreshRateConfigs.getRefreshRateMap().cend()) {
+ ratio = iter->second.fps / float(mContentRefreshRate);
if (std::abs(std::round(ratio) - ratio) <= MARGIN) {
currRefreshRateType = iter->first;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 5d8bb4c..da0a015 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -49,9 +49,7 @@
}
using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
- using GetCurrentRefreshRateTypeCallback = std::function<RefreshRateType()>;
using ChangeRefreshRateCallback = std::function<void(RefreshRateType, ConfigEvent)>;
- using GetVsyncPeriod = std::function<nsecs_t()>;
// Enum to indicate whether to start the transaction early, or at vsync time.
enum class TransactionStart { EARLY, NORMAL };
@@ -81,16 +79,6 @@
const std::unique_ptr<EventThread> thread;
};
- // Stores per-display state about VSYNC.
- struct VsyncState {
- explicit VsyncState(Scheduler& scheduler) : scheduler(scheduler) {}
-
- void resync(const GetVsyncPeriod&);
-
- Scheduler& scheduler;
- std::atomic<nsecs_t> lastResyncTime = 0;
- };
-
explicit Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function,
const scheduler::RefreshRateConfigs& refreshRateConfig);
@@ -98,12 +86,11 @@
/** Creates an EventThread connection. */
sp<ConnectionHandle> createConnection(const char* connectionName, nsecs_t phaseOffsetNs,
- nsecs_t offsetThresholdForNextVsync, ResyncCallback,
+ nsecs_t offsetThresholdForNextVsync,
impl::EventThread::InterceptVSyncsCallback);
sp<IDisplayEventConnection> createDisplayEventConnection(
- const sp<ConnectionHandle>& handle, ResyncCallback,
- ISurfaceComposer::ConfigChanged configChanged);
+ const sp<ConnectionHandle>& handle, ISurfaceComposer::ConfigChanged configChanged);
// Getter methods.
EventThread* getEventThread(const sp<ConnectionHandle>& handle);
@@ -143,8 +130,7 @@
// no-op.
// The period is the vsync period from the current display configuration.
void resyncToHardwareVsync(bool makeAvailable, nsecs_t period);
- // Creates a callback for resyncing.
- ResyncCallback makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod);
+ void resync();
void setRefreshSkipCount(int count);
// Passes a vsync sample to DispSync. periodFlushed will be true if
// DispSync detected that the vsync period changed, and false otherwise.
@@ -167,9 +153,6 @@
void updateFpsBasedOnContent();
// Callback that gets invoked when Scheduler wants to change the refresh rate.
void setChangeRefreshRateCallback(const ChangeRefreshRateCallback&& changeRefreshRateCallback);
- void setGetCurrentRefreshRateTypeCallback(
- const GetCurrentRefreshRateTypeCallback&& getCurrentRefreshRateType);
- void setGetVsyncPeriodCallback(const GetVsyncPeriod&& getVsyncPeriod);
// Returns whether idle timer is enabled or not
bool isIdleTimerEnabled() { return mSetIdleTimerMs > 0; }
@@ -206,7 +189,7 @@
enum class DisplayPowerTimerState { EXPIRED, RESET };
// Creates a connection on the given EventThread and forwards the given callbacks.
- sp<EventThreadConnection> createConnectionInternal(EventThread*, ResyncCallback&&,
+ sp<EventThreadConnection> createConnectionInternal(EventThread*,
ISurfaceComposer::ConfigChanged);
nsecs_t calculateAverage() const;
@@ -261,7 +244,8 @@
std::mutex mHWVsyncLock;
bool mPrimaryHWVsyncEnabled GUARDED_BY(mHWVsyncLock);
bool mHWVsyncAvailable GUARDED_BY(mHWVsyncLock);
- const std::shared_ptr<VsyncState> mPrimaryVsyncState{std::make_shared<VsyncState>(*this)};
+
+ std::atomic<nsecs_t> mLastResyncTime = 0;
std::unique_ptr<DispSync> mPrimaryDispSync;
std::unique_ptr<EventControlThread> mEventControlThread;
@@ -297,9 +281,7 @@
std::unique_ptr<scheduler::IdleTimer> mDisplayPowerTimer;
std::mutex mCallbackLock;
- GetCurrentRefreshRateTypeCallback mGetCurrentRefreshRateTypeCallback GUARDED_BY(mCallbackLock);
ChangeRefreshRateCallback mChangeRefreshRateCallback GUARDED_BY(mCallbackLock);
- GetVsyncPeriod mGetVsyncPeriod GUARDED_BY(mCallbackLock);
// In order to make sure that the features don't override themselves, we need a state machine
// to keep track which feature requested the config change.
diff --git a/services/surfaceflinger/Scheduler/SchedulerUtils.h b/services/surfaceflinger/Scheduler/SchedulerUtils.h
index ac10f83..f193553 100644
--- a/services/surfaceflinger/Scheduler/SchedulerUtils.h
+++ b/services/surfaceflinger/Scheduler/SchedulerUtils.h
@@ -30,12 +30,6 @@
// about layers.
static constexpr size_t ARRAY_SIZE = 30;
-// This number is used to have a place holder for when the screen is not NORMAL/ON. Currently
-// the config is not visible to SF, and is completely maintained by HWC. However, we would
-// still like to keep track of time when the device is in this config.
-static constexpr int SCREEN_OFF_CONFIG_ID = -1;
-static constexpr uint32_t HWC2_SCREEN_OFF_CONFIG_ID = 0xffffffff;
-
// This number is used when we try to determine how long do we keep layer information around
// before we remove it. It is also used to determine how long the layer stays relevant.
// This time period captures infrequent updates when playing YouTube video with static image,
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 30b3801..60b3cf0 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -569,14 +569,16 @@
readPersistentProperties();
mBootStage = BootStage::FINISHED;
- // set the refresh rate according to the policy
- const auto& performanceRefreshRate =
- mRefreshRateConfigs.getRefreshRate(RefreshRateType::PERFORMANCE);
+ if (mRefreshRateConfigs->refreshRateSwitchingSupported()) {
+ // set the refresh rate according to the policy
+ const auto& performanceRefreshRate =
+ mRefreshRateConfigs->getRefreshRateFromType(RefreshRateType::PERFORMANCE);
- if (performanceRefreshRate && isDisplayConfigAllowed(performanceRefreshRate->configId)) {
- setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::Changed);
- } else {
- setRefreshRateTo(RefreshRateType::DEFAULT, Scheduler::ConfigEvent::Changed);
+ if (isDisplayConfigAllowed(performanceRefreshRate.configId)) {
+ setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::Changed);
+ } else {
+ setRefreshRateTo(RefreshRateType::DEFAULT, Scheduler::ConfigEvent::Changed);
+ }
}
}));
}
@@ -619,32 +621,6 @@
ALOGI("Phase offset NS: %" PRId64 "", mPhaseOffsets->getCurrentAppOffset());
Mutex::Autolock _l(mStateLock);
- // start the EventThread
- mScheduler =
- getFactory().createScheduler([this](bool enabled) { setPrimaryVsyncEnabled(enabled); },
- mRefreshRateConfigs);
- auto resyncCallback =
- mScheduler->makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this));
-
- mAppConnectionHandle =
- mScheduler->createConnection("app", mVsyncModulator.getOffsets().app,
- mPhaseOffsets->getOffsetThresholdForNextVsync(),
- resyncCallback,
- impl::EventThread::InterceptVSyncsCallback());
- mSfConnectionHandle =
- mScheduler->createConnection("sf", mVsyncModulator.getOffsets().sf,
- mPhaseOffsets->getOffsetThresholdForNextVsync(),
- resyncCallback, [this](nsecs_t timestamp) {
- mInterceptor->saveVSyncEvent(timestamp);
- });
-
- mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle));
- mVsyncModulator.setSchedulerAndHandles(mScheduler.get(), mAppConnectionHandle.get(),
- mSfConnectionHandle.get());
-
- mRegionSamplingThread =
- new RegionSamplingThread(*this, *mScheduler,
- RegionSamplingThread::EnvironmentTimingTunables());
// Get a RenderEngine for the given display / config (can't fail)
int32_t renderEngineFeature = 0;
@@ -715,37 +691,6 @@
ALOGE("Run StartPropertySetThread failed!");
}
- mScheduler->setChangeRefreshRateCallback(
- [this](RefreshRateType type, Scheduler::ConfigEvent event) {
- Mutex::Autolock lock(mStateLock);
- setRefreshRateTo(type, event);
- });
- mScheduler->setGetCurrentRefreshRateTypeCallback([this] {
- Mutex::Autolock lock(mStateLock);
- const auto display = getDefaultDisplayDeviceLocked();
- if (!display) {
- // If we don't have a default display the fallback to the default
- // refresh rate type
- return RefreshRateType::DEFAULT;
- }
-
- const int configId = display->getActiveConfig();
- for (const auto& [type, refresh] : mRefreshRateConfigs.getRefreshRates()) {
- if (refresh && refresh->configId == configId) {
- return type;
- }
- }
- // This should never happen, but just gracefully fallback to default.
- return RefreshRateType::DEFAULT;
- });
- mScheduler->setGetVsyncPeriodCallback([this] {
- Mutex::Autolock lock(mStateLock);
- return getVsyncPeriod();
- });
-
- mRefreshRateConfigs.populate(getHwComposer().getConfigs(*display->getId()));
- mRefreshRateStats.setConfigMode(getHwComposer().getActiveConfigIndex(*display->getId()));
-
ALOGV("Done initializing");
}
@@ -899,7 +844,8 @@
info.xdpi = xdpi;
info.ydpi = ydpi;
info.fps = 1e9 / hwConfig->getVsyncPeriod();
- const auto refreshRateType = mRefreshRateConfigs.getRefreshRateType(hwConfig->getId());
+ const auto refreshRateType =
+ mRefreshRateConfigs->getRefreshRateTypeFromHwcConfigId(hwConfig->getId());
const auto offset = mPhaseOffsets->getOffsetsForRefreshRate(refreshRateType);
info.appVsyncOffset = offset.late.app;
@@ -1001,7 +947,8 @@
}
std::lock_guard<std::mutex> lock(mActiveConfigLock);
- mRefreshRateStats.setConfigMode(mUpcomingActiveConfig.configId);
+ mRefreshRateConfigs->setCurrentConfig(mUpcomingActiveConfig.configId);
+ mRefreshRateStats->setConfigMode(mUpcomingActiveConfig.configId);
display->setActiveConfig(mUpcomingActiveConfig.configId);
@@ -1280,9 +1227,6 @@
return;
}
- auto resyncCallback =
- mScheduler->makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this));
-
// TODO(b/128863962): Part of the Injector should be refactored, so that it
// can be passed to Scheduler.
if (enable) {
@@ -1294,11 +1238,11 @@
impl::EventThread::InterceptVSyncsCallback(),
"injEventThread");
}
- mEventQueue->setEventThread(mInjectorEventThread.get(), std::move(resyncCallback));
+ mEventQueue->setEventThread(mInjectorEventThread.get(), [&] { mScheduler->resync(); });
} else {
ALOGV("VSync Injections disabled");
mEventQueue->setEventThread(mScheduler->getEventThread(mSfConnectionHandle),
- std::move(resyncCallback));
+ [&] { mScheduler->resync(); });
}
mInjectVSyncs = enable;
@@ -1409,16 +1353,10 @@
sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
ISurfaceComposer::VsyncSource vsyncSource, ISurfaceComposer::ConfigChanged configChanged) {
- auto resyncCallback = mScheduler->makeResyncCallback([this] {
- Mutex::Autolock lock(mStateLock);
- return getVsyncPeriod();
- });
-
const auto& handle =
vsyncSource == eVsyncSourceSurfaceFlinger ? mSfConnectionHandle : mAppConnectionHandle;
- return mScheduler->createDisplayEventConnection(handle, std::move(resyncCallback),
- configChanged);
+ return mScheduler->createDisplayEventConnection(handle, configChanged);
}
// ----------------------------------------------------------------------------
@@ -1515,13 +1453,8 @@
ATRACE_CALL();
// Don't do any updating if the current fps is the same as the new one.
- const auto& refreshRateConfig = mRefreshRateConfigs.getRefreshRate(refreshRate);
- if (!refreshRateConfig) {
- ALOGV("Skipping refresh rate change request for unsupported rate.");
- return;
- }
-
- const int desiredConfigId = refreshRateConfig->configId;
+ const auto& refreshRateConfig = mRefreshRateConfigs->getRefreshRateFromType(refreshRate);
+ const int desiredConfigId = refreshRateConfig.configId;
if (!isDisplayConfigAllowed(desiredConfigId)) {
ALOGV("Skipping config %d as it is not part of allowed configs", desiredConfigId);
@@ -2629,6 +2562,9 @@
if (event.connection == HWC2::Connection::Connected) {
if (!mPhysicalDisplayTokens.count(info->id)) {
ALOGV("Creating display %s", to_string(info->id).c_str());
+ if (event.hwcDisplayId == getHwComposer().getInternalHwcDisplayId()) {
+ initScheduler(info->id);
+ }
mPhysicalDisplayTokens[info->id] = new BBinder();
DisplayDeviceState state;
state.displayId = info->id;
@@ -3074,6 +3010,55 @@
layer->releasePendingBuffer(systemTime());
}
+void SurfaceFlinger::initScheduler(DisplayId primaryDisplayId) {
+ 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;
+ }
+
+ int currentConfig = getHwComposer().getActiveConfigIndex(primaryDisplayId);
+ mRefreshRateConfigs =
+ std::make_unique<scheduler::RefreshRateConfigs>(refresh_rate_switching(false),
+ getHwComposer().getConfigs(
+ primaryDisplayId),
+ currentConfig);
+ mRefreshRateStats =
+ std::make_unique<scheduler::RefreshRateStats>(*mRefreshRateConfigs, *mTimeStats,
+ currentConfig, HWC_POWER_MODE_OFF);
+ mRefreshRateStats->setConfigMode(currentConfig);
+
+ // start the EventThread
+ mScheduler =
+ getFactory().createScheduler([this](bool enabled) { setPrimaryVsyncEnabled(enabled); },
+ *mRefreshRateConfigs);
+ mAppConnectionHandle =
+ mScheduler->createConnection("app", mVsyncModulator.getOffsets().app,
+ mPhaseOffsets->getOffsetThresholdForNextVsync(),
+ impl::EventThread::InterceptVSyncsCallback());
+ mSfConnectionHandle =
+ mScheduler->createConnection("sf", mVsyncModulator.getOffsets().sf,
+ mPhaseOffsets->getOffsetThresholdForNextVsync(),
+ [this](nsecs_t timestamp) {
+ mInterceptor->saveVSyncEvent(timestamp);
+ });
+
+ mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle));
+ mVsyncModulator.setSchedulerAndHandles(mScheduler.get(), mAppConnectionHandle.get(),
+ mSfConnectionHandle.get());
+
+ mRegionSamplingThread =
+ new RegionSamplingThread(*this, *mScheduler,
+ RegionSamplingThread::EnvironmentTimingTunables());
+
+ mScheduler->setChangeRefreshRateCallback(
+ [this](RefreshRateType type, Scheduler::ConfigEvent event) {
+ Mutex::Autolock lock(mStateLock);
+ setRefreshRateTo(type, event);
+ });
+}
+
void SurfaceFlinger::commitTransaction()
{
if (!mLayersPendingRemoval.isEmpty()) {
@@ -4596,7 +4581,7 @@
if (display->isPrimary()) {
mTimeStats->setPowerMode(mode);
- mRefreshRateStats.setPowerMode(mode);
+ mRefreshRateStats->setPowerMode(mode);
mScheduler->setDisplayPowerState(mode == HWC_POWER_MODE_NORMAL);
}
@@ -4768,15 +4753,14 @@
mUseSmart90ForVideo ? "on" : "off");
StringAppendF(&result, "Allowed Display Configs: ");
for (int32_t configId : mAllowedDisplayConfigs) {
- for (auto refresh : mRefreshRateConfigs.getRefreshRates()) {
- if (refresh.second && refresh.second->configId == configId) {
- StringAppendF(&result, "%dHz, ", refresh.second->fps);
- }
- }
+ StringAppendF(&result, "%" PRIu32 " Hz, ",
+ mRefreshRateConfigs->getRefreshRateFromConfigId(configId).fps);
}
StringAppendF(&result, "(config override by backdoor: %s)\n\n",
mDebugDisplayConfigSetByBackdoor ? "yes" : "no");
mScheduler->dump(mAppConnectionHandle, result);
+ StringAppendF(&result, "+ Refresh rate switching: %s\n",
+ mRefreshRateConfigs->refreshRateSwitchingSupported() ? "on" : "off");
}
void SurfaceFlinger::dumpStaticScreenStats(std::string& result) const {
@@ -5138,7 +5122,7 @@
result.append("\nScheduler state:\n");
result.append(mScheduler->doDump() + "\n");
StringAppendF(&result, "+ Smart video mode: %s\n\n", mUseSmart90ForVideo ? "on" : "off");
- result.append(mRefreshRateStats.doDump() + "\n");
+ result.append(mRefreshRateStats->doDump() + "\n");
result.append(mTimeStats->miniDump());
result.append("\n");
@@ -5609,7 +5593,8 @@
case 1034: {
// TODO(b/129297325): expose this via developer menu option
n = data.readInt32();
- if (n && !mRefreshRateOverlay) {
+ if (n && !mRefreshRateOverlay &&
+ mRefreshRateConfigs->refreshRateSwitchingSupported()) {
RefreshRateType type;
{
std::lock_guard<std::mutex> lock(mActiveConfigLock);
@@ -6208,15 +6193,21 @@
mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value,
display->getActiveConfig());
- // Set the highest allowed config by iterating backwards on available refresh rates
- const auto& refreshRates = mRefreshRateConfigs.getRefreshRates();
- for (auto iter = refreshRates.crbegin(); iter != refreshRates.crend(); ++iter) {
- if (iter->second && isDisplayConfigAllowed(iter->second->configId)) {
- ALOGV("switching to config %d", iter->second->configId);
- setDesiredActiveConfig(
- {iter->first, iter->second->configId, Scheduler::ConfigEvent::Changed});
- break;
+ if (mRefreshRateConfigs->refreshRateSwitchingSupported()) {
+ // Set the highest allowed config by iterating backwards on available refresh rates
+ const auto& refreshRates = mRefreshRateConfigs->getRefreshRateMap();
+ for (auto iter = refreshRates.crbegin(); iter != refreshRates.crend(); ++iter) {
+ if (isDisplayConfigAllowed(iter->second.configId)) {
+ ALOGV("switching to allowed config %d", iter->second.configId);
+ setDesiredActiveConfig(
+ {iter->first, iter->second.configId, Scheduler::ConfigEvent::Changed});
+ break;
+ }
}
+ } else if (!isDisplayConfigAllowed(display->getActiveConfig())) {
+ ALOGV("switching to config %d", allowedConfigs[0]);
+ setDesiredActiveConfig(
+ {RefreshRateType::DEFAULT, allowedConfigs[0], Scheduler::ConfigEvent::Changed});
}
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 8e4203a..316a48c 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -556,6 +556,7 @@
void commitInputWindowCommands() REQUIRES(mStateLock);
void setInputWindowsFinished();
void updateCursorAsync();
+ void initScheduler(DisplayId primaryDisplayId);
/* handlePageFlip - latch a new buffer if available and compute the dirty
* region. Returns whether a new buffer has been latched, i.e., whether it
@@ -1137,8 +1138,8 @@
sp<Scheduler::ConnectionHandle> mAppConnectionHandle;
sp<Scheduler::ConnectionHandle> mSfConnectionHandle;
- scheduler::RefreshRateConfigs mRefreshRateConfigs;
- scheduler::RefreshRateStats mRefreshRateStats{mRefreshRateConfigs, *mTimeStats};
+ std::unique_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs;
+ std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats;
// All configs are allowed if the set is empty.
using DisplayConfigs = std::set<int32_t>;
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp
index 768074a..b4716eb 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.cpp
+++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp
@@ -226,6 +226,14 @@
return static_cast<int64_t>(defaultValue);
}
+bool refresh_rate_switching(bool defaultValue) {
+ auto temp = SurfaceFlingerProperties::refresh_rate_switching();
+ if (temp.has_value()) {
+ return *temp;
+ }
+ return defaultValue;
+}
+
int32_t set_idle_timer_ms(int32_t defaultValue) {
auto temp = SurfaceFlingerProperties::set_idle_timer_ms();
if (temp.has_value()) {
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h
index 5f88322..e394cca 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.h
+++ b/services/surfaceflinger/SurfaceFlingerProperties.h
@@ -73,6 +73,8 @@
int64_t color_space_agnostic_dataspace(
android::hardware::graphics::common::V1_2::Dataspace defaultValue);
+bool refresh_rate_switching(bool defaultValue);
+
int32_t set_idle_timer_ms(int32_t defaultValue);
int32_t set_touch_timer_ms(int32_t defaultValue);
diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
index a4f4285..ef43440 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -15,7 +15,7 @@
module: "android.sysprop.SurfaceFlingerProperties"
owner: Platform
-# The following two propertiess define (respectively):
+# The following two properties define (respectively):
#
# - The phase offset between hardware vsync and when apps are woken up by the
# Choreographer callback
@@ -301,6 +301,18 @@
prop_name: "ro.surface_flinger.display_primary_white"
}
+# refreshRateSwitching indicates whether SurfaceFlinger should use refresh rate
+# switching on the device, e.g. to switch between 60 and 90 Hz. The settings
+# below that are related to refresh rate switching will only have an effect if
+# refresh_rate_switching is enabled.
+prop {
+ api_name: "refresh_rate_switching"
+ type: Boolean
+ scope: System
+ access: Readonly
+ prop_name: "ro.surface_flinger.refresh_rate_switching"
+}
+
# setIdleTimerMs indicates what is considered a timeout in milliseconds for Scheduler. This value is
# used by the Scheduler to trigger inactivity callbacks that will switch the display to a lower
# refresh rate. Setting this property to 0 means there is no timer.
diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
index b66e56e..2d52507 100644
--- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
+++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
@@ -73,6 +73,10 @@
enum_values: "ORIENTATION_0|ORIENTATION_90|ORIENTATION_180|ORIENTATION_270"
}
prop {
+ api_name: "refresh_rate_switching"
+ prop_name: "ro.surface_flinger.refresh_rate_switching"
+ }
+ prop {
api_name: "running_without_sync_framework"
prop_name: "ro.surface_flinger.running_without_sync_framework"
}
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 4f8ed1a..349dd3f 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -125,7 +125,17 @@
}
void setupScheduler() {
- mScheduler = new TestableScheduler(mFlinger.mutableRefreshRateConfigs());
+ std::vector<scheduler::RefreshRateConfigs::InputConfig> configs{{/*hwcId=*/0, 16666667}};
+ mFlinger.mutableRefreshRateConfigs() =
+ std::make_unique<scheduler::RefreshRateConfigs>(/*refreshRateSwitching=*/false,
+ configs,
+ /*currentConfig=*/0);
+ mFlinger.mutableRefreshRateStats() =
+ std::make_unique<scheduler::RefreshRateStats>(*mFlinger.mutableRefreshRateConfigs(),
+ *mFlinger.mutableTimeStats(),
+ /*currentConfig=*/0,
+ /*powerMode=*/HWC_POWER_MODE_OFF);
+ mScheduler = new TestableScheduler(*mFlinger.mutableRefreshRateConfigs());
mScheduler->mutableEventControlThread().reset(mEventControlThread);
mScheduler->mutablePrimaryDispSync().reset(mPrimaryDispSync);
EXPECT_CALL(*mEventThread.get(), registerDisplayEventConnection(_));
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 5f58e7d..f40996e 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -29,6 +29,7 @@
#include <ui/DebugUtils.h>
#include "DisplayIdentificationTest.h"
+#include "Scheduler/RefreshRateConfigs.h"
#include "TestableScheduler.h"
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
@@ -179,7 +180,16 @@
}
void DisplayTransactionTest::setupScheduler() {
- mScheduler = new TestableScheduler(mFlinger.mutableRefreshRateConfigs());
+ std::vector<scheduler::RefreshRateConfigs::InputConfig> configs{{/*hwcId=*/0, 16666667}};
+ mFlinger.mutableRefreshRateConfigs() =
+ std::make_unique<scheduler::RefreshRateConfigs>(/*refreshRateSwitching=*/false, configs,
+ /*currentConfig=*/0);
+ mFlinger.mutableRefreshRateStats() =
+ std::make_unique<scheduler::RefreshRateStats>(*mFlinger.mutableRefreshRateConfigs(),
+ *mFlinger.mutableTimeStats(),
+ /*currentConfig=*/0,
+ /*powerMode=*/HWC_POWER_MODE_OFF);
+ mScheduler = new TestableScheduler(*mFlinger.mutableRefreshRateConfigs());
mScheduler->mutableEventControlThread().reset(mEventControlThread);
mScheduler->mutablePrimaryDispSync().reset(mPrimaryDispSync);
EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_));
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 5067fe8..f315a8a 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -23,7 +23,6 @@
#include "DisplayHardware/HWC2.h"
#include "Scheduler/RefreshRateConfigs.h"
-#include "mock/DisplayHardware/MockDisplay.h"
using namespace std::chrono_literals;
using testing::_;
@@ -50,9 +49,8 @@
ASSERT_EQ(left.configId, right.configId);
ASSERT_EQ(left.name, right.name);
ASSERT_EQ(left.fps, right.fps);
+ ASSERT_EQ(left.vsyncPeriod, right.vsyncPeriod);
}
-
- RefreshRateConfigs mConfigs;
};
RefreshRateConfigsTest::RefreshRateConfigsTest() {
@@ -71,101 +69,39 @@
/* ------------------------------------------------------------------------
* Test cases
*/
-TEST_F(RefreshRateConfigsTest, zeroDeviceConfigs_storesPowerSavingConfig) {
- std::vector<std::shared_ptr<const HWC2::Display::Config>> displayConfigs;
- mConfigs.populate(displayConfigs);
-
- // We always store a configuration for screen off.
- const auto& rates = mConfigs.getRefreshRates();
- ASSERT_EQ(1, rates.size());
- const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING);
- ASSERT_NE(rates.end(), powerSavingRate);
- ASSERT_EQ(rates.end(), rates.find(RefreshRateType::PERFORMANCE));
- ASSERT_EQ(rates.end(), rates.find(RefreshRateType::DEFAULT));
-
- RefreshRate expectedConfig =
- RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0, HWC2_SCREEN_OFF_CONFIG_ID};
- assertRatesEqual(expectedConfig, *powerSavingRate->second);
-
- ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING));
- assertRatesEqual(expectedConfig, *mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING));
- ASSERT_FALSE(mConfigs.getRefreshRate(RefreshRateType::PERFORMANCE));
- ASSERT_FALSE(mConfigs.getRefreshRate(RefreshRateType::DEFAULT));
-
- // Sanity check that getRefreshRate() does not modify the underlying configs.
- ASSERT_EQ(1, mConfigs.getRefreshRates().size());
+TEST_F(RefreshRateConfigsTest, oneDeviceConfig_isRejected) {
+ std::vector<RefreshRateConfigs::InputConfig> configs{{HWC2_CONFIG_ID_60, VSYNC_60}};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
+ /*currentConfig=*/0);
+ ASSERT_FALSE(refreshRateConfigs->refreshRateSwitchingSupported());
}
-TEST_F(RefreshRateConfigsTest, oneDeviceConfig_storesDefaultConfig) {
- auto display = new Hwc2::mock::Display();
- std::vector<std::shared_ptr<const HWC2::Display::Config>> displayConfigs;
- auto config60 = HWC2::Display::Config::Builder(*display, CONFIG_ID_60);
- config60.setVsyncPeriod(VSYNC_60);
- displayConfigs.push_back(config60.build());
- mConfigs.populate(displayConfigs);
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap) {
+ std::vector<RefreshRateConfigs::InputConfig> configs{{HWC2_CONFIG_ID_60, VSYNC_60},
+ {HWC2_CONFIG_ID_90, VSYNC_90}};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
+ /*currentConfig=*/0);
- const auto& rates = mConfigs.getRefreshRates();
+ ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+ const auto& rates = refreshRateConfigs->getRefreshRateMap();
ASSERT_EQ(2, rates.size());
- const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING);
- const auto& defaultRate = rates.find(RefreshRateType::DEFAULT);
- ASSERT_NE(rates.end(), powerSavingRate);
- ASSERT_NE(rates.end(), defaultRate);
- ASSERT_EQ(rates.end(), rates.find(RefreshRateType::PERFORMANCE));
-
- RefreshRate expectedPowerSavingConfig =
- RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0, HWC2_SCREEN_OFF_CONFIG_ID};
- assertRatesEqual(expectedPowerSavingConfig, *powerSavingRate->second);
- RefreshRate expectedDefaultConfig = RefreshRate{CONFIG_ID_60, "60fps", 60, HWC2_CONFIG_ID_60};
- assertRatesEqual(expectedDefaultConfig, *defaultRate->second);
-
- ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING));
- assertRatesEqual(expectedPowerSavingConfig,
- *mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING));
- ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::DEFAULT));
- assertRatesEqual(expectedDefaultConfig, *mConfigs.getRefreshRate(RefreshRateType::DEFAULT));
- ASSERT_FALSE(mConfigs.getRefreshRate(RefreshRateType::PERFORMANCE));
-
- // Sanity check that getRefreshRate() does not modify the underlying configs.
- ASSERT_EQ(2, mConfigs.getRefreshRates().size());
-}
-
-TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesPerformanceConfig) {
- auto display = new Hwc2::mock::Display();
- std::vector<std::shared_ptr<const HWC2::Display::Config>> displayConfigs;
- auto config60 = HWC2::Display::Config::Builder(*display, CONFIG_ID_60);
- config60.setVsyncPeriod(VSYNC_60);
- displayConfigs.push_back(config60.build());
- auto config90 = HWC2::Display::Config::Builder(*display, CONFIG_ID_90);
- config90.setVsyncPeriod(VSYNC_90);
- displayConfigs.push_back(config90.build());
- mConfigs.populate(displayConfigs);
-
- const auto& rates = mConfigs.getRefreshRates();
- ASSERT_EQ(3, rates.size());
- const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING);
const auto& defaultRate = rates.find(RefreshRateType::DEFAULT);
const auto& performanceRate = rates.find(RefreshRateType::PERFORMANCE);
- ASSERT_NE(rates.end(), powerSavingRate);
ASSERT_NE(rates.end(), defaultRate);
ASSERT_NE(rates.end(), performanceRate);
- RefreshRate expectedPowerSavingConfig =
- RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0, HWC2_SCREEN_OFF_CONFIG_ID};
- assertRatesEqual(expectedPowerSavingConfig, *powerSavingRate->second);
- RefreshRate expectedDefaultConfig = RefreshRate{CONFIG_ID_60, "60fps", 60, HWC2_CONFIG_ID_60};
- assertRatesEqual(expectedDefaultConfig, *defaultRate->second);
- RefreshRate expectedPerformanceConfig =
- RefreshRate{CONFIG_ID_90, "90fps", 90, HWC2_CONFIG_ID_90};
- assertRatesEqual(expectedPerformanceConfig, *performanceRate->second);
+ RefreshRate expectedDefaultConfig = {CONFIG_ID_60, "60fps", 60, VSYNC_60, HWC2_CONFIG_ID_60};
+ assertRatesEqual(expectedDefaultConfig, defaultRate->second);
+ RefreshRate expectedPerformanceConfig = {CONFIG_ID_90, "90fps", 90, VSYNC_90,
+ HWC2_CONFIG_ID_90};
+ assertRatesEqual(expectedPerformanceConfig, performanceRate->second);
- ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING));
- assertRatesEqual(expectedPowerSavingConfig,
- *mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING));
- ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::DEFAULT));
- assertRatesEqual(expectedDefaultConfig, *mConfigs.getRefreshRate(RefreshRateType::DEFAULT));
- ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::PERFORMANCE));
+ assertRatesEqual(expectedDefaultConfig,
+ refreshRateConfigs->getRefreshRateFromType(RefreshRateType::DEFAULT));
assertRatesEqual(expectedPerformanceConfig,
- *mConfigs.getRefreshRate(RefreshRateType::PERFORMANCE));
+ refreshRateConfigs->getRefreshRateFromType(RefreshRateType::PERFORMANCE));
}
} // namespace
} // namespace scheduler
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
index 411ec61..cec0b32 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -22,7 +22,6 @@
#include <thread>
#include "Scheduler/RefreshRateStats.h"
-#include "mock/DisplayHardware/MockDisplay.h"
#include "mock/MockTimeStats.h"
using namespace std::chrono_literals;
@@ -42,9 +41,18 @@
RefreshRateStatsTest();
~RefreshRateStatsTest();
+ void init(const std::vector<RefreshRateConfigs::InputConfig>& configs) {
+ mRefreshRateConfigs = std::make_unique<RefreshRateConfigs>(
+ /*refreshRateSwitching=*/true, configs, /*currentConfig=*/0);
+ mRefreshRateStats =
+ std::make_unique<RefreshRateStats>(*mRefreshRateConfigs, mTimeStats,
+ /*currentConfig=*/0,
+ /*currentPowerMode=*/HWC_POWER_MODE_OFF);
+ }
+
mock::TimeStats mTimeStats;
- RefreshRateConfigs mRefreshRateConfigs;
- RefreshRateStats mRefreshRateStats{mRefreshRateConfigs, mTimeStats};
+ std::unique_ptr<RefreshRateConfigs> mRefreshRateConfigs;
+ std::unique_ptr<RefreshRateStats> mRefreshRateStats;
};
RefreshRateStatsTest::RefreshRateStatsTest() {
@@ -63,63 +71,46 @@
/* ------------------------------------------------------------------------
* Test cases
*/
-TEST_F(RefreshRateStatsTest, canCreateAndDestroyTest) {
- std::vector<std::shared_ptr<const HWC2::Display::Config>> configs;
- mRefreshRateConfigs.populate(configs);
-
- // There is one default config, so the refresh rates should have one item.
- EXPECT_EQ(1, mRefreshRateStats.getTotalTimes().size());
-}
-
TEST_F(RefreshRateStatsTest, oneConfigTest) {
- auto display = new Hwc2::mock::Display();
-
- auto config = HWC2::Display::Config::Builder(*display, CONFIG_ID_90);
- config.setVsyncPeriod(VSYNC_90);
- std::vector<std::shared_ptr<const HWC2::Display::Config>> configs;
- configs.push_back(config.build());
-
- mRefreshRateConfigs.populate(configs);
+ init({{CONFIG_ID_90, VSYNC_90}});
EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1));
EXPECT_CALL(mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1));
- std::unordered_map<std::string, int64_t> times = mRefreshRateStats.getTotalTimes();
- EXPECT_EQ(2, times.size());
+ std::unordered_map<std::string, int64_t> times = mRefreshRateStats->getTotalTimes();
+ ASSERT_EQ(1, times.size());
EXPECT_NE(0u, times.count("ScreenOff"));
- EXPECT_EQ(1u, times.count("90fps"));
- EXPECT_EQ(0, times["90fps"]);
// Setting up tests on mobile harness can be flaky with time passing, so testing for
// exact time changes can result in flaxy numbers. To avoid that remember old
// numbers to make sure the correct values are increasing in the next test.
int screenOff = times["ScreenOff"];
- int ninety = times["90fps"];
// Screen is off by default.
std::this_thread::sleep_for(std::chrono::milliseconds(2));
- times = mRefreshRateStats.getTotalTimes();
+ times = mRefreshRateStats->getTotalTimes();
EXPECT_LT(screenOff, times["ScreenOff"]);
- EXPECT_EQ(0, times["90fps"]);
+ EXPECT_EQ(0u, times.count("90fps"));
- mRefreshRateStats.setConfigMode(CONFIG_ID_90);
- mRefreshRateStats.setPowerMode(HWC_POWER_MODE_NORMAL);
- screenOff = mRefreshRateStats.getTotalTimes()["ScreenOff"];
+ mRefreshRateStats->setConfigMode(CONFIG_ID_90);
+ mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+ screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
- times = mRefreshRateStats.getTotalTimes();
+ times = mRefreshRateStats->getTotalTimes();
EXPECT_EQ(screenOff, times["ScreenOff"]);
- EXPECT_LT(ninety, times["90fps"]);
+ ASSERT_EQ(1u, times.count("90fps"));
+ EXPECT_LT(0, times["90fps"]);
- mRefreshRateStats.setPowerMode(HWC_POWER_MODE_DOZE);
- ninety = mRefreshRateStats.getTotalTimes()["90fps"];
+ mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE);
+ int ninety = mRefreshRateStats->getTotalTimes()["90fps"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
- times = mRefreshRateStats.getTotalTimes();
+ times = mRefreshRateStats->getTotalTimes();
EXPECT_LT(screenOff, times["ScreenOff"]);
EXPECT_EQ(ninety, times["90fps"]);
- mRefreshRateStats.setConfigMode(CONFIG_ID_90);
- screenOff = mRefreshRateStats.getTotalTimes()["ScreenOff"];
+ mRefreshRateStats->setConfigMode(CONFIG_ID_90);
+ screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
- times = mRefreshRateStats.getTotalTimes();
+ times = mRefreshRateStats->getTotalTimes();
// Because the power mode is not HWC_POWER_MODE_NORMAL, switching the config
// does not update refresh rates that come from the config.
EXPECT_LT(screenOff, times["ScreenOff"]);
@@ -127,93 +118,75 @@
}
TEST_F(RefreshRateStatsTest, twoConfigsTest) {
- auto display = new Hwc2::mock::Display();
-
- auto config90 = HWC2::Display::Config::Builder(*display, CONFIG_ID_90);
- config90.setVsyncPeriod(VSYNC_90);
- std::vector<std::shared_ptr<const HWC2::Display::Config>> configs;
- configs.push_back(config90.build());
-
- auto config60 = HWC2::Display::Config::Builder(*display, CONFIG_ID_60);
- config60.setVsyncPeriod(VSYNC_60);
- configs.push_back(config60.build());
-
- mRefreshRateConfigs.populate(configs);
+ init({{CONFIG_ID_90, VSYNC_90}, {CONFIG_ID_60, VSYNC_60}});
EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1));
EXPECT_CALL(mTimeStats, recordRefreshRate(60, _)).Times(AtLeast(1));
EXPECT_CALL(mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1));
- std::unordered_map<std::string, int64_t> times = mRefreshRateStats.getTotalTimes();
- EXPECT_EQ(3, times.size());
+ std::unordered_map<std::string, int64_t> times = mRefreshRateStats->getTotalTimes();
+ ASSERT_EQ(1, times.size());
EXPECT_NE(0u, times.count("ScreenOff"));
- EXPECT_EQ(1u, times.count("60fps"));
- EXPECT_EQ(0, times["60fps"]);
- EXPECT_EQ(1u, times.count("90fps"));
- EXPECT_EQ(0, times["90fps"]);
// Setting up tests on mobile harness can be flaky with time passing, so testing for
// exact time changes can result in flaxy numbers. To avoid that remember old
// numbers to make sure the correct values are increasing in the next test.
int screenOff = times["ScreenOff"];
- int sixty = times["60fps"];
- int ninety = times["90fps"];
// Screen is off by default.
std::this_thread::sleep_for(std::chrono::milliseconds(2));
- times = mRefreshRateStats.getTotalTimes();
+ times = mRefreshRateStats->getTotalTimes();
EXPECT_LT(screenOff, times["ScreenOff"]);
- EXPECT_EQ(sixty, times["60fps"]);
- EXPECT_EQ(ninety, times["90fps"]);
- mRefreshRateStats.setConfigMode(CONFIG_ID_90);
- mRefreshRateStats.setPowerMode(HWC_POWER_MODE_NORMAL);
- screenOff = mRefreshRateStats.getTotalTimes()["ScreenOff"];
+ mRefreshRateStats->setConfigMode(CONFIG_ID_90);
+ mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+ screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
- times = mRefreshRateStats.getTotalTimes();
+ times = mRefreshRateStats->getTotalTimes();
EXPECT_EQ(screenOff, times["ScreenOff"]);
- EXPECT_EQ(sixty, times["60fps"]);
- EXPECT_LT(ninety, times["90fps"]);
+ ASSERT_EQ(1u, times.count("90fps"));
+ EXPECT_LT(0, times["90fps"]);
// When power mode is normal, time for configs updates.
- mRefreshRateStats.setConfigMode(CONFIG_ID_60);
- ninety = mRefreshRateStats.getTotalTimes()["90fps"];
+ mRefreshRateStats->setConfigMode(CONFIG_ID_60);
+ int ninety = mRefreshRateStats->getTotalTimes()["90fps"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
- times = mRefreshRateStats.getTotalTimes();
+ times = mRefreshRateStats->getTotalTimes();
EXPECT_EQ(screenOff, times["ScreenOff"]);
EXPECT_EQ(ninety, times["90fps"]);
- EXPECT_LT(sixty, times["60fps"]);
+ ASSERT_EQ(1u, times.count("60fps"));
+ EXPECT_LT(0, times["60fps"]);
- mRefreshRateStats.setConfigMode(CONFIG_ID_90);
- sixty = mRefreshRateStats.getTotalTimes()["60fps"];
+ mRefreshRateStats->setConfigMode(CONFIG_ID_90);
+ int sixty = mRefreshRateStats->getTotalTimes()["60fps"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
- times = mRefreshRateStats.getTotalTimes();
+ times = mRefreshRateStats->getTotalTimes();
EXPECT_EQ(screenOff, times["ScreenOff"]);
EXPECT_LT(ninety, times["90fps"]);
EXPECT_EQ(sixty, times["60fps"]);
- mRefreshRateStats.setConfigMode(CONFIG_ID_60);
- ninety = mRefreshRateStats.getTotalTimes()["90fps"];
+ mRefreshRateStats->setConfigMode(CONFIG_ID_60);
+ ninety = mRefreshRateStats->getTotalTimes()["90fps"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
- times = mRefreshRateStats.getTotalTimes();
+ times = mRefreshRateStats->getTotalTimes();
EXPECT_EQ(screenOff, times["ScreenOff"]);
EXPECT_EQ(ninety, times["90fps"]);
EXPECT_LT(sixty, times["60fps"]);
// Because the power mode is not HWC_POWER_MODE_NORMAL, switching the config
// does not update refresh rates that come from the config.
- mRefreshRateStats.setPowerMode(HWC_POWER_MODE_DOZE);
- mRefreshRateStats.setConfigMode(CONFIG_ID_90);
- sixty = mRefreshRateStats.getTotalTimes()["60fps"];
+ mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE);
+ mRefreshRateStats->setConfigMode(CONFIG_ID_90);
+ sixty = mRefreshRateStats->getTotalTimes()["60fps"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
- times = mRefreshRateStats.getTotalTimes();
+ times = mRefreshRateStats->getTotalTimes();
EXPECT_LT(screenOff, times["ScreenOff"]);
EXPECT_EQ(ninety, times["90fps"]);
EXPECT_EQ(sixty, times["60fps"]);
- mRefreshRateStats.setConfigMode(CONFIG_ID_60);
- screenOff = mRefreshRateStats.getTotalTimes()["ScreenOff"];
+ mRefreshRateStats->setConfigMode(CONFIG_ID_60);
+ screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
- times = mRefreshRateStats.getTotalTimes();
+ times = mRefreshRateStats->getTotalTimes();
EXPECT_LT(screenOff, times["ScreenOff"]);
EXPECT_EQ(ninety, times["90fps"]);
EXPECT_EQ(sixty, times["60fps"]);
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 740115e..571fdfd 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -3,13 +3,13 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-
#include <log/log.h>
#include <mutex>
#include "Scheduler/EventControlThread.h"
#include "Scheduler/EventThread.h"
+#include "Scheduler/RefreshRateConfigs.h"
#include "Scheduler/Scheduler.h"
#include "mock/MockEventThread.h"
@@ -34,7 +34,7 @@
MOCK_METHOD0(requestNextVsync, void());
};
- scheduler::RefreshRateConfigs mRefreshRateConfigs;
+ std::unique_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs;
/**
* This mock Scheduler class uses implementation of mock::EventThread but keeps everything else
@@ -73,9 +73,14 @@
::testing::UnitTest::GetInstance()->current_test_info();
ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+ std::vector<scheduler::RefreshRateConfigs::InputConfig> configs{{/*hwcId=*/0, 16666667}};
+ mRefreshRateConfigs =
+ std::make_unique<scheduler::RefreshRateConfigs>(/*refreshRateSwitching=*/false, configs,
+ /*currentConfig=*/0);
+
std::unique_ptr<mock::EventThread> eventThread = std::make_unique<mock::EventThread>();
mEventThread = eventThread.get();
- mScheduler = std::make_unique<MockScheduler>(mRefreshRateConfigs, std::move(eventThread));
+ mScheduler = std::make_unique<MockScheduler>(*mRefreshRateConfigs, std::move(eventThread));
EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_)).WillOnce(Return(0));
mEventThreadConnection = new MockEventThreadConnection(mEventThread);
@@ -85,7 +90,7 @@
EXPECT_CALL(*mEventThread, createEventConnection(_, _))
.WillRepeatedly(Return(mEventThreadConnection));
- mConnectionHandle = mScheduler->createConnection("appConnection", 16, 16, ResyncCallback(),
+ mConnectionHandle = mScheduler->createConnection("appConnection", 16, 16,
impl::EventThread::InterceptVSyncsCallback());
EXPECT_TRUE(mConnectionHandle != nullptr);
}
@@ -107,7 +112,7 @@
sp<IDisplayEventConnection> returnedValue;
ASSERT_NO_FATAL_FAILURE(
returnedValue =
- mScheduler->createDisplayEventConnection(nullptr, ResyncCallback(),
+ mScheduler->createDisplayEventConnection(nullptr,
ISurfaceComposer::
eConfigChangedSuppress));
EXPECT_TRUE(returnedValue == nullptr);
@@ -130,7 +135,7 @@
sp<IDisplayEventConnection> returnedValue;
ASSERT_NO_FATAL_FAILURE(
returnedValue =
- mScheduler->createDisplayEventConnection(connectionHandle, ResyncCallback(),
+ mScheduler->createDisplayEventConnection(connectionHandle,
ISurfaceComposer::
eConfigChangedSuppress));
EXPECT_TRUE(returnedValue == nullptr);
@@ -161,7 +166,7 @@
sp<IDisplayEventConnection> returnedValue;
ASSERT_NO_FATAL_FAILURE(
returnedValue =
- mScheduler->createDisplayEventConnection(mConnectionHandle, ResyncCallback(),
+ mScheduler->createDisplayEventConnection(mConnectionHandle,
ISurfaceComposer::
eConfigChangedSuppress));
EXPECT_TRUE(returnedValue != nullptr);
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 64d34ee..1c1b020 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -32,11 +32,11 @@
#include "Layer.h"
#include "NativeWindowSurface.h"
#include "Scheduler/MessageQueue.h"
+#include "Scheduler/RefreshRateConfigs.h"
#include "StartPropertySetThread.h"
#include "SurfaceFlinger.h"
#include "SurfaceFlingerFactory.h"
#include "SurfaceInterceptor.h"
-
#include "TimeStats/TimeStats.h"
namespace android {
@@ -342,6 +342,8 @@
auto& mutableAppConnectionHandle() { return mFlinger->mAppConnectionHandle; }
auto& mutableSfConnectionHandle() { return mFlinger->mSfConnectionHandle; }
auto& mutableRefreshRateConfigs() { return mFlinger->mRefreshRateConfigs; }
+ auto& mutableRefreshRateStats() { return mFlinger->mRefreshRateStats; }
+ auto& mutableTimeStats() { return mFlinger->mTimeStats; }
~TestableSurfaceFlinger() {
// All these pointer and container clears help ensure that GMock does
diff --git a/services/vr/virtual_touchpad/Android.bp b/services/vr/virtual_touchpad/Android.bp
index dcaa663..9cf4905 100644
--- a/services/vr/virtual_touchpad/Android.bp
+++ b/services/vr/virtual_touchpad/Android.bp
@@ -14,6 +14,7 @@
]
header_libraries = [
+ "jni_headers",
"libdvr_headers",
]
diff --git a/vulkan/libvulkan/api.cpp b/vulkan/libvulkan/api.cpp
index 3d56656..6e08d23 100644
--- a/vulkan/libvulkan/api.cpp
+++ b/vulkan/libvulkan/api.cpp
@@ -124,7 +124,7 @@
};
void AddImplicitLayers() {
- if (!is_instance_ || !driver::Debuggable())
+ if (!is_instance_)
return;
GetLayersFromSettings();
@@ -370,7 +370,8 @@
private:
bool EnableDebugCallback() const {
- return (is_instance_ && driver::Debuggable() &&
+ return (is_instance_ &&
+ android::GraphicsEnv::getInstance().isDebuggable() &&
property_get_bool("debug.vulkan.enable_callback", false));
}
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index ff84730..bdf5ddf 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -755,10 +755,6 @@
} // anonymous namespace
-bool Debuggable() {
- return (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) >= 0);
-}
-
bool OpenHAL() {
return Hal::Open();
}
diff --git a/vulkan/libvulkan/driver.h b/vulkan/libvulkan/driver.h
index 047a27a..ffe2a8b 100644
--- a/vulkan/libvulkan/driver.h
+++ b/vulkan/libvulkan/driver.h
@@ -101,7 +101,6 @@
uint32_t driver_version;
};
-bool Debuggable();
bool OpenHAL();
const VkAllocationCallbacks& GetDefaultAllocator();
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index dd91739..7326692 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -462,8 +462,7 @@
void DiscoverLayers() {
ATRACE_CALL();
- if (property_get_bool("ro.debuggable", false) &&
- prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) {
+ if (android::GraphicsEnv::getInstance().isDebuggable()) {
DiscoverLayersInPathList(kSystemLayerLibraryDir);
}
if (!android::GraphicsEnv::getInstance().getLayerPaths().empty())