Merge "Provide a fixed transform hint if the layer is in a fixed orientation 1/2" into rvc-dev
diff --git a/data/etc/android.hardware.camera.concurrent.xml b/data/etc/android.hardware.camera.concurrent.xml
new file mode 100644
index 0000000..2cbb263
--- /dev/null
+++ b/data/etc/android.hardware.camera.concurrent.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- This is the set of features required for a camera2 device that supports concurrent operation
+ of front and back cameras -->
+<permissions>
+ <feature name="android.hardware.camera.front" />
+ <feature name="android.hardware.camera.concurrent" />
+</permissions>
diff --git a/data/etc/android.hardware.sensor.hinge_angle.xml b/data/etc/android.hardware.sensor.hinge_angle.xml
new file mode 100644
index 0000000..d744305
--- /dev/null
+++ b/data/etc/android.hardware.sensor.hinge_angle.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- Feature for devices with a hinge angle sensor. -->
+<permissions>
+ <feature name="android.hardware.sensor.hinge_angle" />
+</permissions>
\ No newline at end of file
diff --git a/headers/Android.bp b/headers/Android.bp
index 82bc8a1..5337235 100644
--- a/headers/Android.bp
+++ b/headers/Android.bp
@@ -17,4 +17,5 @@
"libutils_headers",
"libstagefright_foundation_headers",
],
+ min_sdk_version: "29",
}
diff --git a/libs/nativedisplay/include/android/choreographer.h b/include/android/choreographer.h
similarity index 88%
rename from libs/nativedisplay/include/android/choreographer.h
rename to include/android/choreographer.h
index 5fd3de9..c1c4a72 100644
--- a/libs/nativedisplay/include/android/choreographer.h
+++ b/include/android/choreographer.h
@@ -75,14 +75,16 @@
* Deprecated: Use AChoreographer_postFrameCallback64 instead.
*/
void AChoreographer_postFrameCallback(AChoreographer* choreographer,
- AChoreographer_frameCallback callback, void* data) __INTRODUCED_IN(24) __DEPRECATED_IN(29);
+ AChoreographer_frameCallback callback, void* data)
+ __INTRODUCED_IN(24) __DEPRECATED_IN(29);
/**
* Deprecated: Use AChoreographer_postFrameCallbackDelayed64 instead.
*/
void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer,
- AChoreographer_frameCallback callback, void* data,
- long delayMillis) __INTRODUCED_IN(24) __DEPRECATED_IN(29);
+ AChoreographer_frameCallback callback, void* data,
+ long delayMillis) __INTRODUCED_IN(24)
+ __DEPRECATED_IN(29);
#endif /* __ANDROID_API__ >= 24 */
@@ -95,7 +97,8 @@
* Available since API level 29.
*/
void AChoreographer_postFrameCallback64(AChoreographer* choreographer,
- AChoreographer_frameCallback64 callback, void* data) __INTRODUCED_IN(29);
+ AChoreographer_frameCallback64 callback, void* data)
+ __INTRODUCED_IN(29);
/**
* Post a callback to be run on the frame following the specified delay. The
@@ -105,7 +108,8 @@
* Available since API level 29.
*/
void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer,
- AChoreographer_frameCallback64 callback, void* data, uint32_t delayMillis) __INTRODUCED_IN(29);
+ AChoreographer_frameCallback64 callback, void* data,
+ uint32_t delayMillis) __INTRODUCED_IN(29);
#endif /* __ANDROID_API__ >= 29 */
diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h
index a695a8f..c5e56fd 100644
--- a/include/input/InputWindow.h
+++ b/include/input/InputWindow.h
@@ -68,46 +68,48 @@
// Window types from WindowManager.LayoutParams
enum {
FIRST_APPLICATION_WINDOW = 1,
- TYPE_BASE_APPLICATION = 1,
- TYPE_APPLICATION = 2,
+ TYPE_BASE_APPLICATION = 1,
+ TYPE_APPLICATION = 2,
TYPE_APPLICATION_STARTING = 3,
LAST_APPLICATION_WINDOW = 99,
- FIRST_SUB_WINDOW = 1000,
- TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW,
- TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW+1,
- TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW+2,
- TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW+3,
- TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW+4,
- LAST_SUB_WINDOW = 1999,
- FIRST_SYSTEM_WINDOW = 2000,
- TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW,
- TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1,
- TYPE_PHONE = FIRST_SYSTEM_WINDOW+2,
- TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW+3,
- TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW+4,
- TYPE_TOAST = FIRST_SYSTEM_WINDOW+5,
- TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+6,
- TYPE_PRIORITY_PHONE = FIRST_SYSTEM_WINDOW+7,
- TYPE_SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW+8,
- TYPE_KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW+9,
- TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW+10,
- TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW+11,
- TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12,
- TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW+13,
- TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW+14,
- TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15,
- TYPE_DRAG = FIRST_SYSTEM_WINDOW+16,
- TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+17,
- TYPE_POINTER = FIRST_SYSTEM_WINDOW+18,
- TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19,
- TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20,
- TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21,
- TYPE_INPUT_CONSUMER = FIRST_SYSTEM_WINDOW+22,
- TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW+24,
- TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27,
- TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW+32,
- TYPE_DOCK_DIVIDER = FIRST_SYSTEM_WINDOW+34,
- LAST_SYSTEM_WINDOW = 2999,
+ FIRST_SUB_WINDOW = 1000,
+ TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW,
+ TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1,
+ TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2,
+ TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3,
+ TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW + 4,
+ LAST_SUB_WINDOW = 1999,
+ FIRST_SYSTEM_WINDOW = 2000,
+ TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW,
+ TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW + 1,
+ TYPE_PHONE = FIRST_SYSTEM_WINDOW + 2,
+ TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW + 3,
+ TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW + 4,
+ TYPE_TOAST = FIRST_SYSTEM_WINDOW + 5,
+ TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW + 6,
+ TYPE_PRIORITY_PHONE = FIRST_SYSTEM_WINDOW + 7,
+ TYPE_SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW + 8,
+ TYPE_KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW + 9,
+ TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW + 10,
+ TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW + 11,
+ TYPE_INPUT_METHOD_DIALOG = FIRST_SYSTEM_WINDOW + 12,
+ TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW + 13,
+ TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW + 14,
+ TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW + 15,
+ TYPE_DRAG = FIRST_SYSTEM_WINDOW + 16,
+ TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW + 17,
+ TYPE_POINTER = FIRST_SYSTEM_WINDOW + 18,
+ TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW + 19,
+ TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW + 20,
+ TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW + 21,
+ TYPE_INPUT_CONSUMER = FIRST_SYSTEM_WINDOW + 22,
+ TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW + 24,
+ TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 27,
+ TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW + 32,
+ TYPE_DOCK_DIVIDER = FIRST_SYSTEM_WINDOW + 34,
+ TYPE_NOTIFICATION_SHADE = FIRST_SYSTEM_WINDOW + 40,
+ TYPE_TRUSTED_APPLICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 42,
+ LAST_SYSTEM_WINDOW = 2999,
};
enum {
diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp
index 2518b14..f66673f 100644
--- a/libs/arect/Android.bp
+++ b/libs/arect/Android.bp
@@ -35,4 +35,5 @@
enabled: true,
},
},
+ min_sdk_version: "29",
}
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 7298282..db4aba8 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -28,6 +28,7 @@
"libcutils_headers",
"libutils_headers",
],
+ min_sdk_version: "29",
}
// These interfaces are android-specific implementation unrelated to binder
@@ -152,6 +153,7 @@
sanitize: {
misc_undefined: ["integer"],
},
+ min_sdk_version: "29",
}
// AIDL interface between libbinder and framework.jar
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 69fdd7c..c0da2cd 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -27,7 +27,9 @@
defaults: ["binder_test_defaults"],
srcs: ["binderDriverInterfaceTest.cpp"],
compile_multilib: "32",
+ multilib: { lib32: { suffix: "" } },
cflags: ["-DBINDER_IPC_32BIT=1"],
+ test_suites: ["vts"],
}
cc_test {
@@ -52,7 +54,10 @@
"libutils",
],
compile_multilib: "32",
+ multilib: { lib32: { suffix: "" } },
cflags: ["-DBINDER_IPC_32BIT=1"],
+ test_suites: ["vts"],
+ require_root: true,
}
cc_test {
diff --git a/libs/binder/tests/binderAbiHelper.h b/libs/binder/tests/binderAbiHelper.h
new file mode 100644
index 0000000..369b55d
--- /dev/null
+++ b/libs/binder/tests/binderAbiHelper.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <stdlib.h>
+#include <iostream>
+
+#ifdef BINDER_IPC_32BIT
+static constexpr bool kBuild32Abi = true;
+#else
+static constexpr bool kBuild32Abi = false;
+#endif
+
+// TODO: remove when CONFIG_ANDROID_BINDER_IPC_32BIT is no longer supported
+static inline bool ReadKernelConfigIs32BitAbi() {
+ // failure case implies we run with standard ABI
+ return 0 == system("zcat /proc/config.gz | grep -E \"^CONFIG_ANDROID_BINDER_IPC_32BIT=y$\"");
+}
+
+static inline void ExitIfWrongAbi() {
+ bool runtime32Abi = ReadKernelConfigIs32BitAbi();
+
+ if (kBuild32Abi != runtime32Abi) {
+ std::cout << "[==========] Running 1 test from 1 test suite." << std::endl;
+ std::cout << "[----------] Global test environment set-up." << std::endl;
+ std::cout << "[----------] 1 tests from BinderLibTest" << std::endl;
+ std::cout << "[ RUN ] BinderTest.AbortForWrongAbi" << std::endl;
+ std::cout << "[ INFO ] test build abi 32: " << kBuild32Abi << " runtime abi 32: " << runtime32Abi << " so, skipping tests " << std::endl;
+ std::cout << "[ OK ] BinderTest.AbortForWrongAbi (0 ms) " << std::endl;
+ std::cout << "[----------] 1 tests from BinderTest (0 ms total)" << std::endl;
+ std::cout << "" << std::endl;
+ std::cout << "[----------] Global test environment tear-down" << std::endl;
+ std::cout << "[==========] 1 test from 1 test suite ran. (0 ms total)" << std::endl;
+ std::cout << "[ PASSED ] 1 tests." << std::endl;
+ exit(0);
+ }
+}
+
diff --git a/libs/binder/tests/binderDriverInterfaceTest.cpp b/libs/binder/tests/binderDriverInterfaceTest.cpp
index f3ed6a6..8cc3054 100644
--- a/libs/binder/tests/binderDriverInterfaceTest.cpp
+++ b/libs/binder/tests/binderDriverInterfaceTest.cpp
@@ -25,6 +25,8 @@
#include <sys/mman.h>
#include <poll.h>
+#include "binderAbiHelper.h"
+
#define BINDER_DEV_NAME "/dev/binder"
testing::Environment* binder_env;
@@ -361,6 +363,7 @@
}
int main(int argc, char **argv) {
+ ExitIfWrongAbi();
::testing::InitGoogleTest(&argc, argv);
binder_env = AddGlobalTestEnvironment(new BinderDriverInterfaceTestEnv());
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index e343df7..40de2db 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -32,6 +32,8 @@
#include <sys/epoll.h>
#include <sys/prctl.h>
+#include "binderAbiHelper.h"
+
#define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
using namespace android;
@@ -1451,6 +1453,8 @@
}
int main(int argc, char **argv) {
+ ExitIfWrongAbi();
+
if (argc == 4 && !strcmp(argv[1], "--servername")) {
binderservername = argv[2];
} else {
diff --git a/libs/binderthreadstate/Android.bp b/libs/binderthreadstate/Android.bp
index 5eb509c..88752ee 100644
--- a/libs/binderthreadstate/Android.bp
+++ b/libs/binderthreadstate/Android.bp
@@ -22,7 +22,7 @@
shared_libs: [
"libbinder",
- "libhidlbase", // libhwbinder is in here
+ "libhidlbase", // libhwbinder is in here
],
export_include_dirs: ["include"],
@@ -31,6 +31,7 @@
"-Wall",
"-Werror",
],
+ min_sdk_version: "29",
}
hidl_package_root {
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 7f57f5d..7976ecb 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -27,6 +27,7 @@
"android.hardware.graphics.bufferqueue@1.0",
"android.hardware.graphics.bufferqueue@2.0",
],
+ min_sdk_version: "29",
}
cc_library_shared {
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index 15f966d..b33bc9e 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -36,10 +36,7 @@
DisplayEventDispatcher::DisplayEventDispatcher(const sp<Looper>& looper,
ISurfaceComposer::VsyncSource vsyncSource,
ISurfaceComposer::ConfigChanged configChanged)
- : mLooper(looper),
- mReceiver(vsyncSource, configChanged),
- mWaitingForVsync(false),
- mConfigChangeFlag(configChanged) {
+ : mLooper(looper), mReceiver(vsyncSource, configChanged), mWaitingForVsync(false) {
ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this);
}
@@ -92,16 +89,12 @@
return OK;
}
-void DisplayEventDispatcher::toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag) {
- if (mConfigChangeFlag == configChangeFlag) {
- return;
- }
- status_t status = mReceiver.toggleConfigEvents(configChangeFlag);
+void DisplayEventDispatcher::requestLatestConfig() {
+ status_t status = mReceiver.requestLatestConfig();
if (status) {
ALOGW("Failed enable config events, status=%d", status);
return;
}
- mConfigChangeFlag = configChangeFlag;
}
int DisplayEventDispatcher::getFd() const {
diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp
index fd6aaf8..1fed509 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -79,10 +79,9 @@
return NO_INIT;
}
-status_t DisplayEventReceiver::toggleConfigEvents(
- ISurfaceComposer::ConfigChanged configChangeFlag) {
+status_t DisplayEventReceiver::requestLatestConfig() {
if (mEventConnection != nullptr) {
- mEventConnection->toggleConfigEvents(configChangeFlag);
+ mEventConnection->requestLatestConfig();
return NO_ERROR;
}
return NO_INIT;
diff --git a/libs/gui/IDisplayEventConnection.cpp b/libs/gui/IDisplayEventConnection.cpp
index dda5acf..aa74bfd 100644
--- a/libs/gui/IDisplayEventConnection.cpp
+++ b/libs/gui/IDisplayEventConnection.cpp
@@ -26,8 +26,8 @@
STEAL_RECEIVE_CHANNEL = IBinder::FIRST_CALL_TRANSACTION,
SET_VSYNC_RATE,
REQUEST_NEXT_VSYNC,
- TOGGLE_CONFIG_EVENTS,
- LAST = TOGGLE_CONFIG_EVENTS,
+ REQUEST_LATEST_CONFIG,
+ LAST = REQUEST_LATEST_CONFIG,
};
} // Anonymous namespace
@@ -55,10 +55,9 @@
Tag::REQUEST_NEXT_VSYNC);
}
- void toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag) override {
- callRemoteAsync<decltype(
- &IDisplayEventConnection::toggleConfigEvents)>(Tag::TOGGLE_CONFIG_EVENTS,
- configChangeFlag);
+ void requestLatestConfig() override {
+ callRemoteAsync<decltype(&IDisplayEventConnection::requestLatestConfig)>(
+ Tag::REQUEST_LATEST_CONFIG);
}
};
@@ -81,8 +80,8 @@
return callLocal(data, reply, &IDisplayEventConnection::setVsyncRate);
case Tag::REQUEST_NEXT_VSYNC:
return callLocalAsync(data, reply, &IDisplayEventConnection::requestNextVsync);
- case Tag::TOGGLE_CONFIG_EVENTS:
- return callLocalAsync(data, reply, &IDisplayEventConnection::toggleConfigEvents);
+ case Tag::REQUEST_LATEST_CONFIG:
+ return callLocalAsync(data, reply, &IDisplayEventConnection::requestLatestConfig);
}
}
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index f911e70..2bf8ff7 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -57,7 +57,8 @@
return op == NATIVE_WINDOW_SET_CANCEL_INTERCEPTOR ||
op == NATIVE_WINDOW_SET_DEQUEUE_INTERCEPTOR ||
op == NATIVE_WINDOW_SET_PERFORM_INTERCEPTOR ||
- op == NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR;
+ op == NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR ||
+ op == NATIVE_WINDOW_SET_QUERY_INTERCEPTOR;
}
} // namespace
@@ -501,6 +502,19 @@
int Surface::hook_query(const ANativeWindow* window, int what, int* value) {
const Surface* c = getSelf(window);
+ {
+ std::shared_lock<std::shared_mutex> lock(c->mInterceptorMutex);
+ if (c->mQueryInterceptor != nullptr) {
+ auto interceptor = c->mQueryInterceptor;
+ auto data = c->mQueryInterceptorData;
+ return interceptor(window, Surface::queryInternal, data, what, value);
+ }
+ }
+ return c->query(what, value);
+}
+
+int Surface::queryInternal(const ANativeWindow* window, int what, int* value) {
+ const Surface* c = getSelf(window);
return c->query(what, value);
}
@@ -1177,6 +1191,9 @@
case NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR:
res = dispatchAddQueueInterceptor(args);
break;
+ case NATIVE_WINDOW_SET_QUERY_INTERCEPTOR:
+ res = dispatchAddQueryInterceptor(args);
+ break;
case NATIVE_WINDOW_ALLOCATE_BUFFERS:
allocateBuffers();
res = NO_ERROR;
@@ -1457,6 +1474,15 @@
return NO_ERROR;
}
+int Surface::dispatchAddQueryInterceptor(va_list args) {
+ ANativeWindow_queryInterceptor interceptor = va_arg(args, ANativeWindow_queryInterceptor);
+ void* data = va_arg(args, void*);
+ std::lock_guard<std::shared_mutex> lock(mInterceptorMutex);
+ mQueryInterceptor = interceptor;
+ mQueryInterceptorData = data;
+ return NO_ERROR;
+}
+
int Surface::dispatchGetLastQueuedBuffer(va_list args) {
AHardwareBuffer** buffer = va_arg(args, AHardwareBuffer**);
int* fence = va_arg(args, int*);
diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h
index fcdf6bf..f210c34 100644
--- a/libs/gui/include/gui/DisplayEventDispatcher.h
+++ b/libs/gui/include/gui/DisplayEventDispatcher.h
@@ -31,7 +31,7 @@
status_t initialize();
void dispose();
status_t scheduleVsync();
- void toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag);
+ void requestLatestConfig();
int getFd() const;
virtual int handleEvent(int receiveFd, int events, void* data);
@@ -42,7 +42,6 @@
sp<Looper> mLooper;
DisplayEventReceiver mReceiver;
bool mWaitingForVsync;
- ISurfaceComposer::ConfigChanged mConfigChangeFlag;
virtual void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) = 0;
virtual void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId,
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index d9a0253..8d49184 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -147,9 +147,10 @@
status_t requestNextVsync();
/*
- * toggleConfigEvents() toggles delivery of config change events.
+ * requestLatestConfig() force-requests the current config for the primary
+ * display.
*/
- status_t toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag);
+ status_t requestLatestConfig();
private:
sp<IDisplayEventConnection> mEventConnection;
diff --git a/libs/gui/include/gui/IDisplayEventConnection.h b/libs/gui/include/gui/IDisplayEventConnection.h
index 8b35ef6..674aafd 100644
--- a/libs/gui/include/gui/IDisplayEventConnection.h
+++ b/libs/gui/include/gui/IDisplayEventConnection.h
@@ -53,11 +53,9 @@
virtual void requestNextVsync() = 0; // Asynchronous
/*
- * togglesConfigEvents() configures whether or not display config changes
- * should be propagated.
+ * requestLatestConfig() requests the config for the primary display.
*/
- virtual void toggleConfigEvents(
- ISurfaceComposer::ConfigChanged configChangeFlag) = 0; // Asynchronous
+ virtual void requestLatestConfig() = 0; // Asynchronous
};
class BnDisplayEventConnection : public SafeBnInterface<IDisplayEventConnection> {
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 917c0d4..49c83da 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -209,6 +209,7 @@
int* fenceFd);
static int performInternal(ANativeWindow* window, int operation, va_list args);
static int queueBufferInternal(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd);
+ static int queryInternal(const ANativeWindow* window, int what, int* value);
static int hook_cancelBuffer_DEPRECATED(ANativeWindow* window,
ANativeWindowBuffer* buffer);
@@ -261,6 +262,7 @@
int dispatchAddDequeueInterceptor(va_list args);
int dispatchAddPerformInterceptor(va_list args);
int dispatchAddQueueInterceptor(va_list args);
+ int dispatchAddQueryInterceptor(va_list args);
int dispatchGetLastQueuedBuffer(va_list args);
bool transformToDisplayInverse();
@@ -468,7 +470,7 @@
mutable Mutex mMutex;
// mInterceptorMutex is the mutex guarding interceptors.
- std::shared_mutex mInterceptorMutex;
+ mutable std::shared_mutex mInterceptorMutex;
ANativeWindow_cancelBufferInterceptor mCancelInterceptor = nullptr;
void* mCancelInterceptorData = nullptr;
@@ -478,6 +480,8 @@
void* mPerformInterceptorData = nullptr;
ANativeWindow_queueBufferInterceptor mQueueInterceptor = nullptr;
void* mQueueInterceptorData = nullptr;
+ ANativeWindow_queryInterceptor mQueryInterceptor = nullptr;
+ void* mQueryInterceptorData = nullptr;
// must be used from the lock/unlock thread
sp<GraphicBuffer> mLockedBuffer;
diff --git a/libs/gui/sysprop/Android.bp b/libs/gui/sysprop/Android.bp
index e7f7c1f..64b1eac 100644
--- a/libs/gui/sysprop/Android.bp
+++ b/libs/gui/sysprop/Android.bp
@@ -4,4 +4,7 @@
api_packages: ["android.sysprop"],
property_owner: "Platform",
vendor_available: true,
+ cpp: {
+ min_sdk_version: "29",
+ },
}
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index c59afba..5188a09 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -178,7 +178,7 @@
mInputInfo.name = "Test info";
mInputInfo.layoutParamsFlags = InputWindowInfo::FLAG_NOT_TOUCH_MODAL;
mInputInfo.layoutParamsType = InputWindowInfo::TYPE_BASE_APPLICATION;
- mInputInfo.dispatchingTimeout = 100000;
+ mInputInfo.dispatchingTimeout = seconds_to_nanoseconds(5);
mInputInfo.globalScaleFactor = 1.0;
mInputInfo.canReceiveKeys = true;
mInputInfo.hasFocus = true;
@@ -196,7 +196,7 @@
InputApplicationInfo aInfo;
aInfo.token = new BBinder();
aInfo.name = "Test app info";
- aInfo.dispatchingTimeout = 100000;
+ aInfo.dispatchingTimeout = seconds_to_nanoseconds(5);
mInputInfo.applicationInfo = aInfo;
}
diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp
index 6e4c97d..85a2015 100644
--- a/libs/input/InputWindow.cpp
+++ b/libs/input/InputWindow.cpp
@@ -42,17 +42,18 @@
&& y >= frameTop && y < frameBottom;
}
+// TODO(b/155781676): Remove and replace call points with trustedOverlay when that is ready.
bool InputWindowInfo::isTrustedOverlay() const {
- return layoutParamsType == TYPE_INPUT_METHOD
- || layoutParamsType == TYPE_INPUT_METHOD_DIALOG
- || layoutParamsType == TYPE_MAGNIFICATION_OVERLAY
- || layoutParamsType == TYPE_STATUS_BAR
- || layoutParamsType == TYPE_NAVIGATION_BAR
- || layoutParamsType == TYPE_NAVIGATION_BAR_PANEL
- || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY
- || layoutParamsType == TYPE_DOCK_DIVIDER
- || layoutParamsType == TYPE_ACCESSIBILITY_OVERLAY
- || layoutParamsType == TYPE_INPUT_CONSUMER;
+ return layoutParamsType == TYPE_INPUT_METHOD || layoutParamsType == TYPE_INPUT_METHOD_DIALOG ||
+ layoutParamsType == TYPE_MAGNIFICATION_OVERLAY || layoutParamsType == TYPE_STATUS_BAR ||
+ layoutParamsType == TYPE_NOTIFICATION_SHADE ||
+ layoutParamsType == TYPE_NAVIGATION_BAR ||
+ layoutParamsType == TYPE_NAVIGATION_BAR_PANEL ||
+ layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY ||
+ layoutParamsType == TYPE_DOCK_DIVIDER ||
+ layoutParamsType == TYPE_ACCESSIBILITY_OVERLAY ||
+ layoutParamsType == TYPE_INPUT_CONSUMER ||
+ layoutParamsType == TYPE_TRUSTED_APPLICATION_OVERLAY;
}
bool InputWindowInfo::supportsSplitTouch() const {
diff --git a/libs/nativebase/Android.bp b/libs/nativebase/Android.bp
index 7375a2b..9e7e4a2 100644
--- a/libs/nativebase/Android.bp
+++ b/libs/nativebase/Android.bp
@@ -25,5 +25,6 @@
windows: {
enabled: true,
},
- }
+ },
+ min_sdk_version: "29",
}
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index 0ff33ac..e458b2e 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -17,24 +17,63 @@
#define LOG_TAG "Choreographer"
//#define LOG_NDEBUG 0
-#include <apex/choreographer.h>
+#include <android-base/thread_annotations.h>
#include <gui/DisplayEventDispatcher.h>
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
+#include <nativehelper/JNIHelp.h>
+#include <private/android/choreographer.h>
#include <utils/Looper.h>
-#include <utils/Mutex.h>
#include <utils/Timers.h>
#include <cinttypes>
+#include <mutex>
#include <optional>
#include <queue>
#include <thread>
-namespace android {
+namespace {
+struct {
+ // Global JVM that is provided by zygote
+ JavaVM* jvm = nullptr;
+ struct {
+ jclass clazz;
+ jmethodID getInstance;
+ jmethodID registerNativeChoreographerForRefreshRateCallbacks;
+ jmethodID unregisterNativeChoreographerForRefreshRateCallbacks;
+ } displayManagerGlobal;
+} gJni;
-static inline const char* toString(bool value) {
+// Gets the JNIEnv* for this thread, and performs one-off initialization if we
+// have never retrieved a JNIEnv* pointer before.
+JNIEnv* getJniEnv() {
+ if (gJni.jvm == nullptr) {
+ ALOGW("AChoreographer: No JVM provided!");
+ return nullptr;
+ }
+
+ JNIEnv* env = nullptr;
+ if (gJni.jvm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK) {
+ ALOGD("Attaching thread to JVM for AChoreographer");
+ JavaVMAttachArgs args = {JNI_VERSION_1_4, "AChoreographer_env", NULL};
+ jint attachResult = gJni.jvm->AttachCurrentThreadAsDaemon(&env, (void*)&args);
+ if (attachResult != JNI_OK) {
+ ALOGE("Unable to attach thread. Error: %d", attachResult);
+ return nullptr;
+ }
+ }
+ if (env == nullptr) {
+ ALOGW("AChoreographer: No JNI env available!");
+ }
+ return env;
+}
+
+inline const char* toString(bool value) {
return value ? "true" : "false";
}
+} // namespace
+
+namespace android {
struct FrameCallback {
AChoreographer_frameCallback callback;
@@ -52,24 +91,43 @@
struct RefreshRateCallback {
AChoreographer_refreshRateCallback callback;
void* data;
+ bool firstCallbackFired = false;
};
+class Choreographer;
+
+struct {
+ std::mutex lock;
+ std::vector<Choreographer*> ptrs GUARDED_BY(lock);
+ bool registeredToDisplayManager GUARDED_BY(lock) = false;
+
+ std::atomic<nsecs_t> mLastKnownVsync = -1;
+} gChoreographers;
+
class Choreographer : public DisplayEventDispatcher, public MessageHandler {
public:
- explicit Choreographer(const sp<Looper>& looper);
+ explicit Choreographer(const sp<Looper>& looper) EXCLUDES(gChoreographers.lock);
void postFrameCallbackDelayed(AChoreographer_frameCallback cb,
AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay);
- void registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data);
+ void registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data)
+ EXCLUDES(gChoreographers.lock);
void unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data);
+ // Drains the queue of pending vsync periods and dispatches refresh rate
+ // updates to callbacks.
+ // The assumption is that this method is only called on a single
+ // processing thread, either by looper or by AChoreographer_handleEvents
+ void handleRefreshRateUpdates();
+ void scheduleLatestConfigRequest();
enum {
MSG_SCHEDULE_CALLBACKS = 0,
- MSG_SCHEDULE_VSYNC = 1
+ MSG_SCHEDULE_VSYNC = 1,
+ MSG_HANDLE_REFRESH_RATE_UPDATES = 2,
};
virtual void handleMessage(const Message& message) override;
static Choreographer* getForThread();
- virtual ~Choreographer() = default;
+ virtual ~Choreographer() override EXCLUDES(gChoreographers.lock);
private:
Choreographer(const Choreographer&) = delete;
@@ -81,21 +139,17 @@
void scheduleCallbacks();
+ std::mutex mLock;
// Protected by mLock
std::priority_queue<FrameCallback> mFrameCallbacks;
-
- // Protected by mLock
std::vector<RefreshRateCallback> mRefreshRateCallbacks;
- nsecs_t mVsyncPeriod = 0;
- mutable Mutex mLock;
+ nsecs_t mLatestVsyncPeriod = -1;
const sp<Looper> mLooper;
const std::thread::id mThreadId;
- const std::optional<PhysicalDisplayId> mInternalDisplayId;
};
-
static thread_local Choreographer* gChoreographer;
Choreographer* Choreographer::getForThread() {
if (gChoreographer == nullptr) {
@@ -115,17 +169,47 @@
}
Choreographer::Choreographer(const sp<Looper>& looper)
- : DisplayEventDispatcher(looper),
+ : DisplayEventDispatcher(looper, ISurfaceComposer::VsyncSource::eVsyncSourceApp,
+ ISurfaceComposer::ConfigChanged::eConfigChangedDispatch),
mLooper(looper),
- mThreadId(std::this_thread::get_id()),
- mInternalDisplayId(SurfaceComposerClient::getInternalDisplayId()) {}
+ mThreadId(std::this_thread::get_id()) {
+ std::lock_guard<std::mutex> _l(gChoreographers.lock);
+ gChoreographers.ptrs.push_back(this);
+}
+
+Choreographer::~Choreographer() {
+ std::lock_guard<std::mutex> _l(gChoreographers.lock);
+ gChoreographers.ptrs.erase(std::remove_if(gChoreographers.ptrs.begin(),
+ gChoreographers.ptrs.end(),
+ [=](Choreographer* c) { return c == this; }),
+ gChoreographers.ptrs.end());
+ // Only poke DisplayManagerGlobal to unregister if we previously registered
+ // callbacks.
+ if (gChoreographers.ptrs.empty() && gChoreographers.registeredToDisplayManager) {
+ JNIEnv* env = getJniEnv();
+ if (env == nullptr) {
+ ALOGW("JNI environment is unavailable, skipping choreographer cleanup");
+ return;
+ }
+ jobject dmg = env->CallStaticObjectMethod(gJni.displayManagerGlobal.clazz,
+ gJni.displayManagerGlobal.getInstance);
+ if (dmg == nullptr) {
+ ALOGW("DMS is not initialized yet, skipping choreographer cleanup");
+ } else {
+ env->CallVoidMethod(dmg,
+ gJni.displayManagerGlobal
+ .unregisterNativeChoreographerForRefreshRateCallbacks);
+ env->DeleteLocalRef(dmg);
+ }
+ }
+}
void Choreographer::postFrameCallbackDelayed(
AChoreographer_frameCallback cb, AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
FrameCallback callback{cb, cb64, data, now + delay};
{
- AutoMutex _l{mLock};
+ std::lock_guard<std::mutex> _l{mLock};
mFrameCallbacks.push(callback);
}
if (callback.dueTime <= now) {
@@ -150,37 +234,68 @@
}
void Choreographer::registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data) {
+ std::lock_guard<std::mutex> _l{mLock};
+ for (const auto& callback : mRefreshRateCallbacks) {
+ // Don't re-add callbacks.
+ if (cb == callback.callback && data == callback.data) {
+ return;
+ }
+ }
+ mRefreshRateCallbacks.emplace_back(
+ RefreshRateCallback{.callback = cb, .data = data, .firstCallbackFired = false});
+ bool needsRegistration = false;
{
- AutoMutex _l{mLock};
- for (const auto& callback : mRefreshRateCallbacks) {
- // Don't re-add callbacks.
- if (cb == callback.callback && data == callback.data) {
- return;
+ std::lock_guard<std::mutex> _l2(gChoreographers.lock);
+ needsRegistration = !gChoreographers.registeredToDisplayManager;
+ }
+ if (needsRegistration) {
+ JNIEnv* env = getJniEnv();
+ if (env == nullptr) {
+ ALOGW("JNI environment is unavailable, skipping registration");
+ return;
+ }
+ jobject dmg = env->CallStaticObjectMethod(gJni.displayManagerGlobal.clazz,
+ gJni.displayManagerGlobal.getInstance);
+ if (dmg == nullptr) {
+ ALOGW("DMS is not initialized yet: skipping registration");
+ return;
+ } else {
+ env->CallVoidMethod(dmg,
+ gJni.displayManagerGlobal
+ .registerNativeChoreographerForRefreshRateCallbacks,
+ reinterpret_cast<int64_t>(this));
+ env->DeleteLocalRef(dmg);
+ {
+ std::lock_guard<std::mutex> _l2(gChoreographers.lock);
+ gChoreographers.registeredToDisplayManager = true;
}
}
- mRefreshRateCallbacks.emplace_back(RefreshRateCallback{cb, data});
- toggleConfigEvents(ISurfaceComposer::ConfigChanged::eConfigChangedDispatch);
+ } else {
+ scheduleLatestConfigRequest();
}
}
void Choreographer::unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb,
void* data) {
- {
- AutoMutex _l{mLock};
- mRefreshRateCallbacks.erase(std::remove_if(mRefreshRateCallbacks.begin(),
- mRefreshRateCallbacks.end(),
- [&](const RefreshRateCallback& callback) {
- return cb == callback.callback &&
- data == callback.data;
- }),
- mRefreshRateCallbacks.end());
- if (mRefreshRateCallbacks.empty()) {
- toggleConfigEvents(ISurfaceComposer::ConfigChanged::eConfigChangedSuppress);
- // If callbacks are empty then clear out the most recently seen
- // vsync period so that when another callback is registered then the
- // up-to-date refresh rate can be communicated to the app again.
- mVsyncPeriod = 0;
- }
+ std::lock_guard<std::mutex> _l{mLock};
+ mRefreshRateCallbacks.erase(std::remove_if(mRefreshRateCallbacks.begin(),
+ mRefreshRateCallbacks.end(),
+ [&](const RefreshRateCallback& callback) {
+ return cb == callback.callback &&
+ data == callback.data;
+ }),
+ mRefreshRateCallbacks.end());
+}
+
+void Choreographer::scheduleLatestConfigRequest() {
+ if (mLooper != nullptr) {
+ Message m{MSG_HANDLE_REFRESH_RATE_UPDATES};
+ mLooper->sendMessage(this, m);
+ } else {
+ // If the looper thread is detached from Choreographer, then refresh rate
+ // changes will be handled in AChoreographer_handlePendingEvents, so we
+ // need to redispatch a config from SF
+ requestLatestConfig();
}
}
@@ -188,7 +303,7 @@
const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
nsecs_t dueTime;
{
- AutoMutex _{mLock};
+ std::lock_guard<std::mutex> _l{mLock};
// If there are no pending callbacks then don't schedule a vsync
if (mFrameCallbacks.empty()) {
return;
@@ -203,13 +318,35 @@
}
}
+void Choreographer::handleRefreshRateUpdates() {
+ std::vector<RefreshRateCallback> callbacks{};
+ const nsecs_t pendingPeriod = gChoreographers.mLastKnownVsync.load();
+ const nsecs_t lastPeriod = mLatestVsyncPeriod;
+ if (pendingPeriod > 0) {
+ mLatestVsyncPeriod = pendingPeriod;
+ }
+ {
+ std::lock_guard<std::mutex> _l{mLock};
+ for (auto& cb : mRefreshRateCallbacks) {
+ callbacks.push_back(cb);
+ cb.firstCallbackFired = true;
+ }
+ }
+
+ for (auto& cb : callbacks) {
+ if (!cb.firstCallbackFired || (pendingPeriod > 0 && pendingPeriod != lastPeriod)) {
+ cb.callback(pendingPeriod, cb.data);
+ }
+ }
+}
+
// TODO(b/74619554): The PhysicalDisplayId is ignored because SF only emits VSYNC events for the
// internal display and DisplayEventReceiver::requestNextVsync only allows requesting VSYNC for
// the internal display implicitly.
void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t) {
std::vector<FrameCallback> callbacks{};
{
- AutoMutex _l{mLock};
+ std::lock_guard<std::mutex> _l{mLock};
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
while (!mFrameCallbacks.empty() && mFrameCallbacks.top().dueTime < now) {
callbacks.push_back(mFrameCallbacks.top());
@@ -236,20 +373,29 @@
// display, so as such Choreographer does not support the notion of multiple
// displays. When multi-display choreographer is properly supported, then
// PhysicalDisplayId should no longer be ignored.
-void Choreographer::dispatchConfigChanged(nsecs_t, PhysicalDisplayId, int32_t,
+void Choreographer::dispatchConfigChanged(nsecs_t, PhysicalDisplayId displayId, int32_t configId,
nsecs_t vsyncPeriod) {
+ ALOGV("choreographer %p ~ received config change event "
+ "(displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", configId=%d).",
+ this, displayId, configId);
+
+ const nsecs_t lastPeriod = mLatestVsyncPeriod;
+ std::vector<RefreshRateCallback> callbacks{};
{
- AutoMutex _l{mLock};
- for (const auto& cb : mRefreshRateCallbacks) {
- // Only perform the callback when the old refresh rate is different
- // from the new refresh rate, so that we don't dispatch the callback
- // on every single configuration change.
- if (mVsyncPeriod != vsyncPeriod) {
- cb.callback(vsyncPeriod, cb.data);
- }
+ std::lock_guard<std::mutex> _l{mLock};
+ for (auto& cb : mRefreshRateCallbacks) {
+ callbacks.push_back(cb);
+ cb.firstCallbackFired = true;
}
- mVsyncPeriod = vsyncPeriod;
}
+
+ for (auto& cb : callbacks) {
+ if (!cb.firstCallbackFired || (vsyncPeriod > 0 && vsyncPeriod != lastPeriod)) {
+ cb.callback(vsyncPeriod, cb.data);
+ }
+ }
+
+ mLatestVsyncPeriod = vsyncPeriod;
}
void Choreographer::handleMessage(const Message& message) {
@@ -260,19 +406,80 @@
case MSG_SCHEDULE_VSYNC:
scheduleVsync();
break;
+ case MSG_HANDLE_REFRESH_RATE_UPDATES:
+ handleRefreshRateUpdates();
+ break;
}
}
-}
-
-/* Glue for the NDK interface */
-
+} // namespace android
using namespace android;
static inline Choreographer* AChoreographer_to_Choreographer(AChoreographer* choreographer) {
return reinterpret_cast<Choreographer*>(choreographer);
}
+// Glue for private C api
+namespace android {
+void AChoreographer_signalRefreshRateCallbacks(nsecs_t vsyncPeriod) EXCLUDES(gChoreographers.lock) {
+ std::lock_guard<std::mutex> _l(gChoreographers.lock);
+ gChoreographers.mLastKnownVsync.store(vsyncPeriod);
+ for (auto c : gChoreographers.ptrs) {
+ c->scheduleLatestConfigRequest();
+ }
+}
+
+void AChoreographer_initJVM(JNIEnv* env) {
+ env->GetJavaVM(&gJni.jvm);
+ // Now we need to find the java classes.
+ jclass dmgClass = env->FindClass("android/hardware/display/DisplayManagerGlobal");
+ gJni.displayManagerGlobal.clazz = static_cast<jclass>(env->NewGlobalRef(dmgClass));
+ gJni.displayManagerGlobal.getInstance =
+ env->GetStaticMethodID(dmgClass, "getInstance",
+ "()Landroid/hardware/display/DisplayManagerGlobal;");
+ gJni.displayManagerGlobal.registerNativeChoreographerForRefreshRateCallbacks =
+ env->GetMethodID(dmgClass, "registerNativeChoreographerForRefreshRateCallbacks", "()V");
+ gJni.displayManagerGlobal.unregisterNativeChoreographerForRefreshRateCallbacks =
+ env->GetMethodID(dmgClass, "unregisterNativeChoreographerForRefreshRateCallbacks",
+ "()V");
+}
+
+AChoreographer* AChoreographer_routeGetInstance() {
+ return AChoreographer_getInstance();
+}
+void AChoreographer_routePostFrameCallback(AChoreographer* choreographer,
+ AChoreographer_frameCallback callback, void* data) {
+ return AChoreographer_postFrameCallback(choreographer, callback, data);
+}
+void AChoreographer_routePostFrameCallbackDelayed(AChoreographer* choreographer,
+ AChoreographer_frameCallback callback, void* data,
+ long delayMillis) {
+ return AChoreographer_postFrameCallbackDelayed(choreographer, callback, data, delayMillis);
+}
+void AChoreographer_routePostFrameCallback64(AChoreographer* choreographer,
+ AChoreographer_frameCallback64 callback, void* data) {
+ return AChoreographer_postFrameCallback64(choreographer, callback, data);
+}
+void AChoreographer_routePostFrameCallbackDelayed64(AChoreographer* choreographer,
+ AChoreographer_frameCallback64 callback,
+ void* data, uint32_t delayMillis) {
+ return AChoreographer_postFrameCallbackDelayed64(choreographer, callback, data, delayMillis);
+}
+void AChoreographer_routeRegisterRefreshRateCallback(AChoreographer* choreographer,
+ AChoreographer_refreshRateCallback callback,
+ void* data) {
+ return AChoreographer_registerRefreshRateCallback(choreographer, callback, data);
+}
+void AChoreographer_routeUnregisterRefreshRateCallback(AChoreographer* choreographer,
+ AChoreographer_refreshRateCallback callback,
+ void* data) {
+ return AChoreographer_unregisterRefreshRateCallback(choreographer, callback, data);
+}
+
+} // namespace android
+
+/* Glue for the NDK interface */
+
static inline const Choreographer* AChoreographer_to_Choreographer(
const AChoreographer* choreographer) {
return reinterpret_cast<const Choreographer*>(choreographer);
@@ -343,5 +550,6 @@
// Pass dummy fd and events args to handleEvent, since the underlying
// DisplayEventDispatcher doesn't need them outside of validating that a
// Looper instance didn't break, but these args circumvent those checks.
- AChoreographer_to_Choreographer(choreographer)->handleEvent(-1, Looper::EVENT_INPUT, data);
+ Choreographer* impl = AChoreographer_to_Choreographer(choreographer);
+ impl->handleEvent(-1, Looper::EVENT_INPUT, data);
}
diff --git a/libs/nativedisplay/Android.bp b/libs/nativedisplay/Android.bp
index c956578..f56b3a2 100644
--- a/libs/nativedisplay/Android.bp
+++ b/libs/nativedisplay/Android.bp
@@ -12,23 +12,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-ndk_headers {
- name: "libnativedisplay_ndk_headers",
- from: "include/android",
- to: "android",
- srcs: ["include/android/*.h"],
- license: "NOTICE",
-}
-
cc_library_headers {
name: "libnativedisplay_headers",
- export_include_dirs: ["include"],
+ export_include_dirs: ["include",],
}
-cc_library {
+cc_library_shared {
name: "libnativedisplay",
export_include_dirs: [
"include",
+ "include-private",
],
clang: true,
@@ -63,6 +56,10 @@
"libnativehelper",
],
+ export_shared_lib_headers: [
+ "libnativehelper",
+ ],
+
header_libs: [
"libnativedisplay_headers",
],
diff --git a/libs/nativedisplay/include-private/private/android/choreographer.h b/libs/nativedisplay/include-private/private/android/choreographer.h
new file mode 100644
index 0000000..2164930
--- /dev/null
+++ b/libs/nativedisplay/include-private/private/android/choreographer.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <apex/choreographer.h>
+#include <inttypes.h>
+#include <nativehelper/JNIHelp.h>
+
+namespace android {
+
+// Registers the global JVM for AChoreographer
+void AChoreographer_initJVM(JNIEnv* env);
+
+// Signals all AChoregorapher* instances that a new vsync period is available
+// for consumption by callbacks.
+void AChoreographer_signalRefreshRateCallbacks(int64_t vsyncPeriod);
+
+// Trampoline functions allowing libandroid.so to define the NDK symbols without including
+// the entirety of libnativedisplay as a whole static lib. As libnativedisplay
+// maintains global state, libnativedisplay can never be directly statically
+// linked so that global state won't be duplicated. This way libandroid.so can
+// reroute the NDK methods into the implementations defined by libnativedisplay
+AChoreographer* AChoreographer_routeGetInstance();
+void AChoreographer_routePostFrameCallback(AChoreographer* choreographer,
+ AChoreographer_frameCallback callback, void* data);
+void AChoreographer_routePostFrameCallbackDelayed(AChoreographer* choreographer,
+ AChoreographer_frameCallback callback, void* data,
+ long delayMillis);
+void AChoreographer_routePostFrameCallback64(AChoreographer* choreographer,
+ AChoreographer_frameCallback64 callback, void* data);
+void AChoreographer_routePostFrameCallbackDelayed64(AChoreographer* choreographer,
+ AChoreographer_frameCallback64 callback,
+ void* data, uint32_t delayMillis);
+void AChoreographer_routeRegisterRefreshRateCallback(AChoreographer* choreographer,
+ AChoreographer_refreshRateCallback callback,
+ void* data);
+void AChoreographer_routeUnregisterRefreshRateCallback(AChoreographer* choreographer,
+ AChoreographer_refreshRateCallback callback,
+ void* data);
+
+} // namespace android
diff --git a/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h b/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h
index 6a94a77..e2d036b 100644
--- a/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h
+++ b/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h
@@ -19,7 +19,7 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
-
+#include <nativehelper/JNIHelp.h>
#include <system/graphics.h>
// This file provides a facade API on top of SurfaceTexture, which avoids using
@@ -30,6 +30,20 @@
namespace android {
+// Trampoline functions allowing libandroid.so to define the NDK symbols without including
+// the entirety of libnativedisplay as a whole static lib. As libnativedisplay
+// maintains global state, libnativedisplay can never be directly statically
+// linked so that global state won't be duplicated. This way libandroid.so can
+// reroute the NDK methods into the implementations defined by libnativedisplay
+ANativeWindow* ASurfaceTexture_routeAcquireANativeWindow(ASurfaceTexture* st);
+int ASurfaceTexture_routeAttachToGLContext(ASurfaceTexture* st, uint32_t texName);
+int ASurfaceTexture_routeDetachFromGLContext(ASurfaceTexture* st);
+void ASurfaceTexture_routeRelease(ASurfaceTexture* st);
+int ASurfaceTexture_routeUpdateTexImage(ASurfaceTexture* st);
+void ASurfaceTexture_routeGetTransformMatrix(ASurfaceTexture* st, float mtx[16]);
+int64_t ASurfaceTexture_routeGetTimestamp(ASurfaceTexture* st);
+ASurfaceTexture* ASurfaceTexture_routeFromSurfaceTexture(JNIEnv* env, jobject surfacetexture);
+
/**
* ASurfaceTexture_getCurrentTextureTarget returns the texture target of the
* current texture.
diff --git a/libs/nativedisplay/libnativedisplay.map.txt b/libs/nativedisplay/libnativedisplay.map.txt
index 483fb25..fc59431 100644
--- a/libs/nativedisplay/libnativedisplay.map.txt
+++ b/libs/nativedisplay/libnativedisplay.map.txt
@@ -20,6 +20,15 @@
LIBNATIVEDISPLAY_PLATFORM {
global:
extern "C++" {
+ android::AChoreographer_initJVM*;
+ android::AChoreographer_routeGetInstance*;
+ android::AChoreographer_routePostFrameCallback*;
+ android::AChoreographer_routePostFrameCallbackDelayed*;
+ android::AChoreographer_routePostFrameCallback64*;
+ android::AChoreographer_routePostFrameCallbackDelayed64*;
+ android::AChoreographer_routeRegisterRefreshRateCallback*;
+ android::AChoreographer_routeUnregisterRefreshRateCallback*;
+ android::AChoreographer_signalRefreshRateCallbacks*;
android::ADisplay_acquirePhysicalDisplays*;
android::ADisplay_release*;
android::ADisplay_getMaxSupportedFps*;
@@ -36,6 +45,14 @@
android::ASurfaceTexture_takeConsumerOwnership*;
android::ASurfaceTexture_releaseConsumerOwnership*;
android::ASurfaceTexture_dequeueBuffer*;
+ android::ASurfaceTexture_routeAcquireANativeWindow*;
+ android::ASurfaceTexture_routeAttachToGLContext*;
+ android::ASurfaceTexture_routeDetachFromGLContext*;
+ android::ASurfaceTexture_routeGetTimestamp*;
+ android::ASurfaceTexture_routeGetTransformMatrix*;
+ android::ASurfaceTexture_routeUpdateTexImage*;
+ android::ASurfaceTexture_routeFromSurfaceTexture*;
+ android::ASurfaceTexture_routeRelease*;
android::SurfaceTexture*;
};
ASurfaceTexture_acquireANativeWindow;
diff --git a/libs/nativedisplay/surfacetexture/surface_texture.cpp b/libs/nativedisplay/surfacetexture/surface_texture.cpp
index 1670fbb..d1bcd8d 100644
--- a/libs/nativedisplay/surfacetexture/surface_texture.cpp
+++ b/libs/nativedisplay/surfacetexture/surface_texture.cpp
@@ -149,6 +149,37 @@
// The following functions are private/unstable API.
namespace android {
+ANativeWindow* ASurfaceTexture_routeAcquireANativeWindow(ASurfaceTexture* st) {
+ return ASurfaceTexture_acquireANativeWindow(st);
+}
+
+int ASurfaceTexture_routeAttachToGLContext(ASurfaceTexture* st, uint32_t texName) {
+ return ASurfaceTexture_attachToGLContext(st, texName);
+}
+
+void ASurfaceTexture_routeRelease(ASurfaceTexture* st) {
+ return ASurfaceTexture_release(st);
+}
+
+int ASurfaceTexture_routeDetachFromGLContext(ASurfaceTexture* st) {
+ return ASurfaceTexture_detachFromGLContext(st);
+}
+
+int ASurfaceTexture_routeUpdateTexImage(ASurfaceTexture* st) {
+ return ASurfaceTexture_updateTexImage(st);
+}
+
+void ASurfaceTexture_routeGetTransformMatrix(ASurfaceTexture* st, float mtx[16]) {
+ return ASurfaceTexture_getTransformMatrix(st, mtx);
+}
+
+int64_t ASurfaceTexture_routeGetTimestamp(ASurfaceTexture* st) {
+ return ASurfaceTexture_getTimestamp(st);
+}
+
+ASurfaceTexture* ASurfaceTexture_routeFromSurfaceTexture(JNIEnv* env, jobject surfacetexture) {
+ return ASurfaceTexture_fromSurfaceTexture(env, surfacetexture);
+}
unsigned int ASurfaceTexture_getCurrentTextureTarget(ASurfaceTexture* st) {
return st->consumer->getCurrentTextureTarget();
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index 5baec2f..ee006aa 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -25,6 +25,7 @@
name: "libnativewindow_headers",
export_include_dirs: ["include"],
vendor_available: true,
+ min_sdk_version: "29",
}
ndk_library {
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 869ca9e..b78fc5d 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -254,6 +254,7 @@
NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR = 44, /* private */
NATIVE_WINDOW_ALLOCATE_BUFFERS = 45, /* private */
NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER = 46, /* private */
+ NATIVE_WINDOW_SET_QUERY_INTERCEPTOR = 47, /* private */
// clang-format on
};
@@ -1062,4 +1063,38 @@
return value;
}
+/**
+ * Prototype of the function that an ANativeWindow implementation would call
+ * when ANativeWindow_query is called.
+ */
+typedef int (*ANativeWindow_queryFn)(const ANativeWindow* window, int what, int* value);
+
+/**
+ * Prototype of the function that intercepts an invocation of
+ * ANativeWindow_queryFn, along with a data pointer that's passed by the
+ * caller who set the interceptor, as well as arguments that would be
+ * passed to ANativeWindow_queryFn if it were to be called.
+ */
+typedef int (*ANativeWindow_queryInterceptor)(const ANativeWindow* window,
+ ANativeWindow_queryFn perform, void* data,
+ int what, int* value);
+
+/**
+ * Registers an interceptor for ANativeWindow_query. Instead of calling
+ * the underlying query function, instead the provided interceptor is
+ * called, which may optionally call the underlying query function. An
+ * optional data pointer is also provided to side-channel additional arguments.
+ *
+ * Note that usage of this should only be used for specialized use-cases by
+ * either the system partition or to Mainline modules. This should never be
+ * exposed to NDK or LL-NDK.
+ *
+ * Returns NO_ERROR on success, -errno if registration failed.
+ */
+static inline int ANativeWindow_setQueryInterceptor(ANativeWindow* window,
+ ANativeWindow_queryInterceptor interceptor,
+ void* data) {
+ return window->perform(window, NATIVE_WINDOW_SET_QUERY_INTERCEPTOR, interceptor, data);
+}
+
__END_DECLS
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 458ee67..1ee8c71 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -133,6 +133,7 @@
"libhardware_headers",
"libui_headers",
],
+ min_sdk_version: "29",
}
cc_library_headers {
@@ -151,6 +152,7 @@
export_header_lib_headers: [
"libnativewindow_headers",
],
+ min_sdk_version: "29",
}
// defaults to enable VALIDATE_REGIONS traces
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index 82ce757..e01309b 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -224,6 +224,11 @@
validate(*this, "this->operator=");
validate(rhs, "rhs.operator=");
#endif
+ if (this == &rhs) {
+ // Already equal to itself
+ return *this;
+ }
+
mStorage.clear();
mStorage.insert(mStorage.begin(), rhs.mStorage.begin(), rhs.mStorage.end());
return *this;
diff --git a/libs/ui/tests/Region_test.cpp b/libs/ui/tests/Region_test.cpp
index b104a46..c6b826d 100644
--- a/libs/ui/tests/Region_test.cpp
+++ b/libs/ui/tests/Region_test.cpp
@@ -152,5 +152,20 @@
}
}
+TEST_F(RegionTest, EqualsToSelf) {
+ Region touchableRegion;
+ touchableRegion.orSelf(Rect(0, 0, 100, 100));
+
+ ASSERT_TRUE(touchableRegion.contains(50, 50));
+
+ // Compiler prevents us from directly calling 'touchableRegion = touchableRegion'
+ Region& referenceTouchableRegion = touchableRegion;
+ touchableRegion = referenceTouchableRegion;
+
+ ASSERT_FALSE(touchableRegion.isEmpty());
+
+ ASSERT_TRUE(touchableRegion.contains(50, 50));
+}
+
}; // namespace android
diff --git a/libs/vr/libpdx/Android.bp b/libs/vr/libpdx/Android.bp
index 23a4224..24ba830 100644
--- a/libs/vr/libpdx/Android.bp
+++ b/libs/vr/libpdx/Android.bp
@@ -2,6 +2,7 @@
name: "libpdx_headers",
export_include_dirs: ["private"],
vendor_available: true,
+ min_sdk_version: "29",
}
cc_library_static {
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index 7c5c9c5..5a14133 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -28,8 +28,8 @@
static const int32_t INJECTOR_PID = 999;
static const int32_t INJECTOR_UID = 1001;
-static const int32_t INJECT_EVENT_TIMEOUT = 5000;
-static const int32_t DISPATCHING_TIMEOUT = 100000;
+static constexpr std::chrono::duration INJECT_EVENT_TIMEOUT = 5s;
+static constexpr std::chrono::nanoseconds DISPATCHING_TIMEOUT = 100ms;
static nsecs_t now() {
return systemTime(SYSTEM_TIME_MONOTONIC);
@@ -47,7 +47,7 @@
private:
virtual void notifyConfigurationChanged(nsecs_t) override {}
- virtual nsecs_t notifyANR(const sp<InputApplicationHandle>&, const sp<IBinder>&,
+ virtual nsecs_t notifyAnr(const sp<InputApplicationHandle>&, const sp<IBinder>&,
const std::string& name) override {
ALOGE("The window is not responding : %s", name.c_str());
return 0;
@@ -98,7 +98,7 @@
virtual ~FakeApplicationHandle() {}
virtual bool updateInfo() {
- mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
+ mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT.count();
return true;
}
};
@@ -163,7 +163,7 @@
mInfo.name = "FakeWindowHandle";
mInfo.layoutParamsFlags = 0;
mInfo.layoutParamsType = InputWindowInfo::TYPE_APPLICATION;
- mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
+ mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT.count();
mInfo.frameLeft = mFrame.left;
mInfo.frameTop = mFrame.top;
mInfo.frameRight = mFrame.right;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index baf2f2b..1dbcf98 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -531,7 +531,7 @@
}
// Get ready to dispatch the event.
- resetANRTimeoutsLocked();
+ resetAnrTimeoutsLocked();
}
// Now we have an event to dispatch.
@@ -888,7 +888,7 @@
void InputDispatcher::releasePendingEventLocked() {
if (mPendingEvent) {
- resetANRTimeoutsLocked();
+ resetAnrTimeoutsLocked();
releaseInboundEventLocked(mPendingEvent);
mPendingEvent = nullptr;
}
@@ -1299,7 +1299,7 @@
}
if (currentTime >= mInputTargetWaitTimeoutTime) {
- onANRLocked(currentTime, applicationHandle, windowHandle, entry.eventTime,
+ onAnrLocked(currentTime, applicationHandle, windowHandle, entry.eventTime,
mInputTargetWaitStartTime, reason);
// Force poll loop to wake up immediately on next iteration once we get the
@@ -1352,7 +1352,7 @@
return 0;
}
-void InputDispatcher::resetANRTimeoutsLocked() {
+void InputDispatcher::resetAnrTimeoutsLocked() {
if (DEBUG_FOCUS) {
ALOGD("Resetting ANR timeouts.");
}
@@ -2748,7 +2748,10 @@
// Monitor channels are never explicitly unregistered.
// We do it automatically when the remote endpoint is closed so don't warn
// about them.
- notify = !connection->monitor;
+ const bool stillHaveWindowHandle =
+ d->getWindowHandleLocked(connection->inputChannel->getConnectionToken()) !=
+ nullptr;
+ notify = !connection->monitor && stillHaveWindowHandle;
if (notify) {
ALOGW("channel '%s' ~ Consumer closed input channel or an error occurred. "
"events=0x%x",
@@ -3273,14 +3276,14 @@
int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injectorPid,
int32_t injectorUid, int32_t syncMode,
- int32_t timeoutMillis, uint32_t policyFlags) {
+ std::chrono::milliseconds timeout, uint32_t policyFlags) {
#if DEBUG_INBOUND_EVENT_DETAILS
ALOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, "
- "syncMode=%d, timeoutMillis=%d, policyFlags=0x%08x",
- event->getType(), injectorPid, injectorUid, syncMode, timeoutMillis, policyFlags);
+ "syncMode=%d, timeout=%lld, policyFlags=0x%08x",
+ event->getType(), injectorPid, injectorUid, syncMode, timeout.count(), policyFlags);
#endif
- nsecs_t endTime = now() + milliseconds_to_nanoseconds(timeoutMillis);
+ nsecs_t endTime = now() + std::chrono::duration_cast<std::chrono::nanoseconds>(timeout).count();
policyFlags |= POLICY_FLAG_INJECTED;
if (hasInjectionPermission(injectorPid, injectorUid)) {
@@ -3467,8 +3470,7 @@
} // release lock
#if DEBUG_INJECTION
- ALOGD("injectInputEvent - Finished with result %d. "
- "injectorPid=%d, injectorUid=%d",
+ ALOGD("injectInputEvent - Finished with result %d. injectorPid=%d, injectorUid=%d",
injectionResult, injectorPid, injectorUid);
#endif
@@ -3800,12 +3802,12 @@
if (inputApplicationHandle != nullptr && inputApplicationHandle->updateInfo()) {
if (oldFocusedApplicationHandle != inputApplicationHandle) {
if (oldFocusedApplicationHandle != nullptr) {
- resetANRTimeoutsLocked();
+ resetAnrTimeoutsLocked();
}
mFocusedApplicationHandlesByDisplay[displayId] = inputApplicationHandle;
}
} else if (oldFocusedApplicationHandle != nullptr) {
- resetANRTimeoutsLocked();
+ resetAnrTimeoutsLocked();
oldFocusedApplicationHandle.clear();
mFocusedApplicationHandlesByDisplay.erase(displayId);
}
@@ -3886,7 +3888,7 @@
if (mDispatchEnabled != enabled || mDispatchFrozen != frozen) {
if (mDispatchFrozen && !frozen) {
- resetANRTimeoutsLocked();
+ resetAnrTimeoutsLocked();
}
if (mDispatchEnabled && !enabled) {
@@ -4026,7 +4028,7 @@
resetKeyRepeatLocked();
releasePendingEventLocked();
drainInboundQueueLocked();
- resetANRTimeoutsLocked();
+ resetAnrTimeoutsLocked();
mTouchStatesByDisplay.clear();
mLastHoverWindowHandle.clear();
@@ -4526,7 +4528,7 @@
postCommandLocked(std::move(commandEntry));
}
-void InputDispatcher::onANRLocked(nsecs_t currentTime,
+void InputDispatcher::onAnrLocked(nsecs_t currentTime,
const sp<InputApplicationHandle>& applicationHandle,
const sp<InputWindowHandle>& windowHandle, nsecs_t eventTime,
nsecs_t waitStartTime, const char* reason) {
@@ -4543,19 +4545,19 @@
localtime_r(&t, &tm);
char timestr[64];
strftime(timestr, sizeof(timestr), "%F %T", &tm);
- mLastANRState.clear();
- mLastANRState += INDENT "ANR:\n";
- mLastANRState += StringPrintf(INDENT2 "Time: %s\n", timestr);
- mLastANRState +=
+ mLastAnrState.clear();
+ mLastAnrState += INDENT "ANR:\n";
+ mLastAnrState += StringPrintf(INDENT2 "Time: %s\n", timestr);
+ mLastAnrState +=
StringPrintf(INDENT2 "Window: %s\n",
getApplicationWindowLabel(applicationHandle, windowHandle).c_str());
- mLastANRState += StringPrintf(INDENT2 "DispatchLatency: %0.1fms\n", dispatchLatency);
- mLastANRState += StringPrintf(INDENT2 "WaitDuration: %0.1fms\n", waitDuration);
- mLastANRState += StringPrintf(INDENT2 "Reason: %s\n", reason);
- dumpDispatchStateLocked(mLastANRState);
+ mLastAnrState += StringPrintf(INDENT2 "DispatchLatency: %0.1fms\n", dispatchLatency);
+ mLastAnrState += StringPrintf(INDENT2 "WaitDuration: %0.1fms\n", waitDuration);
+ mLastAnrState += StringPrintf(INDENT2 "Reason: %s\n", reason);
+ dumpDispatchStateLocked(mLastAnrState);
std::unique_ptr<CommandEntry> commandEntry =
- std::make_unique<CommandEntry>(&InputDispatcher::doNotifyANRLockedInterruptible);
+ std::make_unique<CommandEntry>(&InputDispatcher::doNotifyAnrLockedInterruptible);
commandEntry->inputApplicationHandle = applicationHandle;
commandEntry->inputChannel =
windowHandle != nullptr ? getInputChannelLocked(windowHandle->getToken()) : nullptr;
@@ -4591,13 +4593,13 @@
mLock.lock();
}
-void InputDispatcher::doNotifyANRLockedInterruptible(CommandEntry* commandEntry) {
+void InputDispatcher::doNotifyAnrLockedInterruptible(CommandEntry* commandEntry) {
sp<IBinder> token =
commandEntry->inputChannel ? commandEntry->inputChannel->getConnectionToken() : nullptr;
mLock.unlock();
nsecs_t newTimeout =
- mPolicy->notifyANR(commandEntry->inputApplicationHandle, token, commandEntry->reason);
+ mPolicy->notifyAnr(commandEntry->inputApplicationHandle, token, commandEntry->reason);
mLock.lock();
@@ -4958,9 +4960,9 @@
dump += "Input Dispatcher State:\n";
dumpDispatchStateLocked(dump);
- if (!mLastANRState.empty()) {
+ if (!mLastAnrState.empty()) {
dump += "\nInput Dispatcher State at time of last ANR:\n";
- dump += mLastANRState;
+ dump += mLastAnrState;
}
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 2b9cbce..670d0e1 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -103,7 +103,8 @@
virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
virtual int32_t injectInputEvent(const InputEvent* event, int32_t injectorPid,
- int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
+ int32_t injectorUid, int32_t syncMode,
+ std::chrono::milliseconds timeout,
uint32_t policyFlags) override;
virtual std::unique_ptr<VerifiedInputEvent> verifyInputEvent(const InputEvent& event) override;
@@ -314,7 +315,7 @@
int32_t mFocusedDisplayId GUARDED_BY(mLock);
// Dispatcher state at time of last ANR.
- std::string mLastANRState GUARDED_BY(mLock);
+ std::string mLastAnrState GUARDED_BY(mLock);
// Dispatch inbound events.
bool dispatchConfigurationChangedLocked(nsecs_t currentTime, ConfigurationChangedEntry* entry)
@@ -360,7 +361,7 @@
const sp<IBinder>& inputConnectionToken)
REQUIRES(mLock);
nsecs_t getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime) REQUIRES(mLock);
- void resetANRTimeoutsLocked() REQUIRES(mLock);
+ void resetAnrTimeoutsLocked() REQUIRES(mLock);
int32_t getTargetDisplayId(const EventEntry& entry);
int32_t findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry& entry,
@@ -468,7 +469,7 @@
REQUIRES(mLock);
void onFocusChangedLocked(const sp<InputWindowHandle>& oldFocus,
const sp<InputWindowHandle>& newFocus) REQUIRES(mLock);
- void onANRLocked(nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle,
+ void onAnrLocked(nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle,
const sp<InputWindowHandle>& windowHandle, nsecs_t eventTime,
nsecs_t waitStartTime, const char* reason) REQUIRES(mLock);
@@ -477,7 +478,7 @@
REQUIRES(mLock);
void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
void doNotifyFocusChangedLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
- void doNotifyANRLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
+ void doNotifyAnrLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
void doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry)
REQUIRES(mLock);
void doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index 09dc92c..9b002f4 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -90,8 +90,8 @@
* This method may be called on any thread (usually by the input manager).
*/
virtual int32_t injectInputEvent(const InputEvent* event, int32_t injectorPid,
- int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
- uint32_t policyFlags) = 0;
+ int32_t injectorUid, int32_t syncMode,
+ std::chrono::milliseconds timeout, uint32_t policyFlags) = 0;
/*
* Check whether InputEvent actually happened by checking the signature of the event.
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
index 4214488..667af9b 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
@@ -47,7 +47,7 @@
/* Notifies the system that an application is not responding.
* Returns a new timeout to continue waiting, or 0 to abort dispatch. */
- virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
+ virtual nsecs_t notifyAnr(const sp<InputApplicationHandle>& inputApplicationHandle,
const sp<IBinder>& token, const std::string& reason) = 0;
/* Notifies the system that an input channel is unrecoverably broken. */
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 365d43d..eeff757 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -127,19 +127,16 @@
mConfigurationChangedTime = when;
}
- virtual nsecs_t notifyANR(const sp<InputApplicationHandle>&,
- const sp<IBinder>&,
- const std::string&) {
+ virtual nsecs_t notifyAnr(const sp<InputApplicationHandle>&, const sp<IBinder>&,
+ const std::string&) override {
return 0;
}
- virtual void notifyInputChannelBroken(const sp<IBinder>&) {
- }
+ virtual void notifyInputChannelBroken(const sp<IBinder>&) override {}
- virtual void notifyFocusChanged(const sp<IBinder>&, const sp<IBinder>&) {
- }
+ virtual void notifyFocusChanged(const sp<IBinder>&, const sp<IBinder>&) override {}
- virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) {
+ virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) override {
*outConfig = mConfig;
}
@@ -160,19 +157,17 @@
return true;
}
- virtual void interceptKeyBeforeQueueing(const KeyEvent*, uint32_t&) {
- }
+ virtual void interceptKeyBeforeQueueing(const KeyEvent*, uint32_t&) override {}
- virtual void interceptMotionBeforeQueueing(int32_t, nsecs_t, uint32_t&) {
- }
+ virtual void interceptMotionBeforeQueueing(int32_t, nsecs_t, uint32_t&) override {}
- virtual nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>&,
- const KeyEvent*, uint32_t) {
+ virtual nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>&, const KeyEvent*,
+ uint32_t) override {
return 0;
}
- virtual bool dispatchUnhandledKey(const sp<IBinder>&,
- const KeyEvent*, uint32_t, KeyEvent*) {
+ virtual bool dispatchUnhandledKey(const sp<IBinder>&, const KeyEvent*, uint32_t,
+ KeyEvent*) override {
return false;
}
@@ -184,14 +179,13 @@
mLastNotifySwitch = NotifySwitchArgs(1 /*id*/, when, policyFlags, switchValues, switchMask);
}
- virtual void pokeUserActivity(nsecs_t, int32_t) {
- }
+ virtual void pokeUserActivity(nsecs_t, int32_t) override {}
- virtual bool checkInjectEventsPermissionNonReentrant(int32_t, int32_t) {
+ virtual bool checkInjectEventsPermissionNonReentrant(int32_t, int32_t) override {
return false;
}
- virtual void onPointerDownOutsideFocus(const sp<IBinder>& newToken) {
+ virtual void onPointerDownOutsideFocus(const sp<IBinder>& newToken) override {
mOnPointerDownToken = newToken;
}
@@ -313,18 +307,18 @@
INVALID_HMAC,
/*action*/ -1, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME,
ARBITRARY_TIME);
- ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
- &event,
- INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
+ ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED,
+ mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ INPUT_EVENT_INJECTION_SYNC_NONE, 0ms, 0))
<< "Should reject key events with undefined action.";
// Rejects ACTION_MULTIPLE since it is not supported despite being defined in the API.
event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
INVALID_HMAC, AKEY_EVENT_ACTION_MULTIPLE, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0,
ARBITRARY_TIME, ARBITRARY_TIME);
- ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
- &event,
- INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
+ ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED,
+ mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ INPUT_EVENT_INJECTION_SYNC_NONE, 0ms, 0))
<< "Should reject key events with ACTION_MULTIPLE.";
}
@@ -350,9 +344,9 @@
1 /* yScale */, 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
- ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
- &event,
- INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
+ ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED,
+ mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ INPUT_EVENT_INJECTION_SYNC_NONE, 0ms, 0))
<< "Should reject motion events with undefined action.";
// Rejects pointer down with invalid index.
@@ -363,9 +357,9 @@
0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
- ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
- &event,
- INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
+ ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED,
+ mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ INPUT_EVENT_INJECTION_SYNC_NONE, 0ms, 0))
<< "Should reject motion events with pointer down index too large.";
event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
@@ -375,9 +369,9 @@
0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
- ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
- &event,
- INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
+ ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED,
+ mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ INPUT_EVENT_INJECTION_SYNC_NONE, 0ms, 0))
<< "Should reject motion events with pointer down index too small.";
// Rejects pointer up with invalid index.
@@ -388,9 +382,9 @@
0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
- ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
- &event,
- INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
+ ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED,
+ mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ INPUT_EVENT_INJECTION_SYNC_NONE, 0ms, 0))
<< "Should reject motion events with pointer up index too large.";
event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
@@ -400,9 +394,9 @@
0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
- ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
- &event,
- INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
+ ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED,
+ mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ INPUT_EVENT_INJECTION_SYNC_NONE, 0ms, 0))
<< "Should reject motion events with pointer up index too small.";
// Rejects motion events with invalid number of pointers.
@@ -412,9 +406,9 @@
AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 0, pointerProperties, pointerCoords);
- ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
- &event,
- INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
+ ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED,
+ mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ INPUT_EVENT_INJECTION_SYNC_NONE, 0ms, 0))
<< "Should reject motion events with 0 pointers.";
event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
@@ -423,9 +417,9 @@
AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords);
- ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
- &event,
- INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
+ ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED,
+ mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ INPUT_EVENT_INJECTION_SYNC_NONE, 0ms, 0))
<< "Should reject motion events with more than MAX_POINTERS pointers.";
// Rejects motion events with invalid pointer ids.
@@ -436,9 +430,9 @@
AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
- ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
- &event,
- INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
+ ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED,
+ mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ INPUT_EVENT_INJECTION_SYNC_NONE, 0ms, 0))
<< "Should reject motion events with pointer ids less than 0.";
pointerProperties[0].id = MAX_POINTER_ID + 1;
@@ -448,9 +442,9 @@
AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
- ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
- &event,
- INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
+ ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED,
+ mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ INPUT_EVENT_INJECTION_SYNC_NONE, 0ms, 0))
<< "Should reject motion events with pointer ids greater than MAX_POINTER_ID.";
// Rejects motion events with duplicate pointer ids.
@@ -462,9 +456,9 @@
AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 2, pointerProperties, pointerCoords);
- ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
- &event,
- INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
+ ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED,
+ mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ INPUT_EVENT_INJECTION_SYNC_NONE, 0ms, 0))
<< "Should reject motion events with duplicate pointer ids.";
}
@@ -490,16 +484,16 @@
}
// --- InputDispatcherTest SetInputWindowTest ---
-static constexpr int32_t INJECT_EVENT_TIMEOUT = 500;
-static constexpr nsecs_t DISPATCHING_TIMEOUT = seconds_to_nanoseconds(5);
+static constexpr std::chrono::duration INJECT_EVENT_TIMEOUT = 500ms;
+static constexpr std::chrono::duration DISPATCHING_TIMEOUT = 5s;
class FakeApplicationHandle : public InputApplicationHandle {
public:
FakeApplicationHandle() {}
virtual ~FakeApplicationHandle() {}
- virtual bool updateInfo() {
- mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
+ virtual bool updateInfo() override {
+ mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT.count();
return true;
}
};
@@ -638,7 +632,7 @@
mInfo.name = name;
mInfo.layoutParamsFlags = 0;
mInfo.layoutParamsType = InputWindowInfo::TYPE_APPLICATION;
- mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
+ mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT.count();
mInfo.frameLeft = 0;
mInfo.frameTop = 0;
mInfo.frameRight = WIDTH;
@@ -811,13 +805,15 @@
}
static int32_t injectMotionDown(const sp<InputDispatcher>& dispatcher, int32_t source,
- int32_t displayId, int32_t x = 100, int32_t y = 200) {
- return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_DOWN, source, displayId, x, y);
+ int32_t displayId, const PointF& location = {100, 200}) {
+ return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_DOWN, source, displayId, location.x,
+ location.y);
}
static int32_t injectMotionUp(const sp<InputDispatcher>& dispatcher, int32_t source,
- int32_t displayId, int32_t x = 100, int32_t y = 200) {
- return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_UP, source, displayId, x, y);
+ int32_t displayId, const PointF& location = {100, 200}) {
+ return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_UP, source, displayId, location.x,
+ location.y);
}
static NotifyKeyArgs generateKeyArgs(int32_t action, int32_t displayId = ADISPLAY_ID_NONE) {
@@ -881,6 +877,55 @@
window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
}
+/**
+ * Calling setInputWindows once with FLAG_NOT_TOUCH_MODAL should not cause any issues.
+ * To ensure that window receives only events that were directly inside of it, add
+ * FLAG_NOT_TOUCH_MODAL. This will enforce using the touchableRegion of the input
+ * when finding touched windows.
+ * This test serves as a sanity check for the next test, where setInputWindows is
+ * called twice.
+ */
+TEST_F(InputDispatcherTest, SetInputWindowOnce_SingleWindowTouch) {
+ sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+ window->setFrame(Rect(0, 0, 100, 100));
+ window->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL);
+
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {50, 50}))
+ << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+
+ // Window should receive motion event.
+ window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+}
+
+/**
+ * Calling setInputWindows twice, with the same info, should not cause any issues.
+ * To ensure that window receives only events that were directly inside of it, add
+ * FLAG_NOT_TOUCH_MODAL. This will enforce using the touchableRegion of the input
+ * when finding touched windows.
+ */
+TEST_F(InputDispatcherTest, SetInputWindowTwice_SingleWindowTouch) {
+ sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+ window->setFrame(Rect(0, 0, 100, 100));
+ window->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL);
+
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {50, 50}))
+ << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+
+ // Window should receive motion event.
+ window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+}
+
// The foreground window should receive the first touch down event.
TEST_F(InputDispatcherTest, SetInputWindow_MultiWindowsTouch) {
sp<FakeApplicationHandle> application = new FakeApplicationHandle();
@@ -1822,7 +1867,6 @@
new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
mFocusedWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL);
- mFocusedWindowTouchPoint = 60;
// Set focused application.
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -1843,15 +1887,16 @@
protected:
sp<FakeWindowHandle> mUnfocusedWindow;
sp<FakeWindowHandle> mFocusedWindow;
- int32_t mFocusedWindowTouchPoint;
+ static constexpr PointF FOCUSED_WINDOW_TOUCH_POINT = {60, 60};
};
// Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action
// DOWN on the window that doesn't have focus. Ensure the window that didn't have focus received
// the onPointerDownOutsideFocus callback.
TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_Success) {
- ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher,
- AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, 20, 20))
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {20, 20}))
<< "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
mUnfocusedWindow->consumeMotionDown();
@@ -1863,8 +1908,8 @@
// DOWN on the window that doesn't have focus. Ensure no window received the
// onPointerDownOutsideFocus callback.
TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonPointerSource) {
- ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher,
- AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_DEFAULT, 20, 20))
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_DEFAULT, {20, 20}))
<< "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
mFocusedWindow->consumeMotionDown();
@@ -1890,7 +1935,7 @@
OnPointerDownOutsideFocus_OnAlreadyFocusedWindow) {
ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED,
injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
- mFocusedWindowTouchPoint, mFocusedWindowTouchPoint))
+ FOCUSED_WINDOW_TOUCH_POINT))
<< "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
mFocusedWindow->consumeMotionDown();
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
index d3712d9..a0606b4 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
@@ -24,6 +24,7 @@
#include <compositionengine/LayerFE.h>
#include <compositionengine/OutputColorSetting.h>
#include <math/mat4.h>
+#include <ui/Transform.h>
namespace android::compositionengine {
@@ -57,6 +58,9 @@
// Forces a color mode on the outputs being refreshed
ui::ColorMode forceOutputColorMode{ui::ColorMode::NATIVE};
+ // Used to correctly apply an inverse-display buffer transform if applicable
+ ui::Transform::RotationFlags internalDisplayRotationFlags{ui::Transform::ROT_0};
+
// If true, GPU clocks will be increased when rendering blurs
bool blursAreExpensive{false};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
index cf77738..aa70ef8 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
@@ -19,6 +19,7 @@
#include <optional>
#include <string>
+#include <ui/Transform.h>
#include <utils/StrongPointer.h>
// TODO(b/129481165): remove the #pragma below and fix conversion issues
@@ -77,7 +78,12 @@
// Recalculates the state of the output layer from the output-independent
// layer. If includeGeometry is false, the geometry state can be skipped.
- virtual void updateCompositionState(bool includeGeometry, bool forceClientComposition) = 0;
+ // internalDisplayRotationFlags must be set to the rotation flags for the
+ // internal display, and is used to properly compute the inverse-display
+ // transform, if needed.
+ virtual void updateCompositionState(
+ bool includeGeometry, bool forceClientComposition,
+ ui::Transform::RotationFlags internalDisplayRotationFlags) = 0;
// Writes the geometry state to the HWC, or does nothing if this layer does
// not use the HWC. If includeGeometry is false, the geometry state can be
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
index 79df9b2..8cb5ae8 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -39,7 +39,8 @@
void setHwcLayer(std::shared_ptr<HWC2::Layer>) override;
- void updateCompositionState(bool includeGeometry, bool forceClientComposition) override;
+ void updateCompositionState(bool includeGeometry, bool forceClientComposition,
+ ui::Transform::RotationFlags) override;
void writeStateToHWC(bool) override;
void writeCursorPositionToHWC() const override;
@@ -55,7 +56,8 @@
virtual FloatRect calculateOutputSourceCrop() const;
virtual Rect calculateOutputDisplayFrame() const;
- virtual uint32_t calculateOutputRelativeBufferTransform() const;
+ virtual uint32_t calculateOutputRelativeBufferTransform(
+ uint32_t internalDisplayRotationFlags) const;
protected:
// Implemented by the final implementation for the final state it uses.
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
index 2ecbad8..81e1fc7 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
@@ -38,7 +38,7 @@
MOCK_CONST_METHOD0(getState, const impl::OutputLayerCompositionState&());
MOCK_METHOD0(editState, impl::OutputLayerCompositionState&());
- MOCK_METHOD2(updateCompositionState, void(bool, bool));
+ MOCK_METHOD3(updateCompositionState, void(bool, bool, ui::Transform::RotationFlags));
MOCK_METHOD1(writeStateToHWC, void(bool));
MOCK_CONST_METHOD0(writeCursorPositionToHWC, void());
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index cb7ddda..e8f54f5 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -588,7 +588,8 @@
for (auto* layer : getOutputLayersOrderedByZ()) {
layer->updateCompositionState(refreshArgs.updatingGeometryThisFrame,
refreshArgs.devOptForceClientComposition ||
- forceClientComposition);
+ forceClientComposition,
+ refreshArgs.internalDisplayRotationFlags);
if (mLayerRequestingBackgroundBlur == layer) {
forceClientComposition = false;
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index c9a070d..81f2dd1 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -223,7 +223,8 @@
return displayTransform.transform(frame);
}
-uint32_t OutputLayer::calculateOutputRelativeBufferTransform() const {
+uint32_t OutputLayer::calculateOutputRelativeBufferTransform(
+ uint32_t internalDisplayRotationFlags) const {
const auto& layerState = *getLayerFE().getCompositionState();
const auto& outputState = getOutput().getState();
@@ -241,10 +242,11 @@
if (layerState.geomBufferUsesDisplayInverseTransform) {
/*
- * the code below applies the primary display's inverse transform to the
- * buffer
+ * We must apply the internal display's inverse transform to the buffer
+ * transform, and not the one for the output this layer is on.
*/
- uint32_t invTransform = outputState.orientation;
+ uint32_t invTransform = internalDisplayRotationFlags;
+
// calculate the inverse transform
if (invTransform & HAL_TRANSFORM_ROT_90) {
invTransform ^= HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_FLIP_H;
@@ -261,9 +263,11 @@
// this gives us only the "orientation" component of the transform
return transform.getOrientation();
-} // namespace impl
+}
-void OutputLayer::updateCompositionState(bool includeGeometry, bool forceClientComposition) {
+void OutputLayer::updateCompositionState(
+ bool includeGeometry, bool forceClientComposition,
+ ui::Transform::RotationFlags internalDisplayRotationFlags) {
const auto* layerFEState = getLayerFE().getCompositionState();
if (!layerFEState) {
return;
@@ -283,8 +287,8 @@
state.displayFrame = calculateOutputDisplayFrame();
state.sourceCrop = calculateOutputSourceCrop();
- state.bufferTransform =
- static_cast<Hwc2::Transform>(calculateOutputRelativeBufferTransform());
+ state.bufferTransform = static_cast<Hwc2::Transform>(
+ calculateOutputRelativeBufferTransform(internalDisplayRotationFlags));
if ((layerFEState->isSecure && !outputState.isSecure) ||
(state.bufferTransform & ui::Transform::ROT_INVALID)) {
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index bdacb22..020f93a 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -361,7 +361,7 @@
mOutputState.orientation = entry.display;
mOutputState.transform = ui::Transform{entry.display};
- auto actual = mOutputLayer.calculateOutputRelativeBufferTransform();
+ const auto actual = mOutputLayer.calculateOutputRelativeBufferTransform(entry.display);
EXPECT_EQ(entry.expected, actual) << "entry " << i;
}
}
@@ -371,56 +371,109 @@
mLayerFEState.geomBufferUsesDisplayInverseTransform = true;
struct Entry {
- uint32_t layer;
+ uint32_t layer; /* shouldn't affect the result, so we just use arbitrary values */
uint32_t buffer;
uint32_t display;
+ uint32_t internal;
uint32_t expected;
};
- // Not an exhaustive list of cases, but hopefully enough.
- const std::array<Entry, 24> testData = {
+ const std::array<Entry, 64> testData = {
// clang-format off
- // layer buffer display expected
- /* 0 */ Entry{TR_IDENT, TR_IDENT, TR_IDENT, TR_IDENT},
- /* 1 */ Entry{TR_IDENT, TR_IDENT, TR_ROT_90, TR_IDENT},
- /* 2 */ Entry{TR_IDENT, TR_IDENT, TR_ROT_180, TR_IDENT},
- /* 3 */ Entry{TR_IDENT, TR_IDENT, TR_ROT_270, TR_IDENT},
+ // layer buffer display internal expected
+ Entry{TR_IDENT, TR_IDENT, TR_IDENT, TR_IDENT, TR_IDENT},
+ Entry{TR_IDENT, TR_IDENT, TR_IDENT, TR_ROT_90, TR_ROT_270},
+ Entry{TR_IDENT, TR_IDENT, TR_IDENT, TR_ROT_180, TR_ROT_180},
+ Entry{TR_IDENT, TR_IDENT, TR_IDENT, TR_ROT_270, TR_ROT_90},
- /* 4 */ Entry{TR_IDENT, TR_FLP_H, TR_IDENT, TR_FLP_H},
- /* 5 */ Entry{TR_IDENT, TR_FLP_H, TR_ROT_90, TR_FLP_H},
- /* 6 */ Entry{TR_IDENT, TR_FLP_H, TR_ROT_180, TR_FLP_H},
- /* 7 */ Entry{TR_IDENT, TR_FLP_H, TR_ROT_270, TR_FLP_H},
+ Entry{TR_IDENT, TR_IDENT, TR_ROT_90, TR_IDENT, TR_ROT_90},
+ Entry{TR_ROT_90, TR_IDENT, TR_ROT_90, TR_ROT_90, TR_IDENT},
+ Entry{TR_ROT_180, TR_IDENT, TR_ROT_90, TR_ROT_180, TR_ROT_270},
+ Entry{TR_ROT_90, TR_IDENT, TR_ROT_90, TR_ROT_270, TR_ROT_180},
- /* 8 */ Entry{TR_IDENT, TR_FLP_V, TR_IDENT, TR_FLP_V},
- /* 9 */ Entry{TR_IDENT, TR_ROT_90, TR_ROT_90, TR_ROT_90},
- /* 10 */ Entry{TR_IDENT, TR_ROT_180, TR_ROT_180, TR_ROT_180},
- /* 11 */ Entry{TR_IDENT, TR_ROT_270, TR_ROT_270, TR_ROT_270},
+ Entry{TR_ROT_180, TR_IDENT, TR_ROT_180, TR_IDENT, TR_ROT_180},
+ Entry{TR_ROT_90, TR_IDENT, TR_ROT_180, TR_ROT_90, TR_ROT_90},
+ Entry{TR_ROT_180, TR_IDENT, TR_ROT_180, TR_ROT_180, TR_IDENT},
+ Entry{TR_ROT_270, TR_IDENT, TR_ROT_180, TR_ROT_270, TR_ROT_270},
- /* 12 */ Entry{TR_ROT_90, TR_IDENT, TR_IDENT, TR_IDENT},
- /* 13 */ Entry{TR_ROT_90, TR_FLP_H, TR_ROT_90, TR_FLP_H},
- /* 14 */ Entry{TR_ROT_90, TR_IDENT, TR_ROT_180, TR_IDENT},
- /* 15 */ Entry{TR_ROT_90, TR_FLP_H, TR_ROT_270, TR_FLP_H},
+ Entry{TR_ROT_270, TR_IDENT, TR_ROT_270, TR_IDENT, TR_ROT_270},
+ Entry{TR_ROT_270, TR_IDENT, TR_ROT_270, TR_ROT_90, TR_ROT_180},
+ Entry{TR_ROT_180, TR_IDENT, TR_ROT_270, TR_ROT_180, TR_ROT_90},
+ Entry{TR_IDENT, TR_IDENT, TR_ROT_270, TR_ROT_270, TR_IDENT},
- /* 16 */ Entry{TR_ROT_180, TR_FLP_H, TR_IDENT, TR_FLP_H},
- /* 17 */ Entry{TR_ROT_180, TR_IDENT, TR_ROT_90, TR_IDENT},
- /* 18 */ Entry{TR_ROT_180, TR_FLP_H, TR_ROT_180, TR_FLP_H},
- /* 19 */ Entry{TR_ROT_180, TR_IDENT, TR_ROT_270, TR_IDENT},
+ // layer buffer display internal expected
+ Entry{TR_IDENT, TR_ROT_90, TR_IDENT, TR_IDENT, TR_ROT_90},
+ Entry{TR_ROT_90, TR_ROT_90, TR_IDENT, TR_ROT_90, TR_IDENT},
+ Entry{TR_ROT_180, TR_ROT_90, TR_IDENT, TR_ROT_180, TR_ROT_270},
+ Entry{TR_ROT_270, TR_ROT_90, TR_IDENT, TR_ROT_270, TR_ROT_180},
- /* 20 */ Entry{TR_ROT_270, TR_IDENT, TR_IDENT, TR_IDENT},
- /* 21 */ Entry{TR_ROT_270, TR_FLP_H, TR_ROT_90, TR_FLP_H},
- /* 22 */ Entry{TR_ROT_270, TR_FLP_H, TR_ROT_180, TR_FLP_H},
- /* 23 */ Entry{TR_ROT_270, TR_IDENT, TR_ROT_270, TR_IDENT},
+ Entry{TR_ROT_90, TR_ROT_90, TR_ROT_90, TR_IDENT, TR_ROT_180},
+ Entry{TR_ROT_90, TR_ROT_90, TR_ROT_90, TR_ROT_90, TR_ROT_90},
+ Entry{TR_ROT_90, TR_ROT_90, TR_ROT_90, TR_ROT_180, TR_IDENT},
+ Entry{TR_ROT_270, TR_ROT_90, TR_ROT_90, TR_ROT_270, TR_ROT_270},
+
+ Entry{TR_IDENT, TR_ROT_90, TR_ROT_180, TR_IDENT, TR_ROT_270},
+ Entry{TR_ROT_90, TR_ROT_90, TR_ROT_180, TR_ROT_90, TR_ROT_180},
+ Entry{TR_ROT_180, TR_ROT_90, TR_ROT_180, TR_ROT_180, TR_ROT_90},
+ Entry{TR_ROT_90, TR_ROT_90, TR_ROT_180, TR_ROT_270, TR_IDENT},
+
+ Entry{TR_IDENT, TR_ROT_90, TR_ROT_270, TR_IDENT, TR_IDENT},
+ Entry{TR_ROT_270, TR_ROT_90, TR_ROT_270, TR_ROT_90, TR_ROT_270},
+ Entry{TR_ROT_180, TR_ROT_90, TR_ROT_270, TR_ROT_180, TR_ROT_180},
+ Entry{TR_ROT_270, TR_ROT_90, TR_ROT_270, TR_ROT_270, TR_ROT_90},
+
+ // layer buffer display internal expected
+ Entry{TR_IDENT, TR_ROT_180, TR_IDENT, TR_IDENT, TR_ROT_180},
+ Entry{TR_IDENT, TR_ROT_180, TR_IDENT, TR_ROT_90, TR_ROT_90},
+ Entry{TR_ROT_180, TR_ROT_180, TR_IDENT, TR_ROT_180, TR_IDENT},
+ Entry{TR_ROT_270, TR_ROT_180, TR_IDENT, TR_ROT_270, TR_ROT_270},
+
+ Entry{TR_IDENT, TR_ROT_180, TR_ROT_90, TR_IDENT, TR_ROT_270},
+ Entry{TR_ROT_90, TR_ROT_180, TR_ROT_90, TR_ROT_90, TR_ROT_180},
+ Entry{TR_ROT_180, TR_ROT_180, TR_ROT_90, TR_ROT_180, TR_ROT_90},
+ Entry{TR_ROT_180, TR_ROT_180, TR_ROT_90, TR_ROT_270, TR_IDENT},
+
+ Entry{TR_IDENT, TR_ROT_180, TR_ROT_180, TR_IDENT, TR_IDENT},
+ Entry{TR_ROT_180, TR_ROT_180, TR_ROT_180, TR_ROT_90, TR_ROT_270},
+ Entry{TR_ROT_180, TR_ROT_180, TR_ROT_180, TR_ROT_180, TR_ROT_180},
+ Entry{TR_ROT_270, TR_ROT_180, TR_ROT_180, TR_ROT_270, TR_ROT_90},
+
+ Entry{TR_ROT_270, TR_ROT_180, TR_ROT_270, TR_IDENT, TR_ROT_90},
+ Entry{TR_ROT_180, TR_ROT_180, TR_ROT_270, TR_ROT_90, TR_IDENT},
+ Entry{TR_ROT_180, TR_ROT_180, TR_ROT_270, TR_ROT_180, TR_ROT_270},
+ Entry{TR_ROT_270, TR_ROT_180, TR_ROT_270, TR_ROT_270, TR_ROT_180},
+
+ // layer buffer display internal expected
+ Entry{TR_IDENT, TR_ROT_270, TR_IDENT, TR_IDENT, TR_ROT_270},
+ Entry{TR_ROT_90, TR_ROT_270, TR_IDENT, TR_ROT_90, TR_ROT_180},
+ Entry{TR_ROT_270, TR_ROT_270, TR_IDENT, TR_ROT_180, TR_ROT_90},
+ Entry{TR_IDENT, TR_ROT_270, TR_IDENT, TR_ROT_270, TR_IDENT},
+
+ Entry{TR_ROT_270, TR_ROT_270, TR_ROT_90, TR_IDENT, TR_IDENT},
+ Entry{TR_ROT_90, TR_ROT_270, TR_ROT_90, TR_ROT_90, TR_ROT_270},
+ Entry{TR_ROT_180, TR_ROT_270, TR_ROT_90, TR_ROT_180, TR_ROT_180},
+ Entry{TR_ROT_90, TR_ROT_270, TR_ROT_90, TR_ROT_270, TR_ROT_90},
+
+ Entry{TR_IDENT, TR_ROT_270, TR_ROT_180, TR_IDENT, TR_ROT_90},
+ Entry{TR_ROT_270, TR_ROT_270, TR_ROT_180, TR_ROT_90, TR_IDENT},
+ Entry{TR_ROT_180, TR_ROT_270, TR_ROT_180, TR_ROT_180, TR_ROT_270},
+ Entry{TR_ROT_270, TR_ROT_270, TR_ROT_180, TR_ROT_270, TR_ROT_180},
+
+ Entry{TR_IDENT, TR_ROT_270, TR_ROT_270, TR_IDENT, TR_ROT_180},
+ Entry{TR_ROT_90, TR_ROT_270, TR_ROT_270, TR_ROT_90, TR_ROT_90},
+ Entry{TR_ROT_270, TR_ROT_270, TR_ROT_270, TR_ROT_180, TR_IDENT},
+ Entry{TR_ROT_270, TR_ROT_270, TR_ROT_270, TR_ROT_270, TR_ROT_270},
// clang-format on
};
for (size_t i = 0; i < testData.size(); i++) {
const auto& entry = testData[i];
- mLayerFEState.geomLayerTransform = ui::Transform{entry.layer};
+ mLayerFEState.geomLayerTransform.set(entry.layer, 1920, 1080);
mLayerFEState.geomBufferTransform = entry.buffer;
mOutputState.orientation = entry.display;
mOutputState.transform = ui::Transform{entry.display};
- auto actual = mOutputLayer.calculateOutputRelativeBufferTransform();
+ const auto actual = mOutputLayer.calculateOutputRelativeBufferTransform(entry.internal);
EXPECT_EQ(entry.expected, actual) << "entry " << i;
}
}
@@ -436,7 +489,7 @@
// Mock everything called by updateCompositionState to simplify testing it.
MOCK_CONST_METHOD0(calculateOutputSourceCrop, FloatRect());
MOCK_CONST_METHOD0(calculateOutputDisplayFrame, Rect());
- MOCK_CONST_METHOD0(calculateOutputRelativeBufferTransform, uint32_t());
+ MOCK_CONST_METHOD1(calculateOutputRelativeBufferTransform, uint32_t(uint32_t));
// compositionengine::OutputLayer overrides
const compositionengine::Output& getOutput() const override { return mOutput; }
@@ -463,10 +516,11 @@
~OutputLayerUpdateCompositionStateTest() = default;
- void setupGeometryChildCallValues() {
+ void setupGeometryChildCallValues(ui::Transform::RotationFlags internalDisplayRotationFlags) {
EXPECT_CALL(mOutputLayer, calculateOutputSourceCrop()).WillOnce(Return(kSourceCrop));
EXPECT_CALL(mOutputLayer, calculateOutputDisplayFrame()).WillOnce(Return(kDisplayFrame));
- EXPECT_CALL(mOutputLayer, calculateOutputRelativeBufferTransform())
+ EXPECT_CALL(mOutputLayer,
+ calculateOutputRelativeBufferTransform(internalDisplayRotationFlags))
.WillOnce(Return(mBufferTransform));
}
@@ -489,7 +543,7 @@
TEST_F(OutputLayerUpdateCompositionStateTest, doesNothingIfNoFECompositionState) {
EXPECT_CALL(*mLayerFE, getCompositionState()).WillOnce(Return(nullptr));
- mOutputLayer.updateCompositionState(true, false);
+ mOutputLayer.updateCompositionState(true, false, ui::Transform::RotationFlags::ROT_90);
}
TEST_F(OutputLayerUpdateCompositionStateTest, setsStateNormally) {
@@ -497,9 +551,9 @@
mOutputState.isSecure = true;
mOutputLayer.editState().forceClientComposition = true;
- setupGeometryChildCallValues();
+ setupGeometryChildCallValues(ui::Transform::RotationFlags::ROT_90);
- mOutputLayer.updateCompositionState(true, false);
+ mOutputLayer.updateCompositionState(true, false, ui::Transform::RotationFlags::ROT_90);
validateComputedGeometryState();
@@ -511,9 +565,9 @@
mLayerFEState.isSecure = true;
mOutputState.isSecure = false;
- setupGeometryChildCallValues();
+ setupGeometryChildCallValues(ui::Transform::RotationFlags::ROT_0);
- mOutputLayer.updateCompositionState(true, false);
+ mOutputLayer.updateCompositionState(true, false, ui::Transform::RotationFlags::ROT_0);
validateComputedGeometryState();
@@ -527,9 +581,9 @@
mBufferTransform = ui::Transform::ROT_INVALID;
- setupGeometryChildCallValues();
+ setupGeometryChildCallValues(ui::Transform::RotationFlags::ROT_0);
- mOutputLayer.updateCompositionState(true, false);
+ mOutputLayer.updateCompositionState(true, false, ui::Transform::RotationFlags::ROT_0);
validateComputedGeometryState();
@@ -544,7 +598,7 @@
// should use the layers requested colorspace.
mLayerFEState.isColorspaceAgnostic = false;
- mOutputLayer.updateCompositionState(false, false);
+ mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0);
EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mOutputLayer.getState().dataspace);
@@ -552,7 +606,7 @@
// should use the colorspace chosen for the whole output.
mLayerFEState.isColorspaceAgnostic = true;
- mOutputLayer.updateCompositionState(false, false);
+ mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0);
EXPECT_EQ(ui::Dataspace::V0_SCRGB, mOutputLayer.getState().dataspace);
}
@@ -560,7 +614,7 @@
TEST_F(OutputLayerUpdateCompositionStateTest, doesNotRecomputeGeometryIfNotRequested) {
mOutputLayer.editState().forceClientComposition = false;
- mOutputLayer.updateCompositionState(false, false);
+ mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0);
EXPECT_EQ(false, mOutputLayer.getState().forceClientComposition);
}
@@ -569,7 +623,7 @@
doesNotClearForceClientCompositionIfNotDoingGeometry) {
mOutputLayer.editState().forceClientComposition = true;
- mOutputLayer.updateCompositionState(false, false);
+ mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0);
EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition);
}
@@ -578,7 +632,7 @@
mLayerFEState.forceClientComposition = true;
mOutputLayer.editState().forceClientComposition = false;
- mOutputLayer.updateCompositionState(false, false);
+ mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0);
EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition);
}
@@ -588,7 +642,7 @@
mOutputLayer.editState().forceClientComposition = false;
EXPECT_CALL(mDisplayColorProfile, isDataspaceSupported(_)).WillRepeatedly(Return(false));
- mOutputLayer.updateCompositionState(false, false);
+ mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0);
EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition);
}
@@ -597,15 +651,15 @@
mLayerFEState.forceClientComposition = false;
mOutputLayer.editState().forceClientComposition = false;
- mOutputLayer.updateCompositionState(false, true);
+ mOutputLayer.updateCompositionState(false, true, ui::Transform::RotationFlags::ROT_0);
EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition);
mOutputLayer.editState().forceClientComposition = false;
- setupGeometryChildCallValues();
+ setupGeometryChildCallValues(ui::Transform::RotationFlags::ROT_0);
- mOutputLayer.updateCompositionState(true, true);
+ mOutputLayer.updateCompositionState(true, true, ui::Transform::RotationFlags::ROT_0);
EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition);
}
@@ -810,7 +864,7 @@
// geomBufferTransform is set to the inverse transform.
mLayerFEState.geomBufferTransform = TR_ROT_270;
- EXPECT_EQ(TR_IDENT, mOutputLayer.calculateOutputRelativeBufferTransform());
+ EXPECT_EQ(TR_IDENT, mOutputLayer.calculateOutputRelativeBufferTransform(ui::Transform::ROT_90));
}
TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSolidColor) {
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 762d76c..59ed72e 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -696,11 +696,11 @@
InjectedLayer layer2;
InjectedLayer layer3;
- EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, false));
+ EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180));
EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(false));
- EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, false));
+ EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180));
EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(false));
- EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false));
+ EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180));
EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(false));
injectOutputLayer(layer1);
@@ -712,6 +712,7 @@
CompositionRefreshArgs args;
args.updatingGeometryThisFrame = false;
args.devOptForceClientComposition = false;
+ args.internalDisplayRotationFlags = ui::Transform::ROT_180;
mOutput->updateAndWriteCompositionState(args);
}
@@ -720,11 +721,11 @@
InjectedLayer layer2;
InjectedLayer layer3;
- EXPECT_CALL(*layer1.outputLayer, updateCompositionState(true, false));
+ EXPECT_CALL(*layer1.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(true));
- EXPECT_CALL(*layer2.outputLayer, updateCompositionState(true, false));
+ EXPECT_CALL(*layer2.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(true));
- EXPECT_CALL(*layer3.outputLayer, updateCompositionState(true, false));
+ EXPECT_CALL(*layer3.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(true));
injectOutputLayer(layer1);
@@ -744,11 +745,11 @@
InjectedLayer layer2;
InjectedLayer layer3;
- EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true));
+ EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(false));
- EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true));
+ EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(false));
- EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, true));
+ EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(false));
injectOutputLayer(layer1);
@@ -3337,7 +3338,7 @@
mLayer.layerFEState.backgroundBlurRadius = 10;
mOutput.editState().isEnabled = true;
- EXPECT_CALL(mLayer.outputLayer, updateCompositionState(false, true));
+ EXPECT_CALL(mLayer.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
EXPECT_CALL(mLayer.outputLayer, writeStateToHWC(false));
EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
.WillOnce(Return(std::vector<LayerFE::LayerSettings>{}));
@@ -3916,11 +3917,11 @@
InjectedLayer layer3;
// Layer requesting blur, or below, should request client composition.
- EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true));
+ EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(false));
- EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true));
+ EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(false));
- EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false));
+ EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0));
EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(false));
layer2.layerFEState.backgroundBlurRadius = 10;
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index 2e7fbc1..f602412 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -200,26 +200,22 @@
}
}
-void RefreshRateOverlay::changeRefreshRate(const RefreshRate& refreshRate) {
- const auto display = mFlinger.getDefaultDisplayDeviceLocked();
- if (!display) {
- return;
- }
-
- const int32_t left = display->getWidth() / 32;
- const int32_t top = display->getHeight() / 32;
- const int32_t right = left + display->getWidth() / 8;
- const int32_t buttom = top + display->getHeight() / 32;
-
- auto buffer = mBufferCache[refreshRate.getFps()];
- mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, {});
-
- mLayer->setFrame(Rect(left, top, right, buttom));
+void RefreshRateOverlay::setViewport(ui::Size viewport) {
+ Rect frame(viewport.width >> 3, viewport.height >> 5);
+ frame.offsetBy(viewport.width >> 5, viewport.height >> 4);
+ mLayer->setFrame(frame);
mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
}
-}; // namespace android
+void RefreshRateOverlay::changeRefreshRate(const RefreshRate& refreshRate) {
+ auto buffer = mBufferCache[refreshRate.getFps()];
+ mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, {});
+
+ mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
+}
+
+} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h
index 6d34df2..35c8020 100644
--- a/services/surfaceflinger/RefreshRateOverlay.h
+++ b/services/surfaceflinger/RefreshRateOverlay.h
@@ -13,19 +13,35 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
#pragma once
-#include "SurfaceFlinger.h"
+#include <unordered_map>
+
+#include <math/vec4.h>
+#include <ui/Rect.h>
+#include <ui/Size.h>
+#include <utils/StrongPointer.h>
+
+#include "Scheduler/RefreshRateConfigs.h"
namespace android {
+class Client;
+class GraphicBuffer;
+class IBinder;
+class IGraphicBufferProducer;
+class Layer;
+class SurfaceFlinger;
+
using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate;
class RefreshRateOverlay {
public:
- RefreshRateOverlay(SurfaceFlinger& flinger);
+ explicit RefreshRateOverlay(SurfaceFlinger&);
- void changeRefreshRate(const RefreshRate& refreshRate);
+ void setViewport(ui::Size);
+ void changeRefreshRate(const RefreshRate&);
private:
class SevenSegmentDrawer {
@@ -56,7 +72,7 @@
void primeCache();
SurfaceFlinger& mFlinger;
- sp<Client> mClient;
+ const sp<Client> mClient;
sp<Layer> mLayer;
sp<IBinder> mIBinder;
sp<IGraphicBufferProducer> mGbp;
@@ -68,4 +84,4 @@
const half3 HIGH_FPS_COLOR = half3(0.0f, 1.0f, 0.0f);
};
-}; // namespace android
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 5dedb6a..cee36a1 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -152,16 +152,9 @@
mEventThread->requestNextVsync(this);
}
-void EventThreadConnection::toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag) {
- ATRACE_NAME("enableConfigEvents");
- mConfigChanged = configChangeFlag;
-
- // In principle it's possible for rapidly toggling config events to drop an
- // event here, but it's unlikely in practice.
- if (configChangeFlag == ISurfaceComposer::eConfigChangedDispatch) {
- mForcedConfigChangeDispatch = true;
- mEventThread->requestLatestConfig();
- }
+void EventThreadConnection::requestLatestConfig() {
+ ATRACE_NAME("requestLatestConfig");
+ mEventThread->requestLatestConfig(this);
}
status_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) {
@@ -276,8 +269,12 @@
}
}
-void EventThread::requestLatestConfig() {
+void EventThread::requestLatestConfig(const sp<EventThreadConnection>& connection) {
std::lock_guard<std::mutex> lock(mMutex);
+ if (connection->mForcedConfigChangeDispatch) {
+ return;
+ }
+ connection->mForcedConfigChangeDispatch = true;
auto pendingConfigChange =
std::find_if(std::begin(mPendingEvents), std::end(mPendingEvents),
[&](const DisplayEventReceiver::Event& event) {
@@ -384,6 +381,10 @@
vsyncRequested |= connection->vsyncRequest != VSyncRequest::None;
if (event && shouldConsumeEvent(*event, connection)) {
+ if (event->header.type == DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED &&
+ connection->mForcedConfigChangeDispatch) {
+ connection->mForcedConfigChangeDispatch = false;
+ }
consumers.push_back(connection);
}
@@ -459,8 +460,8 @@
return true;
case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED: {
- const bool forcedDispatch = connection->mForcedConfigChangeDispatch.exchange(false);
- return forcedDispatch ||
+ const bool oneTimeDispatch = connection->mForcedConfigChangeDispatch;
+ return oneTimeDispatch ||
connection->mConfigChanged == ISurfaceComposer::eConfigChangedDispatch;
}
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 9e7086e..64acbd7 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -81,19 +81,19 @@
status_t stealReceiveChannel(gui::BitTube* outChannel) override;
status_t setVsyncRate(uint32_t rate) override;
void requestNextVsync() override; // asynchronous
- void toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag) override;
+ void requestLatestConfig() override; // asynchronous
// Called in response to requestNextVsync.
const ResyncCallback resyncCallback;
VSyncRequest vsyncRequest = VSyncRequest::None;
- std::atomic<ISurfaceComposer::ConfigChanged> mConfigChanged =
+ ISurfaceComposer::ConfigChanged mConfigChanged =
ISurfaceComposer::ConfigChanged::eConfigChangedSuppress;
// Store whether we need to force dispatching a config change separately -
// if mConfigChanged ever changes before the config change is dispatched
// then we still need to propagate an initial config to the app if we
// haven't already.
- std::atomic<bool> mForcedConfigChangeDispatch = false;
+ bool mForcedConfigChangeDispatch = false;
private:
virtual void onFirstRef();
@@ -129,11 +129,10 @@
virtual void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) = 0;
// Requests the next vsync. If resetIdleTimer is set to true, it resets the idle timer.
virtual void requestNextVsync(const sp<EventThreadConnection>& connection) = 0;
-
// Dispatches the most recent configuration
// Usage of this method assumes that only the primary internal display
// supports multiple display configurations.
- virtual void requestLatestConfig() = 0;
+ virtual void requestLatestConfig(const sp<EventThreadConnection>& connection) = 0;
// Retrieves the number of event connections tracked by this EventThread.
virtual size_t getEventThreadConnectionCount() = 0;
@@ -154,7 +153,7 @@
status_t registerDisplayEventConnection(const sp<EventThreadConnection>& connection) override;
void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) override;
void requestNextVsync(const sp<EventThreadConnection>& connection) override;
- void requestLatestConfig() override;
+ void requestLatestConfig(const sp<EventThreadConnection>& connection) override;
// called before the screen is turned off from main thread
void onScreenReleased() override;
diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
index bf1fb88..ce57ea8 100644
--- a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
@@ -111,24 +111,35 @@
// Calculate the refresh rate by finding the average delta between frames
nsecs_t totalPresentTimeDeltas = 0;
+ int numFrames = 0;
for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) {
// If there are no presentation timestamp provided we can't calculate the refresh rate
if (it->presetTime == 0 || (it + 1)->presetTime == 0) {
- return std::nullopt;
+ continue;
}
totalPresentTimeDeltas +=
std::max(((it + 1)->presetTime - it->presetTime), mHighRefreshRatePeriod);
+ numFrames++;
}
- const float averageFrameTime =
- static_cast<float>(totalPresentTimeDeltas) / (mFrameTimes.size() - 1);
+ if (numFrames == 0) {
+ return std::nullopt;
+ }
+ const float averageFrameTime = static_cast<float>(totalPresentTimeDeltas) / numFrames;
// Now once we calculated the refresh rate we need to make sure that all the frames we captured
// are evenly distributed and we don't calculate the average across some burst of frames.
for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) {
- const nsecs_t presentTimeDeltas =
- std::max(((it + 1)->presetTime - it->presetTime), mHighRefreshRatePeriod);
- if (std::abs(presentTimeDeltas - averageFrameTime) > 2 * averageFrameTime) {
+ const nsecs_t frameTimeDeltas = [&] {
+ nsecs_t delta;
+ if (it->presetTime == 0 || (it + 1)->presetTime == 0) {
+ delta = (it + 1)->queueTime - it->queueTime;
+ } else {
+ delta = (it + 1)->presetTime - it->presetTime;
+ }
+ return std::max(delta, mHighRefreshRatePeriod);
+ }();
+ if (std::abs(frameTimeDeltas - averageFrameTime) > 2 * averageFrameTime) {
return std::nullopt;
}
}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index a2e9e2f..3b66fa9 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -189,7 +189,7 @@
using ConditionalLock = ConditionalLockGuard<Mutex>;
// TODO(b/141333600): Consolidate with HWC2::Display::Config::Builder::getDefaultDensity.
-constexpr float FALLBACK_DENSITY = ACONFIGURATION_DENSITY_TV / 160.f;
+constexpr float FALLBACK_DENSITY = ACONFIGURATION_DENSITY_TV;
float getDensityFromProperty(const char* property, bool required) {
char value[PROPERTY_VALUE_MAX];
@@ -198,7 +198,7 @@
ALOGE("%s must be defined as a build property", property);
return FALLBACK_DENSITY;
}
- return density / 160.f;
+ return density;
}
// Currently we only support V0_SRGB and DISPLAY_P3 as composition preference.
@@ -582,14 +582,13 @@
LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM,
ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
- static_cast<void>(schedule([this]() NO_THREAD_SAFETY_ANALYSIS {
+ static_cast<void>(schedule([this] {
readPersistentProperties();
mPowerAdvisor.onBootFinished();
mBootStage = BootStage::FINISHED;
if (property_get_bool("sf.debug.show_refresh_rate_overlay", false)) {
- mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(*this);
- mRefreshRateOverlay->changeRefreshRate(mRefreshRateConfigs->getCurrentRefreshRate());
+ enableRefreshRateOverlay(true);
}
}));
}
@@ -830,6 +829,7 @@
? mInternalDisplayDensity
: FALLBACK_DENSITY;
}
+ info->density /= ACONFIGURATION_DENSITY_MEDIUM;
info->secure = display->isSecure();
info->deviceProductInfo = getDeviceProductInfoLocked(*display);
@@ -934,9 +934,8 @@
}
if (isPrimary) {
- std::lock_guard<std::mutex> lock(mActiveConfigLock);
- if (mDesiredActiveConfigChanged) {
- return mDesiredActiveConfig.configId.value();
+ if (const auto config = getDesiredActiveConfig()) {
+ return config->configId.value();
}
}
@@ -1063,14 +1062,7 @@
ATRACE_CALL();
ALOGV("performSetActiveConfig");
// Store the local variable to release the lock.
- const auto desiredActiveConfig = [&]() -> std::optional<ActiveConfigInfo> {
- std::lock_guard<std::mutex> lock(mActiveConfigLock);
- if (mDesiredActiveConfigChanged) {
- return mDesiredActiveConfig;
- }
- return std::nullopt;
- }();
-
+ const auto desiredActiveConfig = getDesiredActiveConfig();
if (!desiredActiveConfig) {
// No desired active config pending to be applied
return;
@@ -1605,7 +1597,7 @@
}
void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hal::HWDisplayId hwcDisplayId,
- hal::Connection connection) {
+ hal::Connection connection) NO_THREAD_SAFETY_ANALYSIS {
ALOGV("%s(%d, %" PRIu64 ", %s)", __FUNCTION__, sequenceId, hwcDisplayId,
connection == hal::Connection::CONNECTED ? "connected" : "disconnected");
@@ -1927,8 +1919,11 @@
ATRACE_NAME("Jank detected");
ALOGD("Detected janky event. Missed frames: %d", mMissedFrameJankCount);
const int32_t jankyDurationMillis = jankDuration / (1000 * 1000);
- android::util::stats_write(android::util::DISPLAY_JANK_REPORTED,
- jankyDurationMillis, mMissedFrameJankCount);
+ {
+ ATRACE_NAME("Pushing to statsd");
+ android::util::stats_write(android::util::DISPLAY_JANK_REPORTED,
+ jankyDurationMillis, mMissedFrameJankCount);
+ }
}
// We either reported a jank event or we missed the trace
@@ -2047,6 +2042,7 @@
refreshArgs.updatingOutputGeometryThisFrame = mVisibleRegionsDirty;
refreshArgs.updatingGeometryThisFrame = mGeometryInvalid || mVisibleRegionsDirty;
refreshArgs.blursAreExpensive = mBlursAreExpensive;
+ refreshArgs.internalDisplayRotationFlags = DisplayDevice::getPrimaryDisplayRotationFlags();
if (CC_UNLIKELY(mDrawingState.colorMatrixChanged)) {
refreshArgs.colorTransformMatrix = mDrawingState.colorMatrix;
@@ -2678,9 +2674,14 @@
if (currentState.width != drawingState.width ||
currentState.height != drawingState.height) {
display->setDisplaySize(currentState.width, currentState.height);
+
if (display->isPrimary()) {
mScheduler->onPrimaryDisplayAreaChanged(currentState.width * currentState.height);
}
+
+ if (mRefreshRateOverlay) {
+ mRefreshRateOverlay->setViewport(display->getSize());
+ }
}
}
}
@@ -5239,15 +5240,15 @@
return NO_ERROR;
}
case 1034: {
- n = data.readInt32();
- if (n == 1 && !mRefreshRateOverlay) {
- mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(*this);
- auto& current = mRefreshRateConfigs->getCurrentRefreshRate();
- mRefreshRateOverlay->changeRefreshRate(current);
- } else if (n == 0) {
- mRefreshRateOverlay.reset();
- } else {
- reply->writeBool(mRefreshRateOverlay != nullptr);
+ switch (n = data.readInt32()) {
+ case 0:
+ case 1:
+ enableRefreshRateOverlay(static_cast<bool>(n));
+ break;
+ default: {
+ Mutex::Autolock lock(mStateLock);
+ reply->writeBool(mRefreshRateOverlay != nullptr);
+ }
}
return NO_ERROR;
}
@@ -5295,29 +5296,26 @@
void SurfaceFlinger::kernelTimerChanged(bool expired) {
static bool updateOverlay =
property_get_bool("debug.sf.kernel_idle_timer_update_overlay", true);
- if (!updateOverlay || !mRefreshRateOverlay) return;
+ if (!updateOverlay) return;
+ if (Mutex::Autolock lock(mStateLock); !mRefreshRateOverlay) return;
// Update the overlay on the main thread to avoid race conditions with
// mRefreshRateConfigs->getCurrentRefreshRate()
- static_cast<void>(schedule([=]() NO_THREAD_SAFETY_ANALYSIS {
- if (mRefreshRateOverlay) {
+ static_cast<void>(schedule([=] {
+ const auto desiredActiveConfig = getDesiredActiveConfig();
+ const auto& current = desiredActiveConfig
+ ? mRefreshRateConfigs->getRefreshRateFromConfigId(desiredActiveConfig->configId)
+ : mRefreshRateConfigs->getCurrentRefreshRate();
+ const auto& min = mRefreshRateConfigs->getMinRefreshRate();
+
+ if (current != min) {
const auto kernelTimerEnabled = property_get_bool(KERNEL_IDLE_TIMER_PROP, false);
const bool timerExpired = kernelTimerEnabled && expired;
- const auto& current = [this]() -> const RefreshRate& {
- std::lock_guard<std::mutex> lock(mActiveConfigLock);
- if (mDesiredActiveConfigChanged) {
- return mRefreshRateConfigs->getRefreshRateFromConfigId(
- mDesiredActiveConfig.configId);
- }
- return mRefreshRateConfigs->getCurrentRefreshRate();
- }();
- const auto& min = mRefreshRateConfigs->getMinRefreshRate();
-
- if (current != min) {
+ if (Mutex::Autolock lock(mStateLock); mRefreshRateOverlay) {
mRefreshRateOverlay->changeRefreshRate(timerExpired ? min : current);
- mEventQueue->invalidate();
}
+ mEventQueue->invalidate();
}
}));
}
@@ -6234,6 +6232,29 @@
}));
}
+void SurfaceFlinger::enableRefreshRateOverlay(bool enable) {
+ static_cast<void>(schedule([=] {
+ std::unique_ptr<RefreshRateOverlay> overlay;
+ if (enable) {
+ overlay = std::make_unique<RefreshRateOverlay>(*this);
+ }
+
+ {
+ Mutex::Autolock lock(mStateLock);
+
+ // Destroy the layer of the current overlay, if any, outside the lock.
+ mRefreshRateOverlay.swap(overlay);
+ if (!mRefreshRateOverlay) return;
+
+ if (const auto display = getDefaultDisplayDeviceLocked()) {
+ mRefreshRateOverlay->setViewport(display->getSize());
+ }
+
+ mRefreshRateOverlay->changeRefreshRate(mRefreshRateConfigs->getCurrentRefreshRate());
+ }
+ }));
+}
+
} // namespace android
#if defined(__gl_h_)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 7a51328..509de0f 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -828,13 +828,13 @@
const DisplayDeviceState& state,
const sp<compositionengine::DisplaySurface>& displaySurface,
const sp<IGraphicBufferProducer>& producer);
- void processDisplayChangesLocked();
+ void processDisplayChangesLocked() REQUIRES(mStateLock);
void processDisplayAdded(const wp<IBinder>& displayToken, const DisplayDeviceState& state);
void processDisplayRemoved(const wp<IBinder>& displayToken);
void processDisplayChanged(const wp<IBinder>& displayToken,
const DisplayDeviceState& currentState,
- const DisplayDeviceState& drawingState);
- void processDisplayHotplugEventsLocked();
+ const DisplayDeviceState& drawingState) REQUIRES(mStateLock);
+ void processDisplayHotplugEventsLocked() REQUIRES(mStateLock);
void dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected);
@@ -1215,6 +1215,12 @@
* Misc
*/
+ std::optional<ActiveConfigInfo> getDesiredActiveConfig() EXCLUDES(mActiveConfigLock) {
+ std::lock_guard<std::mutex> lock(mActiveConfigLock);
+ if (mDesiredActiveConfigChanged) return mDesiredActiveConfig;
+ return std::nullopt;
+ }
+
std::mutex mActiveConfigLock;
// This bit is set once we start setting the config. We read from this bit during the
// process. If at the end, this bit is different than mDesiredActiveConfig, we restart
@@ -1257,7 +1263,8 @@
// This should only be accessed on the main thread.
nsecs_t mFrameStartTime = 0;
- std::unique_ptr<RefreshRateOverlay> mRefreshRateOverlay;
+ void enableRefreshRateOverlay(bool enable);
+ std::unique_ptr<RefreshRateOverlay> mRefreshRateOverlay GUARDED_BY(mStateLock);
// Flag used to set override allowed display configs from backdoor
bool mDebugDisplayConfigSetByBackdoor = false;
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
index 6fca673..15207c9 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
@@ -512,5 +512,46 @@
EXPECT_EQ(1, frequentLayerCount(time));
}
+TEST_F(LayerHistoryTestV2, calculateRefreshRate30Hz) {
+ const auto layer = createLayer();
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+
+ nsecs_t time = systemTime();
+ const nsecs_t frameTime = 33'333'333;
+
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ time += frameTime;
+ history().record(layer.get(), time, time);
+ }
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, history().summarize(time)[0].vote);
+ EXPECT_FLOAT_EQ(30.f, history().summarize(time)[0].desiredRefreshRate);
+}
+
+TEST_F(LayerHistoryTestV2, calculateRefreshRate30HzSkipTimestamp) {
+ const auto layer = createLayer();
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+
+ nsecs_t time = systemTime();
+ const nsecs_t frameTime = 33'333'333;
+
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ time += frameTime;
+ const auto timestamp = (i == PRESENT_TIME_HISTORY_SIZE / 2) ? 0 : time;
+ history().record(layer.get(), timestamp, time);
+ }
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, history().summarize(time)[0].vote);
+ EXPECT_FLOAT_EQ(30.f, history().summarize(time)[0].desiredRefreshRate);
+}
+
} // namespace
} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index 50eb390..054aaf8 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -40,7 +40,7 @@
status_t(const sp<android::EventThreadConnection> &));
MOCK_METHOD2(setVsyncRate, void(uint32_t, const sp<android::EventThreadConnection> &));
MOCK_METHOD1(requestNextVsync, void(const sp<android::EventThreadConnection> &));
- MOCK_METHOD0(requestLatestConfig, void());
+ MOCK_METHOD1(requestLatestConfig, void(const sp<android::EventThreadConnection> &));
MOCK_METHOD1(pauseVsyncCallback, void(bool));
MOCK_METHOD0(getEventThreadConnectionCount, size_t());
};
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index a5f0c9f..7bcb2c1 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -252,18 +252,6 @@
result = LoadUpdatedDriver(&module);
if (result == -ENOENT) {
result = LoadBuiltinDriver(&module);
- if (result != 0) {
- // -ENOENT means the sphal namespace doesn't exist, not that there
- // is a problem with the driver.
- ALOGW_IF(
- result != -ENOENT,
- "Failed to load Vulkan driver into sphal namespace. This "
- "usually means the driver has forbidden library dependencies."
- "Please fix, this will soon stop working.");
- result =
- hw_get_module(HWVULKAN_HARDWARE_MODULE_ID,
- reinterpret_cast<const hw_module_t**>(&module));
- }
}
if (result != 0) {
android::GraphicsEnv::getInstance().setDriverLoaded(