Merge "Include cache files from sdk data when cleaning using freeCache" into tm-dev
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 684aa4f..a49f563 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -3002,13 +3002,15 @@
// Dumps the contents of a profile file, using pkgname's dex files for pretty
// printing the result.
binder::Status InstalldNativeService::dumpProfiles(int32_t uid, const std::string& packageName,
- const std::string& profileName, const std::string& codePath, bool* _aidl_return) {
+ const std::string& profileName,
+ const std::string& codePath,
+ bool dumpClassesAndMethods, bool* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
CHECK_ARGUMENT_PATH(codePath);
LOCK_PACKAGE();
- *_aidl_return = dump_profiles(uid, packageName, profileName, codePath);
+ *_aidl_return = dump_profiles(uid, packageName, profileName, codePath, dumpClassesAndMethods);
return ok();
}
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 0432222..521afc3 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -134,7 +134,8 @@
binder::Status mergeProfiles(int32_t uid, const std::string& packageName,
const std::string& profileName, int* _aidl_return);
binder::Status dumpProfiles(int32_t uid, const std::string& packageName,
- const std::string& profileName, const std::string& codePath, bool* _aidl_return);
+ const std::string& profileName, const std::string& codePath,
+ bool dumpClassesAndMethods, bool* _aidl_return);
binder::Status copySystemProfile(const std::string& systemProfile,
int32_t uid, const std::string& packageName, const std::string& profileName,
bool* _aidl_return);
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index db03411..9ad853b 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -77,7 +77,7 @@
int mergeProfiles(int uid, @utf8InCpp String packageName, @utf8InCpp String profileName);
boolean dumpProfiles(int uid, @utf8InCpp String packageName, @utf8InCpp String profileName,
- @utf8InCpp String codePath);
+ @utf8InCpp String codePath, boolean dumpClassesAndMethods);
boolean copySystemProfile(@utf8InCpp String systemProfile, int uid,
@utf8InCpp String packageName, @utf8InCpp String profileName);
void clearAppProfiles(@utf8InCpp String packageName, @utf8InCpp String profileName);
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 894c7d3..ebb7891 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -624,12 +624,15 @@
/*for_boot_image*/false);
}
- void SetupDump(const std::vector<unique_fd>& profiles_fd,
- const unique_fd& reference_profile_fd,
+ void SetupDump(const std::vector<unique_fd>& profiles_fd, const unique_fd& reference_profile_fd,
const std::vector<std::string>& dex_locations,
- const std::vector<unique_fd>& apk_fds,
+ const std::vector<unique_fd>& apk_fds, bool dump_classes_and_methods,
const unique_fd& output_fd) {
- AddArg("--dump-only");
+ if (dump_classes_and_methods) {
+ AddArg("--dump-classes-and-methods");
+ } else {
+ AddArg("--dump-only");
+ }
AddArg(StringPrintf("--dump-output-to-fd=%d", output_fd.get()));
SetupArgs(profiles_fd,
reference_profile_fd,
@@ -772,7 +775,7 @@
}
bool dump_profiles(int32_t uid, const std::string& pkgname, const std::string& profile_name,
- const std::string& code_path) {
+ const std::string& code_path, bool dump_classes_and_methods) {
std::vector<unique_fd> profile_fds;
unique_fd reference_profile_fd;
std::string out_file_name = StringPrintf("/data/misc/profman/%s-%s.txt",
@@ -808,7 +811,8 @@
RunProfman profman_dump;
- profman_dump.SetupDump(profile_fds, reference_profile_fd, dex_locations, apk_fds, output_fd);
+ profman_dump.SetupDump(profile_fds, reference_profile_fd, dex_locations, apk_fds,
+ dump_classes_and_methods, output_fd);
pid_t pid = fork();
if (pid == 0) {
/* child -- drop privileges before continuing */
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index f7af929..5cf402c 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -88,10 +88,8 @@
const std::string& profile_name,
const std::string& classpath);
-bool dump_profiles(int32_t uid,
- const std::string& pkgname,
- const std::string& profile_name,
- const std::string& code_path);
+bool dump_profiles(int32_t uid, const std::string& pkgname, const std::string& profile_name,
+ const std::string& code_path, bool dump_classes_and_methods);
bool copy_system_profile(const std::string& system_profile,
uid_t packageUid,
diff --git a/include/android/input.h b/include/android/input.h
index fb5e204..38b27bc 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -810,7 +810,7 @@
/**
* Constants that identify different gesture classification types.
*/
-enum {
+enum AMotionClassification : uint32_t {
/**
* Classification constant: None.
*
@@ -820,7 +820,8 @@
/**
* Classification constant: Ambiguous gesture.
*
- * The user's intent with respect to the current event stream is not yet determined.
+ * The user's intent with respect to the current event stream is not yet determined. Events
+ * starting in AMBIGUOUS_GESTURE will eventually resolve into either DEEP_PRESS or NONE.
* Gestural actions, such as scrolling, should be inhibited until the classification resolves
* to another value or the event stream ends.
*/
@@ -1357,8 +1358,17 @@
* Get the action button for the motion event. Returns a valid action button when the
* event is associated with a button press or button release action. For other actions
* the return value is undefined.
+ *
+ * @see #AMOTION_EVENT_BUTTON_PRIMARY
+ * @see #AMOTION_EVENT_BUTTON_SECONDARY
+ * @see #AMOTION_EVENT_BUTTON_TERTIARY
+ * @see #AMOTION_EVENT_BUTTON_BACK
+ * @see #AMOTION_EVENT_BUTTON_FORWARD
+ * @see #AMOTION_EVENT_BUTTON_STYLUS_PRIMARY
+ * @see #AMOTION_EVENT_BUTTON_STYLUS_SECONDARY
*/
-int32_t AMotionEvent_getActionButton(const AInputEvent* motion_event);
+int32_t AMotionEvent_getActionButton(const AInputEvent* motion_event)
+ __INTRODUCED_IN(__ANDROID_API_T__);
/**
* Returns the classification for the current gesture.
@@ -1368,7 +1378,8 @@
* @see #AMOTION_EVENT_CLASSIFICATION_AMBIGUOUS_GESTURE
* @see #AMOTION_EVENT_CLASSIFICATION_DEEP_PRESS
*/
-int32_t AMotionEvent_getClassification(const AInputEvent* motion_event);
+int32_t AMotionEvent_getClassification(const AInputEvent* motion_event)
+ __INTRODUCED_IN(__ANDROID_API_T__);
/**
* Creates a native AInputEvent* object that is a copy of the specified Java
diff --git a/libs/battery/MultiStateCounter.h b/libs/battery/MultiStateCounter.h
index 0caf005..ce9cd1c 100644
--- a/libs/battery/MultiStateCounter.h
+++ b/libs/battery/MultiStateCounter.h
@@ -139,22 +139,35 @@
return;
}
- if (!enabled) {
+ if (isEnabled) {
// Confirm the current state for the side-effect of updating the time-in-state
// counter for the current state.
setState(currentState, timestamp);
- }
+ isEnabled = false;
+ } else {
+ // If the counter is being enabled with an out-of-order timestamp, just push back
+ // the timestamp to avoid having the situation where
+ // timeInStateSinceUpdate > timeSinceUpdate
+ if (timestamp < lastUpdateTimestamp) {
+ timestamp = lastUpdateTimestamp;
+ }
- isEnabled = enabled;
-
- if (lastStateChangeTimestamp >= 0) {
- lastStateChangeTimestamp = timestamp;
+ if (lastStateChangeTimestamp >= 0) {
+ lastStateChangeTimestamp = timestamp;
+ }
+ isEnabled = true;
}
}
template <class T>
void MultiStateCounter<T>::setState(state_t state, time_t timestamp) {
- if (isEnabled && lastStateChangeTimestamp >= 0) {
+ if (isEnabled && lastStateChangeTimestamp >= 0 && lastUpdateTimestamp >= 0) {
+ // If the update arrived out-of-order, just push back the timestamp to
+ // avoid having the situation where timeInStateSinceUpdate > timeSinceUpdate
+ if (timestamp < lastUpdateTimestamp) {
+ timestamp = lastUpdateTimestamp;
+ }
+
if (timestamp >= lastStateChangeTimestamp) {
states[currentState].timeInStateSinceUpdate += timestamp - lastStateChangeTimestamp;
} else {
@@ -185,6 +198,12 @@
// If the counter is disabled, we ignore the update, except when the counter got disabled after
// the previous update, in which case we still need to pick up the residual delta.
if (isEnabled || lastUpdateTimestamp < lastStateChangeTimestamp) {
+ // If the update arrived out of order, just push back the timestamp to
+ // avoid having the situation where timeInStateSinceUpdate > timeSinceUpdate
+ if (timestamp < lastStateChangeTimestamp) {
+ timestamp = lastStateChangeTimestamp;
+ }
+
// Confirm the current state for the side-effect of updating the time-in-state
// counter for the current state.
setState(currentState, timestamp);
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index 1bc8464..a579442 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -35,9 +35,9 @@
class RpcTransport;
class FdTrigger;
-constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_NEXT = 0;
+constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_NEXT = 1;
constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL = 0xF0000000;
-constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION = RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL;
+constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION = 0;
/**
* This represents a session (group of connections) between a client
diff --git a/libs/binder/tests/binderRpcWireProtocolTest.cpp b/libs/binder/tests/binderRpcWireProtocolTest.cpp
index a807afa..4fcf42d 100644
--- a/libs/binder/tests/binderRpcWireProtocolTest.cpp
+++ b/libs/binder/tests/binderRpcWireProtocolTest.cpp
@@ -237,8 +237,9 @@
checkRepr(kCurrentRepr, RPC_WIRE_PROTOCOL_VERSION);
}
-static_assert(RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL,
- "you better update this test!");
+static_assert(RPC_WIRE_PROTOCOL_VERSION == 0,
+ "If the binder wire protocol is updated, this test should test additional versions. "
+ "The binder wire protocol should only be updated on upstream AOSP.");
TEST(RpcWire, ReleaseBranchHasFrozenRpcWireProtocol) {
if (RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL) {
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index c2793ac..dbccf30 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -165,6 +165,17 @@
mCurrentMaxAcquiredBufferCount = mMaxAcquiredBuffers;
mNumAcquired = 0;
mNumFrameAvailable = 0;
+
+ TransactionCompletedListener::getInstance()->addQueueStallListener(
+ [&]() {
+ std::function<void(bool)> callbackCopy;
+ {
+ std::unique_lock _lock{mMutex};
+ callbackCopy = mTransactionHangCallback;
+ }
+ if (callbackCopy) callbackCopy(true);
+ }, this);
+
BQA_LOGV("BLASTBufferQueue created");
}
@@ -175,6 +186,7 @@
}
BLASTBufferQueue::~BLASTBufferQueue() {
+ TransactionCompletedListener::getInstance()->removeQueueStallListener(this);
if (mPendingTransactions.empty()) {
return;
}
@@ -1113,4 +1125,9 @@
return SurfaceControl::isSameSurface(mSurfaceControl, surfaceControl);
}
+void BLASTBufferQueue::setTransactionHangCallback(std::function<void(bool)> callback) {
+ std::unique_lock _lock{mMutex};
+ mTransactionHangCallback = callback;
+}
+
} // namespace android
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index f7392d4..e4b8bad 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -29,6 +29,7 @@
enum class Tag : uint32_t {
ON_TRANSACTION_COMPLETED = IBinder::FIRST_CALL_TRANSACTION,
ON_RELEASE_BUFFER,
+ ON_TRANSACTION_QUEUE_STALLED,
LAST = ON_RELEASE_BUFFER,
};
@@ -277,6 +278,11 @@
callbackId, releaseFence,
currentMaxAcquiredBufferCount);
}
+
+ void onTransactionQueueStalled() override {
+ callRemoteAsync<decltype(&ITransactionCompletedListener::onTransactionQueueStalled)>(
+ Tag::ON_TRANSACTION_QUEUE_STALLED);
+ }
};
// Out-of-line virtual method definitions to trigger vtable emission in this translation unit (see
@@ -297,6 +303,9 @@
&ITransactionCompletedListener::onTransactionCompleted);
case Tag::ON_RELEASE_BUFFER:
return callLocalAsync(data, reply, &ITransactionCompletedListener::onReleaseBuffer);
+ case Tag::ON_TRANSACTION_QUEUE_STALLED:
+ return callLocalAsync(data, reply,
+ &ITransactionCompletedListener::onTransactionQueueStalled);
}
}
diff --git a/libs/gui/ScreenCaptureResults.cpp b/libs/gui/ScreenCaptureResults.cpp
index e91f74f..fe38706 100644
--- a/libs/gui/ScreenCaptureResults.cpp
+++ b/libs/gui/ScreenCaptureResults.cpp
@@ -36,6 +36,7 @@
}
SAFE_PARCEL(parcel->writeBool, capturedSecureLayers);
+ SAFE_PARCEL(parcel->writeBool, capturedHdrLayers);
SAFE_PARCEL(parcel->writeUint32, static_cast<uint32_t>(capturedDataspace));
SAFE_PARCEL(parcel->writeInt32, result);
return NO_ERROR;
@@ -57,6 +58,7 @@
}
SAFE_PARCEL(parcel->readBool, &capturedSecureLayers);
+ SAFE_PARCEL(parcel->readBool, &capturedHdrLayers);
uint32_t dataspace = 0;
SAFE_PARCEL(parcel->readUint32, &dataspace);
capturedDataspace = static_cast<ui::Dataspace>(dataspace);
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 7a63af0..501f8cf 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -447,6 +447,27 @@
}
}
+void TransactionCompletedListener::onTransactionQueueStalled() {
+ std::unordered_map<void*, std::function<void()>> callbackCopy;
+ {
+ std::scoped_lock<std::mutex> lock(mMutex);
+ callbackCopy = mQueueStallListeners;
+ }
+ for (auto const& it : callbackCopy) {
+ it.second();
+ }
+}
+
+void TransactionCompletedListener::addQueueStallListener(std::function<void()> stallListener,
+ void* id) {
+ std::scoped_lock<std::mutex> lock(mMutex);
+ mQueueStallListeners[id] = stallListener;
+}
+void TransactionCompletedListener::removeQueueStallListener(void *id) {
+ std::scoped_lock<std::mutex> lock(mMutex);
+ mQueueStallListeners.erase(id);
+}
+
void TransactionCompletedListener::onReleaseBuffer(ReleaseCallbackId callbackId,
sp<Fence> releaseFence,
uint32_t currentMaxAcquiredBufferCount) {
@@ -1495,6 +1516,18 @@
s->bufferData = std::move(bufferData);
registerSurfaceControlForCallback(sc);
+ // With the current infrastructure, a release callback will not be invoked if there's no
+ // transaction callback in the case when a buffer is latched and not released early. This is
+ // because the legacy implementation didn't have a release callback and sent releases in the
+ // transaction callback. Because of this, we need to make sure to have a transaction callback
+ // set up when a buffer is sent in a transaction to ensure the caller gets the release
+ // callback, regardless if they set up a transaction callback.
+ //
+ // TODO (b/230380821): Remove when release callbacks are separated from transaction callbacks
+ addTransactionCompletedCallback([](void*, nsecs_t, const sp<Fence>&,
+ const std::vector<SurfaceControlStats>&) {},
+ nullptr);
+
mContainsBuffer = true;
return *this;
}
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 65fc04d..9328a54 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -113,6 +113,14 @@
uint64_t getLastAcquiredFrameNum();
void abandon();
+ /**
+ * Set a callback to be invoked when we are hung. The boolean parameter
+ * indicates whether the hang is due to an unfired fence.
+ * TODO: The boolean is always true atm, unfired fence is
+ * the only case we detect.
+ */
+ void setTransactionHangCallback(std::function<void(bool)> callback);
+
virtual ~BLASTBufferQueue();
private:
@@ -269,6 +277,8 @@
// transaction that will be applied by some sync consumer.
bool mAppliedLastTransaction = false;
uint64_t mLastAppliedFrameNumber = 0;
+
+ std::function<void(bool)> mTransactionHangCallback;
};
} // namespace android
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
index a791c66..cc136bb 100644
--- a/libs/gui/include/gui/ITransactionCompletedListener.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -194,6 +194,7 @@
virtual void onReleaseBuffer(ReleaseCallbackId callbackId, sp<Fence> releaseFence,
uint32_t currentMaxAcquiredBufferCount) = 0;
+ virtual void onTransactionQueueStalled() = 0;
};
class BnTransactionCompletedListener : public SafeBnInterface<ITransactionCompletedListener> {
diff --git a/libs/gui/include/gui/ScreenCaptureResults.h b/libs/gui/include/gui/ScreenCaptureResults.h
index 99c35c1..724c11c 100644
--- a/libs/gui/include/gui/ScreenCaptureResults.h
+++ b/libs/gui/include/gui/ScreenCaptureResults.h
@@ -33,6 +33,7 @@
sp<GraphicBuffer> buffer;
sp<Fence> fence = Fence::NO_FENCE;
bool capturedSecureLayers{false};
+ bool capturedHdrLayers{false};
ui::Dataspace capturedDataspace{ui::Dataspace::V0_SRGB};
status_t result = OK;
};
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 0cc43d8..efbdb36 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -772,6 +772,7 @@
// This is protected by mSurfaceStatsListenerMutex, but GUARDED_BY isn't supported for
// std::recursive_mutex
std::multimap<int32_t, SurfaceStatsCallbackEntry> mSurfaceStatsListeners;
+ std::unordered_map<void*, std::function<void()>> mQueueStallListeners;
public:
static sp<TransactionCompletedListener> getInstance();
@@ -789,6 +790,9 @@
const sp<SurfaceControl>& surfaceControl,
const std::unordered_set<CallbackId, CallbackIdHash>& callbackIds);
+ void addQueueStallListener(std::function<void()> stallListener, void* id);
+ void removeQueueStallListener(void *id);
+
/*
* Adds a jank listener to be informed about SurfaceFlinger's jank classification for a specific
* surface. Jank classifications arrive as part of the transaction callbacks about previous
@@ -817,6 +821,8 @@
// For Testing Only
static void setInstance(const sp<TransactionCompletedListener>&);
+ void onTransactionQueueStalled() override;
+
private:
ReleaseBufferCallback popReleaseBufferCallbackLocked(const ReleaseCallbackId&);
static sp<TransactionCompletedListener> sInstance;
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 1d4fc1f..5d7874a 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -103,9 +103,6 @@
sanitize: {
misc_undefined: ["integer"],
- diag: {
- misc_undefined: ["integer"],
- },
},
},
host: {
diff --git a/libs/renderengine/TEST_MAPPING b/libs/renderengine/TEST_MAPPING
index 995dba1..db00118 100644
--- a/libs/renderengine/TEST_MAPPING
+++ b/libs/renderengine/TEST_MAPPING
@@ -3,5 +3,11 @@
{
"name": "librenderengine_test"
}
+ ],
+
+ "imports": [
+ {
+ "path": "frameworks/native/services/surfaceflinger"
+ }
]
}
diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h
index a5e0879..59ef991 100644
--- a/libs/renderengine/include/renderengine/DisplaySettings.h
+++ b/libs/renderengine/include/renderengine/DisplaySettings.h
@@ -21,6 +21,7 @@
#include <iosfwd>
#include <math/mat4.h>
+#include <renderengine/PrintMatrix.h>
#include <ui/GraphicTypes.h>
#include <ui/Rect.h>
#include <ui/Region.h>
@@ -82,11 +83,38 @@
static inline bool operator==(const DisplaySettings& lhs, const DisplaySettings& rhs) {
return lhs.physicalDisplay == rhs.physicalDisplay && lhs.clip == rhs.clip &&
- lhs.maxLuminance == rhs.maxLuminance && lhs.outputDataspace == rhs.outputDataspace &&
- lhs.colorTransform == rhs.colorTransform && lhs.orientation == rhs.orientation;
+ lhs.maxLuminance == rhs.maxLuminance &&
+ lhs.currentLuminanceNits == rhs.currentLuminanceNits &&
+ lhs.outputDataspace == rhs.outputDataspace &&
+ lhs.colorTransform == rhs.colorTransform &&
+ lhs.deviceHandlesColorTransform == rhs.deviceHandlesColorTransform &&
+ lhs.orientation == rhs.orientation &&
+ lhs.targetLuminanceNits == rhs.targetLuminanceNits &&
+ lhs.dimmingStage == rhs.dimmingStage && lhs.renderIntent == rhs.renderIntent;
}
-// Defining PrintTo helps with Google Tests.
+static const char* orientation_to_string(uint32_t orientation) {
+ switch (orientation) {
+ case ui::Transform::ROT_0:
+ return "ROT_0";
+ case ui::Transform::FLIP_H:
+ return "FLIP_H";
+ case ui::Transform::FLIP_V:
+ return "FLIP_V";
+ case ui::Transform::ROT_90:
+ return "ROT_90";
+ case ui::Transform::ROT_180:
+ return "ROT_180";
+ case ui::Transform::ROT_270:
+ return "ROT_270";
+ case ui::Transform::ROT_INVALID:
+ return "ROT_INVALID";
+ default:
+ ALOGE("invalid orientation!");
+ return "invalid orientation";
+ }
+}
+
static inline void PrintTo(const DisplaySettings& settings, ::std::ostream* os) {
*os << "DisplaySettings {";
*os << "\n .physicalDisplay = ";
@@ -94,10 +122,19 @@
*os << "\n .clip = ";
PrintTo(settings.clip, os);
*os << "\n .maxLuminance = " << settings.maxLuminance;
+ *os << "\n .currentLuminanceNits = " << settings.currentLuminanceNits;
*os << "\n .outputDataspace = ";
PrintTo(settings.outputDataspace, os);
- *os << "\n .colorTransform = " << settings.colorTransform;
- *os << "\n .clearRegion = ";
+ *os << "\n .colorTransform = ";
+ PrintMatrix(settings.colorTransform, os);
+ *os << "\n .deviceHandlesColorTransform = " << settings.deviceHandlesColorTransform;
+ *os << "\n .orientation = " << orientation_to_string(settings.orientation);
+ *os << "\n .targetLuminanceNits = " << settings.targetLuminanceNits;
+ *os << "\n .dimmingStage = "
+ << aidl::android::hardware::graphics::composer3::toString(settings.dimmingStage).c_str();
+ *os << "\n .renderIntent = "
+ << aidl::android::hardware::graphics::composer3::toString(settings.renderIntent).c_str();
+ *os << "\n}";
}
} // namespace renderengine
diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
index 171cbaa..154e526 100644
--- a/libs/renderengine/include/renderengine/LayerSettings.h
+++ b/libs/renderengine/include/renderengine/LayerSettings.h
@@ -19,7 +19,9 @@
#include <math/mat4.h>
#include <math/vec3.h>
#include <renderengine/ExternalTexture.h>
+#include <renderengine/PrintMatrix.h>
#include <ui/BlurRegion.h>
+#include <ui/DebugUtils.h>
#include <ui/Fence.h>
#include <ui/FloatRect.h>
#include <ui/GraphicBuffer.h>
@@ -208,6 +210,10 @@
lhs.casterIsTranslucent == rhs.casterIsTranslucent;
}
+static inline bool operator!=(const ShadowSettings& lhs, const ShadowSettings& rhs) {
+ return !(operator==(lhs, rhs));
+}
+
static inline bool operator==(const LayerSettings& lhs, const LayerSettings& rhs) {
if (lhs.blurRegions.size() != rhs.blurRegions.size()) {
return false;
@@ -226,18 +232,19 @@
lhs.skipContentDraw == rhs.skipContentDraw && lhs.shadow == rhs.shadow &&
lhs.backgroundBlurRadius == rhs.backgroundBlurRadius &&
lhs.blurRegionTransform == rhs.blurRegionTransform &&
- lhs.stretchEffect == rhs.stretchEffect;
+ lhs.stretchEffect == rhs.stretchEffect && lhs.whitePointNits == rhs.whitePointNits;
}
-// Defining PrintTo helps with Google Tests.
-
static inline void PrintTo(const Buffer& settings, ::std::ostream* os) {
*os << "Buffer {";
- *os << "\n .buffer = " << settings.buffer.get();
+ *os << "\n .buffer = " << settings.buffer.get() << " "
+ << (settings.buffer.get() ? decodePixelFormat(settings.buffer->getPixelFormat()).c_str()
+ : "");
*os << "\n .fence = " << settings.fence.get();
*os << "\n .textureName = " << settings.textureName;
*os << "\n .useTextureFiltering = " << settings.useTextureFiltering;
- *os << "\n .textureTransform = " << settings.textureTransform;
+ *os << "\n .textureTransform = ";
+ PrintMatrix(settings.textureTransform, os);
*os << "\n .usePremultipliedAlpha = " << settings.usePremultipliedAlpha;
*os << "\n .isOpaque = " << settings.isOpaque;
*os << "\n .isY410BT2020 = " << settings.isY410BT2020;
@@ -249,7 +256,8 @@
*os << "Geometry {";
*os << "\n .boundaries = ";
PrintTo(settings.boundaries, os);
- *os << "\n .positionTransform = " << settings.positionTransform;
+ *os << "\n .positionTransform = ";
+ PrintMatrix(settings.positionTransform, os);
*os << "\n .roundedCornersRadius = " << settings.roundedCornersRadius;
*os << "\n .roundedCornersCrop = ";
PrintTo(settings.roundedCornersCrop, os);
@@ -258,10 +266,14 @@
static inline void PrintTo(const PixelSource& settings, ::std::ostream* os) {
*os << "PixelSource {";
- *os << "\n .buffer = ";
- PrintTo(settings.buffer, os);
- *os << "\n .solidColor = " << settings.solidColor;
- *os << "\n}";
+ if (settings.buffer.buffer) {
+ *os << "\n .buffer = ";
+ PrintTo(settings.buffer, os);
+ *os << "\n}";
+ } else {
+ *os << "\n .solidColor = " << settings.solidColor;
+ *os << "\n}";
+ }
}
static inline void PrintTo(const ShadowSettings& settings, ::std::ostream* os) {
@@ -301,18 +313,28 @@
*os << "\n .alpha = " << settings.alpha;
*os << "\n .sourceDataspace = ";
PrintTo(settings.sourceDataspace, os);
- *os << "\n .colorTransform = " << settings.colorTransform;
+ *os << "\n .colorTransform = ";
+ PrintMatrix(settings.colorTransform, os);
*os << "\n .disableBlending = " << settings.disableBlending;
*os << "\n .skipContentDraw = " << settings.skipContentDraw;
- *os << "\n .backgroundBlurRadius = " << settings.backgroundBlurRadius;
- for (auto blurRegion : settings.blurRegions) {
- *os << "\n";
- PrintTo(blurRegion, os);
+ if (settings.shadow != ShadowSettings()) {
+ *os << "\n .shadow = ";
+ PrintTo(settings.shadow, os);
}
- *os << "\n .shadow = ";
- PrintTo(settings.shadow, os);
- *os << "\n .stretchEffect = ";
- PrintTo(settings.stretchEffect, os);
+ *os << "\n .backgroundBlurRadius = " << settings.backgroundBlurRadius;
+ if (settings.blurRegions.size()) {
+ *os << "\n .blurRegions =";
+ for (auto blurRegion : settings.blurRegions) {
+ *os << "\n";
+ PrintTo(blurRegion, os);
+ }
+ }
+ *os << "\n .blurRegionTransform = ";
+ PrintMatrix(settings.blurRegionTransform, os);
+ if (settings.stretchEffect != StretchEffect()) {
+ *os << "\n .stretchEffect = ";
+ PrintTo(settings.stretchEffect, os);
+ }
*os << "\n .whitePointNits = " << settings.whitePointNits;
*os << "\n}";
}
diff --git a/libs/renderengine/include/renderengine/PrintMatrix.h b/libs/renderengine/include/renderengine/PrintMatrix.h
new file mode 100644
index 0000000..11a5c21
--- /dev/null
+++ b/libs/renderengine/include/renderengine/PrintMatrix.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2022 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 <math/mat4.h>
+#include <iosfwd>
+
+namespace android::renderengine {
+
+// This method simplifies printing the identity matrix, so it can be easily
+// skipped over visually.
+inline void PrintMatrix(const mat4& matrix, ::std::ostream* os) {
+ if (matrix == mat4()) {
+ *os << "I";
+ } else {
+ // Print the matrix starting on a new line. This ensures that all lines
+ // are aligned.
+ *os << "\n" << matrix;
+ }
+}
+
+} // namespace android::renderengine
diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp
index a3a1969..f3064f3 100644
--- a/libs/renderengine/skia/Cache.cpp
+++ b/libs/renderengine/skia/Cache.cpp
@@ -96,7 +96,6 @@
.alpha = 1,
};
- auto layers = std::vector<LayerSettings>{layer, caster};
// Four combinations of settings are used (two transforms here, and drawShadowLayers is
// called with two different destination data spaces) They're all rounded rect.
// Three of these are cache misses that generate new shaders.
@@ -115,6 +114,8 @@
for (auto transform : {mat4(), kFlip}) {
layer.geometry.positionTransform = transform;
caster.geometry.positionTransform = transform;
+
+ auto layers = std::vector<LayerSettings>{layer, caster};
renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
base::unique_fd());
}
@@ -141,7 +142,6 @@
}},
};
- auto layers = std::vector<LayerSettings>{layer};
for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) {
layer.sourceDataspace = dataspace;
// Cache shaders for both rects and round rects.
@@ -153,6 +153,7 @@
layer.source.buffer.isOpaque = isOpaque;
for (auto alpha : {half(.2f), half(1.0f)}) {
layer.alpha = alpha;
+ auto layers = std::vector<LayerSettings>{layer};
renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
base::unique_fd());
}
@@ -177,11 +178,11 @@
.alpha = 0.5,
};
- auto layers = std::vector<LayerSettings>{layer};
for (auto transform : {mat4(), kScaleAndTranslate}) {
layer.geometry.positionTransform = transform;
for (float roundedCornersRadius : {0.0f, 50.f}) {
layer.geometry.roundedCornersRadius = roundedCornersRadius;
+ auto layers = std::vector<LayerSettings>{layer};
renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
base::unique_fd());
}
@@ -202,10 +203,10 @@
.skipContentDraw = true,
};
- auto layers = std::vector<LayerSettings>{layer};
// Different blur code is invoked for radii less and greater than 30 pixels
for (int radius : {9, 60}) {
layer.backgroundBlurRadius = radius;
+ auto layers = std::vector<LayerSettings>{layer};
renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
base::unique_fd());
}
@@ -243,7 +244,6 @@
},
};
- auto layers = std::vector<LayerSettings>{layer};
for (auto pixelSource : {bufferSource, bufferOpaque, colorSource}) {
layer.source = pixelSource;
for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) {
@@ -252,7 +252,8 @@
for (auto transform : {kScaleAndTranslate, kScaleAsymmetric}) {
layer.geometry.positionTransform = transform;
for (float alpha : {0.5f, 1.f}) {
- layer.alpha = alpha,
+ layer.alpha = alpha;
+ auto layers = std::vector<LayerSettings>{layer};
renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
base::unique_fd());
}
@@ -438,7 +439,7 @@
const nsecs_t timeAfter = systemTime();
const float compileTimeMs = static_cast<float>(timeAfter - timeBefore) / 1.0E6;
- const int shadersCompiled = renderengine->reportShadersCompiled();
+ const int shadersCompiled = renderengine->reportShadersCompiled() - previousCount;
ALOGD("Shader cache generated %d shaders in %f ms\n", shadersCompiled, compileTimeMs);
}
}
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 76ae2fc..97271cb 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -67,7 +67,7 @@
namespace {
// Debugging settings
static const bool kPrintLayerSettings = false;
-static const bool kFlushAfterEveryLayer = false;
+static const bool kFlushAfterEveryLayer = kPrintLayerSettings;
} // namespace
bool checkGlError(const char* op, int lineNumber);
@@ -292,16 +292,12 @@
void SkiaGLRenderEngine::SkSLCacheMonitor::store(const SkData& key, const SkData& data,
const SkString& description) {
mShadersCachedSinceLastCall++;
-}
-
-void SkiaGLRenderEngine::assertShadersCompiled(int numShaders) {
- const int cached = mSkSLCacheMonitor.shadersCachedSinceLastCall();
- LOG_ALWAYS_FATAL_IF(cached != numShaders, "Attempted to cache %i shaders; cached %i",
- numShaders, cached);
+ mTotalShadersCompiled++;
+ ATRACE_FORMAT("SF cache: %i shaders", mTotalShadersCompiled);
}
int SkiaGLRenderEngine::reportShadersCompiled() {
- return mSkSLCacheMonitor.shadersCachedSinceLastCall();
+ return mSkSLCacheMonitor.totalShadersCompiled();
}
SkiaGLRenderEngine::SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display,
@@ -744,6 +740,23 @@
return std::abs(expected - value) < margin;
}
+namespace {
+template <typename T>
+void logSettings(const T& t) {
+ std::stringstream stream;
+ PrintTo(t, &stream);
+ auto string = stream.str();
+ size_t pos = 0;
+ // Perfetto ignores \n, so split up manually into separate ALOGD statements.
+ const size_t size = string.size();
+ while (pos < size) {
+ const size_t end = std::min(string.find("\n", pos), size);
+ ALOGD("%s", string.substr(pos, end - pos).c_str());
+ pos = end + 1;
+ }
+}
+} // namespace
+
void SkiaGLRenderEngine::drawLayersInternal(
const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
const DisplaySettings& display, const std::vector<LayerSettings>& layers,
@@ -853,18 +866,14 @@
canvas->clear(SK_ColorTRANSPARENT);
initCanvas(canvas, display);
+ if (kPrintLayerSettings) {
+ logSettings(display);
+ }
for (const auto& layer : layers) {
ATRACE_FORMAT("DrawLayer: %s", layer.name.c_str());
if (kPrintLayerSettings) {
- std::stringstream ls;
- PrintTo(layer, &ls);
- auto debugs = ls.str();
- int pos = 0;
- while (pos < debugs.size()) {
- ALOGD("cache_debug %s", debugs.substr(pos, 1000).c_str());
- pos += 1000;
- }
+ logSettings(layer);
}
sk_sp<SkImage> blurInput;
@@ -1190,11 +1199,15 @@
static constexpr float kInverseGamma22 = 1.f / 2.2f;
const auto gammaCorrectedDimmingRatio =
std::pow(layerDimmingRatio, kInverseGamma22);
- const auto dimmingMatrix =
+ auto dimmingMatrix =
mat4::scale(vec4(gammaCorrectedDimmingRatio, gammaCorrectedDimmingRatio,
gammaCorrectedDimmingRatio, 1.f));
- paint.setColorFilter(SkColorFilters::Matrix(
- toSkColorMatrix(display.colorTransform * dimmingMatrix)));
+
+ const auto colorFilter =
+ SkColorFilters::Matrix(toSkColorMatrix(std::move(dimmingMatrix)));
+ paint.setColorFilter(displayColorTransform
+ ? displayColorTransform->makeComposed(colorFilter)
+ : colorFilter);
} else {
paint.setColorFilter(displayColorTransform);
}
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index a650313..5ef9944 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -61,7 +61,6 @@
bool supportsProtectedContent() const override;
void useProtectedContext(bool useProtectedContext) override;
bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; }
- void assertShadersCompiled(int numShaders) override;
void onActiveDisplaySizeChanged(ui::Size size) override;
int reportShadersCompiled() override;
@@ -178,8 +177,11 @@
return shadersCachedSinceLastCall;
}
+ int totalShadersCompiled() const { return mTotalShadersCompiled; }
+
private:
int mShadersCachedSinceLastCall = 0;
+ int mTotalShadersCompiled = 0;
};
SkSLCacheMonitor mSkSLCacheMonitor;
diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h
index 5d10b6f..160a186 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.h
+++ b/libs/renderengine/skia/SkiaRenderEngine.h
@@ -45,7 +45,6 @@
virtual bool isProtected() const override { return false; } // mInProtectedContext; }
virtual bool supportsProtectedContent() const override { return false; };
virtual int getContextPriority() override { return 0; }
- virtual void assertShadersCompiled(int numShaders) {}
virtual int reportShadersCompiled() { return 0; }
virtual void setEnableTracing(bool tracingEnabled) override;
diff --git a/libs/renderengine/tests/Android.bp b/libs/renderengine/tests/Android.bp
index e66fee1..bbab792 100644
--- a/libs/renderengine/tests/Android.bp
+++ b/libs/renderengine/tests/Android.bp
@@ -29,6 +29,8 @@
],
test_suites: ["device-tests"],
srcs: [
+ "DisplaySettingsTest.cpp",
+ "LayerSettingsTest.cpp",
"RenderEngineTest.cpp",
"RenderEngineThreadedTest.cpp",
],
diff --git a/libs/renderengine/tests/DisplaySettingsTest.cpp b/libs/renderengine/tests/DisplaySettingsTest.cpp
new file mode 100644
index 0000000..0e93c88
--- /dev/null
+++ b/libs/renderengine/tests/DisplaySettingsTest.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "DisplaySettingsTest"
+
+#include <gtest/gtest.h>
+#include <renderengine/DisplaySettings.h>
+
+namespace android::renderengine {
+
+TEST(DisplaySettingsTest, currentLuminanceNits) {
+ DisplaySettings a, b;
+ ASSERT_EQ(a, b);
+
+ a.currentLuminanceNits = 45.f;
+
+ ASSERT_FALSE(a == b);
+}
+
+TEST(DisplaySettingsTest, targetLuminanceNits) {
+ DisplaySettings a, b;
+ ASSERT_EQ(a, b);
+
+ a.targetLuminanceNits = 45.f;
+
+ ASSERT_FALSE(a == b);
+}
+
+TEST(DisplaySettingsTest, deviceHandlesColorTransform) {
+ DisplaySettings a, b;
+ ASSERT_EQ(a, b);
+
+ a.deviceHandlesColorTransform = true;
+
+ ASSERT_FALSE(a == b);
+}
+
+TEST(DisplaySettingsTest, dimmingStage) {
+ DisplaySettings a, b;
+ ASSERT_EQ(a, b);
+
+ a.dimmingStage = aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF;
+
+ ASSERT_FALSE(a == b);
+}
+
+TEST(DisplaySettingsTest, renderIntent) {
+ DisplaySettings a, b;
+ ASSERT_EQ(a, b);
+
+ a.renderIntent = aidl::android::hardware::graphics::composer3::RenderIntent::TONE_MAP_ENHANCE;
+
+ ASSERT_FALSE(a == b);
+}
+} // namespace android::renderengine
diff --git a/libs/renderengine/tests/LayerSettingsTest.cpp b/libs/renderengine/tests/LayerSettingsTest.cpp
new file mode 100644
index 0000000..4737335
--- /dev/null
+++ b/libs/renderengine/tests/LayerSettingsTest.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LayerSettingsTest"
+
+#include <gtest/gtest.h>
+#include <renderengine/LayerSettings.h>
+
+namespace android::renderengine {
+
+TEST(LayerSettingsTest, whitePointNits) {
+ LayerSettings a, b;
+ ASSERT_EQ(a, b);
+
+ a.whitePointNits = 45.f;
+
+ ASSERT_FALSE(a == b);
+}
+} // namespace android::renderengine
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 2493242..7c70a74 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -91,6 +91,14 @@
sign(linear.b) * OETF_sRGB(linear.b));
}
+// clang-format off
+// Converts red channels to green channels, and zeroes out an existing green channel.
+static const auto kRemoveGreenAndMoveRedToGreenMat4 = mat4(0, 1, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1);
+// clang-format on
+
} // namespace
class RenderEngineFactory {
@@ -2557,6 +2565,133 @@
expectBufferColor(Rect(2, 0, 3, 1), 122, 0, 0, 255, 1);
}
+TEST_P(RenderEngineTest, testDimming_inGammaSpace_withDisplayColorTransform) {
+ if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
+ GTEST_SKIP();
+ }
+ initializeRenderEngine();
+
+ const ui::Dataspace dataspace = static_cast<ui::Dataspace>(ui::Dataspace::STANDARD_BT709 |
+ ui::Dataspace::TRANSFER_GAMMA2_2 |
+ ui::Dataspace::RANGE_FULL);
+
+ const auto displayRect = Rect(3, 1);
+ const renderengine::DisplaySettings display{
+ .physicalDisplay = displayRect,
+ .clip = displayRect,
+ .outputDataspace = dataspace,
+ .colorTransform = kRemoveGreenAndMoveRedToGreenMat4,
+ .targetLuminanceNits = 1000.f,
+ .dimmingStage = aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF,
+ };
+
+ const auto greenBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(0, 255, 0, 255));
+ const auto blueBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(0, 0, 255, 255));
+ const auto redBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(255, 0, 0, 255));
+
+ const renderengine::LayerSettings greenLayer{
+ .geometry.boundaries = FloatRect(0.f, 0.f, 1.f, 1.f),
+ .source =
+ renderengine::PixelSource{
+ .buffer =
+ renderengine::Buffer{
+ .buffer = greenBuffer,
+ .usePremultipliedAlpha = true,
+ },
+ },
+ .alpha = 1.0f,
+ .sourceDataspace = dataspace,
+ .whitePointNits = 200.f,
+ };
+
+ const renderengine::LayerSettings redLayer{
+ .geometry.boundaries = FloatRect(1.f, 0.f, 2.f, 1.f),
+ .source =
+ renderengine::PixelSource{
+ .buffer =
+ renderengine::Buffer{
+ .buffer = redBuffer,
+ .usePremultipliedAlpha = true,
+ },
+ },
+ .alpha = 1.0f,
+ .sourceDataspace = dataspace,
+ // When the white point is not set for a layer, just ignore it and treat it as the same
+ // as the max layer
+ .whitePointNits = -1.f,
+ };
+
+ std::vector<renderengine::LayerSettings> layers{greenLayer, redLayer};
+ invokeDraw(display, layers);
+
+ expectBufferColor(Rect(1, 1), 0, 0, 0, 255, 1);
+ expectBufferColor(Rect(1, 0, 2, 1), 0, 122, 0, 255, 1);
+}
+
+TEST_P(RenderEngineTest, testDimming_inGammaSpace_withDisplayColorTransform_deviceHandles) {
+ if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
+ GTEST_SKIP();
+ }
+ initializeRenderEngine();
+
+ const ui::Dataspace dataspace = static_cast<ui::Dataspace>(ui::Dataspace::STANDARD_BT709 |
+ ui::Dataspace::TRANSFER_GAMMA2_2 |
+ ui::Dataspace::RANGE_FULL);
+
+ const auto displayRect = Rect(3, 1);
+ const renderengine::DisplaySettings display{
+ .physicalDisplay = displayRect,
+ .clip = displayRect,
+ .outputDataspace = dataspace,
+ .colorTransform = kRemoveGreenAndMoveRedToGreenMat4,
+ .deviceHandlesColorTransform = true,
+ .targetLuminanceNits = 1000.f,
+ .dimmingStage = aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF,
+ };
+
+ const auto greenBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(0, 255, 0, 255));
+ const auto blueBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(0, 0, 255, 255));
+ const auto redBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(255, 0, 0, 255));
+
+ const renderengine::LayerSettings greenLayer{
+ .geometry.boundaries = FloatRect(0.f, 0.f, 1.f, 1.f),
+ .source =
+ renderengine::PixelSource{
+ .buffer =
+ renderengine::Buffer{
+ .buffer = greenBuffer,
+ .usePremultipliedAlpha = true,
+ },
+ },
+ .alpha = 1.0f,
+ .sourceDataspace = dataspace,
+ .whitePointNits = 200.f,
+ };
+
+ const renderengine::LayerSettings redLayer{
+ .geometry.boundaries = FloatRect(1.f, 0.f, 2.f, 1.f),
+ .source =
+ renderengine::PixelSource{
+ .buffer =
+ renderengine::Buffer{
+ .buffer = redBuffer,
+ .usePremultipliedAlpha = true,
+ },
+ },
+ .alpha = 1.0f,
+ .sourceDataspace = dataspace,
+ // When the white point is not set for a layer, just ignore it and treat it as the same
+ // as the max layer
+ .whitePointNits = -1.f,
+ };
+
+ std::vector<renderengine::LayerSettings> layers{greenLayer, redLayer};
+ invokeDraw(display, layers);
+
+ expectBufferColor(Rect(1, 1), 0, 122, 0, 255, 1);
+ expectBufferColor(Rect(1, 0, 2, 1), 122, 0, 0, 255, 1);
+}
+
TEST_P(RenderEngineTest, testDimming_withoutTargetLuminance) {
initializeRenderEngine();
if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
@@ -2796,10 +2931,7 @@
// pure red to pure green. That will occur when the R8 buffer is
// 255. When the R8 buffer is 0, it will still change to black, as
// with r8_behaves_as_mask.
- .colorTransform = mat4(0, 1, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 1, 0,
- 0, 0, 0, 1),
+ .colorTransform = kRemoveGreenAndMoveRedToGreenMat4,
.deviceHandlesColorTransform = false,
};
@@ -2902,6 +3034,23 @@
expectBufferColor(Rect(1, 0, 2, 1), 255, 0, 0, 255); // Still red.
expectBufferColor(Rect(0, 0, 1, 1), 0, 70, 0, 255);
}
+
+TEST_P(RenderEngineTest, primeShaderCache) {
+ if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
+ GTEST_SKIP();
+ }
+
+ initializeRenderEngine();
+
+ auto fut = mRE->primeCache();
+ if (fut.valid()) {
+ fut.wait();
+ }
+
+ const int minimumExpectedShadersCompiled = GetParam()->useColorManagement() ? 60 : 30;
+ ASSERT_GT(static_cast<skia::SkiaGLRenderEngine*>(mRE.get())->reportShadersCompiled(),
+ minimumExpectedShadersCompiled);
+}
} // namespace renderengine
} // namespace android
diff --git a/libs/shaders/shaders.cpp b/libs/shaders/shaders.cpp
index f0d45c2..62745dc 100644
--- a/libs/shaders/shaders.cpp
+++ b/libs/shaders/shaders.cpp
@@ -78,7 +78,7 @@
shader.append(R"(
float EOTF_sRGB(float srgb) {
- return srgb <= 0.08125 ? srgb / 4.50 : pow((srgb + 0.099) / 1.099, 0.45);
+ return srgb <= 0.08125 ? srgb / 4.50 : pow((srgb + 0.099) / 1.099, 1 / 0.45);
}
float3 EOTF_sRGB(float3 srgb) {
diff --git a/libs/ui/DeviceProductInfo.cpp b/libs/ui/DeviceProductInfo.cpp
index 4d6ce43..04d9d3c 100644
--- a/libs/ui/DeviceProductInfo.cpp
+++ b/libs/ui/DeviceProductInfo.cpp
@@ -57,7 +57,7 @@
}
void DeviceProductInfo::dump(std::string& result) const {
- StringAppendF(&result, "{name=%s, ", name.c_str());
+ StringAppendF(&result, "{name=\"%s\", ", name.c_str());
StringAppendF(&result, "manufacturerPnpId=%s, ", manufacturerPnpId.data());
StringAppendF(&result, "productId=%s, ", productId.c_str());
diff --git a/libs/ui/Gralloc4.cpp b/libs/ui/Gralloc4.cpp
index 4f950b8..f6ab7b2 100644
--- a/libs/ui/Gralloc4.cpp
+++ b/libs/ui/Gralloc4.cpp
@@ -1245,8 +1245,9 @@
} else {
if (importBuffers) {
for (uint32_t i = 0; i < bufferCount; i++) {
- error = mMapper.importBuffer(makeFromAidl(result.buffers[i]),
- &outBufferHandles[i]);
+ auto handle = makeFromAidl(result.buffers[i]);
+ error = mMapper.importBuffer(handle, &outBufferHandles[i]);
+ native_handle_delete(handle);
if (error != NO_ERROR) {
for (uint32_t j = 0; j < i; j++) {
mMapper.freeBuffer(outBufferHandles[j]);
diff --git a/libs/vr/libbroadcastring/Android.bp b/libs/vr/libbroadcastring/Android.bp
index d4538f1..fa449ae 100644
--- a/libs/vr/libbroadcastring/Android.bp
+++ b/libs/vr/libbroadcastring/Android.bp
@@ -9,7 +9,7 @@
cc_library_static {
name: "libbroadcastring",
- clang: true,
+
cflags: [
"-Wall",
"-Wextra",
diff --git a/opengl/libs/EGL/BlobCache.cpp b/opengl/libs/EGL/BlobCache.cpp
index beca7f1..86c788d 100644
--- a/opengl/libs/EGL/BlobCache.cpp
+++ b/opengl/libs/EGL/BlobCache.cpp
@@ -52,35 +52,37 @@
ALOGV("initializing random seed using %lld", (unsigned long long)now);
}
-void BlobCache::set(const void* key, size_t keySize, const void* value, size_t valueSize) {
+BlobCache::InsertResult BlobCache::set(const void* key, size_t keySize, const void* value,
+ size_t valueSize) {
if (mMaxKeySize < keySize) {
ALOGV("set: not caching because the key is too large: %zu (limit: %zu)", keySize,
mMaxKeySize);
- return;
+ return InsertResult::kKeyTooBig;
}
if (mMaxValueSize < valueSize) {
ALOGV("set: not caching because the value is too large: %zu (limit: %zu)", valueSize,
mMaxValueSize);
- return;
+ return InsertResult::kValueTooBig;
}
if (mMaxTotalSize < keySize + valueSize) {
ALOGV("set: not caching because the combined key/value size is too "
"large: %zu (limit: %zu)",
keySize + valueSize, mMaxTotalSize);
- return;
+ return InsertResult::kCombinedTooBig;
}
if (keySize == 0) {
ALOGW("set: not caching because keySize is 0");
- return;
+ return InsertResult::kInvalidKeySize;
}
- if (valueSize <= 0) {
+ if (valueSize == 0) {
ALOGW("set: not caching because valueSize is 0");
- return;
+ return InsertResult::kInvalidValueSize;
}
std::shared_ptr<Blob> cacheKey(new Blob(key, keySize, false));
CacheEntry cacheEntry(cacheKey, nullptr);
+ bool didClean = false;
while (true) {
auto index = std::lower_bound(mCacheEntries.begin(), mCacheEntries.end(), cacheEntry);
if (index == mCacheEntries.end() || cacheEntry < *index) {
@@ -92,13 +94,14 @@
if (isCleanable()) {
// Clean the cache and try again.
clean();
+ didClean = true;
continue;
} else {
ALOGV("set: not caching new key/value pair because the "
"total cache size limit would be exceeded: %zu "
"(limit: %zu)",
keySize + valueSize, mMaxTotalSize);
- break;
+ return InsertResult::kNotEnoughSpace;
}
}
mCacheEntries.insert(index, CacheEntry(keyBlob, valueBlob));
@@ -114,12 +117,13 @@
if (isCleanable()) {
// Clean the cache and try again.
clean();
+ didClean = true;
continue;
} else {
ALOGV("set: not caching new value because the total cache "
"size limit would be exceeded: %zu (limit: %zu)",
keySize + valueSize, mMaxTotalSize);
- break;
+ return InsertResult::kNotEnoughSpace;
}
}
index->setValue(valueBlob);
@@ -128,7 +132,7 @@
"value",
keySize, valueSize);
}
- break;
+ return didClean ? InsertResult::kDidClean : InsertResult::kInserted;
}
}
diff --git a/opengl/libs/EGL/BlobCache.h b/opengl/libs/EGL/BlobCache.h
index 50b4e4c..ff03d30 100644
--- a/opengl/libs/EGL/BlobCache.h
+++ b/opengl/libs/EGL/BlobCache.h
@@ -39,6 +39,26 @@
// (key sizes plus value sizes) will not exceed maxTotalSize.
BlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize);
+ // Return value from set(), below.
+ enum class InsertResult {
+ // The key is larger than maxKeySize specified in the constructor.
+ kKeyTooBig,
+ // The value is larger than maxValueSize specified in the constructor.
+ kValueTooBig,
+ // The combined key + value is larger than maxTotalSize specified in the constructor.
+ kCombinedTooBig,
+ // keySize is 0
+ kInvalidKeySize,
+ // valueSize is 0
+ kInvalidValueSize,
+ // Unable to free enough space to fit the new entry.
+ kNotEnoughSpace,
+ // The new entry was inserted, but an old entry had to be evicted.
+ kDidClean,
+ // There was enough room in the cache and the new entry was inserted.
+ kInserted,
+
+ };
// set inserts a new binary value into the cache and associates it with the
// given binary key. If the key or value are too large for the cache then
// the cache remains unchanged. This includes the case where a different
@@ -54,7 +74,7 @@
// 0 < keySize
// value != NULL
// 0 < valueSize
- void set(const void* key, size_t keySize, const void* value, size_t valueSize);
+ InsertResult set(const void* key, size_t keySize, const void* value, size_t valueSize);
// get retrieves from the cache the binary value associated with a given
// binary key. If the key is present in the cache then the length of the
diff --git a/opengl/libs/EGL/BlobCache_test.cpp b/opengl/libs/EGL/BlobCache_test.cpp
index d31373b..ceea0fb 100644
--- a/opengl/libs/EGL/BlobCache_test.cpp
+++ b/opengl/libs/EGL/BlobCache_test.cpp
@@ -49,7 +49,7 @@
TEST_F(BlobCacheTest, CacheSingleValueSucceeds) {
unsigned char buf[4] = {0xee, 0xee, 0xee, 0xee};
- mBC->set("abcd", 4, "efgh", 4);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
ASSERT_EQ('e', buf[0]);
ASSERT_EQ('f', buf[1]);
@@ -59,8 +59,8 @@
TEST_F(BlobCacheTest, CacheTwoValuesSucceeds) {
unsigned char buf[2] = {0xee, 0xee};
- mBC->set("ab", 2, "cd", 2);
- mBC->set("ef", 2, "gh", 2);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("ab", 2, "cd", 2));
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("ef", 2, "gh", 2));
ASSERT_EQ(size_t(2), mBC->get("ab", 2, buf, 2));
ASSERT_EQ('c', buf[0]);
ASSERT_EQ('d', buf[1]);
@@ -71,7 +71,7 @@
TEST_F(BlobCacheTest, GetOnlyWritesInsideBounds) {
unsigned char buf[6] = {0xee, 0xee, 0xee, 0xee, 0xee, 0xee};
- mBC->set("abcd", 4, "efgh", 4);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf + 1, 4));
ASSERT_EQ(0xee, buf[0]);
ASSERT_EQ('e', buf[1]);
@@ -83,7 +83,7 @@
TEST_F(BlobCacheTest, GetOnlyWritesIfBufferIsLargeEnough) {
unsigned char buf[3] = {0xee, 0xee, 0xee};
- mBC->set("abcd", 4, "efgh", 4);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 3));
ASSERT_EQ(0xee, buf[0]);
ASSERT_EQ(0xee, buf[1]);
@@ -91,14 +91,14 @@
}
TEST_F(BlobCacheTest, GetDoesntAccessNullBuffer) {
- mBC->set("abcd", 4, "efgh", 4);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
ASSERT_EQ(size_t(4), mBC->get("abcd", 4, nullptr, 0));
}
TEST_F(BlobCacheTest, MultipleSetsCacheLatestValue) {
unsigned char buf[4] = {0xee, 0xee, 0xee, 0xee};
- mBC->set("abcd", 4, "efgh", 4);
- mBC->set("abcd", 4, "ijkl", 4);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "ijkl", 4));
ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
ASSERT_EQ('i', buf[0]);
ASSERT_EQ('j', buf[1]);
@@ -108,8 +108,8 @@
TEST_F(BlobCacheTest, SecondSetKeepsFirstValueIfTooLarge) {
unsigned char buf[MAX_VALUE_SIZE + 1] = {0xee, 0xee, 0xee, 0xee};
- mBC->set("abcd", 4, "efgh", 4);
- mBC->set("abcd", 4, buf, MAX_VALUE_SIZE + 1);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
+ ASSERT_EQ(BlobCache::InsertResult::kValueTooBig, mBC->set("abcd", 4, buf, MAX_VALUE_SIZE + 1));
ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
ASSERT_EQ('e', buf[0]);
ASSERT_EQ('f', buf[1]);
@@ -123,7 +123,7 @@
for (int i = 0; i < MAX_KEY_SIZE + 1; i++) {
key[i] = 'a';
}
- mBC->set(key, MAX_KEY_SIZE + 1, "bbbb", 4);
+ ASSERT_EQ(BlobCache::InsertResult::kKeyTooBig, mBC->set(key, MAX_KEY_SIZE + 1, "bbbb", 4));
ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE + 1, buf, 4));
ASSERT_EQ(0xee, buf[0]);
ASSERT_EQ(0xee, buf[1]);
@@ -136,7 +136,7 @@
for (int i = 0; i < MAX_VALUE_SIZE + 1; i++) {
buf[i] = 'b';
}
- mBC->set("abcd", 4, buf, MAX_VALUE_SIZE + 1);
+ ASSERT_EQ(BlobCache::InsertResult::kValueTooBig, mBC->set("abcd", 4, buf, MAX_VALUE_SIZE + 1));
for (int i = 0; i < MAX_VALUE_SIZE + 1; i++) {
buf[i] = 0xee;
}
@@ -163,7 +163,8 @@
buf[i] = 'b';
}
- mBC->set(key, MAX_KEY_SIZE, buf, MAX_VALUE_SIZE);
+ ASSERT_EQ(BlobCache::InsertResult::kCombinedTooBig,
+ mBC->set(key, MAX_KEY_SIZE, buf, MAX_VALUE_SIZE));
ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE, nullptr, 0));
}
@@ -173,7 +174,7 @@
for (int i = 0; i < MAX_KEY_SIZE; i++) {
key[i] = 'a';
}
- mBC->set(key, MAX_KEY_SIZE, "wxyz", 4);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set(key, MAX_KEY_SIZE, "wxyz", 4));
ASSERT_EQ(size_t(4), mBC->get(key, MAX_KEY_SIZE, buf, 4));
ASSERT_EQ('w', buf[0]);
ASSERT_EQ('x', buf[1]);
@@ -186,7 +187,7 @@
for (int i = 0; i < MAX_VALUE_SIZE; i++) {
buf[i] = 'b';
}
- mBC->set("abcd", 4, buf, MAX_VALUE_SIZE);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, buf, MAX_VALUE_SIZE));
for (int i = 0; i < MAX_VALUE_SIZE; i++) {
buf[i] = 0xee;
}
@@ -212,13 +213,45 @@
buf[i] = 'b';
}
- mBC->set(key, MAX_KEY_SIZE, buf, bufSize);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set(key, MAX_KEY_SIZE, buf, bufSize));
ASSERT_EQ(size_t(bufSize), mBC->get(key, MAX_KEY_SIZE, nullptr, 0));
}
+// Verify that kNotEnoughSpace is returned from BlobCache::set when expected.
+// Note: This relies on internal knowledge of how BlobCache works.
+TEST_F(BlobCacheTest, NotEnoughSpace) {
+ // Insert a small entry into the cache.
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("x", 1, "y", 1));
+
+ // Attempt to put a max size entry into the cache. If the cache were empty,
+ // as in CacheMaxKeyValuePairSizeSucceeds, this would succeed. Based on the
+ // current logic of BlobCache, the small entry is not big enough to allow it
+ // to be cleaned to insert the new entry.
+ ASSERT_TRUE(MAX_KEY_SIZE < MAX_TOTAL_SIZE);
+
+ enum { bufSize = MAX_TOTAL_SIZE - MAX_KEY_SIZE };
+
+ char key[MAX_KEY_SIZE];
+ char buf[bufSize];
+ for (int i = 0; i < MAX_KEY_SIZE; i++) {
+ key[i] = 'a';
+ }
+ for (int i = 0; i < bufSize; i++) {
+ buf[i] = 'b';
+ }
+
+ ASSERT_EQ(BlobCache::InsertResult::kNotEnoughSpace, mBC->set(key, MAX_KEY_SIZE, buf, bufSize));
+ ASSERT_EQ(0, mBC->get(key, MAX_KEY_SIZE, nullptr, 0));
+
+ // The original entry remains in the cache.
+ unsigned char buf2[1] = {0xee};
+ ASSERT_EQ(size_t(1), mBC->get("x", 1, buf2, 1));
+ ASSERT_EQ('y', buf2[0]);
+}
+
TEST_F(BlobCacheTest, CacheMinKeyAndValueSizeSucceeds) {
unsigned char buf[1] = {0xee};
- mBC->set("x", 1, "y", 1);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("x", 1, "y", 1));
ASSERT_EQ(size_t(1), mBC->get("x", 1, buf, 1));
ASSERT_EQ('y', buf[0]);
}
@@ -243,12 +276,12 @@
const int maxEntries = MAX_TOTAL_SIZE / 2;
for (int i = 0; i < maxEntries; i++) {
uint8_t k = i;
- mBC->set(&k, 1, "x", 1);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set(&k, 1, "x", 1));
}
// Insert one more entry, causing a cache overflow.
{
uint8_t k = maxEntries;
- mBC->set(&k, 1, "x", 1);
+ ASSERT_EQ(BlobCache::InsertResult::kDidClean, mBC->set(&k, 1, "x", 1));
}
// Count the number of entries in the cache.
int numCached = 0;
@@ -261,6 +294,14 @@
ASSERT_EQ(maxEntries / 2 + 1, numCached);
}
+TEST_F(BlobCacheTest, InvalidKeySize) {
+ ASSERT_EQ(BlobCache::InsertResult::kInvalidKeySize, mBC->set("", 0, "efgh", 4));
+}
+
+TEST_F(BlobCacheTest, InvalidValueSize) {
+ ASSERT_EQ(BlobCache::InsertResult::kInvalidValueSize, mBC->set("abcd", 4, "", 0));
+}
+
class BlobCacheFlattenTest : public BlobCacheTest {
protected:
virtual void SetUp() {
diff --git a/services/inputflinger/dispatcher/DragState.h b/services/inputflinger/dispatcher/DragState.h
index 4636820..d1c8b8a 100644
--- a/services/inputflinger/dispatcher/DragState.h
+++ b/services/inputflinger/dispatcher/DragState.h
@@ -26,7 +26,8 @@
namespace inputdispatcher {
struct DragState {
- DragState(const sp<android::gui::WindowInfoHandle>& windowHandle) : dragWindow(windowHandle) {}
+ DragState(const sp<android::gui::WindowInfoHandle>& windowHandle, int32_t pointerId)
+ : dragWindow(windowHandle), pointerId(pointerId) {}
void dump(std::string& dump, const char* prefix = "");
// The window being dragged.
@@ -37,6 +38,8 @@
bool isStartDrag = false;
// Indicate if the stylus button is down at the start of the drag.
bool isStylusButtonDownAtStart = false;
+ // Indicate which pointer id is tracked by the drag and drop.
+ const int32_t pointerId;
};
} // namespace inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 1cc4589..7852b30 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -1421,8 +1421,10 @@
// Enable Pointer Capture.
if (haveWindowWithPointerCapture &&
(entry->pointerCaptureRequest == mCurrentPointerCaptureRequest)) {
- LOG_ALWAYS_FATAL("This request to enable Pointer Capture has already been dispatched "
- "to the window.");
+ // This can happen if pointer capture is disabled and re-enabled before we notify the
+ // app of the state change, so there is no need to notify the app.
+ ALOGI("Skipping dispatch of Pointer Capture being enabled: no state change.");
+ return;
}
if (!mCurrentPointerCaptureRequest.enable) {
// This can happen if a window requests capture and immediately releases capture.
@@ -1745,18 +1747,12 @@
}
void InputDispatcher::enqueueDragEventLocked(const sp<WindowInfoHandle>& windowHandle,
- bool isExiting, const MotionEntry& motionEntry) {
- // If the window needs enqueue a drag event, the pointerCount should be 1 and the action should
- // be AMOTION_EVENT_ACTION_MOVE, that could guarantee the first pointer is always valid.
- LOG_ALWAYS_FATAL_IF(motionEntry.pointerCount != 1);
- PointerCoords pointerCoords;
- pointerCoords.copyFrom(motionEntry.pointerCoords[0]);
- pointerCoords.transform(windowHandle->getInfo()->transform);
-
+ bool isExiting, const int32_t rawX,
+ const int32_t rawY) {
+ const vec2 xy = windowHandle->getInfo()->transform.transform(vec2(rawX, rawY));
std::unique_ptr<DragEntry> dragEntry =
- std::make_unique<DragEntry>(mIdGenerator.nextId(), motionEntry.eventTime,
- windowHandle->getToken(), isExiting, pointerCoords.getX(),
- pointerCoords.getY());
+ std::make_unique<DragEntry>(mIdGenerator.nextId(), now(), windowHandle->getToken(),
+ isExiting, xy.x, xy.y);
enqueueInboundEventLocked(std::move(dragEntry));
}
@@ -2544,13 +2540,14 @@
vec2 local = dropWindow->getInfo()->transform.transform(x, y);
sendDropWindowCommandLocked(dropWindow->getToken(), local.x, local.y);
} else {
+ ALOGW("No window found when drop.");
sendDropWindowCommandLocked(nullptr, 0, 0);
}
mDragState.reset();
}
void InputDispatcher::addDragEventLocked(const MotionEntry& entry) {
- if (entry.pointerCount != 1 || !mDragState) {
+ if (!mDragState) {
return;
}
@@ -2560,42 +2557,75 @@
(entry.buttonState & AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) != 0;
}
- int32_t maskedAction = entry.action & AMOTION_EVENT_ACTION_MASK;
- int32_t x = static_cast<int32_t>(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));
- int32_t y = static_cast<int32_t>(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
- if (maskedAction == AMOTION_EVENT_ACTION_MOVE) {
- // Handle the special case : stylus button no longer pressed.
- bool isStylusButtonDown = (entry.buttonState & AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) != 0;
- if (mDragState->isStylusButtonDownAtStart && !isStylusButtonDown) {
- finishDragAndDrop(entry.displayId, x, y);
- return;
+ // Find the pointer index by id.
+ int32_t pointerIndex = 0;
+ for (; static_cast<uint32_t>(pointerIndex) < entry.pointerCount; pointerIndex++) {
+ const PointerProperties& pointerProperties = entry.pointerProperties[pointerIndex];
+ if (pointerProperties.id == mDragState->pointerId) {
+ break;
}
+ }
- // Prevent stylus interceptor windows from affecting drag and drop behavior for now, until
- // we have an explicit reason to support it.
- constexpr bool isStylus = false;
-
- const sp<WindowInfoHandle> hoverWindowHandle =
- findTouchedWindowAtLocked(entry.displayId, x, y, nullptr /*touchState*/, isStylus,
- false /*addOutsideTargets*/, true /*ignoreDragWindow*/);
- // enqueue drag exit if needed.
- if (hoverWindowHandle != mDragState->dragHoverWindowHandle &&
- !haveSameToken(hoverWindowHandle, mDragState->dragHoverWindowHandle)) {
- if (mDragState->dragHoverWindowHandle != nullptr) {
- enqueueDragEventLocked(mDragState->dragHoverWindowHandle, true /*isExiting*/,
- entry);
- }
- mDragState->dragHoverWindowHandle = hoverWindowHandle;
- }
- // enqueue drag location if needed.
- if (hoverWindowHandle != nullptr) {
- enqueueDragEventLocked(hoverWindowHandle, false /*isExiting*/, entry);
- }
- } else if (maskedAction == AMOTION_EVENT_ACTION_UP) {
- finishDragAndDrop(entry.displayId, x, y);
- } else if (maskedAction == AMOTION_EVENT_ACTION_CANCEL) {
+ if (uint32_t(pointerIndex) == entry.pointerCount) {
+ LOG_ALWAYS_FATAL("Should find a valid pointer index by id %d", mDragState->pointerId);
sendDropWindowCommandLocked(nullptr, 0, 0);
mDragState.reset();
+ return;
+ }
+
+ const int32_t maskedAction = entry.action & AMOTION_EVENT_ACTION_MASK;
+ const int32_t x = entry.pointerCoords[pointerIndex].getX();
+ const int32_t y = entry.pointerCoords[pointerIndex].getY();
+
+ switch (maskedAction) {
+ case AMOTION_EVENT_ACTION_MOVE: {
+ // Handle the special case : stylus button no longer pressed.
+ bool isStylusButtonDown =
+ (entry.buttonState & AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) != 0;
+ if (mDragState->isStylusButtonDownAtStart && !isStylusButtonDown) {
+ finishDragAndDrop(entry.displayId, x, y);
+ return;
+ }
+
+ // Prevent stylus interceptor windows from affecting drag and drop behavior for now,
+ // until we have an explicit reason to support it.
+ constexpr bool isStylus = false;
+
+ const sp<WindowInfoHandle> hoverWindowHandle =
+ findTouchedWindowAtLocked(entry.displayId, x, y, nullptr /*touchState*/,
+ isStylus, false /*addOutsideTargets*/,
+ true /*ignoreDragWindow*/);
+ // enqueue drag exit if needed.
+ if (hoverWindowHandle != mDragState->dragHoverWindowHandle &&
+ !haveSameToken(hoverWindowHandle, mDragState->dragHoverWindowHandle)) {
+ if (mDragState->dragHoverWindowHandle != nullptr) {
+ enqueueDragEventLocked(mDragState->dragHoverWindowHandle, true /*isExiting*/, x,
+ y);
+ }
+ mDragState->dragHoverWindowHandle = hoverWindowHandle;
+ }
+ // enqueue drag location if needed.
+ if (hoverWindowHandle != nullptr) {
+ enqueueDragEventLocked(hoverWindowHandle, false /*isExiting*/, x, y);
+ }
+ break;
+ }
+
+ case AMOTION_EVENT_ACTION_POINTER_UP:
+ if (getMotionEventActionPointerIndex(entry.action) != pointerIndex) {
+ break;
+ }
+ // The drag pointer is up.
+ [[fallthrough]];
+ case AMOTION_EVENT_ACTION_UP:
+ finishDragAndDrop(entry.displayId, x, y);
+ break;
+ case AMOTION_EVENT_ACTION_CANCEL: {
+ ALOGD("Receiving cancel when drag and drop.");
+ sendDropWindowCommandLocked(nullptr, 0, 0);
+ mDragState.reset();
+ break;
+ }
}
}
@@ -5115,7 +5145,15 @@
// Store the dragging window.
if (isDragDrop) {
- mDragState = std::make_unique<DragState>(toWindowHandle);
+ if (pointerIds.count() > 1) {
+ ALOGW("The drag and drop cannot be started when there is more than 1 pointer on the"
+ " window.");
+ return false;
+ }
+ // If the window didn't not support split or the source is mouse, the pointerIds count
+ // would be 0, so we have to track the pointer 0.
+ const int32_t id = pointerIds.count() == 0 ? 0 : pointerIds.firstMarkedBit();
+ mDragState = std::make_unique<DragState>(toWindowHandle, id);
}
// Synthesize cancel for old window and down for new window.
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index f3dac19..34aed3b 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -221,7 +221,8 @@
const std::string& reason) REQUIRES(mLock);
// Enqueues a drag event.
void enqueueDragEventLocked(const sp<android::gui::WindowInfoHandle>& windowToken,
- bool isExiting, const MotionEntry& motionEntry) REQUIRES(mLock);
+ bool isExiting, const int32_t rawX, const int32_t rawY)
+ REQUIRES(mLock);
// Adds an event to a queue of recent events for debugging purposes.
void addRecentEventLocked(std::shared_ptr<EventEntry> entry) REQUIRES(mLock);
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 31d331b..9c5a129 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -47,8 +47,8 @@
mEventHub(eventHub),
mPolicy(policy),
mQueuedListener(listener),
- mGlobalMetaState(0),
- mLedMetaState(AMETA_NUM_LOCK_ON),
+ mGlobalMetaState(AMETA_NONE),
+ mLedMetaState(AMETA_NONE),
mGeneration(1),
mNextInputDeviceId(END_RESERVED_ID),
mDisableVirtualKeysTimeout(LLONG_MIN),
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index dc5fcec..a9a4c71 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -27,6 +27,9 @@
namespace android {
+// The default velocity control parameters that has no effect.
+static const VelocityControlParameters FLAT_VELOCITY_CONTROL_PARAMS{};
+
// --- CursorMotionAccumulator ---
CursorMotionAccumulator::CursorMotionAccumulator() {
@@ -154,8 +157,9 @@
mHWheelScale = 1.0f;
}
- if ((!changes && config->pointerCaptureRequest.enable) ||
- (changes & InputReaderConfiguration::CHANGE_POINTER_CAPTURE)) {
+ const bool configurePointerCapture = (!changes && config->pointerCaptureRequest.enable) ||
+ (changes & InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
+ if (configurePointerCapture) {
if (config->pointerCaptureRequest.enable) {
if (mParameters.mode == Parameters::MODE_POINTER) {
mParameters.mode = Parameters::MODE_POINTER_RELATIVE;
@@ -180,10 +184,18 @@
}
}
- if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) {
- mPointerVelocityControl.setParameters(config->pointerVelocityControlParameters);
- mWheelXVelocityControl.setParameters(config->wheelVelocityControlParameters);
- mWheelYVelocityControl.setParameters(config->wheelVelocityControlParameters);
+ if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED) ||
+ configurePointerCapture) {
+ if (config->pointerCaptureRequest.enable) {
+ // Disable any acceleration or scaling when Pointer Capture is enabled.
+ mPointerVelocityControl.setParameters(FLAT_VELOCITY_CONTROL_PARAMS);
+ mWheelXVelocityControl.setParameters(FLAT_VELOCITY_CONTROL_PARAMS);
+ mWheelYVelocityControl.setParameters(FLAT_VELOCITY_CONTROL_PARAMS);
+ } else {
+ mPointerVelocityControl.setParameters(config->pointerVelocityControlParameters);
+ mWheelXVelocityControl.setParameters(config->wheelVelocityControlParameters);
+ mWheelYVelocityControl.setParameters(config->wheelVelocityControlParameters);
+ }
}
if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index c1934ff..637b1cb 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -1657,9 +1657,8 @@
dispatchPointerUsage(when, readTime, policyFlags, pointerUsage);
} else {
- updateTouchSpots();
-
if (!mCurrentMotionAborted) {
+ updateTouchSpots();
dispatchButtonRelease(when, readTime, policyFlags);
dispatchHoverExit(when, readTime, policyFlags);
dispatchTouches(when, readTime, policyFlags);
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index a167271..61e5fe3 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -5671,6 +5671,25 @@
mWindow->consumeCaptureEvent(true);
}
+TEST_F(InputDispatcherPointerCaptureTests, RapidToggleRequests) {
+ requestAndVerifyPointerCapture(mWindow, true);
+
+ // App toggles pointer capture off and on.
+ mDispatcher->requestPointerCapture(mWindow->getToken(), false);
+ mFakePolicy->assertSetPointerCaptureCalled(false);
+
+ mDispatcher->requestPointerCapture(mWindow->getToken(), true);
+ auto enableRequest = mFakePolicy->assertSetPointerCaptureCalled(true);
+
+ // InputReader notifies that the latest "enable" request was processed, while skipping over the
+ // preceding "disable" request.
+ notifyPointerCaptureChanged(enableRequest);
+
+ // Since pointer capture was never disabled during the rapid toggle, the window does not receive
+ // any notifications.
+ mWindow->assertNoEvents();
+}
+
class InputDispatcherUntrustedTouchesTest : public InputDispatcherTest {
protected:
constexpr static const float MAXIMUM_OBSCURING_OPACITY = 0.8;
@@ -6091,8 +6110,7 @@
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}}});
}
- // Start performing drag, we will create a drag window and transfer touch to it.
- void performDrag() {
+ void injectDown() {
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
{50, 50}))
@@ -6100,6 +6118,15 @@
// Window should receive motion event.
mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ }
+
+ // Start performing drag, we will create a drag window and transfer touch to it.
+ // @param sendDown : if true, send a motion down on first window before perform drag and drop.
+ // Returns true on success.
+ bool performDrag(bool sendDown = true) {
+ if (sendDown) {
+ injectDown();
+ }
// The drag window covers the entire display
mDragWindow = new FakeWindowHandle(mApp, mDispatcher, "DragWindow", ADISPLAY_ID_DEFAULT);
@@ -6107,10 +6134,14 @@
{{ADISPLAY_ID_DEFAULT, {mDragWindow, mWindow, mSecondWindow}}});
// Transfer touch focus to the drag window
- mDispatcher->transferTouchFocus(mWindow->getToken(), mDragWindow->getToken(),
- true /* isDragDrop */);
- mWindow->consumeMotionCancel();
- mDragWindow->consumeMotionDown();
+ bool transferred =
+ mDispatcher->transferTouchFocus(mWindow->getToken(), mDragWindow->getToken(),
+ true /* isDragDrop */);
+ if (transferred) {
+ mWindow->consumeMotionCancel();
+ mDragWindow->consumeMotionDown();
+ }
+ return transferred;
}
// Start performing drag, we will create a drag window and transfer touch to it.
@@ -6257,7 +6288,7 @@
mSecondWindow->assertNoEvents();
}
-TEST_F(InputDispatcherDragTests, DragAndDrop_InvalidWindow) {
+TEST_F(InputDispatcherDragTests, DragAndDropOnInvalidWindow) {
performDrag();
// Set second window invisible.
@@ -6293,6 +6324,89 @@
mSecondWindow->assertNoEvents();
}
+TEST_F(InputDispatcherDragTests, NoDragAndDropWhenMultiFingers) {
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {50, 50}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+
+ const MotionEvent secondFingerDownEvent =
+ MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+ .displayId(ADISPLAY_ID_DEFAULT)
+ .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+ .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
+ .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(75).y(50))
+ .build();
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
+ InputEventInjectionSync::WAIT_FOR_RESULT))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ mWindow->consumeMotionPointerDown(1 /* pointerIndex */);
+
+ // Should not perform drag and drop when window has multi fingers.
+ ASSERT_FALSE(performDrag(false));
+}
+
+TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouch) {
+ // First down on second window.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {150, 50}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+ mSecondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+
+ // Second down on first window.
+ const MotionEvent secondFingerDownEvent =
+ MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+ .displayId(ADISPLAY_ID_DEFAULT)
+ .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+ .pointer(
+ PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(50))
+ .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
+ .build();
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
+ InputEventInjectionSync::WAIT_FOR_RESULT))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+
+ // Perform drag and drop from first window.
+ ASSERT_TRUE(performDrag(false));
+
+ // Move on window.
+ const MotionEvent secondFingerMoveEvent =
+ MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
+ .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+ .pointer(
+ PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(50))
+ .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
+ .build();
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT,
+ InputEventInjectionSync::WAIT_FOR_RESULT));
+ mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT);
+ mWindow->consumeDragEvent(false, 50, 50);
+ mSecondWindow->consumeMotionMove();
+
+ // Release the drag pointer should perform drop.
+ const MotionEvent secondFingerUpEvent =
+ MotionEventBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
+ .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+ .pointer(
+ PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(50))
+ .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
+ .build();
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT,
+ InputEventInjectionSync::WAIT_FOR_RESULT));
+ mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT);
+ mFakePolicy->assertDropTargetEquals(mWindow->getToken());
+ mWindow->assertNoEvents();
+ mSecondWindow->consumeMotionMove();
+}
+
class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {};
TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) {
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index bda7755..a26a0bc 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -375,6 +375,11 @@
float getPointerGestureMovementSpeedRatio() { return mConfig.pointerGestureMovementSpeedRatio; }
+ void setVelocityControlParams(const VelocityControlParameters& params) {
+ mConfig.pointerVelocityControlParameters = params;
+ mConfig.wheelVelocityControlParameters = params;
+ }
+
private:
uint32_t mNextPointerCaptureSequenceNumber = 0;
@@ -2949,7 +2954,10 @@
}
void configureDevice(uint32_t changes) {
- if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
+ if (!changes ||
+ (changes &
+ (InputReaderConfiguration::CHANGE_DISPLAY_INFO |
+ InputReaderConfiguration::CHANGE_POINTER_CAPTURE))) {
mReader->requestRefreshConfiguration(changes);
mReader->loopOnce();
}
@@ -3364,9 +3372,8 @@
KeyboardInputMapper& mapper =
addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
AINPUT_KEYBOARD_TYPE_ALPHABETIC);
- // Initial metastate to AMETA_NONE.
- ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper.getMetaState());
- mapper.updateMetaState(AKEYCODE_NUM_LOCK);
+ // Initial metastate is AMETA_NONE.
+ ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
// Key down by scan code.
process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_HOME, 1);
@@ -3491,9 +3498,8 @@
addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
AINPUT_KEYBOARD_TYPE_ALPHABETIC);
- // Initial metastate to AMETA_NONE.
- ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper.getMetaState());
- mapper.updateMetaState(AKEYCODE_NUM_LOCK);
+ // Initial metastate is AMETA_NONE.
+ ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
// Metakey down.
process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_LEFTSHIFT, 1);
@@ -3738,9 +3744,8 @@
KeyboardInputMapper& mapper =
addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
AINPUT_KEYBOARD_TYPE_ALPHABETIC);
- // Initialize metastate to AMETA_NUM_LOCK_ON.
- ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper.getMetaState());
- mapper.updateMetaState(AKEYCODE_NUM_LOCK);
+ // Initial metastate is AMETA_NONE.
+ ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
// Initialization should have turned all of the lights off.
ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
@@ -3806,8 +3811,6 @@
addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC);
- // Initial metastate should be AMETA_NONE as no meta keys added.
- ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
// Meta state should be AMETA_NONE after reset
mapper.reset(ARBITRARY_TIME);
ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
@@ -3922,9 +3925,8 @@
KeyboardInputMapper& mapper =
addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
AINPUT_KEYBOARD_TYPE_ALPHABETIC);
- // Initial metastate to AMETA_NONE.
- ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper.getMetaState());
- mapper.updateMetaState(AKEYCODE_NUM_LOCK);
+ // Initial metastate is AMETA_NONE.
+ ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
// Initialization should have turned all of the lights off.
ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
@@ -3991,9 +3993,8 @@
KeyboardInputMapper& mapper =
addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
AINPUT_KEYBOARD_TYPE_ALPHABETIC);
- // Initialize metastate to AMETA_NUM_LOCK_ON.
- ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper.getMetaState());
- mapper.updateMetaState(AKEYCODE_NUM_LOCK);
+ // Initial metastate is AMETA_NONE.
+ ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
mReader->toggleCapsLockState(DEVICE_ID);
ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper.getMetaState());
@@ -4033,7 +4034,13 @@
device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0 /*changes*/);
device2->reset(ARBITRARY_TIME);
- // Initial metastate is AMETA_NUM_LOCK_ON, turn it off.
+ // Initial metastate is AMETA_NONE.
+ ASSERT_EQ(AMETA_NONE, mapper1.getMetaState());
+ ASSERT_EQ(AMETA_NONE, mapper2.getMetaState());
+
+ // Toggle num lock on and off.
+ process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 1);
+ process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 0);
ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper1.getMetaState());
ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper2.getMetaState());
@@ -4914,6 +4921,54 @@
ASSERT_NO_FATAL_FAILURE(assertPosition(*mFakePointerController, 110.0f, 220.0f));
}
+/**
+ * When Pointer Capture is enabled, we expect to report unprocessed relative movements, so any
+ * pointer acceleration or speed processing should not be applied.
+ */
+TEST_F(CursorInputMapperTest, PointerCaptureDisablesVelocityProcessing) {
+ addConfigurationProperty("cursor.mode", "pointer");
+ const VelocityControlParameters testParams(5.f /*scale*/, 0.f /*low threshold*/,
+ 100.f /*high threshold*/, 10.f /*acceleration*/);
+ mFakePolicy->setVelocityControlParams(testParams);
+ CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
+
+ NotifyDeviceResetArgs resetArgs;
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
+ ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime);
+ ASSERT_EQ(DEVICE_ID, resetArgs.deviceId);
+
+ NotifyMotionArgs args;
+
+ // Move and verify scale is applied.
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 10);
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_Y, 20);
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AINPUT_SOURCE_MOUSE, args.source);
+ ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, args.action);
+ const float relX = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
+ const float relY = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
+ ASSERT_GT(relX, 10);
+ ASSERT_GT(relY, 20);
+
+ // Enable Pointer Capture
+ mFakePolicy->setPointerCapture(true);
+ configureDevice(InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
+ NotifyPointerCaptureChangedArgs captureArgs;
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyCaptureWasCalled(&captureArgs));
+ ASSERT_TRUE(captureArgs.request.enable);
+
+ // Move and verify scale is not applied.
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 10);
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_Y, 20);
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AINPUT_SOURCE_MOUSE_RELATIVE, args.source);
+ ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
+ ASSERT_EQ(10, args.pointerCoords[0].getX());
+ ASSERT_EQ(20, args.pointerCoords[0].getY());
+}
+
TEST_F(CursorInputMapperTest, Process_ShouldHandleDisplayId) {
CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
diff --git a/services/sensorservice/BatteryService.cpp b/services/sensorservice/BatteryService.cpp
index 14f9a12..94de55c 100644
--- a/services/sensorservice/BatteryService.cpp
+++ b/services/sensorservice/BatteryService.cpp
@@ -74,23 +74,6 @@
}
}
-void BatteryService::cleanupImpl(uid_t uid) {
- if (checkService()) {
- Mutex::Autolock _l(mActivationsLock);
- int64_t identity = IPCThreadState::self()->clearCallingIdentity();
- for (size_t i=0 ; i<mActivations.size() ; ) {
- const Info& info(mActivations[i]);
- if (info.uid == uid) {
- mBatteryStatService->noteStopSensor(info.uid, info.handle);
- mActivations.removeAt(i);
- } else {
- i++;
- }
- }
- IPCThreadState::self()->restoreCallingIdentity(identity);
- }
-}
-
bool BatteryService::checkService() {
if (mBatteryStatService == nullptr) {
const sp<IServiceManager> sm(defaultServiceManager());
diff --git a/services/sensorservice/BatteryService.h b/services/sensorservice/BatteryService.h
index 09eb2c1..13fc58a 100644
--- a/services/sensorservice/BatteryService.h
+++ b/services/sensorservice/BatteryService.h
@@ -32,7 +32,6 @@
void enableSensorImpl(uid_t uid, int handle);
void disableSensorImpl(uid_t uid, int handle);
- void cleanupImpl(uid_t uid);
struct Info {
uid_t uid;
@@ -58,9 +57,6 @@
static void disableSensor(uid_t uid, int handle) {
BatteryService::getInstance().disableSensorImpl(uid, handle);
}
- static void cleanup(uid_t uid) {
- BatteryService::getInstance().cleanupImpl(uid);
- }
};
// ---------------------------------------------------------------------------
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 53a3025..de050e0 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -612,8 +612,10 @@
return SENSORS_DEVICE_API_VERSION_1_4;
}
-status_t SensorDevice::flush(void* /*ident*/, int handle) {
+status_t SensorDevice::flush(void* ident, int handle) {
if (mHalWrapper == nullptr) return NO_INIT;
+ if (isClientDisabled(ident)) return INVALID_OPERATION;
+ ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w flush %d", handle);
return mHalWrapper->flush(handle);
}
@@ -754,6 +756,13 @@
status_t SensorDevice::injectSensorData(const sensors_event_t* injected_sensor_event) {
if (mHalWrapper == nullptr) return NO_INIT;
+ ALOGD_IF(DEBUG_CONNECTIONS,
+ "sensor_event handle=%d ts=%" PRId64 " data=%.2f, %.2f, %.2f %.2f %.2f %.2f",
+ injected_sensor_event->sensor, injected_sensor_event->timestamp,
+ injected_sensor_event->data[0], injected_sensor_event->data[1],
+ injected_sensor_event->data[2], injected_sensor_event->data[3],
+ injected_sensor_event->data[4], injected_sensor_event->data[5]);
+
return mHalWrapper->injectSensorData(injected_sensor_event);
}
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 8b81d48..88cf5ab 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -1611,7 +1611,9 @@
} else {
ALOGE("sensor interface of handle=0x%08x is null!", handle);
}
- c->removeSensor(handle);
+ if (c->removeSensor(handle)) {
+ BatteryService::disableSensor(c->getUid(), handle);
+ }
}
SensorRecord* rec = mActiveSensors.valueAt(i);
ALOGE_IF(!rec, "mActiveSensors[%zu] is null (handle=0x%08x)!", i, handle);
@@ -1631,7 +1633,6 @@
}
c->updateLooperRegistration(mLooper);
mConnectionHolder.removeEventConnection(connection);
- BatteryService::cleanup(c->getUid());
if (c->needsWakeLock()) {
checkWakeLockStateLocked(&connLock);
}
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 5846e67..db2fd1b 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -267,6 +267,9 @@
// Enables predicting composition strategy to run client composition earlier
virtual void setPredictCompositionStrategy(bool) = 0;
+ // Enables overriding the 170M trasnfer function as sRGB
+ virtual void setTreat170mAsSrgb(bool) = 0;
+
protected:
virtual void setDisplayColorProfile(std::unique_ptr<DisplayColorProfile>) = 0;
virtual void setRenderSurface(std::unique_ptr<RenderSurface>) = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h
index a63145a..49013e0 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h
@@ -120,16 +120,16 @@
} // namespace compositionengine
-inline std::string to_string(const android::compositionengine::ProjectionSpace& space) {
- return android::base::
- StringPrintf("ProjectionSpace(bounds = %s, content = %s, orientation = %s)",
- to_string(space.getBoundsAsRect()).c_str(),
- to_string(space.getContent()).c_str(), toCString(space.getOrientation()));
+inline std::string to_string(const compositionengine::ProjectionSpace& space) {
+ return base::StringPrintf("ProjectionSpace{bounds=%s, content=%s, orientation=%s}",
+ to_string(space.getBoundsAsRect()).c_str(),
+ to_string(space.getContent()).c_str(),
+ toCString(space.getOrientation()));
}
// Defining PrintTo helps with Google Tests.
-inline void PrintTo(const android::compositionengine::ProjectionSpace& space, ::std::ostream* os) {
+inline void PrintTo(const compositionengine::ProjectionSpace& space, std::ostream* os) {
*os << to_string(space);
}
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 0feb9f7..31c51e6 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -108,6 +108,7 @@
void cacheClientCompositionRequests(uint32_t) override;
bool canPredictCompositionStrategy(const CompositionRefreshArgs&) override;
void setPredictCompositionStrategy(bool) override;
+ void setTreat170mAsSrgb(bool) override;
// Testing
const ReleasedLayers& getReleasedLayersForTest() const;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index 5fa0d67..c65d467 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -155,11 +155,15 @@
SUCCESS = 1,
// Composition strategy prediction failed for this frame.
FAIL = 2,
+
+ ftl_last = FAIL
};
CompositionStrategyPredictionState strategyPrediction =
CompositionStrategyPredictionState::DISABLED;
+ bool treat170mAsSrgb = false;
+
// Debugging
void dump(std::string& result) const;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
index d64d676..ecd432f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -60,7 +60,7 @@
std::vector<LayerFE::LayerSettings> getOverrideCompositionList() const override;
void dump(std::string&) const override;
- virtual FloatRect calculateOutputSourceCrop() const;
+ virtual FloatRect calculateOutputSourceCrop(uint32_t internalDisplayRotationFlags) const;
virtual Rect calculateOutputDisplayFrame() const;
virtual uint32_t calculateOutputRelativeBufferTransform(
uint32_t internalDisplayRotationFlags) const;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index fa86076..cb9fbad 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -132,6 +132,7 @@
MOCK_METHOD1(cacheClientCompositionRequests, void(uint32_t));
MOCK_METHOD1(canPredictCompositionStrategy, bool(const CompositionRefreshArgs&));
MOCK_METHOD1(setPredictCompositionStrategy, void(bool));
+ MOCK_METHOD1(setTreat170mAsSrgb, void(bool));
};
} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index f545886..b79b46b 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -131,15 +131,11 @@
}
void Display::dump(std::string& out) const {
- using android::base::StringAppendF;
+ const char* const type = isVirtual() ? "virtual" : "physical";
+ base::StringAppendF(&out, "Display %s (%s, \"%s\")", to_string(mId).c_str(), type,
+ getName().c_str());
- StringAppendF(&out, " Composition Display State: [\"%s\"]", getName().c_str());
-
- out.append("\n ");
- dumpVal(out, "isVirtual", isVirtual());
- dumpVal(out, "DisplayId", to_string(mId));
- out.append("\n");
-
+ out.append("\n Composition Display State:\n");
Output::dumpBase(out);
}
diff --git a/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
index 01c368d..290c710 100644
--- a/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
@@ -89,7 +89,6 @@
void dumpVal(std::string& out, const char* name, const ui::Transform& transform) {
transform.dump(out, name);
- out.append(" ");
}
void dumpVal(std::string& out, const char* name, const mat4& tr) {
@@ -99,7 +98,7 @@
"[%0.3f,%0.3f,%0.3f,%0.3f]"
"[%0.3f,%0.3f,%0.3f,%0.3f]"
"[%0.3f,%0.3f,%0.3f,%0.3f]"
- "[%0.3f,%0.3f,%0.3f,%0.3f]]",
+ "[%0.3f,%0.3f,%0.3f,%0.3f]] ",
name,
tr[0][0], tr[1][0], tr[2][0], tr[3][0],
tr[0][1], tr[1][1], tr[2][1], tr[3][1],
@@ -109,9 +108,9 @@
}
void dumpVal(std::string& out, const char* name, const StretchEffect& effect) {
- StringAppendF(&out, "%s={ width =%f, height = %f, vec=(%f, %f), max=(%f, %f) } ", name,
- effect.width, effect.height,
- effect.vectorX, effect.vectorY, effect.maxAmountX, effect.maxAmountY);
+ StringAppendF(&out, "%s={width=%f, height=%f, vec=(%f, %f), max=(%f, %f)} ", name, effect.width,
+ effect.height, effect.vectorX, effect.vectorY, effect.maxAmountX,
+ effect.maxAmountY);
}
} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 004e071..4c30f99 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -294,17 +294,15 @@
}
void Output::dump(std::string& out) const {
- using android::base::StringAppendF;
-
- StringAppendF(&out, " Composition Output State: [\"%s\"]", mName.c_str());
-
- out.append("\n ");
+ base::StringAppendF(&out, "Output \"%s\"", mName.c_str());
+ out.append("\n Composition Output State:\n");
dumpBase(out);
}
void Output::dumpBase(std::string& out) const {
dumpState(out);
+ out += '\n';
if (mDisplayColorProfile) {
mDisplayColorProfile->dump(out);
@@ -312,13 +310,15 @@
out.append(" No display color profile!\n");
}
+ out += '\n';
+
if (mRenderSurface) {
mRenderSurface->dump(out);
} else {
out.append(" No render surface!\n");
}
- android::base::StringAppendF(&out, "\n %zu Layers\n", getOutputLayerCount());
+ base::StringAppendF(&out, "\n %zu Layers\n", getOutputLayerCount());
for (const auto* outputLayer : getOutputLayersOrderedByZ()) {
if (!outputLayer) {
continue;
@@ -329,7 +329,7 @@
void Output::dumpPlannerInfo(const Vector<String16>& args, std::string& out) const {
if (!mPlanner) {
- base::StringAppendF(&out, "Planner is disabled\n");
+ out.append("Planner is disabled\n");
return;
}
base::StringAppendF(&out, "Planner info for display [%s]\n", mName.c_str());
@@ -1488,6 +1488,10 @@
}
}
+void Output::setTreat170mAsSrgb(bool enable) {
+ editState().treat170mAsSrgb = enable;
+}
+
bool Output::canPredictCompositionStrategy(const CompositionRefreshArgs& refreshArgs) {
if (!getState().isEnabled || !mHwComposerAsyncWorker) {
ALOGV("canPredictCompositionStrategy disabled");
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
index 7188281..948c0c9 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
@@ -14,40 +14,30 @@
* limitations under the License.
*/
+#include <ftl/enum.h>
+
#include <compositionengine/impl/DumpHelpers.h>
#include <compositionengine/impl/OutputCompositionState.h>
namespace android::compositionengine::impl {
-using CompositionStrategyPredictionState =
- OutputCompositionState::CompositionStrategyPredictionState;
-
-std::string toString(CompositionStrategyPredictionState state) {
- switch (state) {
- case CompositionStrategyPredictionState::DISABLED:
- return "Disabled";
- case CompositionStrategyPredictionState::SUCCESS:
- return "Success";
- case CompositionStrategyPredictionState::FAIL:
- return "Fail";
- }
-}
void OutputCompositionState::dump(std::string& out) const {
out.append(" ");
dumpVal(out, "isEnabled", isEnabled);
dumpVal(out, "isSecure", isSecure);
-
- dumpVal(out, "usesClientComposition", usesClientComposition);
dumpVal(out, "usesDeviceComposition", usesDeviceComposition);
+
+ out.append("\n ");
+ dumpVal(out, "usesClientComposition", usesClientComposition);
dumpVal(out, "flipClientTarget", flipClientTarget);
dumpVal(out, "reusedClientComposition", reusedClientComposition);
- dumpVal(out, "layerFilter", layerFilter);
out.append("\n ");
-
+ dumpVal(out, "layerFilter", layerFilter);
+ out.append("\n ");
dumpVal(out, "transform", transform);
- out.append("\n ");
+ out.append(" "); // ui::Transform::dump appends EOL.
dumpVal(out, "layerStackSpace", to_string(layerStackSpace));
out.append("\n ");
dumpVal(out, "framebufferSpace", to_string(framebufferSpace));
@@ -59,19 +49,27 @@
dumpVal(out, "needsFiltering", needsFiltering);
out.append("\n ");
-
dumpVal(out, "colorMode", toString(colorMode), colorMode);
dumpVal(out, "renderIntent", toString(renderIntent), renderIntent);
dumpVal(out, "dataspace", toString(dataspace), dataspace);
+ dumpVal(out, "targetDataspace", toString(targetDataspace), targetDataspace);
+
+ out.append("\n ");
dumpVal(out, "colorTransformMatrix", colorTransformMatrix);
- dumpVal(out, "target dataspace", toString(targetDataspace), targetDataspace);
+
+ out.append("\n ");
dumpVal(out, "displayBrightnessNits", displayBrightnessNits);
dumpVal(out, "sdrWhitePointNits", sdrWhitePointNits);
dumpVal(out, "clientTargetBrightness", clientTargetBrightness);
dumpVal(out, "displayBrightness", displayBrightness);
- dumpVal(out, "compositionStrategyPredictionState", toString(strategyPrediction));
- out.append("\n");
+ out.append("\n ");
+ dumpVal(out, "compositionStrategyPredictionState", ftl::enum_string(strategyPrediction));
+
+ out.append("\n ");
+ dumpVal(out, "treate170mAsSrgb", treat170mAsSrgb);
+
+ out += '\n';
}
} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 3289d55..5ffbb7f 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -106,9 +106,8 @@
return activeCrop;
}
-FloatRect OutputLayer::calculateOutputSourceCrop() const {
+FloatRect OutputLayer::calculateOutputSourceCrop(uint32_t internalDisplayRotationFlags) const {
const auto& layerState = *getLayerFE().getCompositionState();
- const auto& outputState = getOutput().getState();
if (!layerState.geomUsesSourceCrop) {
return {};
@@ -140,8 +139,7 @@
* the code below applies the primary display's inverse transform to the
* buffer
*/
- uint32_t invTransformOrient =
- ui::Transform::toRotationFlags(outputState.displaySpace.getOrientation());
+ uint32_t invTransformOrient = internalDisplayRotationFlags;
// calculate the inverse transform
if (invTransformOrient & HAL_TRANSFORM_ROT_90) {
invTransformOrient ^= HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_FLIP_H;
@@ -304,7 +302,7 @@
state.forceClientComposition = false;
state.displayFrame = calculateOutputDisplayFrame();
- state.sourceCrop = calculateOutputSourceCrop();
+ state.sourceCrop = calculateOutputSourceCrop(internalDisplayRotationFlags);
state.bufferTransform = static_cast<Hwc2::Transform>(
calculateOutputRelativeBufferTransform(internalDisplayRotationFlags));
@@ -322,6 +320,17 @@
? outputState.targetDataspace
: layerFEState->dataspace;
+ // Override the dataspace transfer from 170M to sRGB if the device configuration requests this.
+ // We do this here instead of in buffer info so that dumpsys can still report layers that are
+ // using the 170M transfer. Also we only do this if the colorspace is not agnostic for the
+ // layer, in case the color profile uses a 170M transfer function.
+ if (outputState.treat170mAsSrgb && !layerFEState->isColorspaceAgnostic &&
+ (state.dataspace & HAL_DATASPACE_TRANSFER_MASK) == HAL_DATASPACE_TRANSFER_SMPTE_170M) {
+ state.dataspace = static_cast<ui::Dataspace>(
+ (state.dataspace & HAL_DATASPACE_STANDARD_MASK) |
+ (state.dataspace & HAL_DATASPACE_RANGE_MASK) | HAL_DATASPACE_TRANSFER_SRGB);
+ }
+
// For hdr content, treat the white point as the display brightness - HDR content should not be
// boosted or dimmed.
// If the layer explicitly requests to disable dimming, then don't dim either.
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index ceee48c..7038e8c 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -169,7 +169,7 @@
FloatRect calculateOutputSourceCrop() {
mLayerFEState.geomInverseLayerTransform = mLayerFEState.geomLayerTransform.inverse();
- return mOutputLayer.calculateOutputSourceCrop();
+ return mOutputLayer.calculateOutputSourceCrop(ui::Transform::RotationFlags::ROT_0);
}
};
@@ -533,7 +533,7 @@
sp<compositionengine::LayerFE> layerFE)
: mOutput(output), mLayerFE(layerFE) {}
// Mock everything called by updateCompositionState to simplify testing it.
- MOCK_CONST_METHOD0(calculateOutputSourceCrop, FloatRect());
+ MOCK_CONST_METHOD1(calculateOutputSourceCrop, FloatRect(uint32_t));
MOCK_CONST_METHOD0(calculateOutputDisplayFrame, Rect());
MOCK_CONST_METHOD1(calculateOutputRelativeBufferTransform, uint32_t(uint32_t));
@@ -563,7 +563,8 @@
~OutputLayerUpdateCompositionStateTest() = default;
void setupGeometryChildCallValues(ui::Transform::RotationFlags internalDisplayRotationFlags) {
- EXPECT_CALL(mOutputLayer, calculateOutputSourceCrop()).WillOnce(Return(kSourceCrop));
+ EXPECT_CALL(mOutputLayer, calculateOutputSourceCrop(internalDisplayRotationFlags))
+ .WillOnce(Return(kSourceCrop));
EXPECT_CALL(mOutputLayer, calculateOutputDisplayFrame()).WillOnce(Return(kDisplayFrame));
EXPECT_CALL(mOutputLayer,
calculateOutputRelativeBufferTransform(internalDisplayRotationFlags))
@@ -657,6 +658,23 @@
EXPECT_EQ(ui::Dataspace::V0_SCRGB, mOutputLayer.getState().dataspace);
}
+TEST_F(OutputLayerUpdateCompositionStateTest, setsOutputLayerColorspaceWith170mReplacement) {
+ mLayerFEState.dataspace = ui::Dataspace::TRANSFER_SMPTE_170M;
+ mOutputState.targetDataspace = ui::Dataspace::V0_SCRGB;
+ mOutputState.treat170mAsSrgb = false;
+ mLayerFEState.isColorspaceAgnostic = false;
+
+ mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0);
+
+ EXPECT_EQ(ui::Dataspace::TRANSFER_SMPTE_170M, mOutputLayer.getState().dataspace);
+
+ // Rewrite SMPTE 170M as sRGB
+ mOutputState.treat170mAsSrgb = true;
+ mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0);
+
+ EXPECT_EQ(ui::Dataspace::TRANSFER_SRGB, mOutputLayer.getState().dataspace);
+}
+
TEST_F(OutputLayerUpdateCompositionStateTest, setsWhitePointNitsAndDimmingRatioCorrectly) {
mOutputState.sdrWhitePointNits = 200.f;
mOutputState.displayBrightnessNits = 800.f;
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 42c8b37..862ab1d 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -248,6 +248,20 @@
}
/*
+ * Output::setTreat170mAsSrgb()
+ */
+
+TEST_F(OutputTest, setTreat170mAsSrgb) {
+ EXPECT_FALSE(mOutput->getState().treat170mAsSrgb);
+
+ mOutput->setTreat170mAsSrgb(true);
+ EXPECT_TRUE(mOutput->getState().treat170mAsSrgb);
+
+ mOutput->setTreat170mAsSrgb(false);
+ EXPECT_FALSE(mOutput->getState().treat170mAsSrgb);
+}
+
+/*
* Output::setLayerCachingEnabled()
*/
@@ -3354,7 +3368,6 @@
static constexpr float kDefaultMaxLuminance = 0.9f;
static constexpr float kDefaultAvgLuminance = 0.7f;
static constexpr float kDefaultMinLuminance = 0.1f;
- static constexpr float kUnknownLuminance = -1.f;
static constexpr float kDisplayLuminance = 400.f;
static constexpr float kClientTargetLuminanceNits = 200.f;
static constexpr float kClientTargetBrightness = 0.5f;
@@ -3752,7 +3765,7 @@
TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forHdrMixedComposition) {
verify().ifMixedCompositionIs(true)
.andIfUsesHdr(true)
- .withDisplayBrightnessNits(kUnknownLuminance)
+ .withDisplayBrightnessNits(kDisplayLuminance)
.withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
.withRenderIntent(
aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
@@ -3761,7 +3774,7 @@
{.physicalDisplay = kDefaultOutputDestinationClip,
.clip = kDefaultOutputViewport,
.maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDisplayLuminance,
.outputDataspace = kDefaultOutputDataspace,
.colorTransform = kDefaultColorTransformMat,
.deviceHandlesColorTransform = true,
@@ -3806,7 +3819,7 @@
forHdrMixedCompositionWithDimmingStage) {
verify().ifMixedCompositionIs(true)
.andIfUsesHdr(true)
- .withDisplayBrightnessNits(kUnknownLuminance)
+ .withDisplayBrightnessNits(kDisplayLuminance)
.withDimmingStage(
aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF)
.withRenderIntent(
@@ -3816,7 +3829,7 @@
{.physicalDisplay = kDefaultOutputDestinationClip,
.clip = kDefaultOutputViewport,
.maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDisplayLuminance,
.outputDataspace = kDefaultOutputDataspace,
.colorTransform = kDefaultColorTransformMat,
.deviceHandlesColorTransform = true,
@@ -3834,7 +3847,7 @@
forHdrMixedCompositionWithRenderIntent) {
verify().ifMixedCompositionIs(true)
.andIfUsesHdr(true)
- .withDisplayBrightnessNits(kUnknownLuminance)
+ .withDisplayBrightnessNits(kDisplayLuminance)
.withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
.withRenderIntent(aidl::android::hardware::graphics::composer3::RenderIntent::ENHANCE)
.andIfSkipColorTransform(false)
@@ -3842,7 +3855,7 @@
{.physicalDisplay = kDefaultOutputDestinationClip,
.clip = kDefaultOutputViewport,
.maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDisplayLuminance,
.outputDataspace = kDefaultOutputDataspace,
.colorTransform = kDefaultColorTransformMat,
.deviceHandlesColorTransform = true,
@@ -3859,7 +3872,7 @@
TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forNonHdrMixedComposition) {
verify().ifMixedCompositionIs(true)
.andIfUsesHdr(false)
- .withDisplayBrightnessNits(kUnknownLuminance)
+ .withDisplayBrightnessNits(kDisplayLuminance)
.withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
.withRenderIntent(
aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
@@ -3868,7 +3881,7 @@
{.physicalDisplay = kDefaultOutputDestinationClip,
.clip = kDefaultOutputViewport,
.maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDisplayLuminance,
.outputDataspace = kDefaultOutputDataspace,
.colorTransform = kDefaultColorTransformMat,
.deviceHandlesColorTransform = true,
@@ -3885,7 +3898,7 @@
TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forHdrOnlyClientComposition) {
verify().ifMixedCompositionIs(false)
.andIfUsesHdr(true)
- .withDisplayBrightnessNits(kUnknownLuminance)
+ .withDisplayBrightnessNits(kDisplayLuminance)
.withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
.withRenderIntent(
aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
@@ -3894,7 +3907,7 @@
{.physicalDisplay = kDefaultOutputDestinationClip,
.clip = kDefaultOutputViewport,
.maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDisplayLuminance,
.outputDataspace = kDefaultOutputDataspace,
.colorTransform = kDefaultColorTransformMat,
.deviceHandlesColorTransform = false,
@@ -3911,7 +3924,7 @@
TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forNonHdrOnlyClientComposition) {
verify().ifMixedCompositionIs(false)
.andIfUsesHdr(false)
- .withDisplayBrightnessNits(kUnknownLuminance)
+ .withDisplayBrightnessNits(kDisplayLuminance)
.withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
.withRenderIntent(
aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
@@ -3920,7 +3933,7 @@
{.physicalDisplay = kDefaultOutputDestinationClip,
.clip = kDefaultOutputViewport,
.maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDisplayLuminance,
.outputDataspace = kDefaultOutputDataspace,
.colorTransform = kDefaultColorTransformMat,
.deviceHandlesColorTransform = false,
@@ -3938,7 +3951,7 @@
usesExpectedDisplaySettingsForHdrOnlyClientCompositionWithSkipClientTransform) {
verify().ifMixedCompositionIs(false)
.andIfUsesHdr(true)
- .withDisplayBrightnessNits(kUnknownLuminance)
+ .withDisplayBrightnessNits(kDisplayLuminance)
.withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
.withRenderIntent(
aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
@@ -3947,7 +3960,7 @@
{.physicalDisplay = kDefaultOutputDestinationClip,
.clip = kDefaultOutputViewport,
.maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDisplayLuminance,
.outputDataspace = kDefaultOutputDataspace,
.colorTransform = kDefaultColorTransformMat,
.deviceHandlesColorTransform = true,
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 65e7a7f..a915b61 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -24,7 +24,6 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include <android-base/stringprintf.h>
#include <compositionengine/CompositionEngine.h>
#include <compositionengine/Display.h>
#include <compositionengine/DisplayColorProfile.h>
@@ -49,8 +48,6 @@
namespace hal = hardware::graphics::composer::hal;
-using android::base::StringAppendF;
-
ui::Transform::RotationFlags DisplayDevice::sPrimaryDisplayRotationFlags = ui::Transform::ROT_0;
DisplayDeviceCreationArgs::DisplayDeviceCreationArgs(
@@ -92,6 +89,7 @@
}
mCompositionDisplay->setPredictCompositionStrategy(mFlinger->mPredictCompositionStrategy);
+ mCompositionDisplay->setTreat170mAsSrgb(mFlinger->mTreat170mAsSrgb);
mCompositionDisplay->createDisplayColorProfile(
compositionengine::DisplayColorProfileCreationArgsBuilder()
.setHasWideColorGamut(args.hasWideColorGamut)
@@ -342,38 +340,40 @@
}
std::string DisplayDevice::getDebugName() const {
- const char* type = "virtual";
+ using namespace std::string_literals;
+
+ std::string name = "Display "s + to_string(getId()) + " ("s;
+
if (mConnectionType) {
- type = isInternal() ? "internal" : "external";
+ name += isInternal() ? "internal"s : "external"s;
+ } else {
+ name += "virtual"s;
}
- return base::StringPrintf("DisplayDevice{%s, %s%s, \"%s\"}", to_string(getId()).c_str(), type,
- isPrimary() ? ", primary" : "", mDisplayName.c_str());
+ if (isPrimary()) {
+ name += ", primary"s;
+ }
+
+ return name + ", \""s + mDisplayName + "\")"s;
}
void DisplayDevice::dump(std::string& result) const {
- StringAppendF(&result, "+ %s\n", getDebugName().c_str());
- StringAppendF(&result, " powerMode=%s (%d)\n", to_string(mPowerMode).c_str(),
- static_cast<int32_t>(mPowerMode));
- const auto activeMode = getActiveMode();
- StringAppendF(&result, " activeMode=%s\n",
- activeMode ? to_string(*activeMode).c_str() : "none");
+ using namespace std::string_literals;
- result.append(" supportedModes=\n");
- for (const auto& [id, mode] : mSupportedModes) {
- result.append(" ");
- result.append(to_string(*mode));
- result.push_back('\n');
+ result += getDebugName();
+
+ if (!isVirtual()) {
+ result += "\n deviceProductInfo="s;
+ if (mDeviceProductInfo) {
+ mDeviceProductInfo->dump(result);
+ } else {
+ result += "{}"s;
+ }
}
- StringAppendF(&result, " deviceProductInfo=");
- if (mDeviceProductInfo) {
- mDeviceProductInfo->dump(result);
- } else {
- result.append("{}");
- }
- result.append("\n");
- getCompositionDisplay()->dump(result);
+ result += "\n powerMode="s;
+ result += to_string(mPowerMode);
+ result += '\n';
if (mRefreshRateConfigs) {
mRefreshRateConfigs->dump(result);
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 8d685cf..eb14933 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -44,18 +44,10 @@
#include "HWComposer.h"
#include "../SurfaceFlinger.h"
-// ----------------------------------------------------------------------------
namespace android {
-// ----------------------------------------------------------------------------
using ui::Dataspace;
-/*
- * This implements the (main) framebuffer management. This class is used
- * mostly by SurfaceFlinger, but also by command line GL application.
- *
- */
-
FramebufferSurface::FramebufferSurface(HWComposer& hwc, PhysicalDisplayId displayId,
const sp<IGraphicBufferConsumer>& consumer,
const ui::Size& size, const ui::Size& maxSize)
@@ -205,14 +197,14 @@
void FramebufferSurface::dumpAsString(String8& result) const {
Mutex::Autolock lock(mMutex);
- result.appendFormat(" FramebufferSurface: dataspace: %s(%d)\n",
+ result.append(" FramebufferSurface\n");
+ result.appendFormat(" mDataSpace=%s (%d)\n",
dataspaceDetails(static_cast<android_dataspace>(mDataSpace)).c_str(),
mDataSpace);
- ConsumerBase::dumpLocked(result, " ");
+ ConsumerBase::dumpLocked(result, " ");
}
-void FramebufferSurface::dumpLocked(String8& result, const char* prefix) const
-{
+void FramebufferSurface::dumpLocked(String8& result, const char* prefix) const {
ConsumerBase::dumpLocked(result, prefix);
}
@@ -220,9 +212,7 @@
return mCurrentFence;
}
-// ----------------------------------------------------------------------------
-}; // namespace android
-// ----------------------------------------------------------------------------
+} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 670233a..79e4c75 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -376,11 +376,6 @@
}
ATRACE_CALL();
- if (displayData.powerMode == hal::PowerMode::DOZE && enabled == hal::Vsync::ENABLE) {
- ALOGV("%s will not enable vsync for display %s due to power mode %s", __FUNCTION__,
- to_string(displayId).c_str(), to_string(displayData.powerMode).c_str());
- return;
- }
auto error = displayData.hwcDisplay->setVsyncEnabled(enabled);
RETURN_IF_HWC_ERROR(error, displayId);
@@ -557,7 +552,6 @@
setVsyncEnabled(displayId, hal::Vsync::DISABLE);
}
- mDisplayData[displayId].powerMode = mode;
const auto& displayData = mDisplayData[displayId];
auto& hwcDisplay = displayData.hwcDisplay;
switch (mode) {
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 8d67589..7dc10ea 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -462,8 +462,6 @@
std::mutex vsyncEnabledLock;
hal::Vsync vsyncEnabled GUARDED_BY(vsyncEnabledLock) = hal::Vsync::DISABLE;
- hal::PowerMode powerMode = hal::PowerMode::ON;
-
nsecs_t lastHwVsync = 0;
};
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index cbafdd3..659efd8 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -564,6 +564,7 @@
if (!wrapper->shouldReconnectHAL()) {
return wrapper;
}
+ ALOGD("Reconnecting Power HAL");
sHalWrapper = nullptr;
}
@@ -576,7 +577,9 @@
// If that didn't succeed, attempt to connect to the HIDL Power HAL
if (sHalWrapper == nullptr) {
sHalWrapper = HidlPowerHalWrapper::connect();
- } else { // if AIDL, pass on any existing hint session values
+ } else {
+ ALOGD("Successfully connecting AIDL Power HAL");
+ // if AIDL, pass on any existing hint session values
// thread ids always safe to set
sHalWrapper->setPowerHintSessionThreadIds(oldPowerHintSessionThreadIds);
// only set duration and start if duration is defined
diff --git a/services/surfaceflinger/FlagManager.cpp b/services/surfaceflinger/FlagManager.cpp
index bd3cf74..f8ad8f6 100644
--- a/services/surfaceflinger/FlagManager.cpp
+++ b/services/surfaceflinger/FlagManager.cpp
@@ -96,7 +96,8 @@
}
bool FlagManager::use_adpf_cpu_hint() const {
- std::optional<bool> sysPropVal = std::nullopt;
+ std::optional<bool> sysPropVal =
+ doParse<bool>(base::GetProperty("debug.sf.enable_adpf_cpu_hint", "").c_str());
return getValue("AdpfFeature__adpf_cpu_hint", sysPropVal, false);
}
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index d8a5601..e1eec8b 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -47,6 +47,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>
+#include <system/graphics-base-v1.0.h>
#include <ui/DataspaceUtils.h>
#include <ui/DebugUtils.h>
#include <ui/GraphicBuffer.h>
@@ -600,6 +601,18 @@
layerSettings.alpha = alpha;
layerSettings.sourceDataspace = getDataSpace();
+ // Override the dataspace transfer from 170M to sRGB if the device configuration requests this.
+ // We do this here instead of in buffer info so that dumpsys can still report layers that are
+ // using the 170M transfer.
+ if (mFlinger->mTreat170mAsSrgb &&
+ (layerSettings.sourceDataspace & HAL_DATASPACE_TRANSFER_MASK) ==
+ HAL_DATASPACE_TRANSFER_SMPTE_170M) {
+ layerSettings.sourceDataspace = static_cast<ui::Dataspace>(
+ (layerSettings.sourceDataspace & HAL_DATASPACE_STANDARD_MASK) |
+ (layerSettings.sourceDataspace & HAL_DATASPACE_RANGE_MASK) |
+ HAL_DATASPACE_TRANSFER_SRGB);
+ }
+
layerSettings.whitePointNits = targetSettings.whitePointNits;
switch (targetSettings.blurSetting) {
case LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled:
@@ -2664,6 +2677,18 @@
mDrawingState.callbackHandles = {};
}
+bool Layer::setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& handles) {
+ if (handles.empty()) {
+ return false;
+ }
+
+ for (const auto& handle : handles) {
+ mFlinger->getTransactionCallbackInvoker().registerUnpresentedCallbackHandle(handle);
+ }
+
+ return true;
+}
+
// ---------------------------------------------------------------------------
std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 565a6ff..ecea744 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -431,9 +431,7 @@
virtual bool setApi(int32_t /*api*/) { return false; };
virtual bool setSidebandStream(const sp<NativeHandle>& /*sidebandStream*/) { return false; };
virtual bool setTransactionCompletedListeners(
- const std::vector<sp<CallbackHandle>>& /*handles*/) {
- return false;
- };
+ const std::vector<sp<CallbackHandle>>& /*handles*/);
virtual bool addFrameEvent(const sp<Fence>& /*acquireFence*/, nsecs_t /*postedTime*/,
nsecs_t /*requestedPresentTime*/) {
return false;
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 3226f22..ca83496 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -133,9 +133,9 @@
} // namespace
std::string RefreshRateConfigs::Policy::toString() const {
- return base::StringPrintf("default mode ID: %d, allowGroupSwitching = %d"
- ", primary range: %s, app request range: %s",
- defaultMode.value(), allowGroupSwitching,
+ return base::StringPrintf("{defaultModeId=%d, allowGroupSwitching=%s"
+ ", primaryRange=%s, appRequestRange=%s}",
+ defaultMode.value(), allowGroupSwitching ? "true" : "false",
to_string(primaryRange).c_str(), to_string(appRequestRange).c_str());
}
@@ -922,41 +922,46 @@
}
void RefreshRateConfigs::dump(std::string& result) const {
+ using namespace std::string_literals;
+
std::lock_guard lock(mLock);
- base::StringAppendF(&result, "DesiredDisplayModeSpecs (DisplayManager): %s\n\n",
- mDisplayManagerPolicy.toString().c_str());
- scheduler::RefreshRateConfigs::Policy currentPolicy = *getCurrentPolicyLocked();
- if (mOverridePolicy && currentPolicy != mDisplayManagerPolicy) {
- base::StringAppendF(&result, "DesiredDisplayModeSpecs (Override): %s\n\n",
- currentPolicy.toString().c_str());
- }
- base::StringAppendF(&result, "Active mode: %s\n", to_string(*mActiveModeIt->second).c_str());
+ const auto activeModeId = mActiveModeIt->first;
+ result += " activeModeId="s;
+ result += std::to_string(activeModeId.value());
- result.append("Display modes:\n");
+ result += "\n displayModes=\n"s;
for (const auto& [id, mode] : mDisplayModes) {
- result.push_back('\t');
- result.append(to_string(*mode));
- result.push_back('\n');
+ result += " "s;
+ result += to_string(*mode);
+ result += '\n';
}
- base::StringAppendF(&result, "Supports Frame Rate Override By Content: %s\n",
- mSupportsFrameRateOverrideByContent ? "yes" : "no");
+ base::StringAppendF(&result, " displayManagerPolicy=%s\n",
+ mDisplayManagerPolicy.toString().c_str());
- result.append("Idle timer: ");
- if (const auto controller = mConfig.kernelIdleTimerController) {
- base::StringAppendF(&result, "(kernel via %s) ", ftl::enum_string(*controller).c_str());
- } else {
- result.append("(platform) ");
+ if (const Policy& currentPolicy = *getCurrentPolicyLocked();
+ mOverridePolicy && currentPolicy != mDisplayManagerPolicy) {
+ base::StringAppendF(&result, " overridePolicy=%s\n", currentPolicy.toString().c_str());
}
+ base::StringAppendF(&result, " supportsFrameRateOverrideByContent=%s\n",
+ mSupportsFrameRateOverrideByContent ? "true" : "false");
+
+ result += " idleTimer="s;
if (mIdleTimer) {
- result.append(mIdleTimer->dump());
+ result += mIdleTimer->dump();
} else {
- result.append("off");
+ result += "off"s;
}
- result.append("\n\n");
+ if (const auto controller = mConfig.kernelIdleTimerController) {
+ base::StringAppendF(&result, " (kernel via %s)", ftl::enum_string(*controller).c_str());
+ } else {
+ result += " (platform)"s;
+ }
+
+ result += '\n';
}
std::chrono::milliseconds RefreshRateConfigs::getIdleTimerTimeout() {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index ccd218d..e6b64c1 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -419,6 +419,9 @@
property_get("debug.sf.predict_hwc_composition_strategy", value, "1");
mPredictCompositionStrategy = atoi(value);
+ property_get("debug.sf.treat_170m_as_sRGB", value, "0");
+ mTreat170mAsSrgb = atoi(value);
+
// We should be reading 'persist.sys.sf.color_saturation' here
// but since /data may be encrypted, we need to wait until after vold
// comes online to attempt to read the property. The property is
@@ -583,14 +586,8 @@
std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIdsLocked() const {
std::vector<PhysicalDisplayId> displayIds;
displayIds.reserve(mPhysicalDisplayTokens.size());
- const auto defaultDisplayId = [this]() REQUIRES(mStateLock) {
- if (const auto display = getDefaultDisplayDeviceLocked()) {
- return display->getPhysicalId();
- }
- // fallback to the internal display id if the active display is unknown
- return getInternalDisplayIdLocked();
- }();
+ const auto defaultDisplayId = getDefaultDisplayDeviceLocked()->getPhysicalId();
displayIds.push_back(defaultDisplayId);
for (const auto& [id, token] : mPhysicalDisplayTokens) {
@@ -604,7 +601,7 @@
status_t SurfaceFlinger::getPrimaryPhysicalDisplayId(PhysicalDisplayId* id) const {
Mutex::Autolock lock(mStateLock);
- *id = getInternalDisplayIdLocked();
+ *id = getPrimaryDisplayIdLocked();
return NO_ERROR;
}
@@ -681,8 +678,12 @@
readPersistentProperties();
mPowerAdvisor->onBootFinished();
- mPowerAdvisor->enablePowerHint(mFlagManager.use_adpf_cpu_hint());
- if (mPowerAdvisor->usePowerHintSession()) {
+ const bool powerHintEnabled = mFlagManager.use_adpf_cpu_hint();
+ mPowerAdvisor->enablePowerHint(powerHintEnabled);
+ const bool powerHintUsed = mPowerAdvisor->usePowerHintSession();
+ ALOGD("Power hint is %s",
+ powerHintUsed ? "supported" : (powerHintEnabled ? "unsupported" : "disabled"));
+ if (powerHintUsed) {
std::optional<pid_t> renderEngineTid = getRenderEngine().getRenderEngineTid();
std::vector<int32_t> tidList;
tidList.emplace_back(gettid());
@@ -1315,17 +1316,25 @@
}
status_t SurfaceFlinger::getDisplayNativePrimaries(const sp<IBinder>& displayToken,
- ui::DisplayPrimaries &primaries) {
+ ui::DisplayPrimaries& primaries) {
if (!displayToken) {
return BAD_VALUE;
}
- // Currently we only support this API for a single internal display.
- if (getInternalDisplayToken() != displayToken) {
+ Mutex::Autolock lock(mStateLock);
+
+ const auto display = getDisplayDeviceLocked(displayToken);
+ if (!display) {
return NAME_NOT_FOUND;
}
- memcpy(&primaries, &mInternalDisplayPrimaries, sizeof(ui::DisplayPrimaries));
+ const auto connectionType = display->getConnectionType();
+ if (connectionType != ui::DisplayConnectionType::Internal) {
+ return INVALID_OPERATION;
+ }
+
+ // TODO(b/229846990): For now, assume that all internal displays have the same primaries.
+ primaries = mInternalDisplayPrimaries;
return NO_ERROR;
}
@@ -2826,7 +2835,7 @@
}
if (const auto id = PhysicalDisplayId::tryCast(compositionDisplay->getId())) {
- creationArgs.isPrimary = id == getInternalDisplayIdLocked();
+ creationArgs.isPrimary = id == getPrimaryDisplayIdLocked();
if (useColorManagement) {
std::vector<ColorMode> modes = getHwComposer().getColorModes(*id);
@@ -3466,6 +3475,15 @@
l->latchAndReleaseBuffer();
}
+ // If a layer has a parent, we allow it to out-live it's handle
+ // with the idea that the parent holds a reference and will eventually
+ // be cleaned up. However no one cleans up the top-level so we do so
+ // here.
+ if (l->isAtRoot()) {
+ l->setIsAtRoot(false);
+ mCurrentState.layersSortedByZ.remove(l);
+ }
+
// If the layer has been removed and has no parent, then it will not be reachable
// when traversing layers on screen. Add the layer to the offscreenLayers set to
// ensure we can copy its current to drawing state.
@@ -3703,12 +3721,13 @@
auto& transaction = transactionQueue.front();
const auto ready =
- transactionIsReadyToBeApplied(transaction.frameTimelineInfo,
- transaction.isAutoTimestamp,
- transaction.desiredPresentTime,
- transaction.originUid, transaction.states,
- bufferLayersReadyToPresent, transactions.size(),
- tryApplyUnsignaled);
+ transactionIsReadyToBeApplied(transaction,
+ transaction.frameTimelineInfo,
+ transaction.isAutoTimestamp,
+ transaction.desiredPresentTime,
+ transaction.originUid, transaction.states,
+ bufferLayersReadyToPresent, transactions.size(),
+ tryApplyUnsignaled);
ATRACE_INT("TransactionReadiness", static_cast<int>(ready));
if (ready == TransactionReadiness::NotReady) {
setTransactionFlags(eTransactionFlushNeeded);
@@ -3785,7 +3804,7 @@
return TransactionReadiness::NotReady;
}
- return transactionIsReadyToBeApplied(transaction.frameTimelineInfo,
+ return transactionIsReadyToBeApplied(transaction, transaction.frameTimelineInfo,
transaction.isAutoTimestamp,
transaction.desiredPresentTime,
transaction.originUid, transaction.states,
@@ -3947,7 +3966,7 @@
return true;
}
-auto SurfaceFlinger::transactionIsReadyToBeApplied(
+auto SurfaceFlinger::transactionIsReadyToBeApplied(TransactionState& transaction,
const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime,
uid_t originUid, const Vector<ComposerState>& states,
const std::unordered_map<
@@ -3976,8 +3995,10 @@
}
bool fenceUnsignaled = false;
+ auto queueProcessTime = systemTime();
for (const ComposerState& state : states) {
const layer_state_t& s = state.state;
+
sp<Layer> layer = nullptr;
if (s.surface) {
layer = fromHandle(s.surface).promote();
@@ -4013,6 +4034,15 @@
s.bufferData->acquireFence->getStatus() == Fence::Status::Unsignaled);
if (fenceUnsignaled && !allowLatchUnsignaled) {
+ if (!transaction.sentFenceTimeoutWarning &&
+ queueProcessTime - transaction.queueTime > std::chrono::nanoseconds(4s).count()) {
+ transaction.sentFenceTimeoutWarning = true;
+ auto listener = s.bufferData->releaseBufferListener;
+ if (listener) {
+ listener->onTransactionQueueStalled();
+ }
+ }
+
ATRACE_NAME("fence unsignaled");
return TransactionReadiness::NotReady;
}
@@ -4032,6 +4062,8 @@
}
void SurfaceFlinger::queueTransaction(TransactionState& state) {
+ state.queueTime = systemTime();
+
Mutex::Autolock lock(mQueueLock);
// Generate a CountDownLatch pending state if this is a synchronous transaction.
@@ -4756,14 +4788,6 @@
void SurfaceFlinger::onHandleDestroyed(BBinder* handle, sp<Layer>& layer) {
Mutex::Autolock lock(mStateLock);
- // If a layer has a parent, we allow it to out-live it's handle
- // with the idea that the parent holds a reference and will eventually
- // be cleaned up. However no one cleans up the top-level so we do so
- // here.
- if (layer->isAtRoot()) {
- layer->setIsAtRoot(false);
- mCurrentState.layersSortedByZ.remove(layer);
- }
markLayerPendingRemovalLocked(layer);
mBufferCountTracker.remove(handle);
layer.clear();
@@ -4945,7 +4969,9 @@
pid, uid);
} else {
static const std::unordered_map<std::string, Dumper> dumpers = {
+ {"--comp-displays"s, dumper(&SurfaceFlinger::dumpCompositionDisplays)},
{"--display-id"s, dumper(&SurfaceFlinger::dumpDisplayIdentificationData)},
+ {"--displays"s, dumper(&SurfaceFlinger::dumpDisplays)},
{"--dispsync"s, dumper([this](std::string& s) { mScheduler->dumpVsync(s); })},
{"--edid"s, argsDumper(&SurfaceFlinger::dumpRawDisplayIdentificationData)},
{"--frame-events"s, dumper(&SurfaceFlinger::dumpFrameEventsLocked)},
@@ -5122,6 +5148,20 @@
[&] (Layer* layer) { layer->dumpFrameEvents(result); });
}
+void SurfaceFlinger::dumpCompositionDisplays(std::string& result) const {
+ for (const auto& [token, display] : mDisplays) {
+ display->getCompositionDisplay()->dump(result);
+ result += '\n';
+ }
+}
+
+void SurfaceFlinger::dumpDisplays(std::string& result) const {
+ for (const auto& [token, display] : mDisplays) {
+ display->dump(result);
+ result += '\n';
+ }
+}
+
void SurfaceFlinger::dumpDisplayIdentificationData(std::string& result) const {
for (const auto& [token, display] : mDisplays) {
const auto displayId = PhysicalDisplayId::tryCast(display->getId());
@@ -5330,21 +5370,12 @@
});
}
- /*
- * Dump Display state
- */
-
colorizer.bold(result);
StringAppendF(&result, "Displays (%zu entries)\n", mDisplays.size());
colorizer.reset(result);
- for (const auto& [token, display] : mDisplays) {
- display->dump(result);
- }
- result.append("\n");
-
- /*
- * Dump CompositionEngine state
- */
+ dumpDisplays(result);
+ dumpCompositionDisplays(result);
+ result.push_back('\n');
mCompositionEngine->dump(result);
@@ -6696,6 +6727,9 @@
auto dataspace = renderArea.getReqDataSpace();
auto parent = renderArea.getParentLayer();
auto renderIntent = RenderIntent::TONE_MAP_COLORIMETRIC;
+ auto sdrWhitePointNits = DisplayDevice::sDefaultMaxLumiance;
+ auto displayBrightnessNits = DisplayDevice::sDefaultMaxLumiance;
+
if ((dataspace == ui::Dataspace::UNKNOWN) && (parent != nullptr)) {
Mutex::Autolock lock(mStateLock);
auto display = findDisplay([layerStack = parent->getLayerStack()](const auto& display) {
@@ -6709,6 +6743,8 @@
const ui::ColorMode colorMode = display->getCompositionDisplay()->getState().colorMode;
dataspace = pickDataspaceFromColorMode(colorMode);
renderIntent = display->getCompositionDisplay()->getState().renderIntent;
+ sdrWhitePointNits = display->getCompositionDisplay()->getState().sdrWhitePointNits;
+ displayBrightnessNits = display->getCompositionDisplay()->getState().displayBrightnessNits;
}
captureResults.capturedDataspace = dataspace;
@@ -6767,7 +6803,7 @@
BlurSetting::Disabled
: compositionengine::LayerFE::ClientCompositionTargetSettings::
BlurSetting::Enabled,
- DisplayDevice::sDefaultMaxLumiance,
+ isHdrLayer(layer) ? displayBrightnessNits : sdrWhitePointNits,
};
std::vector<compositionengine::LayerFE::LayerSettings> results =
@@ -6782,6 +6818,7 @@
if (regionSampling) {
settings.backgroundBlurRadius = 0;
}
+ captureResults.capturedHdrLayers |= isHdrLayer(layer);
}
clientCompositionLayers.insert(clientCompositionLayers.end(),
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 011aaef..fc27b62 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -349,6 +349,12 @@
// run parallel to the hwc validateDisplay call and re-run if the predition is incorrect.
bool mPredictCompositionStrategy = false;
+ // If true, then any layer with a SMPTE 170M transfer function is decoded using the sRGB
+ // transfer instead. This is mainly to preserve legacy behavior, where implementations treated
+ // SMPTE 170M as sRGB prior to color management being implemented, and now implementations rely
+ // on this behavior to increase contrast for some media sources.
+ bool mTreat170mAsSrgb = false;
+
protected:
// We're reference counted, never destroy SurfaceFlinger directly
virtual ~SurfaceFlinger();
@@ -525,19 +531,6 @@
bool callingThreadHasUnscopedSurfaceFlingerAccess(bool usePermissionCache = true)
EXCLUDES(mStateLock);
- // the following two methods are moved from ISurfaceComposer.h
- // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
- std::optional<PhysicalDisplayId> getInternalDisplayId() const {
- const auto displayIds = getPhysicalDisplayIds();
- return displayIds.empty() ? std::nullopt : std::make_optional(displayIds.front());
- }
-
- // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
- sp<IBinder> getInternalDisplayToken() const {
- const auto displayId = getInternalDisplayId();
- return displayId ? getPhysicalDisplayToken(*displayId) : nullptr;
- }
-
// Implements ISurfaceComposer
sp<ISurfaceComposerClient> createConnection() override;
sp<IBinder> createDisplay(const String8& displayName, bool secure);
@@ -816,7 +809,7 @@
Ready,
ReadyUnsignaled,
};
- TransactionReadiness transactionIsReadyToBeApplied(
+ TransactionReadiness transactionIsReadyToBeApplied(TransactionState& state,
const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime,
uid_t originUid, const Vector<ComposerState>& states,
const std::unordered_map<
@@ -922,6 +915,13 @@
return nullptr;
}
+ sp<const DisplayDevice> getDisplayDeviceLocked(DisplayId id) const REQUIRES(mStateLock) {
+ // TODO(b/182939859): Replace tokens with IDs for display lookup.
+ return findDisplay([id](const auto& display) { return display.getId() == id; });
+ }
+
+ // Returns the primary display or (for foldables) the active display, assuming that the inner
+ // and outer displays have mutually exclusive power states.
sp<const DisplayDevice> getDefaultDisplayDeviceLocked() const REQUIRES(mStateLock) {
return const_cast<SurfaceFlinger*>(this)->getDefaultDisplayDeviceLocked();
}
@@ -930,12 +930,9 @@
if (const auto display = getDisplayDeviceLocked(mActiveDisplayToken)) {
return display;
}
- // The active display is outdated, fall back to the internal display
+ // The active display is outdated, so fall back to the primary display.
mActiveDisplayToken.clear();
- if (const auto token = getInternalDisplayTokenLocked()) {
- return getDisplayDeviceLocked(token);
- }
- return nullptr;
+ return getDisplayDeviceLocked(getPrimaryDisplayTokenLocked());
}
sp<const DisplayDevice> getDefaultDisplayDevice() const EXCLUDES(mStateLock) {
@@ -952,11 +949,6 @@
return it == mDisplays.end() ? nullptr : it->second;
}
- sp<const DisplayDevice> getDisplayDeviceLocked(DisplayId id) const REQUIRES(mStateLock) {
- // TODO(b/182939859): Replace tokens with IDs for display lookup.
- return findDisplay([id](const auto& display) { return display.getId() == id; });
- }
-
std::vector<PhysicalDisplayId> getPhysicalDisplayIdsLocked() const REQUIRES(mStateLock);
// mark a region of a layer stack dirty. this updates the dirty
@@ -1066,18 +1058,17 @@
return {};
}
- // TODO(b/182939859): SF conflates the primary (a.k.a. default) display with the first display
- // connected at boot, which is typically internal. (Theoretically, it must be internal because
- // SF does not support disconnecting it, though in practice HWC may circumvent this limitation.)
+ // Returns the first display connected at boot.
//
- // SF inherits getInternalDisplayToken and getInternalDisplayId from ISurfaceComposer, so these
- // locked counterparts are named consistently. Once SF supports headless mode and can designate
- // any display as primary, the "internal" misnomer will be phased out.
- sp<IBinder> getInternalDisplayTokenLocked() const REQUIRES(mStateLock) {
- return getPhysicalDisplayTokenLocked(getInternalDisplayIdLocked());
+ // TODO(b/229851933): SF conflates the primary display with the first display connected at boot,
+ // which typically has DisplayConnectionType::Internal. (Theoretically, it must be an internal
+ // display because SF does not support disconnecting it, though in practice HWC may circumvent
+ // this limitation.)
+ sp<IBinder> getPrimaryDisplayTokenLocked() const REQUIRES(mStateLock) {
+ return getPhysicalDisplayTokenLocked(getPrimaryDisplayIdLocked());
}
- PhysicalDisplayId getInternalDisplayIdLocked() const REQUIRES(mStateLock) {
+ PhysicalDisplayId getPrimaryDisplayIdLocked() const REQUIRES(mStateLock) {
return getHwComposer().getPrimaryDisplayId();
}
@@ -1109,9 +1100,13 @@
void dumpStaticScreenStats(std::string& result) const;
// Not const because each Layer needs to query Fences and cache timestamps.
void dumpFrameEventsLocked(std::string& result);
+
+ void dumpCompositionDisplays(std::string& result) const REQUIRES(mStateLock);
+ void dumpDisplays(std::string& result) const REQUIRES(mStateLock);
void dumpDisplayIdentificationData(std::string& result) const REQUIRES(mStateLock);
void dumpRawDisplayIdentificationData(const DumpArgs&, std::string& result) const;
void dumpWideColorInfo(std::string& result) const REQUIRES(mStateLock);
+
LayersProto dumpDrawingStateProto(uint32_t traceFlags) const;
void dumpOffscreenLayersProto(LayersProto& layersProto,
uint32_t traceFlags = LayerTracing::TRACE_ALL) const;
diff --git a/services/surfaceflinger/TransactionState.h b/services/surfaceflinger/TransactionState.h
index bab5326..900d566 100644
--- a/services/surfaceflinger/TransactionState.h
+++ b/services/surfaceflinger/TransactionState.h
@@ -98,6 +98,8 @@
int originUid;
uint64_t id;
std::shared_ptr<CountDownLatch> transactionCommittedSignal;
+ int64_t queueTime = 0;
+ bool sentFenceTimeoutWarning = false;
};
class CountDownLatch {
diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp
index 8a2305b..219db8c 100644
--- a/services/surfaceflinger/tests/LayerCallback_test.cpp
+++ b/services/surfaceflinger/tests/LayerCallback_test.cpp
@@ -55,24 +55,34 @@
return createLayer(mClient, "test", 0, 0, ISurfaceComposerClient::eFXSurfaceBufferState);
}
+ static int fillBuffer(Transaction& transaction, const sp<SurfaceControl>& layer,
+ bool setBuffer = true, bool setBackgroundColor = false) {
+ sp<GraphicBuffer> buffer;
+ sp<Fence> fence;
+ if (setBuffer) {
+ int err = getBuffer(&buffer, &fence);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ transaction.setBuffer(layer, buffer, fence);
+ }
+
+ if (setBackgroundColor) {
+ transaction.setBackgroundColor(layer, /*color*/ half3(1.0f, 0, 0), /*alpha*/ 1.0f,
+ ui::Dataspace::UNKNOWN);
+ }
+
+ return NO_ERROR;
+ }
+
static int fillTransaction(Transaction& transaction, CallbackHelper* callbackHelper,
const sp<SurfaceControl>& layer = nullptr, bool setBuffer = true,
bool setBackgroundColor = false) {
if (layer) {
- sp<GraphicBuffer> buffer;
- sp<Fence> fence;
- if (setBuffer) {
- int err = getBuffer(&buffer, &fence);
- if (err != NO_ERROR) {
- return err;
- }
-
- transaction.setBuffer(layer, buffer, fence);
- }
-
- if (setBackgroundColor) {
- transaction.setBackgroundColor(layer, /*color*/ half3(1.0f, 0, 0), /*alpha*/ 1.0f,
- ui::Dataspace::UNKNOWN);
+ int err = fillBuffer(transaction, layer, setBuffer, setBackgroundColor);
+ if (err != NO_ERROR) {
+ return err;
}
}
@@ -1115,7 +1125,7 @@
Transaction transaction;
CallbackHelper callback;
int err = fillTransaction(transaction, &callback, layer, true);
- err |= fillTransaction(transaction, &callback, offscreenLayer, true);
+ err |= fillBuffer(transaction, offscreenLayer);
if (err) {
GTEST_SUCCEED() << "test not supported";
return;
@@ -1129,5 +1139,86 @@
committedSc.insert(layer);
committedSc.insert(offscreenLayer);
EXPECT_NO_FATAL_FAILURE(waitForCommitCallback(callback, committedSc));
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, offscreenLayer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
}
+
+TEST_F(LayerCallbackTest, TransactionCommittedCallback_BSL) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback, layer, true);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ transaction.addTransactionCommittedCallback(callback.function, callback.getContext()).apply();
+ std::unordered_set<sp<SurfaceControl>, SCHash> committedSc;
+ committedSc.insert(layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCommitCallback(callback, committedSc));
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, TransactionCommittedCallback_EffectLayer) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createColorLayer("ColorLayer", Color::RED));
+
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ transaction.addTransactionCommittedCallback(callback.function, callback.getContext()).apply();
+ std::unordered_set<sp<SurfaceControl>, SCHash> committedSc;
+ EXPECT_NO_FATAL_FAILURE(waitForCommitCallback(callback, committedSc));
+
+ ExpectedResult expected;
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, TransactionCommittedCallback_ContainerLayer) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer(mClient, "Container Layer", 0, 0,
+ ISurfaceComposerClient::eFXSurfaceContainer));
+
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ transaction.addTransactionCommittedCallback(callback.function, callback.getContext()).apply();
+ std::unordered_set<sp<SurfaceControl>, SCHash> committedSc;
+ EXPECT_NO_FATAL_FAILURE(waitForCommitCallback(callback, committedSc));
+
+ ExpectedResult expected;
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, TransactionCommittedCallback_NoLayer) {
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ transaction.addTransactionCommittedCallback(callback.function, callback.getContext()).apply();
+ std::unordered_set<sp<SurfaceControl>, SCHash> committedSc;
+ EXPECT_NO_FATAL_FAILURE(waitForCommitCallback(callback, committedSc));
+
+ ExpectedResult expected;
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
} // namespace android
diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp
index f9b3185..6a7d8b8 100644
--- a/services/surfaceflinger/tests/ScreenCapture_test.cpp
+++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp
@@ -112,7 +112,7 @@
args.captureSecureLayers = true;
ASSERT_EQ(NO_ERROR, ScreenCapture::captureDisplay(args, mCaptureResults));
ASSERT_TRUE(mCaptureResults.capturedSecureLayers);
- ScreenCapture sc(mCaptureResults.buffer);
+ ScreenCapture sc(mCaptureResults.buffer, mCaptureResults.capturedHdrLayers);
sc.expectColor(Rect(0, 0, 32, 32), Color::RED);
}
@@ -147,7 +147,7 @@
args.captureSecureLayers = true;
ASSERT_EQ(NO_ERROR, ScreenCapture::captureDisplay(args, mCaptureResults));
ASSERT_TRUE(mCaptureResults.capturedSecureLayers);
- ScreenCapture sc(mCaptureResults.buffer);
+ ScreenCapture sc(mCaptureResults.buffer, mCaptureResults.capturedHdrLayers);
sc.expectColor(Rect(0, 0, 10, 10), Color::BLUE);
}
@@ -374,7 +374,7 @@
ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::RED, 32, 32));
SurfaceComposerClient::Transaction().apply(true);
ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(args, captureResults));
- ScreenCapture sc(captureResults.buffer);
+ ScreenCapture sc(captureResults.buffer, captureResults.capturedHdrLayers);
sc.expectColor(Rect(0, 0, 9, 9), Color::RED);
}
@@ -860,6 +860,46 @@
mCapture->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
+TEST_F(ScreenCaptureTest, CaptureNonHdrLayer) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test layer", 32, 32,
+ ISurfaceComposerClient::eFXSurfaceBufferState,
+ mBGSurfaceControl.get()));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::BLACK, 32, 32));
+ Transaction()
+ .show(layer)
+ .setLayer(layer, INT32_MAX)
+ .setDataspace(layer, ui::Dataspace::V0_SRGB)
+ .apply();
+
+ LayerCaptureArgs captureArgs;
+ captureArgs.layerHandle = layer->getHandle();
+
+ ScreenCapture::captureLayers(&mCapture, captureArgs);
+ mCapture->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ ASSERT_FALSE(mCapture->capturedHdrLayers());
+}
+
+TEST_F(ScreenCaptureTest, CaptureHdrLayer) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test layer", 32, 32,
+ ISurfaceComposerClient::eFXSurfaceBufferState,
+ mBGSurfaceControl.get()));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::BLACK, 32, 32));
+ Transaction()
+ .show(layer)
+ .setLayer(layer, INT32_MAX)
+ .setDataspace(layer, ui::Dataspace::BT2020_ITU_PQ)
+ .apply();
+
+ LayerCaptureArgs captureArgs;
+ captureArgs.layerHandle = layer->getHandle();
+
+ ScreenCapture::captureLayers(&mCapture, captureArgs);
+ mCapture->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ ASSERT_TRUE(mCapture->capturedHdrLayers());
+}
+
// In the following tests we verify successful skipping of a parent layer,
// so we use the same verification logic and only change how we mutate
// the parent layer to verify that various properties are ignored.
diff --git a/services/surfaceflinger/tests/TransactionTestHarnesses.h b/services/surfaceflinger/tests/TransactionTestHarnesses.h
index 60cffb1..8ce63bc 100644
--- a/services/surfaceflinger/tests/TransactionTestHarnesses.h
+++ b/services/surfaceflinger/tests/TransactionTestHarnesses.h
@@ -79,7 +79,8 @@
BufferItem item;
itemConsumer->acquireBuffer(&item, 0, true);
- auto sc = std::make_unique<ScreenCapture>(item.mGraphicBuffer);
+ constexpr bool kContainsHdr = false;
+ auto sc = std::make_unique<ScreenCapture>(item.mGraphicBuffer, kContainsHdr);
itemConsumer->releaseBuffer(item);
SurfaceComposerClient::destroyDisplay(vDisplay);
return sc;
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
index 0a157c4..8de9e4b 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
@@ -130,8 +130,7 @@
ON_CALL(*mPowerAdvisor, usePowerHintSession()).WillByDefault(Return(true));
const std::chrono::nanoseconds mockVsyncPeriod = 15ms;
- const std::chrono::nanoseconds expectedTargetTime = 14ms;
- EXPECT_CALL(*mPowerAdvisor, setTargetWorkDuration(Gt(expectedTargetTime.count()))).Times(1);
+ EXPECT_CALL(*mPowerAdvisor, setTargetWorkDuration(_)).Times(1);
const nsecs_t now = systemTime();
const std::chrono::nanoseconds mockHwcRunTime = 20ms;
diff --git a/services/surfaceflinger/tests/utils/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
index ee7e92c..f879430 100644
--- a/services/surfaceflinger/tests/utils/ScreenshotUtils.h
+++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
@@ -60,7 +60,8 @@
DisplayCaptureArgs& captureArgs) {
ScreenCaptureResults captureResults;
ASSERT_EQ(NO_ERROR, captureDisplay(captureArgs, captureResults));
- *sc = std::make_unique<ScreenCapture>(captureResults.buffer);
+ *sc = std::make_unique<ScreenCapture>(captureResults.buffer,
+ captureResults.capturedHdrLayers);
}
static status_t captureLayers(LayerCaptureArgs& captureArgs,
@@ -81,9 +82,12 @@
static void captureLayers(std::unique_ptr<ScreenCapture>* sc, LayerCaptureArgs& captureArgs) {
ScreenCaptureResults captureResults;
ASSERT_EQ(NO_ERROR, captureLayers(captureArgs, captureResults));
- *sc = std::make_unique<ScreenCapture>(captureResults.buffer);
+ *sc = std::make_unique<ScreenCapture>(captureResults.buffer,
+ captureResults.capturedHdrLayers);
}
+ bool capturedHdrLayers() const { return mContainsHdr; }
+
void expectColor(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
ASSERT_NE(nullptr, mOutBuffer);
ASSERT_NE(nullptr, mPixels);
@@ -181,7 +185,8 @@
EXPECT_EQ(height, mOutBuffer->getHeight());
}
- explicit ScreenCapture(const sp<GraphicBuffer>& outBuffer) : mOutBuffer(outBuffer) {
+ explicit ScreenCapture(const sp<GraphicBuffer>& outBuffer, bool containsHdr)
+ : mOutBuffer(outBuffer), mContainsHdr(containsHdr) {
if (mOutBuffer) {
mOutBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&mPixels));
}
@@ -193,6 +198,7 @@
private:
sp<GraphicBuffer> mOutBuffer;
+ bool mContainsHdr = mContainsHdr;
uint8_t* mPixels = nullptr;
};
} // namespace