Merge "Add locks to InputDispatcher_test" 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 856c54d..c5e56fd 100644
--- a/include/input/InputWindow.h
+++ b/include/input/InputWindow.h
@@ -108,6 +108,7 @@
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,
};
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/LayerState.cpp b/libs/gui/LayerState.cpp
index f7158d0..e43446a 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -116,6 +116,7 @@
output.writeInt32(frameRateSelectionPriority);
output.writeFloat(frameRate);
output.writeByte(frameRateCompatibility);
+ output.writeUint32(fixedTransformHint);
return NO_ERROR;
}
@@ -198,6 +199,7 @@
frameRateSelectionPriority = input.readInt32();
frameRate = input.readFloat();
frameRateCompatibility = input.readByte();
+ fixedTransformHint = static_cast<ui::Transform::RotationFlags>(input.readUint32());
return NO_ERROR;
}
@@ -433,6 +435,10 @@
frameRate = other.frameRate;
frameRateCompatibility = other.frameRateCompatibility;
}
+ if (other.what & eFixedTransformHintChanged) {
+ what |= eFixedTransformHintChanged;
+ fixedTransformHint = other.fixedTransformHint;
+ }
if ((other.what & what) != other.what) {
ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? "
"other.what=0x%" PRIu64 " what=0x%" PRIu64,
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/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index a52f298..5922f3a 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1437,6 +1437,22 @@
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFixedTransformHint(
+ const sp<SurfaceControl>& sc, int32_t fixedTransformHint) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+
+ const ui::Transform::RotationFlags transform = fixedTransformHint == -1
+ ? ui::Transform::ROT_INVALID
+ : ui::Transform::toRotationFlags(static_cast<ui::Rotation>(fixedTransformHint));
+ s->what |= layer_state_t::eFixedTransformHintChanged;
+ s->fixedTransformHint = transform;
+ return *this;
+}
+
// ---------------------------------------------------------------------------
DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) {
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/LayerState.h b/libs/gui/include/gui/LayerState.h
index 2b2f773..e60f677 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -35,6 +35,7 @@
#include <ui/Rect.h>
#include <ui/Region.h>
#include <ui/Rotation.h>
+#include <ui/Transform.h>
#include <utils/Errors.h>
namespace android {
@@ -103,6 +104,7 @@
eFrameRateChanged = 0x40'00000000,
eBackgroundBlurRadiusChanged = 0x80'00000000,
eProducerDisconnect = 0x100'00000000,
+ eFixedTransformHintChanged = 0x200'00000000,
};
layer_state_t()
@@ -136,7 +138,8 @@
shadowRadius(0.0f),
frameRateSelectionPriority(-1),
frameRate(0.0f),
- frameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT) {
+ frameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT),
+ fixedTransformHint(ui::Transform::ROT_INVALID) {
matrix.dsdx = matrix.dtdy = 1.0f;
matrix.dsdy = matrix.dtdx = 0.0f;
hdrMetadata.validTypes = 0;
@@ -225,6 +228,15 @@
// Layer frame rate and compatibility. See ANativeWindow_setFrameRate().
float frameRate;
int8_t frameRateCompatibility;
+
+ // Set by window manager indicating the layer and all its children are
+ // in a different orientation than the display. The hint suggests that
+ // the graphic producers should receive a transform hint as if the
+ // display was in this orientation. When the display changes to match
+ // the layer orientation, the graphic producer may not need to allocate
+ // a buffer of a different size. -1 means the transform hint is not set,
+ // otherwise the value will be a valid ui::Rotation.
+ ui::Transform::RotationFlags fixedTransformHint;
};
struct ComposerState {
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/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 531aed7..e981a39 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -519,6 +519,14 @@
Transaction& setFrameRate(const sp<SurfaceControl>& sc, float frameRate,
int8_t compatibility);
+ // Set by window manager indicating the layer and all its children are
+ // in a different orientation than the display. The hint suggests that
+ // the graphic producers should receive a transform hint as if the
+ // display was in this orientation. When the display changes to match
+ // the layer orientation, the graphic producer may not need to allocate
+ // a buffer of a different size.
+ Transaction& setFixedTransformHint(const sp<SurfaceControl>& sc, int32_t transformHint);
+
status_t setDisplaySurface(const sp<IBinder>& token,
const sp<IGraphicBufferProducer>& bufferProducer);
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/input/InputWindow.cpp b/libs/input/InputWindow.cpp
index b27b050..85a2015 100644
--- a/libs/input/InputWindow.cpp
+++ b/libs/input/InputWindow.cpp
@@ -42,6 +42,7 @@
&& 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 ||
@@ -51,7 +52,8 @@
layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY ||
layoutParamsType == TYPE_DOCK_DIVIDER ||
layoutParamsType == TYPE_ACCESSIBILITY_OVERLAY ||
- layoutParamsType == TYPE_INPUT_CONSUMER;
+ 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/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/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 155021d..1dbcf98 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -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",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 5b28384..8ecdd95 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -843,6 +843,13 @@
mDrawingState.inputInfo = tmpInputInfo;
}
+void BufferLayer::setTransformHint(ui::Transform::RotationFlags displayTransformHint) const {
+ mTransformHint = getFixedTransformHint();
+ if (mTransformHint == ui::Transform::ROT_INVALID) {
+ mTransformHint = displayTransformHint;
+ }
+}
+
} // namespace android
#if defined(__gl_h_)
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 56bab1b..cfccc8a 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -117,6 +117,10 @@
sp<GraphicBuffer> getBuffer() const override;
+ ui::Transform::RotationFlags getTransformHint() const override { return mTransformHint; }
+
+ void setTransformHint(ui::Transform::RotationFlags displayTransformHint) const override;
+
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
@@ -205,6 +209,10 @@
virtual uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const;
+ // Transform hint provided to the producer. This must be accessed holding
+ /// the mStateLock.
+ mutable ui::Transform::RotationFlags mTransformHint = ui::Transform::ROT_0;
+
private:
// Returns true if this layer requires filtering
bool needsFiltering(const sp<const DisplayDevice>& displayDevice) const override;
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index f4e630e..5d80768 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -58,8 +58,9 @@
}
}
-void BufferQueueLayer::setTransformHint(uint32_t orientation) const {
- mConsumer->setTransformHint(orientation);
+void BufferQueueLayer::setTransformHint(ui::Transform::RotationFlags displayTransformHint) const {
+ BufferLayer::setTransformHint(displayTransformHint);
+ mConsumer->setTransformHint(mTransformHint);
}
std::vector<OccupancyTracker::Segment> BufferQueueLayer::getOccupancyHistory(bool forceFlush) {
@@ -493,10 +494,6 @@
if (!mFlinger->isLayerTripleBufferingDisabled()) {
mProducer->setMaxDequeuedBufferCount(2);
}
-
- if (const auto display = mFlinger->getDefaultDisplayDeviceLocked()) {
- updateTransformHint(display);
- }
}
status_t BufferQueueLayer::setDefaultBufferProperties(uint32_t w, uint32_t h, PixelFormat format) {
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 16b4b6e..9bcb63a 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -43,7 +43,7 @@
void onLayerDisplayed(const sp<Fence>& releaseFence) override;
- void setTransformHint(uint32_t orientation) const override;
+ void setTransformHint(ui::Transform::RotationFlags displayTransformHint) const override;
std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool forceFlush) override;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index a121ce0..a1ed6d7 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -51,9 +51,6 @@
: BufferLayer(args), mHwcSlotGenerator(new HwcSlotGenerator()) {
mOverrideScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
mCurrentState.dataspace = ui::Dataspace::V0_SRGB;
- if (const auto display = args.displayDevice) {
- updateTransformHint(display);
- }
}
BufferStateLayer::~BufferStateLayer() {
@@ -108,10 +105,6 @@
}
}
-void BufferStateLayer::setTransformHint(uint32_t orientation) const {
- mTransformHint = orientation;
-}
-
void BufferStateLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
for (const auto& handle : mDrawingState.callbackHandles) {
handle->transformHint = mTransformHint;
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 5873a73..00fa7f7 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -42,7 +42,6 @@
const char* getType() const override { return "BufferStateLayer"; }
void onLayerDisplayed(const sp<Fence>& releaseFence) override;
- void setTransformHint(uint32_t orientation) const override;
void releasePendingBuffer(nsecs_t dequeueReadyTime) override;
void finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& glDoneFence,
@@ -68,7 +67,6 @@
}
Rect getCrop(const Layer::State& s) const;
- uint32_t getTransformHint() const { return mTransformHint; }
bool setTransform(uint32_t transform) override;
bool setTransformToDisplayInverse(bool transformToDisplayInverse) override;
bool setCrop(const Rect& crop) override;
@@ -164,8 +162,6 @@
bool mReleasePreviousBuffer = false;
nsecs_t mCallbackHandleAcquireTime = -1;
- mutable uint32_t mTransformHint = 0;
-
// TODO(marissaw): support sticky transform for LEGACY camera mode
class HwcSlotGenerator : public ClientCache::ErasedRecipient {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 752407a..25929ed1 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -117,6 +117,7 @@
mCurrentState.metadata = args.metadata;
mCurrentState.shadowRadius = 0.f;
mCurrentState.treeHasFrameRateVote = false;
+ mCurrentState.fixedTransformHint = ui::Transform::ROT_INVALID;
// drawing state & current state are identical
mDrawingState = mCurrentState;
@@ -1333,6 +1334,18 @@
return true;
}
+bool Layer::setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHint) {
+ if (mCurrentState.fixedTransformHint == fixedTransformHint) {
+ return false;
+ }
+
+ mCurrentState.sequence++;
+ mCurrentState.fixedTransformHint = fixedTransformHint;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
void Layer::updateTreeHasFrameRateVote() {
const auto traverseTree = [&](const LayerVector::Visitor& visitor) {
auto parent = getParent();
@@ -1460,19 +1473,19 @@
}
void Layer::updateTransformHint(const sp<const DisplayDevice>& display) const {
- uint32_t orientation = 0;
+ ui::Transform::RotationFlags transformHint = ui::Transform::ROT_0;
// Disable setting transform hint if the debug flag is set.
if (!mFlinger->mDebugDisableTransformHint) {
// The transform hint is used to improve performance, but we can
// only have a single transform hint, it cannot
// apply to all displays.
const ui::Transform& planeTransform = display->getTransform();
- orientation = planeTransform.getOrientation();
- if (orientation & ui::Transform::ROT_INVALID) {
- orientation = 0;
+ transformHint = static_cast<ui::Transform::RotationFlags>(planeTransform.getOrientation());
+ if (transformHint & ui::Transform::ROT_INVALID) {
+ transformHint = ui::Transform::ROT_0;
}
}
- setTransformHint(orientation);
+ setTransformHint(transformHint);
}
// ----------------------------------------------------------------------------
@@ -2076,6 +2089,16 @@
return parentAlpha * getDrawingState().color.a;
}
+ui::Transform::RotationFlags Layer::getFixedTransformHint() const {
+ ui::Transform::RotationFlags fixedTransformHint = mCurrentState.fixedTransformHint;
+ if (fixedTransformHint != ui::Transform::ROT_INVALID) {
+ return fixedTransformHint;
+ }
+ const auto& p = mCurrentParent.promote();
+ if (!p) return fixedTransformHint;
+ return p->getFixedTransformHint();
+}
+
half4 Layer::getColor() const {
const half4 color(getDrawingState().color);
return half4(color.r, color.g, color.b, getAlpha());
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index b630333..224ea19 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -262,6 +262,15 @@
// Indicates whether parents / children of this layer had set FrameRate
bool treeHasFrameRateVote;
+
+ // Set by window manager indicating the layer and all its children are
+ // in a different orientation than the display. The hint suggests that
+ // the graphic producers should receive a transform hint as if the
+ // display was in this orientation. When the display changes to match
+ // the layer orientation, the graphic producer may not need to allocate
+ // a buffer of a different size. ui::Transform::ROT_INVALID means the
+ // a fixed transform hint is not set.
+ ui::Transform::RotationFlags fixedTransformHint;
};
explicit Layer(const LayerCreationArgs& args);
@@ -388,6 +397,7 @@
virtual bool setColorSpaceAgnostic(const bool agnostic);
bool setShadowRadius(float shadowRadius);
virtual bool setFrameRateSelectionPriority(int32_t priority);
+ virtual bool setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHint);
// If the variable is not set on the layer, it traverses up the tree to inherit the frame
// rate priority from its parent.
virtual int32_t getFrameRateSelectionPriority() const;
@@ -611,7 +621,7 @@
bool getClearClientTarget(const sp<const DisplayDevice>& display) const;
virtual bool shouldPresentNow(nsecs_t /*expectedPresentTime*/) const { return false; }
- virtual void setTransformHint(uint32_t /*orientation*/) const { }
+ virtual void setTransformHint(ui::Transform::RotationFlags /*transformHint*/) const {}
/*
* called after composition.
@@ -689,6 +699,8 @@
virtual sp<GraphicBuffer> getBuffer() const { return nullptr; }
+ virtual ui::Transform::RotationFlags getTransformHint() const { return ui::Transform::ROT_0; }
+
/*
* Returns if a frame is ready
*/
@@ -733,6 +745,12 @@
int32_t getBackgroundBlurRadius() const;
bool drawShadows() const { return mEffectiveShadowRadius > 0.f; };
+ // Returns the transform hint set by Window Manager on the layer or one of its parents.
+ // This traverses the current state because the data is needed when creating
+ // the layer(off drawing thread) and the hint should be available before the producer
+ // is ready to acquire a buffer.
+ ui::Transform::RotationFlags getFixedTransformHint() const;
+
// Returns how rounded corners should be drawn for this layer.
// This will traverse the hierarchy until it reaches its root, finding topmost rounded
// corner definition and converting it into current layer's coordinates.
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..b7d0bdd 100644
--- a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
@@ -111,23 +111,46 @@
// Calculate the refresh rate by finding the average delta between frames
nsecs_t totalPresentTimeDeltas = 0;
+ nsecs_t totalQueueTimeDeltas = 0;
+ auto missingPresentTime = false;
for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) {
- // If there are no presentation timestamp provided we can't calculate the refresh rate
+ totalQueueTimeDeltas +=
+ std::max(((it + 1)->queueTime - it->queueTime), mHighRefreshRatePeriod);
+
if (it->presetTime == 0 || (it + 1)->presetTime == 0) {
- return std::nullopt;
+ missingPresentTime = true;
+ continue;
}
totalPresentTimeDeltas +=
std::max(((it + 1)->presetTime - it->presetTime), mHighRefreshRatePeriod);
}
+
+ // If there are no presentation timestamps provided we can't calculate the refresh rate
+ if (missingPresentTime && mLastReportedRefreshRate == 0) {
+ return std::nullopt;
+ }
+
+ // Calculate the average frame time based on presentation timestamps. If those
+ // doesn't exist, we look at the time the buffer was queued only. We can do that only if
+ // we calculated a refresh rate based on presentation timestamps in the past. The reason
+ // we look at the queue time is to handle cases where hwui attaches presentation timestamps
+ // when implementing render ahead for specific refresh rates. When hwui no longer provides
+ // presentation timestamps we look at the queue time to see if the current refresh rate still
+ // matches the content.
const float averageFrameTime =
- static_cast<float>(totalPresentTimeDeltas) / (mFrameTimes.size() - 1);
+ static_cast<float>(missingPresentTime ? totalQueueTimeDeltas : totalPresentTimeDeltas) /
+ (mFrameTimes.size() - 1);
// 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);
+ const auto presentTimeDeltas = [&] {
+ const auto delta = missingPresentTime ? (it + 1)->queueTime - it->queueTime
+ : (it + 1)->presetTime - it->presetTime;
+ return std::max(delta, mHighRefreshRatePeriod);
+ }();
+
if (std::abs(presentTimeDeltas - averageFrameTime) > 2 * averageFrameTime) {
return std::nullopt;
}
diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.h b/services/surfaceflinger/Scheduler/LayerInfoV2.h
index ad91f18..e36b7f7 100644
--- a/services/surfaceflinger/Scheduler/LayerInfoV2.h
+++ b/services/surfaceflinger/Scheduler/LayerInfoV2.h
@@ -88,6 +88,7 @@
// buffer as Max as we don't know anything about this layer or Min as this layer is
// posting infrequent updates.
mFrameTimeValidSince = std::chrono::steady_clock::now();
+ mLastReportedRefreshRate = 0.0f;
}
private:
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 87e73a0..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
@@ -2679,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());
+ }
}
}
}
@@ -2765,7 +2765,7 @@
processDisplayHotplugEventsLocked();
}
- if (transactionFlags & (eDisplayLayerStackChanged|eDisplayTransactionNeeded)) {
+ if (transactionFlags & (eTransformHintUpdateNeeded | eDisplayTransactionNeeded)) {
// The transform hint might have changed for some layers
// (either because a display has changed, or because a layer
// as changed).
@@ -2833,7 +2833,6 @@
});
}
-
/*
* Perform our own transaction if needed
*/
@@ -3138,7 +3137,8 @@
status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<IBinder>& handle,
const sp<IGraphicBufferProducer>& gbc, const sp<Layer>& lbc,
const sp<IBinder>& parentHandle,
- const sp<Layer>& parentLayer, bool addToCurrentState) {
+ const sp<Layer>& parentLayer, bool addToCurrentState,
+ uint32_t* outTransformHint) {
// add this layer to the current state list
{
Mutex::Autolock _l(mStateLock);
@@ -3179,6 +3179,14 @@
mGraphicBufferProducerList.size(),
mMaxGraphicBufferProducerListSize, mNumLayers.load());
}
+
+ if (const auto display = getDefaultDisplayDeviceLocked()) {
+ lbc->updateTransformHint(display);
+ }
+ if (outTransformHint) {
+ *outTransformHint = lbc->getTransformHint();
+ }
+
mLayersAdded = true;
}
@@ -3680,7 +3688,7 @@
mCurrentState.layersSortedByZ.add(layer);
// we need traversal (state changed)
// AND transaction (list changed)
- flags |= eTransactionNeeded|eTraversalNeeded|eDisplayLayerStackChanged;
+ flags |= eTransactionNeeded | eTraversalNeeded | eTransformHintUpdateNeeded;
}
}
if (what & layer_state_t::eDeferTransaction_legacy) {
@@ -3777,6 +3785,11 @@
flags |= eTraversalNeeded;
}
}
+ if (what & layer_state_t::eFixedTransformHintChanged) {
+ if (layer->setFixedTransformHint(s.fixedTransformHint)) {
+ flags |= eTraversalNeeded | eTransformHintUpdateNeeded;
+ }
+ }
// This has to happen after we reparent children because when we reparent to null we remove
// child layers from current state and remove its relative z. If the children are reparented in
// the same transaction, then we have to make sure we reparent the children first so we do not
@@ -3864,7 +3877,8 @@
mirrorLayer->mClonedChild = mirrorFrom->createClone();
}
- return addClientLayer(client, *outHandle, nullptr, mirrorLayer, nullptr, nullptr, false);
+ return addClientLayer(client, *outHandle, nullptr, mirrorLayer, nullptr, nullptr, false,
+ nullptr /* outTransformHint */);
}
status_t SurfaceFlinger::createLayer(const String8& name, const sp<Client>& client, uint32_t w,
@@ -3909,7 +3923,7 @@
break;
case ISurfaceComposerClient::eFXSurfaceBufferState:
result = createBufferStateLayer(client, std::move(uniqueName), w, h, flags,
- std::move(metadata), handle, outTransformHint, &layer);
+ std::move(metadata), handle, &layer);
break;
case ISurfaceComposerClient::eFXSurfaceEffect:
// check if buffer size is set for color layer.
@@ -3947,7 +3961,7 @@
bool addToCurrentState = callingThreadHasUnscopedSurfaceFlingerAccess();
result = addClientLayer(client, *handle, *gbp, layer, parentHandle, parentLayer,
- addToCurrentState);
+ addToCurrentState, outTransformHint);
if (result != NO_ERROR) {
return result;
}
@@ -4024,14 +4038,11 @@
status_t SurfaceFlinger::createBufferStateLayer(const sp<Client>& client, std::string name,
uint32_t w, uint32_t h, uint32_t flags,
LayerMetadata metadata, sp<IBinder>* handle,
- uint32_t* outTransformHint, sp<Layer>* outLayer) {
+ sp<Layer>* outLayer) {
LayerCreationArgs args(this, client, std::move(name), w, h, flags, std::move(metadata));
args.displayDevice = getDefaultDisplayDevice();
args.textureName = getNewTexture();
sp<BufferStateLayer> layer = getFactory().createBufferStateLayer(args);
- if (outTransformHint) {
- *outTransformHint = layer->getTransformHint();
- }
*handle = layer->getHandle();
*outLayer = layer;
@@ -5229,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;
}
@@ -5285,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();
}
}));
}
@@ -6224,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 f3984ed..509de0f 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -117,7 +117,7 @@
eTransactionNeeded = 0x01,
eTraversalNeeded = 0x02,
eDisplayTransactionNeeded = 0x04,
- eDisplayLayerStackChanged = 0x08,
+ eTransformHintUpdateNeeded = 0x08,
eTransactionFlushNeeded = 0x10,
eTransactionMask = 0x1f,
};
@@ -675,8 +675,7 @@
status_t createBufferStateLayer(const sp<Client>& client, std::string name, uint32_t w,
uint32_t h, uint32_t flags, LayerMetadata metadata,
- sp<IBinder>* outHandle, uint32_t* outTransformHint,
- sp<Layer>* outLayer);
+ sp<IBinder>* outHandle, sp<Layer>* outLayer);
status_t createEffectLayer(const sp<Client>& client, std::string name, uint32_t w, uint32_t h,
uint32_t flags, LayerMetadata metadata, sp<IBinder>* outHandle,
@@ -701,7 +700,7 @@
status_t addClientLayer(const sp<Client>& client, const sp<IBinder>& handle,
const sp<IGraphicBufferProducer>& gbc, const sp<Layer>& lbc,
const sp<IBinder>& parentHandle, const sp<Layer>& parentLayer,
- bool addToCurrentState);
+ bool addToCurrentState, uint32_t* outTransformHint);
// Traverse through all the layers and compute and cache its bounds.
void computeLayerBounds();
@@ -829,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);
@@ -1216,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
@@ -1258,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/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(