Merge "Plumb new frameRateSelectionStrategy value" into main
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index a447cda..822ab7f 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -437,6 +437,9 @@
maybe_open_reference_profile(parameters_.pkgName, parameters_.apk_path,
parameters_.profile_name, profile_guided,
is_public, parameters_.uid, is_secondary_dex);
+ // `maybe_open_reference_profile` installs a hook that clears the profile on
+ // destruction. Disable it.
+ reference_profile.DisableCleanup();
struct stat sbuf;
if (reference_profile.fd() == -1 ||
(fstat(reference_profile.fd(), &sbuf) != -1 && sbuf.st_size == 0)) {
diff --git a/include/android/bitmap.h b/include/android/bitmap.h
index 35f87f9..87a14c0 100644
--- a/include/android/bitmap.h
+++ b/include/android/bitmap.h
@@ -196,7 +196,7 @@
*
* @param userContext Pointer to user-defined data passed to
* {@link AndroidBitmap_compress}.
- * @param data Compressed data of |size| bytes to write.
+ * @param data Compressed data of `size` bytes to write.
* @param size Length in bytes of data to write.
* @return Whether the operation succeeded.
*/
@@ -205,7 +205,7 @@
size_t size) __INTRODUCED_IN(30);
/**
- * Compress |pixels| as described by |info|.
+ * Compress `pixels` as described by `info`.
*
* Available since API level 30.
*
diff --git a/include/android/sharedmem.h b/include/android/sharedmem.h
index e0a8045..645fa8a 100644
--- a/include/android/sharedmem.h
+++ b/include/android/sharedmem.h
@@ -53,7 +53,7 @@
/**
* Create a shared memory region.
*
- * Create shared memory region and returns an file descriptor. The resulting file descriptor can be
+ * Create shared memory region and returns a file descriptor. The resulting file descriptor can be
* mmap'ed to process memory space with PROT_READ | PROT_WRITE | PROT_EXEC. Access to shared memory
* region can be restricted with {@link ASharedMemory_setProt}.
*
@@ -65,7 +65,7 @@
* cmsg(3) man pages for more information.
*
* If you intend to share this file descriptor with a child process after
- * calling exec(3), note that you will need to use fcntl(2) with FD_SETFD
+ * calling exec(3), note that you will need to use fcntl(2) with F_SETFD
* to clear the FD_CLOEXEC flag for this to work on all versions of Android.
*
* Available since API level 26.
diff --git a/include/android/thermal.h b/include/android/thermal.h
index 32580ba..1f477f8 100644
--- a/include/android/thermal.h
+++ b/include/android/thermal.h
@@ -188,13 +188,13 @@
* Note that this only attempts to track the headroom of slow-moving sensors, such as
* the skin temperature sensor. This means that there is no benefit to calling this function
* more frequently than about once per second, and attempted to call significantly
- * more frequently may result in the function returning {@code NaN}.
+ * more frequently may result in the function returning `NaN`.
*
* In addition, in order to be able to provide an accurate forecast, the system does
* not attempt to forecast until it has multiple temperature samples from which to
* extrapolate. This should only take a few seconds from the time of the first call,
* but during this time, no forecasting will occur, and the current headroom will be
- * returned regardless of the value of {@code forecastSeconds}.
+ * returned regardless of the value of `forecastSeconds`.
*
* The value returned is a non-negative float that represents how much of the thermal envelope
* is in use (or is forecasted to be in use). A value of 1.0 indicates that the device is
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index 25b8e97..3724fa1 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -433,20 +433,21 @@
EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get()));
}
-TEST(NdkBinder, IsUpdatable) {
- bool isUpdatable = AServiceManager_isUpdatableViaApex("android.hardware.light.ILights/default");
- EXPECT_EQ(isUpdatable, false);
-}
-
-TEST(NdkBinder, GetUpdatableViaApex) {
- std::optional<std::string> updatableViaApex;
- AServiceManager_getUpdatableApexName(
- "android.hardware.light.ILights/default", &updatableViaApex,
- [](const char* apexName, void* context) {
- *static_cast<std::optional<std::string>*>(context) = apexName;
- });
- EXPECT_EQ(updatableViaApex, std::nullopt) << *updatableViaApex;
-}
+// TEST(NdkBinder, IsUpdatable) {
+// bool isUpdatable =
+// AServiceManager_isUpdatableViaApex("android.hardware.light.ILights/default");
+// EXPECT_EQ(isUpdatable, true);
+// }
+//
+// TEST(NdkBinder, GetUpdatableViaApex) {
+// std::optional<std::string> updatableViaApex;
+// AServiceManager_getUpdatableApexName(
+// "android.hardware.light.ILights/default", &updatableViaApex,
+// [](const char* apexName, void* context) {
+// *static_cast<std::optional<std::string>*>(context) = apexName;
+// });
+// EXPECT_NE(updatableViaApex, std::nullopt) << *updatableViaApex;
+// }
// This is too slow
TEST(NdkBinder, CheckLazyServiceShutDown) {
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 2ea4d16..9a27d23 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -204,27 +204,8 @@
aconfig_declarations: "libgui_flags",
}
-cc_library_shared {
- name: "libgui",
- vendor_available: true,
- vndk: {
- enabled: true,
- private: true,
- },
- double_loadable: true,
-
- defaults: ["libgui_bufferqueue-defaults"],
-
- static_libs: [
- "libgui_aidl_static",
- "libgui_window_info_static",
- "libguiflags",
- ],
- export_static_lib_headers: [
- "libgui_aidl_static",
- "libgui_window_info_static",
- ],
-
+filegroup {
+ name: "libgui-sources",
srcs: [
":framework_native_aidl_binder",
":framework_native_aidl_gui",
@@ -268,11 +249,40 @@
"bufferqueue/2.0/B2HProducerListener.cpp",
"bufferqueue/2.0/H2BGraphicBufferProducer.cpp",
],
+}
+cc_defaults {
+ name: "libgui-defaults",
+ defaults: ["libgui_bufferqueue-defaults"],
+ srcs: [":libgui-sources"],
+ static_libs: [
+ "libgui_aidl_static",
+ "libgui_window_info_static",
+ "libguiflags",
+ ],
shared_libs: [
"libbinder",
"libGLESv2",
],
+}
+
+cc_library_shared {
+ name: "libgui",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ private: true,
+ },
+ double_loadable: true,
+
+ defaults: [
+ "libgui-defaults",
+ ],
+
+ export_static_lib_headers: [
+ "libgui_aidl_static",
+ "libgui_window_info_static",
+ ],
export_shared_lib_headers: [
"libbinder",
@@ -346,6 +356,7 @@
"BufferQueueProducer.cpp",
"BufferQueueThreadState.cpp",
"BufferSlot.cpp",
+ "FrameRateUtils.cpp",
"FrameTimestamps.cpp",
"GLConsumerUtils.cpp",
"HdrMetadata.cpp",
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 207fa4f..dd0a028 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -26,6 +26,8 @@
#include <gui/BufferQueueConsumer.h>
#include <gui/BufferQueueCore.h>
#include <gui/BufferQueueProducer.h>
+#include <gui/Flags.h>
+#include <gui/FrameRateUtils.h>
#include <gui/GLConsumer.h>
#include <gui/IProducerListener.h>
#include <gui/Surface.h>
@@ -39,6 +41,9 @@
#include <android-base/thread_annotations.h>
#include <chrono>
+#include <com_android_graphics_libgui_flags.h>
+
+using namespace com::android::graphics::libgui;
using namespace std::chrono_literals;
namespace {
@@ -139,6 +144,16 @@
}
}
+#if FLAG_BQ_SET_FRAME_RATE
+void BLASTBufferItemConsumer::onSetFrameRate(float frameRate, int8_t compatibility,
+ int8_t changeFrameRateStrategy) {
+ sp<BLASTBufferQueue> bbq = mBLASTBufferQueue.promote();
+ if (bbq != nullptr) {
+ bbq->setFrameRate(frameRate, compatibility, changeFrameRateStrategy);
+ }
+}
+#endif
+
void BLASTBufferItemConsumer::resizeFrameEventHistory(size_t newSize) {
Mutex::Autolock lock(mMutex);
mFrameEventHistory.resize(newSize);
@@ -890,6 +905,10 @@
status_t setFrameRate(float frameRate, int8_t compatibility,
int8_t changeFrameRateStrategy) override {
+ if (flags::bq_setframerate()) {
+ return Surface::setFrameRate(frameRate, compatibility, changeFrameRateStrategy);
+ }
+
std::lock_guard _lock{mMutex};
if (mDestroyed) {
return DEAD_OBJECT;
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 66cad03..ab0f6d2 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -22,6 +22,7 @@
#include <gui/BufferQueueConsumer.h>
#include <gui/BufferQueueCore.h>
#include <gui/BufferQueueProducer.h>
+#include <gui/Flags.h>
namespace android {
@@ -98,6 +99,16 @@
}
}
+#if FLAG_BQ_SET_FRAME_RATE
+void BufferQueue::ProxyConsumerListener::onSetFrameRate(float frameRate, int8_t compatibility,
+ int8_t changeFrameRateStrategy) {
+ sp<ConsumerListener> listener(mConsumerListener.promote());
+ if (listener != nullptr) {
+ listener->onSetFrameRate(frameRate, compatibility, changeFrameRateStrategy);
+ }
+}
+#endif
+
void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
sp<IGraphicBufferConsumer>* outConsumer,
bool consumerIsSurfaceFlinger) {
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 920b83d..67dff6d 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -32,6 +32,8 @@
#include <gui/BufferItem.h>
#include <gui/BufferQueueCore.h>
#include <gui/BufferQueueProducer.h>
+#include <gui/Flags.h>
+#include <gui/FrameRateUtils.h>
#include <gui/GLConsumer.h>
#include <gui/IConsumerListener.h>
#include <gui/IProducerListener.h>
@@ -1751,4 +1753,27 @@
return NO_ERROR;
}
+#if FLAG_BQ_SET_FRAME_RATE
+status_t BufferQueueProducer::setFrameRate(float frameRate, int8_t compatibility,
+ int8_t changeFrameRateStrategy) {
+ ATRACE_CALL();
+ BQ_LOGV("setFrameRate: %.2f", frameRate);
+
+ if (!ValidateFrameRate(frameRate, compatibility, changeFrameRateStrategy,
+ "BufferQueueProducer::setFrameRate")) {
+ return BAD_VALUE;
+ }
+
+ sp<IConsumerListener> listener;
+ {
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
+ listener = mCore->mConsumerListener;
+ }
+ if (listener != nullptr) {
+ listener->onSetFrameRate(frameRate, compatibility, changeFrameRateStrategy);
+ }
+ return NO_ERROR;
+}
+#endif
+
} // namespace android
diff --git a/libs/gui/FrameRateUtils.cpp b/libs/gui/FrameRateUtils.cpp
new file mode 100644
index 0000000..6993bfa
--- /dev/null
+++ b/libs/gui/FrameRateUtils.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gui/Flags.h>
+#include <gui/FrameRateUtils.h>
+#include <system/window.h>
+#include <utils/Log.h>
+
+#include <cmath>
+
+namespace android {
+// Returns true if the frameRate is valid.
+//
+// @param frameRate the frame rate in Hz
+// @param compatibility a ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_*
+// @param changeFrameRateStrategy a ANATIVEWINDOW_CHANGE_FRAME_RATE_*
+// @param functionName calling function or nullptr. Used for logging
+// @param privileged whether caller has unscoped surfaceflinger access
+bool ValidateFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy,
+ const char* inFunctionName, bool privileged) {
+ const char* functionName = inFunctionName != nullptr ? inFunctionName : "call";
+ int floatClassification = std::fpclassify(frameRate);
+ if (frameRate < 0 || floatClassification == FP_INFINITE || floatClassification == FP_NAN) {
+ ALOGE("%s failed - invalid frame rate %f", functionName, frameRate);
+ return false;
+ }
+
+ if (compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT &&
+ compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE &&
+ (!privileged ||
+ (compatibility != ANATIVEWINDOW_FRAME_RATE_EXACT &&
+ compatibility != ANATIVEWINDOW_FRAME_RATE_NO_VOTE))) {
+ ALOGE("%s failed - invalid compatibility value %d privileged: %s", functionName,
+ compatibility, privileged ? "yes" : "no");
+ return false;
+ }
+
+ if (__builtin_available(android 31, *)) {
+ if (changeFrameRateStrategy != ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS &&
+ changeFrameRateStrategy != ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS) {
+ ALOGE("%s failed - invalid change frame rate strategy value %d", functionName,
+ changeFrameRateStrategy);
+ if (FLAG_BQ_SET_FRAME_RATE) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+} // namespace android
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 918ff2d..d0c09e4 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -27,11 +27,12 @@
#include <binder/Parcel.h>
#include <binder/IInterface.h>
-#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
-#include <gui/bufferqueue/2.0/H2BGraphicBufferProducer.h>
#include <gui/BufferQueueDefs.h>
+#include <gui/Flags.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/IProducerListener.h>
+#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
+#include <gui/bufferqueue/2.0/H2BGraphicBufferProducer.h>
namespace android {
// ----------------------------------------------------------------------------
@@ -78,6 +79,7 @@
CANCEL_BUFFERS,
QUERY_MULTIPLE,
GET_LAST_QUEUED_BUFFER2,
+ SET_FRAME_RATE,
};
class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
@@ -761,6 +763,21 @@
}
return result;
}
+#if FLAG_BQ_SET_FRAME_RATE
+ virtual status_t setFrameRate(float frameRate, int8_t compatibility,
+ int8_t changeFrameRateStrategy) override {
+ Parcel data, reply;
+ data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
+ data.writeFloat(frameRate);
+ data.writeInt32(compatibility);
+ data.writeInt32(changeFrameRateStrategy);
+ status_t result = remote()->transact(SET_FRAME_RATE, data, &reply);
+ if (result == NO_ERROR) {
+ result = reply.readInt32();
+ }
+ return result;
+ }
+#endif
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -956,6 +973,14 @@
return INVALID_OPERATION;
}
+#if FLAG_BQ_SET_FRAME_RATE
+status_t IGraphicBufferProducer::setFrameRate(float /*frameRate*/, int8_t /*compatibility*/,
+ int8_t /*changeFrameRateStrategy*/) {
+ // No-op for IGBP other than BufferQueue.
+ return INVALID_OPERATION;
+}
+#endif
+
status_t IGraphicBufferProducer::exportToParcel(Parcel* parcel) {
status_t res = OK;
res = parcel->writeUint32(USE_BUFFER_QUEUE);
@@ -1497,6 +1522,17 @@
reply->writeInt32(result);
return NO_ERROR;
}
+#if FLAG_BQ_SET_FRAME_RATE
+ case SET_FRAME_RATE: {
+ CHECK_INTERFACE(IGraphicBuffer, data, reply);
+ float frameRate = data.readFloat();
+ int8_t compatibility = data.readInt32();
+ int8_t changeFrameRateStrategy = data.readInt32();
+ status_t result = setFrameRate(frameRate, compatibility, changeFrameRateStrategy);
+ reply->writeInt32(result);
+ return NO_ERROR;
+ }
+#endif
}
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 27b1d8b..613721e 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -22,6 +22,7 @@
#include <android/gui/ISurfaceComposerClient.h>
#include <android/native_window.h>
#include <binder/Parcel.h>
+#include <gui/FrameRateUtils.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/LayerState.h>
#include <gui/SurfaceControl.h>
@@ -871,34 +872,6 @@
return NO_ERROR;
}
-bool ValidateFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy,
- const char* inFunctionName, bool privileged) {
- const char* functionName = inFunctionName != nullptr ? inFunctionName : "call";
- int floatClassification = std::fpclassify(frameRate);
- if (frameRate < 0 || floatClassification == FP_INFINITE || floatClassification == FP_NAN) {
- ALOGE("%s failed - invalid frame rate %f", functionName, frameRate);
- return false;
- }
-
- if (compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT &&
- compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE &&
- (!privileged ||
- (compatibility != ANATIVEWINDOW_FRAME_RATE_EXACT &&
- compatibility != ANATIVEWINDOW_FRAME_RATE_NO_VOTE))) {
- ALOGE("%s failed - invalid compatibility value %d privileged: %s", functionName,
- compatibility, privileged ? "yes" : "no");
- return false;
- }
-
- if (changeFrameRateStrategy != ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS &&
- changeFrameRateStrategy != ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS) {
- ALOGE("%s failed - invalid change frame rate strategy value %d", functionName,
- changeFrameRateStrategy);
- }
-
- return true;
-}
-
// ----------------------------------------------------------------------------
namespace gui {
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 53a2f64..a87f053 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -43,6 +43,7 @@
#include <gui/AidlStatusUtil.h>
#include <gui/BufferItem.h>
+#include <gui/Flags.h>
#include <gui/IProducerListener.h>
#include <gui/ISurfaceComposer.h>
@@ -50,8 +51,11 @@
#include <private/gui/ComposerService.h>
#include <private/gui/ComposerServiceAIDL.h>
+#include <com_android_graphics_libgui_flags.h>
+
namespace android {
+using namespace com::android::graphics::libgui;
using gui::aidl_utils::statusTFromBinderStatus;
using ui::Dataspace;
@@ -2565,8 +2569,22 @@
mSurfaceListener->onBuffersDiscarded(discardedBufs);
}
-[[deprecated]] status_t Surface::setFrameRate(float /*frameRate*/, int8_t /*compatibility*/,
- int8_t /*changeFrameRateStrategy*/) {
+status_t Surface::setFrameRate(float frameRate, int8_t compatibility,
+ int8_t changeFrameRateStrategy) {
+#if FLAG_BQ_SET_FRAME_RATE
+ if (flags::bq_setframerate()) {
+ status_t err = mGraphicBufferProducer->setFrameRate(frameRate, compatibility,
+ changeFrameRateStrategy);
+ ALOGE_IF(err, "IGraphicBufferProducer::setFrameRate(%.2f) returned %s", frameRate,
+ strerror(-err));
+ return err;
+ }
+#else
+ static_cast<void>(frameRate);
+ static_cast<void>(compatibility);
+ static_cast<void>(changeFrameRateStrategy);
+#endif
+
ALOGI("Surface::setFrameRate is deprecated, setFrameRate hint is dropped as destination is not "
"SurfaceFlinger");
// ISurfaceComposer no longer supports setFrameRate, we will return NO_ERROR when the api is
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index c2543d1..038764b 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -26,6 +26,7 @@
#include <android/gui/IWindowInfosListener.h>
#include <android/gui/TrustedPresentationThresholds.h>
#include <android/os/IInputConstants.h>
+#include <gui/FrameRateUtils.h>
#include <gui/TraceUtils.h>
#include <utils/Errors.h>
#include <utils/Log.h>
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index a49a859..02d7c4d 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -17,9 +17,10 @@
#ifndef ANDROID_GUI_BLAST_BUFFER_QUEUE_H
#define ANDROID_GUI_BLAST_BUFFER_QUEUE_H
-#include <gui/IGraphicBufferProducer.h>
-#include <gui/BufferItemConsumer.h>
#include <gui/BufferItem.h>
+#include <gui/BufferItemConsumer.h>
+#include <gui/Flags.h>
+#include <gui/IGraphicBufferProducer.h>
#include <gui/SurfaceComposerClient.h>
#include <utils/Condition.h>
@@ -58,6 +59,10 @@
protected:
void onSidebandStreamChanged() override EXCLUDES(mMutex);
+#if FLAG_BQ_SET_FRAME_RATE
+ void onSetFrameRate(float frameRate, int8_t compatibility,
+ int8_t changeFrameRateStrategy) override;
+#endif
private:
const wp<BLASTBufferQueue> mBLASTBufferQueue;
diff --git a/libs/gui/include/gui/BufferQueue.h b/libs/gui/include/gui/BufferQueue.h
index 690587f..2756277 100644
--- a/libs/gui/include/gui/BufferQueue.h
+++ b/libs/gui/include/gui/BufferQueue.h
@@ -19,9 +19,10 @@
#include <gui/BufferItem.h>
#include <gui/BufferQueueDefs.h>
+#include <gui/Flags.h>
+#include <gui/IConsumerListener.h>
#include <gui/IGraphicBufferConsumer.h>
#include <gui/IGraphicBufferProducer.h>
-#include <gui/IConsumerListener.h>
namespace android {
@@ -69,6 +70,10 @@
void addAndGetFrameTimestamps(
const NewFrameEventsEntry* newTimestamps,
FrameEventHistoryDelta* outDelta) override;
+#if FLAG_BQ_SET_FRAME_RATE
+ void onSetFrameRate(float frameRate, int8_t compatibility,
+ int8_t changeFrameRateStrategy) override;
+#endif
private:
// mConsumerListener is a weak reference to the IConsumerListener. This is
// the raison d'etre of ProxyConsumerListener.
diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h
index 1d13dab..38805d0 100644
--- a/libs/gui/include/gui/BufferQueueProducer.h
+++ b/libs/gui/include/gui/BufferQueueProducer.h
@@ -18,6 +18,7 @@
#define ANDROID_GUI_BUFFERQUEUEPRODUCER_H
#include <gui/BufferQueueDefs.h>
+#include <gui/Flags.h>
#include <gui/IGraphicBufferProducer.h>
namespace android {
@@ -201,6 +202,11 @@
// See IGraphicBufferProducer::setAutoPrerotation
virtual status_t setAutoPrerotation(bool autoPrerotation);
+#if FLAG_BQ_SET_FRAME_RATE
+ // See IGraphicBufferProducer::setFrameRate
+ status_t setFrameRate(float frameRate, int8_t compatibility,
+ int8_t changeFrameRateStrategy) override;
+#endif
protected:
// see IGraphicsBufferProducer::setMaxDequeuedBufferCount, but with the ability to retrieve the
diff --git a/libs/gui/include/gui/Flags.h b/libs/gui/include/gui/Flags.h
new file mode 100644
index 0000000..a2cff56
--- /dev/null
+++ b/libs/gui/include/gui/Flags.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2023 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
+
+// TODO(281695725): replace this with build time flags, whenever they are available
+#ifndef FLAG_BQ_SET_FRAME_RATE
+#define FLAG_BQ_SET_FRAME_RATE false
+#endif
\ No newline at end of file
diff --git a/libs/gui/include/gui/FrameRateUtils.h b/libs/gui/include/gui/FrameRateUtils.h
new file mode 100644
index 0000000..16896ef
--- /dev/null
+++ b/libs/gui/include/gui/FrameRateUtils.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2023 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 <stdint.h>
+
+namespace android {
+
+bool ValidateFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy,
+ const char* inFunctionName, bool privileged = false);
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/gui/include/gui/IConsumerListener.h b/libs/gui/include/gui/IConsumerListener.h
index 0ab2399..e183bf2 100644
--- a/libs/gui/include/gui/IConsumerListener.h
+++ b/libs/gui/include/gui/IConsumerListener.h
@@ -19,6 +19,8 @@
#include <binder/IInterface.h>
#include <binder/SafeInterface.h>
+#include <gui/Flags.h>
+
#include <utils/Errors.h>
#include <utils/RefBase.h>
@@ -90,6 +92,12 @@
// WARNING: This method can only be called when the BufferQueue is in the consumer's process.
virtual void addAndGetFrameTimestamps(const NewFrameEventsEntry* /*newTimestamps*/,
FrameEventHistoryDelta* /*outDelta*/) {}
+
+#if FLAG_BQ_SET_FRAME_RATE
+ // Notifies the consumer of a setFrameRate call from the producer side.
+ virtual void onSetFrameRate(float /*frameRate*/, int8_t /*compatibility*/,
+ int8_t /*changeFrameRateStrategy*/) {}
+#endif
};
#ifndef NO_BINDER
diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h
index 98df834..3562906 100644
--- a/libs/gui/include/gui/IGraphicBufferProducer.h
+++ b/libs/gui/include/gui/IGraphicBufferProducer.h
@@ -31,6 +31,7 @@
#include <ui/Rect.h>
#include <ui/Region.h>
+#include <gui/Flags.h>
#include <gui/FrameTimestamps.h>
#include <gui/HdrMetadata.h>
@@ -676,6 +677,12 @@
// the width and height used for dequeueBuffer will be additionally swapped.
virtual status_t setAutoPrerotation(bool autoPrerotation);
+#if FLAG_BQ_SET_FRAME_RATE
+ // Sets the apps intended frame rate.
+ virtual status_t setFrameRate(float frameRate, int8_t compatibility,
+ int8_t changeFrameRateStrategy);
+#endif
+
struct RequestBufferOutput : public Flattenable<RequestBufferOutput> {
RequestBufferOutput() = default;
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 35fcccd..4371007 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -480,16 +480,6 @@
return compare_type(lhs.token, rhs.token);
}
-// Returns true if the frameRate is valid.
-//
-// @param frameRate the frame rate in Hz
-// @param compatibility a ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_*
-// @param changeFrameRateStrategy a ANATIVEWINDOW_CHANGE_FRAME_RATE_*
-// @param functionName calling function or nullptr. Used for logging
-// @param privileged whether caller has unscoped surfaceflinger access
-bool ValidateFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy,
- const char* functionName, bool privileged = false);
-
}; // namespace android
#endif // ANDROID_SF_LAYER_STATE_H
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 462ce6e..38c0eed 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -15,9 +15,13 @@
name: "libgui_test",
test_suites: ["device-tests"],
- cflags: [
+ defaults: ["libgui-defaults"],
+
+ cppflags: [
"-Wall",
"-Werror",
+ "-Wno-extra",
+ "-DFLAG_BQ_SET_FRAME_RATE=true",
],
srcs: [
@@ -28,6 +32,7 @@
"CompositorTiming_test.cpp",
"CpuConsumer_test.cpp",
"EndToEndNativeInputTest.cpp",
+ "FrameRateUtilsTest.cpp",
"DisplayInfo_test.cpp",
"DisplayedContentSampling_test.cpp",
"FillBuffer.cpp",
@@ -53,19 +58,12 @@
"android.hardware.configstore@1.0",
"android.hardware.configstore-utils",
"libSurfaceFlingerProp",
- "libbase",
- "liblog",
- "libEGL",
"libGLESv1_CM",
- "libGLESv2",
- "libbinder",
- "libcutils",
- "libgui",
- "libhidlbase",
"libinput",
- "libui",
- "libutils",
- "libnativewindow",
+ ],
+
+ static_libs: [
+ "libgmock",
],
header_libs: ["libsurfaceflinger_headers"],
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 0168877..17aa5f1 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -37,14 +37,18 @@
#include <system/window.h>
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <future>
#include <thread>
+#include <com_android_graphics_libgui_flags.h>
+
using namespace std::chrono_literals;
namespace android {
+using namespace com::android::graphics::libgui;
class BufferQueueTest : public ::testing::Test {
@@ -1261,6 +1265,31 @@
ASSERT_EQ(NO_INIT, mProducer->disconnect(NATIVE_WINDOW_API_CPU));
}
+TEST_F(BufferQueueTest, TestBqSetFrameRateFlagBuildTimeIsSet) {
+ if (flags::bq_setframerate()) {
+ ASSERT_EQ(true, FLAG_BQ_SET_FRAME_RATE);
+ }
+}
+
+struct BufferItemConsumerSetFrameRateListener : public BufferItemConsumer {
+ BufferItemConsumerSetFrameRateListener(const sp<IGraphicBufferConsumer>& consumer)
+ : BufferItemConsumer(consumer, GRALLOC_USAGE_SW_READ_OFTEN, 1) {}
+
+ MOCK_METHOD(void, onSetFrameRate, (float, int8_t, int8_t), (override));
+};
+
+TEST_F(BufferQueueTest, TestSetFrameRate) {
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+
+ sp<BufferItemConsumerSetFrameRateListener> bufferConsumer =
+ sp<BufferItemConsumerSetFrameRateListener>::make(consumer);
+
+ EXPECT_CALL(*bufferConsumer, onSetFrameRate(12.34f, 1, 0)).Times(1);
+ producer->setFrameRate(12.34f, 1, 0);
+}
+
class Latch {
public:
explicit Latch(int expected) : mExpected(expected) {}
diff --git a/libs/gui/tests/FrameRateUtilsTest.cpp b/libs/gui/tests/FrameRateUtilsTest.cpp
new file mode 100644
index 0000000..5fe22b0
--- /dev/null
+++ b/libs/gui/tests/FrameRateUtilsTest.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <gui/FrameRateUtils.h>
+#include <inttypes.h>
+#include <system/window.h>
+
+#include <com_android_graphics_libgui_flags.h>
+
+namespace android {
+using namespace com::android::graphics::libgui;
+
+TEST(FrameRateUtilsTest, ValidateFrameRate) {
+ EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
+ EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
+ EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS, ""));
+ EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
+
+ // Privileged APIs.
+ EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
+ EXPECT_FALSE(ValidateFrameRate(0.0f, ANATIVEWINDOW_FRAME_RATE_NO_VOTE,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
+
+ constexpr bool kPrivileged = true;
+ EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "",
+ kPrivileged));
+ EXPECT_TRUE(ValidateFrameRate(0.0f, ANATIVEWINDOW_FRAME_RATE_NO_VOTE,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "",
+ kPrivileged));
+
+ // Invalid frame rate.
+ EXPECT_FALSE(ValidateFrameRate(-1, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
+ EXPECT_FALSE(ValidateFrameRate(1.0f / 0.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
+ EXPECT_FALSE(ValidateFrameRate(0.0f / 0.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
+
+ // Invalid compatibility.
+ EXPECT_FALSE(
+ ValidateFrameRate(60.0f, -1, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
+ EXPECT_FALSE(ValidateFrameRate(60.0f, 2, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
+
+ // Invalid change frame rate strategy.
+ if (flags::bq_setframerate()) {
+ EXPECT_FALSE(
+ ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, -1, ""));
+ EXPECT_FALSE(
+ ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, 2, ""));
+ }
+}
+
+} // namespace android
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 1f14396..1600013 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -476,8 +476,6 @@
}
status_t InputChannel::receiveMessage(InputMessage* msg) {
- ATRACE_NAME_IF(ATRACE_ENABLED(),
- StringPrintf("receiveMessage(inputChannel=%s)", mName.c_str()));
ssize_t nRead;
do {
nRead = ::recv(getFd(), msg, sizeof(InputMessage), MSG_DONTWAIT);
diff --git a/libs/input/tests/InputDevice_test.cpp b/libs/input/tests/InputDevice_test.cpp
index ee961f0..a0ec6ad 100644
--- a/libs/input/tests/InputDevice_test.cpp
+++ b/libs/input/tests/InputDevice_test.cpp
@@ -20,6 +20,7 @@
#include <input/InputDevice.h>
#include <input/KeyLayoutMap.h>
#include <input/Keyboard.h>
+#include <linux/uinput.h>
#include "android-base/file.h"
namespace android {
@@ -97,7 +98,7 @@
ASSERT_EQ(*map, *mKeyMap.keyCharacterMap);
}
-TEST_F(InputDeviceKeyMapTest, keyCharacteMapApplyMultipleOverlaysTest) {
+TEST_F(InputDeviceKeyMapTest, keyCharacterMapApplyMultipleOverlaysTest) {
std::string frenchOverlayPath = base::GetExecutableDirectory() + "/data/french.kcm";
std::string englishOverlayPath = base::GetExecutableDirectory() + "/data/english_us.kcm";
std::string germanOverlayPath = base::GetExecutableDirectory() + "/data/german.kcm";
@@ -133,14 +134,33 @@
ASSERT_EQ(*mKeyMap.keyCharacterMap, *frenchOverlaidKeyCharacterMap);
}
-TEST_F(InputDeviceKeyMapTest, keyCharacteMapBadAxisLabel) {
+TEST_F(InputDeviceKeyMapTest, keyCharacterMapApplyOverlayTest) {
+ std::string frenchOverlayPath = base::GetExecutableDirectory() + "/data/french.kcm";
+ base::Result<std::shared_ptr<KeyCharacterMap>> frenchOverlay =
+ KeyCharacterMap::load(frenchOverlayPath, KeyCharacterMap::Format::OVERLAY);
+ ASSERT_TRUE(frenchOverlay.ok()) << "Cannot load KeyCharacterMap at " << frenchOverlayPath;
+
+ // Apply the French overlay
+ mKeyMap.keyCharacterMap->combine(*frenchOverlay->get());
+
+ // Check if mapping for key_Q is correct
+ int32_t outKeyCode;
+ status_t mapKeyResult = mKeyMap.keyCharacterMap->mapKey(KEY_Q, /*usageCode=*/0, &outKeyCode);
+ ASSERT_EQ(mapKeyResult, OK) << "No mapping for KEY_Q for " << frenchOverlayPath;
+ ASSERT_EQ(outKeyCode, AKEYCODE_A);
+
+ mapKeyResult = mKeyMap.keyCharacterMap->mapKey(KEY_E, /*usageCode=*/0, &outKeyCode);
+ ASSERT_NE(mapKeyResult, OK) << "Mapping exists for KEY_E for " << frenchOverlayPath;
+}
+
+TEST_F(InputDeviceKeyMapTest, keyCharacterMapBadAxisLabel) {
std::string klPath = base::GetExecutableDirectory() + "/data/bad_axis_label.kl";
base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(klPath);
ASSERT_FALSE(ret.ok()) << "Should not be able to load KeyLayout at " << klPath;
}
-TEST_F(InputDeviceKeyMapTest, keyCharacteMapBadLedLabel) {
+TEST_F(InputDeviceKeyMapTest, keyCharacterMapBadLedLabel) {
std::string klPath = base::GetExecutableDirectory() + "/data/bad_led_label.kl";
base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(klPath);
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index e253ad5..cc1d12b 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -24,6 +24,7 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GrContextOptions.h>
+#include <GrTypes.h>
#include <android-base/stringprintf.h>
#include <gl/GrGLInterface.h>
#include <gui/TraceUtils.h>
@@ -338,7 +339,8 @@
} else {
ATRACE_BEGIN("Submit(sync=false)");
}
- bool success = grContext->submit(requireSync);
+ bool success = grContext->submit(requireSync ? GrSyncCpu::kYes :
+ GrSyncCpu::kNo);
ATRACE_END();
if (!success) {
ALOGE("Failed to flush RenderEngine commands");
diff --git a/libs/ultrahdr/include/ultrahdr/jpegdecoderhelper.h b/libs/ultrahdr/include/ultrahdr/jpegdecoderhelper.h
index 30149c1..b86ce5f4 100644
--- a/libs/ultrahdr/include/ultrahdr/jpegdecoderhelper.h
+++ b/libs/ultrahdr/include/ultrahdr/jpegdecoderhelper.h
@@ -136,7 +136,7 @@
size_t mHeight;
// Position of EXIF package, default value is -1 which means no EXIF package appears.
- size_t mExifPos;
+ ssize_t mExifPos = -1;
};
} /* namespace android::ultrahdr */
diff --git a/libs/ultrahdr/jpegr.cpp b/libs/ultrahdr/jpegr.cpp
index 74760d9..3d70fce 100644
--- a/libs/ultrahdr/jpegr.cpp
+++ b/libs/ultrahdr/jpegr.cpp
@@ -85,13 +85,11 @@
jr_compressed_ptr pSource,
size_t exif_pos,
size_t exif_size) {
- memcpy(pDest, pSource, sizeof(jpegr_compressed_struct));
-
const size_t exif_offset = 4; //exif_pos has 4 bytes offset to the FF sign
pDest->length = pSource->length - exif_size - exif_offset;
pDest->data = new uint8_t[pDest->length];
- std::unique_ptr<uint8_t[]> dest_data;
- dest_data.reset(reinterpret_cast<uint8_t*>(pDest->data));
+ pDest->maxLength = pDest->length;
+ pDest->colorGamut = pSource->colorGamut;
memcpy(pDest->data, pSource->data, exif_pos - exif_offset);
memcpy((uint8_t*)pDest->data + exif_pos - exif_offset,
(uint8_t*)pSource->data + exif_pos + exif_size,
@@ -1262,13 +1260,13 @@
if (!decoder.extractEXIF(primary_jpg_image_ptr->data, primary_jpg_image_ptr->length)) {
return ERROR_JPEGR_DECODE_ERROR;
}
- jpegr_exif_struct exif_from_jpg;
- exif_from_jpg.data = nullptr;
- exif_from_jpg.length = 0;
- jpegr_compressed_struct new_jpg_image;
- new_jpg_image.data = nullptr;
- new_jpg_image.length = 0;
- if (decoder.getEXIFPos() != 0) {
+ jpegr_exif_struct exif_from_jpg = {.data = nullptr, .length = 0};
+ jpegr_compressed_struct new_jpg_image = {.data = nullptr,
+ .length = 0,
+ .maxLength = 0,
+ .colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED};
+ std::unique_ptr<uint8_t[]> dest_data;
+ if (decoder.getEXIFPos() >= 0) {
if (pExif != nullptr) {
ALOGE("received EXIF from outside while the primary image already contains EXIF");
return ERROR_JPEGR_INVALID_INPUT_TYPE;
@@ -1277,6 +1275,7 @@
primary_jpg_image_ptr,
decoder.getEXIFPos(),
decoder.getEXIFSize());
+ dest_data.reset(reinterpret_cast<uint8_t*>(new_jpg_image.data));
exif_from_jpg.data = decoder.getEXIFPtr();
exif_from_jpg.length = decoder.getEXIFSize();
pExif = &exif_from_jpg;
diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp
index 052efb6b..e5b1e44 100644
--- a/services/gpuservice/Android.bp
+++ b/services/gpuservice/Android.bp
@@ -21,7 +21,13 @@
cc_defaults {
name: "libgpuservice_defaults",
- defaults: ["gpuservice_defaults"],
+ defaults: [
+ "gpuservice_defaults",
+ "libvkjson_deps",
+ "libgfxstats_deps",
+ "libgpumem_deps",
+ "libgpumemtracer_deps",
+ ],
cflags: [
"-DLOG_TAG=\"GpuService\"",
],
@@ -29,17 +35,17 @@
"libbase",
"libbinder",
"libcutils",
- "libgfxstats",
- "libgpumem",
"libgpuwork",
- "libgpumemtracer",
"libgraphicsenv",
"liblog",
"libutils",
- "libvkjson",
],
static_libs: [
+ "libgfxstats",
+ "libgpumem",
+ "libgpumemtracer",
"libserviceutils",
+ "libvkjson",
],
export_static_lib_headers: [
"libserviceutils",
@@ -68,7 +74,7 @@
],
}
-cc_library_shared {
+cc_library_static {
name: "libgpuservice",
defaults: ["libgpuservice_production_defaults"],
export_include_dirs: ["include"],
@@ -96,14 +102,17 @@
cc_binary {
name: "gpuservice",
- defaults: ["libgpuservice_binary"],
+ defaults: [
+ "libgpuservice_binary",
+ "libgpuservice_production_defaults",
+ ],
init_rc: ["gpuservice.rc"],
required: [
"bpfloader",
"gpuMem.o",
],
srcs: [":gpuservice_binary_sources"],
- shared_libs: [
+ static_libs: [
"libgpuservice",
],
}
diff --git a/services/gpuservice/gpumem/Android.bp b/services/gpuservice/gpumem/Android.bp
index d0ea856..66a3059 100644
--- a/services/gpuservice/gpumem/Android.bp
+++ b/services/gpuservice/gpumem/Android.bp
@@ -21,12 +21,8 @@
default_applicable_licenses: ["frameworks_native_license"],
}
-cc_library_shared {
- name: "libgpumem",
- srcs: [
- "GpuMem.cpp",
- ],
- header_libs: ["bpf_headers"],
+cc_defaults {
+ name: "libgpumem_deps",
shared_libs: [
"libbase",
"libbpf_bcc",
@@ -34,6 +30,17 @@
"liblog",
"libutils",
],
+}
+
+cc_library_static {
+ name: "libgpumem",
+ defaults: [
+ "libgpumem_deps",
+ ],
+ srcs: [
+ "GpuMem.cpp",
+ ],
+ header_libs: ["bpf_headers"],
export_include_dirs: ["include"],
export_header_lib_headers: ["bpf_headers"],
export_shared_lib_headers: ["libbase"],
diff --git a/services/gpuservice/gpustats/Android.bp b/services/gpuservice/gpustats/Android.bp
index 54291ad..0e64716 100644
--- a/services/gpuservice/gpustats/Android.bp
+++ b/services/gpuservice/gpustats/Android.bp
@@ -7,11 +7,8 @@
default_applicable_licenses: ["frameworks_native_license"],
}
-cc_library_shared {
- name: "libgfxstats",
- srcs: [
- "GpuStats.cpp",
- ],
+cc_defaults {
+ name: "libgfxstats_deps",
shared_libs: [
"libcutils",
"libgraphicsenv",
@@ -22,6 +19,16 @@
"libstatssocket",
"libutils",
],
+}
+
+cc_library_static {
+ name: "libgfxstats",
+ defaults: [
+ "libgfxstats_deps",
+ ],
+ srcs: [
+ "GpuStats.cpp",
+ ],
export_include_dirs: ["include"],
export_shared_lib_headers: [
"libstatspull",
diff --git a/services/gpuservice/tests/fuzzers/Android.bp b/services/gpuservice/tests/fuzzers/Android.bp
index 6bcc5e8..d4d48c4 100644
--- a/services/gpuservice/tests/fuzzers/Android.bp
+++ b/services/gpuservice/tests/fuzzers/Android.bp
@@ -5,10 +5,12 @@
cc_fuzz {
name: "gpu_service_fuzzer",
defaults: [
+ "libgpuservice_defaults",
"service_fuzzer_defaults",
"fuzzer_disable_leaks",
],
static_libs: [
+ "libgpuservice",
"liblog",
],
fuzz_config: {
@@ -20,7 +22,4 @@
},
include_dirs: ["frameworks/native/services/gpuservice/"],
srcs: ["GpuServiceFuzzer.cpp"],
- shared_libs: [
- "libgpuservice",
- ],
}
diff --git a/services/gpuservice/tests/unittests/Android.bp b/services/gpuservice/tests/unittests/Android.bp
index c870b17..8056a2c 100644
--- a/services/gpuservice/tests/unittests/Android.bp
+++ b/services/gpuservice/tests/unittests/Android.bp
@@ -24,6 +24,9 @@
cc_test {
name: "gpuservice_unittest",
test_suites: ["device-tests"],
+ defaults: [
+ "libgpuservice_defaults",
+ ],
srcs: [
"GpuMemTest.cpp",
"GpuMemTracerTest.cpp",
@@ -36,9 +39,6 @@
"libbinder",
"libbpf_bcc",
"libcutils",
- "libgfxstats",
- "libgpumem",
- "libgpumemtracer",
"libgraphicsenv",
"liblog",
"libprotobuf-cpp-lite",
@@ -46,10 +46,10 @@
"libstatslog",
"libstatspull",
"libutils",
- "libgpuservice",
],
static_libs: [
"libgmock",
+ "libgpuservice",
"libperfetto_client_experimental",
"perfetto_trace_protos",
],
diff --git a/services/gpuservice/tracing/Android.bp b/services/gpuservice/tracing/Android.bp
index a1bc1ed..d636b7d 100644
--- a/services/gpuservice/tracing/Android.bp
+++ b/services/gpuservice/tracing/Android.bp
@@ -21,20 +21,28 @@
default_applicable_licenses: ["frameworks_native_license"],
}
-cc_library_shared {
- name: "libgpumemtracer",
- srcs: [
- "GpuMemTracer.cpp",
- ],
+cc_defaults {
+ name: "libgpumemtracer_deps",
shared_libs: [
- "libgpumem",
"libbase",
"liblog",
"libutils",
],
static_libs: [
+ "libgpumem",
"libperfetto_client_experimental",
],
+}
+
+cc_library_static {
+ name: "libgpumemtracer",
+ defaults: [
+ "libgpumemtracer_deps",
+ "libgpumem_deps",
+ ],
+ srcs: [
+ "GpuMemTracer.cpp",
+ ],
export_include_dirs: ["include"],
export_static_lib_headers: [
"libperfetto_client_experimental",
diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
index cb369a8..fa8f548 100644
--- a/services/inputflinger/dispatcher/Entry.cpp
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -269,6 +269,11 @@
return msg;
}
+std::ostream& operator<<(std::ostream& out, const MotionEntry& motionEntry) {
+ out << motionEntry.getDescription();
+ return out;
+}
+
// --- SensorEntry ---
SensorEntry::SensorEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source,
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index 8dc2a2a..dd4aab8 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -24,6 +24,7 @@
#include <stdint.h>
#include <utils/Timers.h>
#include <functional>
+#include <ostream>
#include <string>
namespace android::inputdispatcher {
@@ -189,6 +190,8 @@
~MotionEntry() override;
};
+std::ostream& operator<<(std::ostream& out, const MotionEntry& motionEntry);
+
struct SensorEntry : EventEntry {
int32_t deviceId;
uint32_t source;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index d98641e..0a1e889 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -668,7 +668,15 @@
} else {
// This pointer was already sent to the window. Use ACTION_HOVER_MOVE.
if (CC_UNLIKELY(maskedAction != AMOTION_EVENT_ACTION_HOVER_MOVE)) {
- LOG(FATAL) << "Expected ACTION_HOVER_MOVE instead of " << entry.getDescription();
+ android::base::LogSeverity severity = android::base::LogSeverity::FATAL;
+ if (entry.flags & AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT) {
+ // The Accessibility injected touch exploration event stream
+ // has known inconsistencies, so log ERROR instead of
+ // crashing the device with FATAL.
+ // TODO(b/299977100): Move a11y severity back to FATAL.
+ severity = android::base::LogSeverity::ERROR;
+ }
+ LOG(severity) << "Expected ACTION_HOVER_MOVE instead of " << entry.getDescription();
}
touchedWindow.targetFlags = InputTarget::Flags::DISPATCH_AS_IS;
}
diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp
index 4221e42..9dcf615 100644
--- a/services/inputflinger/dispatcher/TouchState.cpp
+++ b/services/inputflinger/dispatcher/TouchState.cpp
@@ -288,4 +288,9 @@
return out;
}
+std::ostream& operator<<(std::ostream& out, const TouchState& state) {
+ out << state.dump();
+ return out;
+}
+
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h
index 39e63e5..f016936 100644
--- a/services/inputflinger/dispatcher/TouchState.h
+++ b/services/inputflinger/dispatcher/TouchState.h
@@ -17,6 +17,7 @@
#pragma once
#include <bitset>
+#include <ostream>
#include <set>
#include "TouchedWindow.h"
@@ -79,5 +80,7 @@
std::string dump() const;
};
+std::ostream& operator<<(std::ostream& out, const TouchState& state);
+
} // namespace inputdispatcher
} // namespace android
diff --git a/services/inputflinger/dispatcher/TouchedWindow.cpp b/services/inputflinger/dispatcher/TouchedWindow.cpp
index 9807a6d..ff4b425 100644
--- a/services/inputflinger/dispatcher/TouchedWindow.cpp
+++ b/services/inputflinger/dispatcher/TouchedWindow.cpp
@@ -256,5 +256,10 @@
return out;
}
+std::ostream& operator<<(std::ostream& out, const TouchedWindow& window) {
+ out << window.dump();
+ return out;
+}
+
} // namespace inputdispatcher
} // namespace android
diff --git a/services/inputflinger/dispatcher/TouchedWindow.h b/services/inputflinger/dispatcher/TouchedWindow.h
index 0a38f9f..3f760c0 100644
--- a/services/inputflinger/dispatcher/TouchedWindow.h
+++ b/services/inputflinger/dispatcher/TouchedWindow.h
@@ -20,6 +20,7 @@
#include <input/Input.h>
#include <utils/BitSet.h>
#include <bitset>
+#include <ostream>
#include <set>
#include "InputTarget.h"
@@ -92,5 +93,7 @@
static std::string deviceStateToString(const TouchedWindow::DeviceState& state);
};
+std::ostream& operator<<(std::ostream& out, const TouchedWindow& window);
+
} // namespace inputdispatcher
} // namespace android
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index b565454..90bd7c9 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -130,7 +130,10 @@
TouchInputMapper::~TouchInputMapper() {}
uint32_t TouchInputMapper::getSources() const {
- return mSource;
+ // The SOURCE_BLUETOOTH_STYLUS is added to events dynamically if the current stream is modified
+ // by the external stylus state. That's why we don't add it directly to mSource during
+ // configuration.
+ return mSource | (hasExternalStylus() ? AINPUT_SOURCE_BLUETOOTH_STYLUS : 0);
}
void TouchInputMapper::populateDeviceInfo(InputDeviceInfo& info) {
@@ -932,9 +935,6 @@
if (hasStylus()) {
mSource |= AINPUT_SOURCE_STYLUS;
}
- if (hasExternalStylus()) {
- mSource |= AINPUT_SOURCE_BLUETOOTH_STYLUS;
- }
} else if (mParameters.deviceType == Parameters::DeviceType::TOUCH_NAVIGATION) {
mSource = AINPUT_SOURCE_TOUCH_NAVIGATION;
mDeviceMode = DeviceMode::NAVIGATION;
@@ -1664,6 +1664,10 @@
mSource, mViewport.displayId, policyFlags,
mLastCookedState.buttonState, mCurrentCookedState.buttonState);
+ if (mCurrentCookedState.cookedPointerData.pointerCount == 0) {
+ mCurrentStreamModifiedByExternalStylus = false;
+ }
+
// Clear some transient state.
mCurrentRawState.rawVScroll = 0;
mCurrentRawState.rawHScroll = 0;
@@ -1715,6 +1719,10 @@
mExternalStylusButtonsApplied |= pressedButtons;
mExternalStylusButtonsApplied &= ~releasedButtons;
+
+ if (mExternalStylusButtonsApplied != 0 || releasedButtons != 0) {
+ mCurrentStreamModifiedByExternalStylus = true;
+ }
}
}
@@ -1725,6 +1733,8 @@
return;
}
+ mCurrentStreamModifiedByExternalStylus = true;
+
float pressure = lastPointerData.isTouching(*mFusedStylusPointerId)
? lastPointerData.pointerCoordsForId(*mFusedStylusPointerId)
.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)
@@ -3821,6 +3831,9 @@
ALOG_ASSERT(false);
}
}
+ if (mCurrentStreamModifiedByExternalStylus) {
+ source |= AINPUT_SOURCE_BLUETOOTH_STYLUS;
+ }
const int32_t displayId = getAssociatedDisplayId().value_or(ADISPLAY_ID_NONE);
const bool showDirectStylusPointer = mConfig.stylusPointerIconEnabled &&
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index c5dfb00..bd9371d 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -357,6 +357,8 @@
bool mExternalStylusDataPending;
// A subset of the buttons in mCurrentRawState that came from an external stylus.
int32_t mExternalStylusButtonsApplied{0};
+ // True if the current cooked pointer data was modified due to the state of an external stylus.
+ bool mCurrentStreamModifiedByExternalStylus{false};
// True if we sent a HOVER_ENTER event.
bool mSentHoverEnter{false};
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index dc281a3..dd003a6 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -3349,6 +3349,31 @@
}
/**
+ * Test that invalid HOVER events sent by accessibility do not cause a fatal crash.
+ */
+TEST_F(InputDispatcherTest, InvalidA11yHoverStreamDoesNotCrash) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
+ window->setFrame(Rect(0, 0, 1200, 800));
+
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
+
+ mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
+
+ MotionEventBuilder hoverEnterBuilder =
+ MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
+ .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400))
+ .addFlag(AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(*mDispatcher, hoverEnterBuilder.build()));
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(*mDispatcher, hoverEnterBuilder.build()));
+ window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
+ window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
+}
+
+/**
* If mouse is hovering when the touch goes down, the hovering should be stopped via HOVER_EXIT.
*/
TEST_F(InputDispatcherTest, TouchDownAfterMouseHover) {
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index bce0937..6539593 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -91,6 +91,9 @@
static constexpr int32_t ACTION_POINTER_1_UP =
AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+static constexpr uint32_t STYLUS_FUSION_SOURCE =
+ AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_BLUETOOTH_STYLUS;
+
// Minimum timestamp separation between subsequent input events from a Bluetooth device.
static constexpr nsecs_t MIN_BLUETOOTH_TIMESTAMP_DELTA = ms2ns(4);
// Maximum smoothing time delta so that we don't generate events too far into the future.
@@ -2308,6 +2311,22 @@
// ongoing stylus gesture that is being emitted by the touchscreen.
using ExternalStylusIntegrationTest = BaseTouchIntegrationTest;
+TEST_F(ExternalStylusIntegrationTest, ExternalStylusConnectionChangesTouchscreenSource) {
+ // Create an external stylus capable of reporting pressure data that
+ // should be fused with a touch pointer.
+ std::unique_ptr<UinputExternalStylusWithPressure> stylus =
+ createUinputDevice<UinputExternalStylusWithPressure>();
+ ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged());
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyConfigurationChangedWasCalled());
+ const auto stylusInfo = findDeviceByName(stylus->getName());
+ ASSERT_TRUE(stylusInfo);
+
+ // Connecting an external stylus changes the source of the touchscreen.
+ const auto deviceInfo = findDeviceByName(mDevice->getName());
+ ASSERT_TRUE(deviceInfo);
+ ASSERT_TRUE(isFromSource(deviceInfo->getSources(), STYLUS_FUSION_SOURCE));
+}
+
TEST_F(ExternalStylusIntegrationTest, FusedExternalStylusPressureReported) {
const Point centerPoint = mDevice->getCenterPoint();
@@ -2337,17 +2356,17 @@
mDevice->sendDown(centerPoint);
mDevice->sendSync();
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
- WithToolType(ToolType::STYLUS), WithButtonState(0),
- WithDeviceId(touchscreenId), WithPressure(100.f / RAW_PRESSURE_MAX))));
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithToolType(ToolType::STYLUS),
+ WithButtonState(0), WithSource(STYLUS_FUSION_SOURCE), WithDeviceId(touchscreenId),
+ WithPressure(100.f / RAW_PRESSURE_MAX))));
// Change the pressure on the external stylus, and ensure the touchscreen generates a MOVE
// event with the updated pressure.
stylus->setPressure(200);
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
- WithToolType(ToolType::STYLUS), WithButtonState(0),
- WithDeviceId(touchscreenId), WithPressure(200.f / RAW_PRESSURE_MAX))));
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithToolType(ToolType::STYLUS),
+ WithButtonState(0), WithSource(STYLUS_FUSION_SOURCE), WithDeviceId(touchscreenId),
+ WithPressure(200.f / RAW_PRESSURE_MAX))));
// The external stylus did not generate any events.
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasNotCalled());
@@ -2392,8 +2411,8 @@
// it shows up as a finger pointer.
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
- WithToolType(ToolType::FINGER), WithDeviceId(touchscreenId),
- WithPressure(1.f))));
+ WithSource(AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS),
+ WithToolType(ToolType::FINGER), WithDeviceId(touchscreenId), WithPressure(1.f))));
// Change the pressure on the external stylus. Since the pressure was not present at the start
// of the gesture, it is ignored for now.
@@ -2405,6 +2424,7 @@
mDevice->sendSync();
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
+ WithSource(AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS),
WithToolType(ToolType::FINGER))));
// Start a new gesture. Since we have a valid pressure value, it shows up as a stylus.
@@ -2413,9 +2433,9 @@
mDevice->sendDown(centerPoint);
mDevice->sendSync();
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
- WithToolType(ToolType::STYLUS), WithButtonState(0),
- WithDeviceId(touchscreenId), WithPressure(200.f / RAW_PRESSURE_MAX))));
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithSource(STYLUS_FUSION_SOURCE),
+ WithToolType(ToolType::STYLUS), WithButtonState(0), WithDeviceId(touchscreenId),
+ WithPressure(200.f / RAW_PRESSURE_MAX))));
// The external stylus did not generate any events.
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasNotCalled());
@@ -2447,14 +2467,15 @@
std::chrono::milliseconds(ns2ms(EXTERNAL_STYLUS_DATA_TIMEOUT));
mDevice->sendSync();
ASSERT_NO_FATAL_FAILURE(
- mTestListener
- ->assertNotifyMotionWasCalled(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
- WithToolType(
- ToolType::FINGER),
- WithButtonState(0),
- WithDeviceId(touchscreenId),
- WithPressure(1.f)),
- waitUntil));
+ mTestListener->assertNotifyMotionWasCalled(AllOf(WithMotionAction(
+ AMOTION_EVENT_ACTION_DOWN),
+ WithToolType(ToolType::FINGER),
+ WithSource(AINPUT_SOURCE_TOUCHSCREEN |
+ AINPUT_SOURCE_STYLUS),
+ WithButtonState(0),
+ WithDeviceId(touchscreenId),
+ WithPressure(1.f)),
+ waitUntil));
// The external stylus did not generate any events.
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasNotCalled());
@@ -7567,12 +7588,10 @@
protected:
StylusState mStylusState{};
- static constexpr uint32_t EXPECTED_SOURCE =
- AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_BLUETOOTH_STYLUS;
void testStartFusedStylusGesture(SingleTouchInputMapper& mapper) {
auto toolTypeSource =
- AllOf(WithSource(EXPECTED_SOURCE), WithToolType(ToolType::STYLUS));
+ AllOf(WithSource(STYLUS_FUSION_SOURCE), WithToolType(ToolType::STYLUS));
// The first pointer is withheld.
processDown(mapper, 100, 200);
@@ -7606,7 +7625,7 @@
processUp(mapper);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithSource(EXPECTED_SOURCE),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithSource(STYLUS_FUSION_SOURCE),
WithToolType(ToolType::STYLUS))));
mStylusState.pressure = 0.f;
@@ -7616,8 +7635,10 @@
}
void testUnsuccessfulFusionGesture(SingleTouchInputMapper& mapper) {
+ // When stylus fusion is not successful, events should be reported with the original source.
+ // In this case, it is from a touchscreen.
auto toolTypeSource =
- AllOf(WithSource(EXPECTED_SOURCE), WithToolType(ToolType::FINGER));
+ AllOf(WithSource(AINPUT_SOURCE_TOUCHSCREEN), WithToolType(ToolType::FINGER));
// The first pointer is withheld when an external stylus is connected,
// and a timeout is requested.
@@ -7657,7 +7678,7 @@
TEST_F(ExternalStylusFusionTest, UsesBluetoothStylusSource) {
SingleTouchInputMapper& mapper = initializeInputMapperWithExternalStylus();
- ASSERT_EQ(EXPECTED_SOURCE, mapper.getSources());
+ ASSERT_EQ(STYLUS_FUSION_SOURCE, mapper.getSources());
}
TEST_F(ExternalStylusFusionTest, UnsuccessfulFusion) {
@@ -7674,8 +7695,7 @@
// before the touch is reported by the touchscreen.
TEST_F(ExternalStylusFusionTest, SuccessfulFusion_PressureFirst) {
SingleTouchInputMapper& mapper = initializeInputMapperWithExternalStylus();
- auto toolTypeSource =
- AllOf(WithSource(EXPECTED_SOURCE), WithToolType(ToolType::STYLUS));
+ auto toolTypeSource = AllOf(WithSource(STYLUS_FUSION_SOURCE), WithToolType(ToolType::STYLUS));
// The external stylus reports pressure first. It is ignored for now.
mStylusState.pressure = 1.f;
@@ -7717,8 +7737,7 @@
TEST_F(ExternalStylusFusionTest, FusedPointerReportsPressureChanges) {
SingleTouchInputMapper& mapper = initializeInputMapperWithExternalStylus();
- auto toolTypeSource =
- AllOf(WithSource(EXPECTED_SOURCE), WithToolType(ToolType::STYLUS));
+ auto toolTypeSource = AllOf(WithSource(STYLUS_FUSION_SOURCE), WithToolType(ToolType::STYLUS));
mStylusState.pressure = 0.8f;
processExternalStylusState(mapper);
@@ -7779,7 +7798,7 @@
processUp(mapper);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithSource(EXPECTED_SOURCE),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithSource(STYLUS_FUSION_SOURCE),
WithToolType(ToolType::STYLUS))));
ASSERT_NO_FATAL_FAILURE(mReader->getContext()->assertTimeoutWasNotRequested());
@@ -7788,7 +7807,7 @@
TEST_F(ExternalStylusFusionTest, FusedPointerReportsToolTypeChanges) {
SingleTouchInputMapper& mapper = initializeInputMapperWithExternalStylus();
- auto source = WithSource(EXPECTED_SOURCE);
+ auto source = WithSource(STYLUS_FUSION_SOURCE);
mStylusState.pressure = 1.f;
mStylusState.toolType = ToolType::ERASER;
@@ -7841,8 +7860,7 @@
TEST_F(ExternalStylusFusionTest, FusedPointerReportsButtons) {
SingleTouchInputMapper& mapper = initializeInputMapperWithExternalStylus();
- auto toolTypeSource =
- AllOf(WithSource(EXPECTED_SOURCE), WithToolType(ToolType::STYLUS));
+ auto toolTypeSource = AllOf(WithSource(STYLUS_FUSION_SOURCE), WithToolType(ToolType::STYLUS));
ASSERT_NO_FATAL_FAILURE(testStartFusedStylusGesture(mapper));
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 22db247..fe56969 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -844,10 +844,16 @@
bool OutputLayer::needsFiltering() const {
const auto& state = getState();
- const auto& displayFrame = state.displayFrame;
const auto& sourceCrop = state.sourceCrop;
- return sourceCrop.getHeight() != displayFrame.getHeight() ||
- sourceCrop.getWidth() != displayFrame.getWidth();
+ auto displayFrameWidth = static_cast<float>(state.displayFrame.getWidth());
+ auto displayFrameHeight = static_cast<float>(state.displayFrame.getHeight());
+
+ if (state.bufferTransform & HAL_TRANSFORM_ROT_90) {
+ std::swap(displayFrameWidth, displayFrameHeight);
+ }
+
+ return sourceCrop.getHeight() != displayFrameHeight ||
+ sourceCrop.getWidth() != displayFrameWidth;
}
std::optional<LayerFE::LayerSettings> OutputLayer::getOverrideCompositionSettings() const {
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 9039d16..630906a 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -1614,5 +1614,20 @@
EXPECT_TRUE(mOutputLayer.needsFiltering());
}
+TEST_F(OutputLayerTest, needsFilteringReturnsFalseIfRotatedDisplaySizeSameAsSourceSize) {
+ mOutputLayer.editState().displayFrame = Rect(100, 100, 300, 200);
+ mOutputLayer.editState().sourceCrop = FloatRect{0.f, 0.f, 100.f, 200.f};
+ mOutputLayer.editState().bufferTransform = Hwc2::Transform::ROT_90;
+
+ EXPECT_FALSE(mOutputLayer.needsFiltering());
+}
+
+TEST_F(OutputLayerTest, needsFilteringReturnsTrueIfRotatedDisplaySizeDiffersFromSourceSize) {
+ mOutputLayer.editState().displayFrame = Rect(100, 100, 300, 200);
+ mOutputLayer.editState().sourceCrop = FloatRect{0.f, 0.f, 100.f, 200.f};
+
+ EXPECT_TRUE(mOutputLayer.needsFiltering());
+}
+
} // namespace
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
index acec630..fcc1e61 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
@@ -468,12 +468,18 @@
Rect RequestedLayerState::getBufferCrop() const {
// this is the crop rectangle that applies to the buffer
// itself (as opposed to the window)
- if (!bufferCrop.isEmpty()) {
- // if the buffer crop is defined, we use that
- return bufferCrop;
+ if (!bufferCrop.isEmpty() && externalTexture != nullptr) {
+ // if the buffer crop is defined and there's a valid buffer, intersect buffer size and crop
+ // since the crop should never exceed the size of the buffer.
+ Rect sizeAndCrop;
+ externalTexture->getBounds().intersect(bufferCrop, &sizeAndCrop);
+ return sizeAndCrop;
} else if (externalTexture != nullptr) {
// otherwise we use the whole buffer
return externalTexture->getBounds();
+ } else if (!bufferCrop.isEmpty()) {
+ // if the buffer crop is defined, we use that
+ return bufferCrop;
} else {
// if we don't have a buffer yet, we use an empty/invalid crop
return Rect();
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 10768a9..fadde51 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -5828,6 +5828,20 @@
StringAppendF(&result, "Permission Denial: can't dump SurfaceFlinger from pid=%d, uid=%d\n",
pid, uid);
} else {
+ Dumper hwclayersDump = [this](const DumpArgs&, bool, std::string& result)
+ FTL_FAKE_GUARD(mStateLock) -> void const {
+ if (mLayerLifecycleManagerEnabled) {
+ mScheduler
+ ->schedule([this, &result]() FTL_FAKE_GUARD(kMainThreadContext)
+ FTL_FAKE_GUARD(mStateLock) {
+ dumpHwcLayersMinidump(result);
+ })
+ .get();
+ } else {
+ dumpHwcLayersMinidumpLockedLegacy(result);
+ }
+ };
+
static const std::unordered_map<std::string, Dumper> dumpers = {
{"--comp-displays"s, dumper(&SurfaceFlinger::dumpCompositionDisplays)},
{"--display-id"s, dumper(&SurfaceFlinger::dumpDisplayIdentificationData)},
@@ -5836,7 +5850,7 @@
{"--events"s, dumper(&SurfaceFlinger::dumpEvents)},
{"--frametimeline"s, argsDumper(&SurfaceFlinger::dumpFrameTimeline)},
{"--hdrinfo"s, dumper(&SurfaceFlinger::dumpHdrInfo)},
- {"--hwclayers"s, dumper(&SurfaceFlinger::dumpHwcLayersMinidumpLockedLegacy)},
+ {"--hwclayers"s, std::move(hwclayersDump)},
{"--latency"s, argsDumper(&SurfaceFlinger::dumpStatsLocked)},
{"--latency-clear"s, argsDumper(&SurfaceFlinger::clearStatsLocked)},
{"--list"s, dumper(&SurfaceFlinger::listLayersLocked)},
@@ -7822,10 +7836,12 @@
displayBrightnessNits = std::min(sdrWhitePointNits * kMaxScreenshotHeadroom,
displayBrightnessNits);
}
+ }
- if (requestedDataspace == ui::Dataspace::UNKNOWN) {
- renderIntent = state.renderIntent;
- }
+ // Screenshots leaving the device should be colorimetric
+ if (requestedDataspace == ui::Dataspace::UNKNOWN &&
+ renderArea->getHintForSeamlessTransition()) {
+ renderIntent = state.renderIntent;
}
}
}
@@ -7868,6 +7884,10 @@
}
}
+ // Screenshots leaving the device must not dim in gamma space.
+ const bool dimInGammaSpaceForEnhancedScreenshots = mDimInGammaSpaceForEnhancedScreenshots &&
+ renderArea->getHintForSeamlessTransition();
+
std::shared_ptr<ScreenCaptureOutput> output = createScreenCaptureOutput(
ScreenCaptureOutputArgs{.compositionEngine = *compositionEngine,
.colorProfile = colorProfile,
@@ -7880,7 +7900,7 @@
.regionSampling = regionSampling,
.treat170mAsSrgb = mTreat170mAsSrgb,
.dimInGammaSpaceForEnhancedScreenshots =
- mDimInGammaSpaceForEnhancedScreenshots});
+ dimInGammaSpaceForEnhancedScreenshots});
const float colorSaturation = grayscale ? 0 : 1;
compositionengine::CompositionRefreshArgs refreshArgs{
diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
index 32821b7..d7ac038 100644
--- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
+++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
@@ -384,6 +384,17 @@
mLifecycleManager.applyTransactions(transactions);
}
+ void setBufferCrop(uint32_t id, const Rect& bufferCrop) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what = layer_state_t::eBufferCropChanged;
+ transactions.back().states.front().layerId = id;
+ transactions.back().states.front().state.bufferCrop = bufferCrop;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
void setDataspace(uint32_t id, ui::Dataspace dataspace) {
std::vector<TransactionState> transactions;
transactions.emplace_back();
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index 662f4bd..1a9233d 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -846,4 +846,33 @@
aidl::android::hardware::graphics::composer3::Composition::REFRESH_RATE_INDICATOR);
}
+TEST_F(LayerSnapshotTest, setBufferCrop) {
+ // validate no buffer but has crop
+ Rect crop = Rect(0, 0, 50, 50);
+ setBufferCrop(1, crop);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot(1)->geomContentCrop, crop);
+
+ setBuffer(1,
+ std::make_shared<renderengine::mock::FakeExternalTexture>(100U /*width*/,
+ 100U /*height*/,
+ 42ULL /* bufferId */,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ 0 /*usage*/));
+ // validate a buffer crop within the buffer bounds
+ setBufferCrop(1, crop);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot(1)->geomContentCrop, crop);
+
+ // validate a buffer crop outside the buffer bounds
+ crop = Rect(0, 0, 150, 150);
+ setBufferCrop(1, crop);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot(1)->geomContentCrop, Rect(0, 0, 100, 100));
+
+ // validate no buffer crop
+ setBufferCrop(1, Rect());
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot(1)->geomContentCrop, Rect(0, 0, 100, 100));
+}
} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
index 608fa76..9899d42 100644
--- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
@@ -19,6 +19,7 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <gui/FrameRateUtils.h>
#include <gui/LayerMetadata.h>
// TODO(b/129481165): remove the #pragma below and fix conversion issues
@@ -325,48 +326,6 @@
std::make_shared<EffectLayerFactory>()),
PrintToStringParamName);
-TEST_F(SetFrameRateTest, ValidateFrameRate) {
- EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
- ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
- EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
- ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
- EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
- ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS, ""));
- EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
- ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
-
- // Privileged APIs.
- EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT,
- ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
- EXPECT_FALSE(ValidateFrameRate(0.0f, ANATIVEWINDOW_FRAME_RATE_NO_VOTE,
- ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
-
- constexpr bool kPrivileged = true;
- EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT,
- ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "",
- kPrivileged));
- EXPECT_TRUE(ValidateFrameRate(0.0f, ANATIVEWINDOW_FRAME_RATE_NO_VOTE,
- ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "",
- kPrivileged));
-
- // Invalid frame rate.
- EXPECT_FALSE(ValidateFrameRate(-1, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
- ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
- EXPECT_FALSE(ValidateFrameRate(1.0f / 0.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
- ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
- EXPECT_FALSE(ValidateFrameRate(0.0f / 0.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
- ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
-
- // Invalid compatibility.
- EXPECT_FALSE(
- ValidateFrameRate(60.0f, -1, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
- EXPECT_FALSE(ValidateFrameRate(60.0f, 2, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
-
- // Invalid change frame rate strategy.
- EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, -1, ""));
- EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, 2, ""));
-}
-
TEST_P(SetFrameRateTest, SetOnParentActivatesTree) {
const auto& layerFactory = GetParam();
diff --git a/services/surfaceflinger/tests/utils/WindowInfosListenerUtils.h b/services/surfaceflinger/tests/utils/WindowInfosListenerUtils.h
index 8e28a75..11723c7 100644
--- a/services/surfaceflinger/tests/utils/WindowInfosListenerUtils.h
+++ b/services/surfaceflinger/tests/utils/WindowInfosListenerUtils.h
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <android-base/properties.h>
#include <gtest/gtest.h>
#include <gui/SurfaceComposerClient.h>
#include <private/android_filesystem_config.h>
@@ -21,7 +22,8 @@
#include <future>
namespace android {
-using Transaction = SurfaceComposerClient::Transaction;
+
+using base::HwTimeoutMultiplier;
using gui::DisplayInfo;
using gui::WindowInfo;
@@ -36,7 +38,8 @@
auto listener = sp<WindowInfosListener>::make(std::move(predicate), promise);
mClient->addWindowInfosListener(listener);
auto future = promise.get_future();
- bool satisfied = future.wait_for(std::chrono::seconds{1}) == std::future_status::ready;
+ bool satisfied = future.wait_for(std::chrono::seconds{5 * HwTimeoutMultiplier()}) ==
+ std::future_status::ready;
mClient->removeWindowInfosListener(listener);
return satisfied;
}
diff --git a/vulkan/vkjson/Android.bp b/vulkan/vkjson/Android.bp
index b544245..de4271d 100644
--- a/vulkan/vkjson/Android.bp
+++ b/vulkan/vkjson/Android.bp
@@ -7,8 +7,19 @@
default_applicable_licenses: ["frameworks_native_license"],
}
-cc_library_shared {
+cc_defaults {
+ name: "libvkjson_deps",
+ shared_libs: [
+ "libjsoncpp",
+ "libvulkan",
+ ],
+}
+
+cc_library_static {
name: "libvkjson",
+ defaults: [
+ "libvkjson_deps",
+ ],
srcs: [
"vkjson.cc",
"vkjson_instance.cc",
@@ -24,10 +35,6 @@
export_include_dirs: [
".",
],
- shared_libs: [
- "libjsoncpp",
- "libvulkan",
- ],
export_shared_lib_headers: [
"libvulkan",
],