Merge "Convert backend texture creation failure from ALOGE to FATAL log" into udc-dev
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 8ca927e..5dbf7ac 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -3362,23 +3362,25 @@
return;
}
- // Include the proto logging from WMShell.
- RunCommand(
- // Empty name because it's not intended to be classified as a bugreport section.
- // Actual logging files can be found as "/data/misc/wmtrace/shell_log.winscope"
- // in the bugreport.
- "", {"dumpsys", "activity", "service", "SystemUIService",
- "WMShell", "protolog", "save-for-bugreport"},
- CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build());
+ const std::vector<std::vector<std::string>> dumpTracesForBugReportCommands = {
+ {"dumpsys", "activity", "service", "SystemUIService", "WMShell", "protolog",
+ "save-for-bugreport"},
+ {"dumpsys", "activity", "service", "SystemUIService", "WMShell", "transitions", "tracing",
+ "save-for-bugreport"},
+ {"cmd", "input_method", "tracing", "save-for-bugreport"},
+ {"cmd", "window", "tracing", "save-for-bugreport"},
+ {"cmd", "window", "shell", "tracing", "save-for-bugreport"},
+ };
- for (const auto& service : {"input_method", "window", "window shell"}) {
+ for (const auto& command : dumpTracesForBugReportCommands) {
RunCommand(
// Empty name because it's not intended to be classified as a bugreport section.
// Actual tracing files can be found in "/data/misc/wmtrace/" in the bugreport.
- "", {"cmd", service, "tracing", "save-for-bugreport"},
+ "", command,
CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build());
}
+ // This command needs to be run as root
static const auto SURFACEFLINGER_COMMAND_SAVE_ALL_TRACES = std::vector<std::string> {
"service", "call", "SurfaceFlinger", "1042"
};
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index 93d8cdf..5cbcf9f 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -997,17 +997,22 @@
EXPECT_FALSE(ds.dump_pool_);
}
-TEST_F(DumpstateBaseTest, PreDumpUiData) {
- // SurfaceFlinger's transactions trace is always enabled, i.e. it is always pre-dumped
- static const auto kTransactionsTrace =
- std::filesystem::path {"/data/misc/wmtrace/transactions_trace.winscope"};
+TEST_F(DumpstateTest, PreDumpUiData) {
+ // These traces are always enabled, i.e. they are always pre-dumped
+ const std::vector<std::filesystem::path> uiTraces = {
+ std::filesystem::path{"/data/misc/wmtrace/transactions_trace.winscope"},
+ std::filesystem::path{"/data/misc/wmtrace/transition_trace.winscope"},
+ std::filesystem::path{"/data/misc/wmtrace/shell_transition_trace.winscope"},
+ };
- std::system(("rm " + kTransactionsTrace.string()).c_str());
- EXPECT_FALSE(std::filesystem::exists(kTransactionsTrace));
+ for (const auto traceFile : uiTraces) {
+ std::system(("rm -f " + traceFile.string()).c_str());
+ EXPECT_FALSE(std::filesystem::exists(traceFile)) << traceFile << " was not deleted.";
- Dumpstate& ds_ = Dumpstate::GetInstance();
- ds_.PreDumpUiData();
- EXPECT_TRUE(std::filesystem::exists(kTransactionsTrace));
+ Dumpstate& ds_ = Dumpstate::GetInstance();
+ ds_.PreDumpUiData();
+ EXPECT_TRUE(std::filesystem::exists(traceFile)) << traceFile << " was not created.";
+ }
}
class ZippedBugReportStreamTest : public DumpstateBaseTest {
diff --git a/cmds/installd/utils_default.cpp b/cmds/installd/utils_default.cpp
index a6025e6..85ce450 100644
--- a/cmds/installd/utils_default.cpp
+++ b/cmds/installd/utils_default.cpp
@@ -23,7 +23,7 @@
// platform dependent logic.
int rm_package_dir(const std::string& package_dir) {
- return delete_dir_contents_and_dir(package_dir);
+ return rename_delete_dir_contents_and_dir(package_dir);
}
} // namespace installd
diff --git a/headers/media_plugin/media/hardware/VideoAPI.h b/headers/media_plugin/media/hardware/VideoAPI.h
index a090876..5466680 100644
--- a/headers/media_plugin/media/hardware/VideoAPI.h
+++ b/headers/media_plugin/media/hardware/VideoAPI.h
@@ -127,6 +127,8 @@
PrimariesBT601_6_525, // Rec.ITU-R BT.601-6 525 or equivalent
PrimariesGenericFilm, // Generic Film
PrimariesBT2020, // Rec.ITU-R BT.2020 or equivalent
+ PrimariesRP431, // SMPTE RP 431-2 (DCI P3)
+ PrimariesEG432, // SMPTE EG 432-1 (Display P3)
PrimariesOther = 0xff,
};
@@ -173,6 +175,8 @@
StandardBT2020Constant, // PrimariesBT2020 and MatrixBT2020Constant
StandardBT470M, // PrimariesBT470_6M and MatrixBT470_6M
StandardFilm, // PrimariesGenericFilm and KR=0.253, KB=0.068
+ StandardDisplayP3, // PrimariesEG432 and MatrixBT601_6
+ // StandardAdobeRGB, // for placeholder only (not used by media)
StandardOther = 0xff,
};
@@ -282,6 +286,8 @@
case ColorAspects::PrimariesBT601_6_525: return "BT601_6_525";
case ColorAspects::PrimariesGenericFilm: return "GenericFilm";
case ColorAspects::PrimariesBT2020: return "BT2020";
+ case ColorAspects::PrimariesRP431: return "RP431";
+ case ColorAspects::PrimariesEG432: return "EG432";
case ColorAspects::PrimariesOther: return "Other";
default: return def;
}
@@ -332,6 +338,8 @@
case ColorAspects::StandardBT2020Constant: return "BT2020Constant";
case ColorAspects::StandardBT470M: return "BT470M";
case ColorAspects::StandardFilm: return "Film";
+ case ColorAspects::StandardDisplayP3: return "DisplayP3";
+ // case ColorAspects::StandardAdobeRGB: return "AdobeRGB";
case ColorAspects::StandardOther: return "Other";
default: return def;
}
diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h
index 9423041..b2e8baa 100644
--- a/include/input/KeyCharacterMap.h
+++ b/include/input/KeyCharacterMap.h
@@ -26,9 +26,9 @@
#include <android-base/result.h>
#include <input/Input.h>
#include <utils/Errors.h>
-#include <utils/KeyedVector.h>
#include <utils/Tokenizer.h>
#include <utils/Unicode.h>
+#include <map>
// Maximum number of keys supported by KeyCharacterMaps
#define MAX_KEYS 8192
@@ -152,13 +152,9 @@
void writeToParcel(Parcel* parcel) const;
#endif
- bool operator==(const KeyCharacterMap& other) const;
+ bool operator==(const KeyCharacterMap& other) const = default;
- bool operator!=(const KeyCharacterMap& other) const;
-
- KeyCharacterMap(const KeyCharacterMap& other);
-
- virtual ~KeyCharacterMap();
+ KeyCharacterMap(const KeyCharacterMap& other) = default;
private:
struct Behavior {
@@ -173,17 +169,18 @@
/* The replacement keycode if the key has to be replaced outright. */
int32_t replacementKeyCode = 0;
+
+ bool operator==(const Behavior&) const = default;
};
struct Key {
- Key();
- Key(const Key& other);
+ bool operator==(const Key&) const = default;
/* The single character label printed on the key, or 0 if none. */
- char16_t label;
+ char16_t label = 0;
/* The number or symbol character generated by the key, or 0 if none. */
- char16_t number;
+ char16_t number = 0;
/* The list of key behaviors sorted from most specific to least specific
* meta key binding. */
@@ -218,7 +215,6 @@
public:
Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format);
- ~Parser();
status_t parse();
private:
@@ -232,8 +228,8 @@
status_t parseCharacterLiteral(char16_t* outCharacter);
};
- KeyedVector<int32_t, Key*> mKeys;
- KeyboardType mType;
+ std::map<int32_t, Key> mKeys;
+ KeyboardType mType = KeyboardType::UNKNOWN;
std::string mLoadFileName;
bool mLayoutOverlayApplied = false;
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index ed3ce24..03fa699 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -928,7 +928,7 @@
transactionData.size() -
offsetof(RpcWireTransaction, data)};
Span<const uint32_t> objectTableSpan;
- if (session->getProtocolVersion().value() >
+ if (session->getProtocolVersion().value() >=
RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE) {
std::optional<Span<const uint8_t>> objectTableBytes =
parcelSpan.splitOff(transaction->parcelDataSize);
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index a323feb..cb64603 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -37,9 +37,9 @@
class RpcTransport;
class FdTrigger;
-constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_NEXT = 1;
+constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_NEXT = 2;
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 = 1;
// Starting with this version:
//
diff --git a/libs/binder/tests/binderRpcWireProtocolTest.cpp b/libs/binder/tests/binderRpcWireProtocolTest.cpp
index 3dab2c7..642cea4 100644
--- a/libs/binder/tests/binderRpcWireProtocolTest.cpp
+++ b/libs/binder/tests/binderRpcWireProtocolTest.cpp
@@ -237,14 +237,25 @@
checkRepr(kCurrentRepr, 0);
}
+TEST(RpcWire, V1) {
+ checkRepr(kCurrentRepr, 1);
+}
+
TEST(RpcWire, CurrentVersion) {
checkRepr(kCurrentRepr, RPC_WIRE_PROTOCOL_VERSION);
}
-static_assert(RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL,
+static_assert(RPC_WIRE_PROTOCOL_VERSION == 1,
"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, NextIsPlusOneReminder) {
+ if (RPC_WIRE_PROTOCOL_VERSION != RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL) {
+ EXPECT_EQ(RPC_WIRE_PROTOCOL_VERSION + 1, RPC_WIRE_PROTOCOL_VERSION_NEXT)
+ << "Make sure to note what the next version should be.";
+ }
+}
+
TEST(RpcWire, ReleaseBranchHasFrozenRpcWireProtocol) {
if (RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL) {
EXPECT_FALSE(base::GetProperty("ro.build.version.codename", "") == "REL")
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 7f7a043..5217209 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -33,6 +33,7 @@
#include <gui/BufferQueueCore.h>
#include <gui/IConsumerListener.h>
#include <gui/IProducerListener.h>
+#include <gui/TraceUtils.h>
#include <private/gui/BufferQueueThreadState.h>
#ifndef __ANDROID_VNDK__
@@ -646,7 +647,7 @@
status_t BufferQueueConsumer::setMaxAcquiredBufferCount(
int maxAcquiredBuffers) {
- ATRACE_CALL();
+ ATRACE_FORMAT("%s(%d)", __func__, maxAcquiredBuffers);
if (maxAcquiredBuffers < 1 ||
maxAcquiredBuffers > BufferQueueCore::MAX_MAX_ACQUIRED_BUFFERS) {
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 9eb1a9f..9a2343b 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -35,6 +35,7 @@
#include <gui/GLConsumer.h>
#include <gui/IConsumerListener.h>
#include <gui/IProducerListener.h>
+#include <gui/TraceUtils.h>
#include <private/gui/BufferQueueThreadState.h>
#include <utils/Log.h>
@@ -125,7 +126,7 @@
status_t BufferQueueProducer::setMaxDequeuedBufferCount(int maxDequeuedBuffers,
int* maxBufferCount) {
- ATRACE_CALL();
+ ATRACE_FORMAT("%s(%d)", __func__, maxDequeuedBuffers);
BQ_LOGV("setMaxDequeuedBufferCount: maxDequeuedBuffers = %d",
maxDequeuedBuffers);
@@ -502,6 +503,20 @@
if ((buffer == nullptr) ||
buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage))
{
+ if (CC_UNLIKELY(ATRACE_ENABLED())) {
+ if (buffer == nullptr) {
+ ATRACE_FORMAT_INSTANT("%s buffer reallocation: null", mConsumerName.string());
+ } else {
+ ATRACE_FORMAT_INSTANT("%s buffer reallocation actual %dx%d format:%d "
+ "layerCount:%d "
+ "usage:%d requested: %dx%d format:%d layerCount:%d "
+ "usage:%d ",
+ mConsumerName.string(), width, height, format,
+ BQ_LAYER_COUNT, usage, buffer->getWidth(),
+ buffer->getHeight(), buffer->getPixelFormat(),
+ buffer->getLayerCount(), buffer->getUsage());
+ }
+ }
mSlots[found].mAcquireCalled = false;
mSlots[found].mGraphicBuffer = nullptr;
mSlots[found].mRequestBufferCalled = false;
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index fee91a4..2322b70 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -897,11 +897,11 @@
SAFE_PARCEL(output->writeInt32, static_cast<int32_t>(dataspace));
SAFE_PARCEL(output->writeBool, allowProtected);
SAFE_PARCEL(output->writeBool, grayscale);
-
SAFE_PARCEL(output->writeInt32, excludeHandles.size());
for (auto& excludeHandle : excludeHandles) {
SAFE_PARCEL(output->writeStrongBinder, excludeHandle);
}
+ SAFE_PARCEL(output->writeBool, hintForSeamlessTransition);
return NO_ERROR;
}
@@ -918,7 +918,6 @@
dataspace = static_cast<ui::Dataspace>(value);
SAFE_PARCEL(input->readBool, &allowProtected);
SAFE_PARCEL(input->readBool, &grayscale);
-
int32_t numExcludeHandles = 0;
SAFE_PARCEL_READ_SIZE(input->readInt32, &numExcludeHandles, input->dataSize());
excludeHandles.reserve(numExcludeHandles);
@@ -927,6 +926,7 @@
SAFE_PARCEL(input->readStrongBinder, &binder);
excludeHandles.emplace(binder);
}
+ SAFE_PARCEL(input->readBool, &hintForSeamlessTransition);
return NO_ERROR;
}
diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
index aa58e2e..ec3266c 100644
--- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
+++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
@@ -230,6 +230,10 @@
*/
void captureDisplay(in DisplayCaptureArgs args, IScreenCaptureListener listener);
+ /**
+ * Capture the specified screen. This requires the READ_FRAME_BUFFER
+ * permission.
+ */
void captureDisplayById(long displayId, IScreenCaptureListener listener);
/**
diff --git a/libs/gui/include/gui/DisplayCaptureArgs.h b/libs/gui/include/gui/DisplayCaptureArgs.h
index 5c794ae..2676e0a 100644
--- a/libs/gui/include/gui/DisplayCaptureArgs.h
+++ b/libs/gui/include/gui/DisplayCaptureArgs.h
@@ -41,7 +41,7 @@
bool captureSecureLayers{false};
int32_t uid{UNSET_UID};
// Force capture to be in a color space. If the value is ui::Dataspace::UNKNOWN, the captured
- // result will be in the display's colorspace.
+ // result will be in a colorspace appropriate for capturing the display contents
// The display may use non-RGB dataspace (ex. displayP3) that could cause pixel data could be
// different from SRGB (byte per color), and failed when checking colors in tests.
// NOTE: In normal cases, we want the screen to be captured in display's colorspace.
@@ -59,6 +59,15 @@
std::unordered_set<sp<IBinder>, SpHash<IBinder>> excludeHandles;
+ // Hint that the caller will use the screenshot animation as part of a transition animation.
+ // The canonical example would be screen rotation - in such a case any color shift in the
+ // screenshot is a detractor so composition in the display's colorspace is required.
+ // Otherwise, the system may choose a colorspace that is more appropriate for use-cases
+ // such as file encoding or for blending HDR content into an ap's UI, where the display's
+ // exact colorspace is not an appropriate intermediate result.
+ // Note that if the caller is requesting a specific dataspace, this hint does nothing.
+ bool hintForSeamlessTransition = false;
+
virtual status_t writeToParcel(Parcel* output) const;
virtual status_t readFromParcel(const Parcel* input);
};
diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp
index f703901..12c9e53 100644
--- a/libs/input/KeyCharacterMap.cpp
+++ b/libs/input/KeyCharacterMap.cpp
@@ -85,63 +85,7 @@
// --- KeyCharacterMap ---
-KeyCharacterMap::KeyCharacterMap(const std::string& filename)
- : mType(KeyboardType::UNKNOWN), mLoadFileName(filename) {}
-
-KeyCharacterMap::KeyCharacterMap(const KeyCharacterMap& other)
- : mType(other.mType),
- mLoadFileName(other.mLoadFileName),
- mLayoutOverlayApplied(other.mLayoutOverlayApplied),
- mKeyRemapping(other.mKeyRemapping),
- mKeysByScanCode(other.mKeysByScanCode),
- mKeysByUsageCode(other.mKeysByUsageCode) {
- for (size_t i = 0; i < other.mKeys.size(); i++) {
- mKeys.add(other.mKeys.keyAt(i), new Key(*other.mKeys.valueAt(i)));
- }
-}
-
-KeyCharacterMap::~KeyCharacterMap() {
- clear();
-}
-
-bool KeyCharacterMap::operator==(const KeyCharacterMap& other) const {
- if (mType != other.mType) {
- return false;
- }
- if (mLoadFileName != other.mLoadFileName) {
- return false;
- }
- if (mLayoutOverlayApplied != other.mLayoutOverlayApplied) {
- return false;
- }
- if (mKeys.size() != other.mKeys.size() || mKeyRemapping.size() != other.mKeyRemapping.size() ||
- mKeysByScanCode.size() != other.mKeysByScanCode.size() ||
- mKeysByUsageCode.size() != other.mKeysByUsageCode.size()) {
- return false;
- }
-
- for (size_t i = 0; i < mKeys.size(); i++) {
- if (mKeys.keyAt(i) != other.mKeys.keyAt(i)) {
- return false;
- }
- const Key* key = mKeys.valueAt(i);
- const Key* otherKey = other.mKeys.valueAt(i);
- if (key->label != otherKey->label || key->number != otherKey->number) {
- return false;
- }
- }
-
- if (mKeyRemapping != other.mKeyRemapping || mKeysByScanCode != other.mKeysByScanCode ||
- mKeysByUsageCode != other.mKeysByUsageCode) {
- return false;
- }
-
- return true;
-}
-
-bool KeyCharacterMap::operator!=(const KeyCharacterMap& other) const {
- return !(*this == other);
-}
+KeyCharacterMap::KeyCharacterMap(const std::string& filename) : mLoadFileName(filename) {}
base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::load(const std::string& filename,
Format format) {
@@ -207,10 +151,6 @@
void KeyCharacterMap::clear() {
mKeysByScanCode.clear();
mKeysByUsageCode.clear();
- for (size_t i = 0; i < mKeys.size(); i++) {
- Key* key = mKeys.editValueAt(i);
- delete key;
- }
mKeys.clear();
mLayoutOverlayApplied = false;
mType = KeyboardType::UNKNOWN;
@@ -233,24 +173,16 @@
if (mLayoutOverlayApplied) {
reloadBaseFromFile();
}
- for (size_t i = 0; i < overlay.mKeys.size(); i++) {
- int32_t keyCode = overlay.mKeys.keyAt(i);
- Key* key = overlay.mKeys.valueAt(i);
- ssize_t oldIndex = mKeys.indexOfKey(keyCode);
- if (oldIndex >= 0) {
- delete mKeys.valueAt(oldIndex);
- mKeys.editValueAt(oldIndex) = new Key(*key);
- } else {
- mKeys.add(keyCode, new Key(*key));
- }
+ for (const auto& [keyCode, key] : overlay.mKeys) {
+ mKeys.insert_or_assign(keyCode, key);
}
- for (auto const& it : overlay.mKeysByScanCode) {
- mKeysByScanCode.insert_or_assign(it.first, it.second);
+ for (const auto& [fromScanCode, toAndroidKeyCode] : overlay.mKeysByScanCode) {
+ mKeysByScanCode.insert_or_assign(fromScanCode, toAndroidKeyCode);
}
- for (auto const& it : overlay.mKeysByUsageCode) {
- mKeysByUsageCode.insert_or_assign(it.first, it.second);
+ for (const auto& [fromHidUsageCode, toAndroidKeyCode] : overlay.mKeysByUsageCode) {
+ mKeysByUsageCode.insert_or_assign(fromHidUsageCode, toAndroidKeyCode);
}
mLayoutOverlayApplied = true;
}
@@ -343,19 +275,15 @@
if (behavior.character == chars[i]) {
result = behavior.character;
if ((behavior.metaState & metaState) == behavior.metaState) {
- goto ExactMatch;
+ // Found exact match!
+ return result;
}
break;
}
}
}
}
- ExactMatch: ;
}
-#if DEBUG_MAPPING
- ALOGD("getMatch: keyCode=%d, chars=[%s], metaState=0x%08x ~ Result %d.",
- keyCode, toString(chars, numChars).string(), metaState, result);
-#endif
return result;
}
@@ -494,9 +422,9 @@
}
const KeyCharacterMap::Key* KeyCharacterMap::getKey(int32_t keyCode) const {
- ssize_t index = mKeys.indexOfKey(keyCode);
- if (index >= 0) {
- return mKeys.valueAt(index);
+ auto it = mKeys.find(keyCode);
+ if (it != mKeys.end()) {
+ return &it->second;
}
return nullptr;
}
@@ -550,19 +478,17 @@
return false;
}
- for (size_t i = 0; i < mKeys.size(); i++) {
- const Key* key = mKeys.valueAt(i);
-
+ for (const auto& [keyCode, key] : mKeys) {
// Try to find the most general behavior that maps to this character.
// For example, the base key behavior will usually be last in the list.
const Behavior* found = nullptr;
- for (const Behavior& behavior : key->behaviors) {
+ for (const Behavior& behavior : key.behaviors) {
if (behavior.character == ch) {
found = &behavior;
}
}
if (found != nullptr) {
- *outKeyCode = mKeys.keyAt(i);
+ *outKeyCode = keyCode;
*outMetaState = found->metaState;
return true;
}
@@ -714,11 +640,7 @@
return nullptr;
}
- Key* key = new Key();
- key->label = label;
- key->number = number;
- map->mKeys.add(keyCode, key);
-
+ Key key{.label = label, .number = number};
while (parcel->readInt32()) {
int32_t metaState = parcel->readInt32();
char16_t character = parcel->readInt32();
@@ -728,13 +650,14 @@
return nullptr;
}
- key->behaviors.push_back({
+ key.behaviors.push_back({
.metaState = metaState,
.character = character,
.fallbackKeyCode = fallbackKeyCode,
.replacementKeyCode = replacementKeyCode,
});
}
+ map->mKeys.emplace(keyCode, std::move(key));
if (parcel->errorCheck()) {
return nullptr;
@@ -790,13 +713,11 @@
size_t numKeys = mKeys.size();
parcel->writeInt32(numKeys);
- for (size_t i = 0; i < numKeys; i++) {
- int32_t keyCode = mKeys.keyAt(i);
- const Key* key = mKeys.valueAt(i);
+ for (const auto& [keyCode, key] : mKeys) {
parcel->writeInt32(keyCode);
- parcel->writeInt32(key->label);
- parcel->writeInt32(key->number);
- for (const Behavior& behavior : key->behaviors) {
+ parcel->writeInt32(key.label);
+ parcel->writeInt32(key.number);
+ for (const Behavior& behavior : key.behaviors) {
parcel->writeInt32(1);
parcel->writeInt32(behavior.metaState);
parcel->writeInt32(behavior.character);
@@ -826,22 +747,12 @@
}
#endif // __linux__
-// --- KeyCharacterMap::Key ---
-
-KeyCharacterMap::Key::Key() : label(0), number(0) {}
-
-KeyCharacterMap::Key::Key(const Key& other)
- : label(other.label), number(other.number), behaviors(other.behaviors) {}
-
// --- KeyCharacterMap::Parser ---
KeyCharacterMap::Parser::Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format) :
mMap(map), mTokenizer(tokenizer), mFormat(format), mState(STATE_TOP) {
}
-KeyCharacterMap::Parser::~Parser() {
-}
-
status_t KeyCharacterMap::Parser::parse() {
while (!mTokenizer->isEof()) {
#if DEBUG_PARSER
@@ -1021,7 +932,7 @@
keyCodeToken.string());
return BAD_VALUE;
}
- if (mMap->mKeys.indexOfKey(*keyCode) >= 0) {
+ if (mMap->mKeys.find(*keyCode) != mMap->mKeys.end()) {
ALOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().string(),
keyCodeToken.string());
return BAD_VALUE;
@@ -1037,17 +948,17 @@
ALOGD_IF(DEBUG_PARSER, "Parsed beginning of key: keyCode=%d.", *keyCode);
mKeyCode = *keyCode;
- mMap->mKeys.add(*keyCode, new Key());
+ mMap->mKeys.emplace(*keyCode, Key{});
mState = STATE_KEY;
return NO_ERROR;
}
status_t KeyCharacterMap::Parser::parseKeyProperty() {
- Key* key = mMap->mKeys.valueFor(mKeyCode);
+ Key& key = mMap->mKeys[mKeyCode];
String8 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
if (token == "}") {
mState = STATE_TOP;
- return finishKey(*key);
+ return finishKey(key);
}
std::vector<Property> properties;
@@ -1184,43 +1095,41 @@
for (const Property& property : properties) {
switch (property.property) {
case PROPERTY_LABEL:
- if (key->label) {
- ALOGE("%s: Duplicate label for key.",
- mTokenizer->getLocation().string());
- return BAD_VALUE;
- }
- key->label = behavior.character;
+ if (key.label) {
+ ALOGE("%s: Duplicate label for key.", mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
+ key.label = behavior.character;
#if DEBUG_PARSER
- ALOGD("Parsed key label: keyCode=%d, label=%d.", mKeyCode, key->label);
+ ALOGD("Parsed key label: keyCode=%d, label=%d.", mKeyCode, key.label);
#endif
break;
case PROPERTY_NUMBER:
- if (key->number) {
- ALOGE("%s: Duplicate number for key.",
- mTokenizer->getLocation().string());
- return BAD_VALUE;
+ if (key.number) {
+ ALOGE("%s: Duplicate number for key.", mTokenizer->getLocation().string());
+ return BAD_VALUE;
}
- key->number = behavior.character;
+ key.number = behavior.character;
#if DEBUG_PARSER
- ALOGD("Parsed key number: keyCode=%d, number=%d.", mKeyCode, key->number);
+ ALOGD("Parsed key number: keyCode=%d, number=%d.", mKeyCode, key.number);
#endif
break;
case PROPERTY_META: {
- for (const Behavior& b : key->behaviors) {
- if (b.metaState == property.metaState) {
+ for (const Behavior& b : key.behaviors) {
+ if (b.metaState == property.metaState) {
ALOGE("%s: Duplicate key behavior for modifier.",
mTokenizer->getLocation().string());
return BAD_VALUE;
- }
+ }
}
Behavior newBehavior = behavior;
newBehavior.metaState = property.metaState;
- key->behaviors.push_front(newBehavior);
+ key.behaviors.push_front(newBehavior);
ALOGD_IF(DEBUG_PARSER,
"Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d replace=%d.",
- mKeyCode, key->behaviors.front().metaState, key->behaviors.front().character,
- key->behaviors.front().fallbackKeyCode,
- key->behaviors.front().replacementKeyCode);
+ mKeyCode, key.behaviors.front().metaState, key.behaviors.front().character,
+ key.behaviors.front().fallbackKeyCode,
+ key.behaviors.front().replacementKeyCode);
break;
}
}
diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp
index 8256dd8..2a51493 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaRenderEngine.cpp
@@ -517,16 +517,18 @@
} else {
runtimeEffect = effectIter->second;
}
+
mat4 colorTransform = parameters.layer.colorTransform;
colorTransform *=
mat4::scale(vec4(parameters.layerDimmingRatio, parameters.layerDimmingRatio,
parameters.layerDimmingRatio, 1.f));
+
const auto targetBuffer = parameters.layer.source.buffer.buffer;
const auto graphicBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr;
const auto hardwareBuffer = graphicBuffer ? graphicBuffer->toAHardwareBuffer() : nullptr;
- return createLinearEffectShader(parameters.shader, effect, runtimeEffect, colorTransform,
- parameters.display.maxLuminance,
+ return createLinearEffectShader(parameters.shader, effect, runtimeEffect,
+ std::move(colorTransform), parameters.display.maxLuminance,
parameters.display.currentLuminanceNits,
parameters.layer.source.buffer.maxLuminanceNits,
hardwareBuffer, parameters.display.renderIntent);
diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp
index ba190e0..980f8d1 100644
--- a/libs/sensor/SensorManager.cpp
+++ b/libs/sensor/SensorManager.cpp
@@ -176,11 +176,8 @@
mSensors = mSensorServer->getSensorList(mOpPackageName);
size_t count = mSensors.size();
- if (count == 0) {
- ALOGE("Failed to get Sensor list");
- mSensorServer.clear();
- return UNKNOWN_ERROR;
- }
+ // If count is 0, mSensorList will be non-null. This is old
+ // existing behavior and callers expect this.
mSensorList =
static_cast<Sensor const**>(malloc(count * sizeof(Sensor*)));
LOG_ALWAYS_FATAL_IF(mSensorList == nullptr, "mSensorList NULL");
diff --git a/libs/shaders/shaders.cpp b/libs/shaders/shaders.cpp
index a3c403e..19518ea 100644
--- a/libs/shaders/shaders.cpp
+++ b/libs/shaders/shaders.cpp
@@ -191,31 +191,35 @@
)");
break;
default:
+ // Input is SDR so map to its white point luminance
switch (outputDataspace & HAL_DATASPACE_TRANSFER_MASK) {
- case HAL_DATASPACE_TRANSFER_ST2084:
+ // Max HLG output is nominally 1000 nits, but BT. 2100-2 allows
+ // for gamma correcting the HLG OOTF for displays with a different
+ // dynamic range. Scale to 1000 nits to apply an inverse OOTF against
+ // a reference display correctly.
+ // TODO: Use knowledge of the dimming ratio here to prevent
+ // unintended gamma shaft.
case HAL_DATASPACE_TRANSFER_HLG:
- // SDR -> HDR tonemap
shader.append(R"(
float3 ScaleLuminance(float3 xyz) {
- return xyz * in_libtonemap_inputMaxLuminance;
+ return xyz * 1000.0;
}
)");
break;
default:
- // Input and output are both SDR, so no tone-mapping is expected so
- // no-op the luminance normalization.
shader.append(R"(
- float3 ScaleLuminance(float3 xyz) {
- return xyz * in_libtonemap_displayMaxLuminance;
- }
- )");
+ float3 ScaleLuminance(float3 xyz) {
+ return xyz * in_libtonemap_displayMaxLuminance;
+ }
+ )");
break;
}
}
}
// Normalizes from absolute light back to relative light (maps from [0, maxNits] back to [0, 1])
-static void generateLuminanceNormalizationForOOTF(ui::Dataspace outputDataspace,
+static void generateLuminanceNormalizationForOOTF(ui::Dataspace inputDataspace,
+ ui::Dataspace outputDataspace,
std::string& shader) {
switch (outputDataspace & HAL_DATASPACE_TRANSFER_MASK) {
case HAL_DATASPACE_TRANSFER_ST2084:
@@ -226,11 +230,28 @@
)");
break;
case HAL_DATASPACE_TRANSFER_HLG:
- shader.append(R"(
- float3 NormalizeLuminance(float3 xyz) {
- return xyz / 1000.0;
- }
- )");
+ switch (inputDataspace & HAL_DATASPACE_TRANSFER_MASK) {
+ case HAL_DATASPACE_TRANSFER_HLG:
+ shader.append(R"(
+ float3 NormalizeLuminance(float3 xyz) {
+ return xyz / 1000.0;
+ }
+ )");
+ break;
+ default:
+ // Transcoding to HLG requires applying the inverse OOTF
+ // with the expectation that the OOTF is then applied during
+ // tonemapping downstream.
+ shader.append(R"(
+ float3 NormalizeLuminance(float3 xyz) {
+ // BT. 2100-2 operates on normalized luminances,
+ // so renormalize to the input
+ float ootfGain = pow(xyz.y / 1000.0, -0.2 / 1.2) / 1000.0;
+ return xyz * ootfGain;
+ }
+ )");
+ break;
+ }
break;
default:
shader.append(R"(
@@ -250,7 +271,7 @@
.c_str());
generateLuminanceScalesForOOTF(inputDataspace, outputDataspace, shader);
- generateLuminanceNormalizationForOOTF(outputDataspace, shader);
+ generateLuminanceNormalizationForOOTF(inputDataspace, outputDataspace, shader);
shader.append(R"(
float3 OOTF(float3 linearRGB, float3 xyz) {
@@ -501,9 +522,8 @@
tonemap::Metadata metadata{.displayMaxLuminance = maxDisplayLuminance,
// If the input luminance is unknown, use display luminance (aka,
- // no-op any luminance changes)
- // This will be the case for eg screenshots in addition to
- // uncalibrated displays
+ // no-op any luminance changes).
+ // This is expected to only be meaningful for PQ content
.contentMaxLuminance =
maxLuminance > 0 ? maxLuminance : maxDisplayLuminance,
.currentDisplayLuminance = currentDisplayLuminanceNits > 0
diff --git a/opengl/libs/EGL/BlobCache.cpp b/opengl/libs/EGL/BlobCache.cpp
index aecfc6b..b3a4bc1 100644
--- a/opengl/libs/EGL/BlobCache.cpp
+++ b/opengl/libs/EGL/BlobCache.cpp
@@ -15,6 +15,7 @@
*/
//#define LOG_NDEBUG 0
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include "BlobCache.h"
@@ -22,6 +23,7 @@
#include <errno.h>
#include <inttypes.h>
#include <log/log.h>
+#include <utils/Trace.h>
#include <chrono>
@@ -230,6 +232,8 @@
}
int BlobCache::unflatten(void const* buffer, size_t size) {
+ ATRACE_NAME("BlobCache::unflatten");
+
// All errors should result in the BlobCache being in an empty state.
clear();
@@ -293,6 +297,8 @@
}
void BlobCache::clean() {
+ ATRACE_NAME("BlobCache::clean");
+
// Remove a random cache entry until the total cache size gets below half
// the maximum total cache size.
while (mTotalSize > mMaxTotalSize / 2) {
diff --git a/opengl/libs/EGL/FileBlobCache.cpp b/opengl/libs/EGL/FileBlobCache.cpp
index 1026842..4a0fac4 100644
--- a/opengl/libs/EGL/FileBlobCache.cpp
+++ b/opengl/libs/EGL/FileBlobCache.cpp
@@ -14,6 +14,8 @@
** limitations under the License.
*/
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
#include "FileBlobCache.h"
#include <errno.h>
@@ -24,6 +26,7 @@
#include <unistd.h>
#include <log/log.h>
+#include <utils/Trace.h>
// Cache file header
static const char* cacheFileMagic = "EGL$";
@@ -51,6 +54,8 @@
const std::string& filename)
: BlobCache(maxKeySize, maxValueSize, maxTotalSize)
, mFilename(filename) {
+ ATRACE_CALL();
+
if (mFilename.length() > 0) {
size_t headerSize = cacheFileHeaderSize;
@@ -117,6 +122,8 @@
}
void FileBlobCache::writeToFile() {
+ ATRACE_CALL();
+
if (mFilename.length() > 0) {
size_t cacheSize = getFlattenedSize();
size_t headerSize = cacheFileHeaderSize;
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index e04481c..69df45b 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -224,6 +224,9 @@
"libinputservice_test",
"Bug-115739809",
"StructLayout_test",
+ // currently unused, but still must build correctly
+ "inputflinger",
+ "libinputflingerhost",
// native fuzzers
"inputflinger_latencytracker_fuzzer",
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 6b9ad44..8c08ef2 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -54,6 +54,7 @@
#define INDENT4 " "
using namespace android::ftl::flag_operators;
+using android::base::Error;
using android::base::HwTimeoutMultiplier;
using android::base::Result;
using android::base::StringPrintf;
@@ -129,48 +130,68 @@
AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
}
-bool isValidKeyAction(int32_t action) {
+Result<void> checkKeyAction(int32_t action) {
switch (action) {
case AKEY_EVENT_ACTION_DOWN:
case AKEY_EVENT_ACTION_UP:
- return true;
+ return {};
default:
- return false;
+ return Error() << "Key event has invalid action code " << action;
}
}
-bool validateKeyEvent(int32_t action) {
- if (!isValidKeyAction(action)) {
- ALOGE("Key event has invalid action code 0x%x", action);
- return false;
- }
- return true;
+Result<void> validateKeyEvent(int32_t action) {
+ return checkKeyAction(action);
}
-bool isValidMotionAction(int32_t action, int32_t actionButton, int32_t pointerCount) {
+Result<void> checkMotionAction(int32_t action, int32_t actionButton, int32_t pointerCount) {
switch (MotionEvent::getActionMasked(action)) {
case AMOTION_EVENT_ACTION_DOWN:
- case AMOTION_EVENT_ACTION_UP:
- return pointerCount == 1;
+ case AMOTION_EVENT_ACTION_UP: {
+ if (pointerCount != 1) {
+ return Error() << "invalid pointer count " << pointerCount;
+ }
+ return {};
+ }
case AMOTION_EVENT_ACTION_MOVE:
case AMOTION_EVENT_ACTION_HOVER_ENTER:
case AMOTION_EVENT_ACTION_HOVER_MOVE:
- case AMOTION_EVENT_ACTION_HOVER_EXIT:
- return pointerCount >= 1;
+ case AMOTION_EVENT_ACTION_HOVER_EXIT: {
+ if (pointerCount < 1) {
+ return Error() << "invalid pointer count " << pointerCount;
+ }
+ return {};
+ }
case AMOTION_EVENT_ACTION_CANCEL:
case AMOTION_EVENT_ACTION_OUTSIDE:
case AMOTION_EVENT_ACTION_SCROLL:
- return true;
+ return {};
case AMOTION_EVENT_ACTION_POINTER_DOWN:
case AMOTION_EVENT_ACTION_POINTER_UP: {
const int32_t index = MotionEvent::getActionIndex(action);
- return index >= 0 && index < pointerCount && pointerCount > 1;
+ if (index < 0) {
+ return Error() << "invalid index " << index << " for "
+ << MotionEvent::actionToString(action);
+ }
+ if (index >= pointerCount) {
+ return Error() << "invalid index " << index << " for pointerCount " << pointerCount;
+ }
+ if (pointerCount <= 1) {
+ return Error() << "invalid pointer count " << pointerCount << " for "
+ << MotionEvent::actionToString(action);
+ }
+ return {};
}
case AMOTION_EVENT_ACTION_BUTTON_PRESS:
- case AMOTION_EVENT_ACTION_BUTTON_RELEASE:
- return actionButton != 0;
+ case AMOTION_EVENT_ACTION_BUTTON_RELEASE: {
+ if (actionButton == 0) {
+ return Error() << "action button should be nonzero for "
+ << MotionEvent::actionToString(action);
+ }
+ return {};
+ }
default:
- return false;
+ return Error() << "invalid action " << action;
}
}
@@ -178,32 +199,50 @@
return std::chrono::duration_cast<std::chrono::milliseconds>(t).count();
}
-bool validateMotionEvent(int32_t action, int32_t actionButton, size_t pointerCount,
- const PointerProperties* pointerProperties) {
- if (!isValidMotionAction(action, actionButton, pointerCount)) {
- ALOGE("Motion event has invalid action code 0x%x", action);
- return false;
+Result<void> validateMotionEvent(int32_t action, int32_t actionButton, size_t pointerCount,
+ const PointerProperties* pointerProperties) {
+ Result<void> actionCheck = checkMotionAction(action, actionButton, pointerCount);
+ if (!actionCheck.ok()) {
+ return actionCheck;
}
if (pointerCount < 1 || pointerCount > MAX_POINTERS) {
- ALOGE("Motion event has invalid pointer count %zu; value must be between 1 and %zu.",
- pointerCount, MAX_POINTERS);
- return false;
+ return Error() << "Motion event has invalid pointer count " << pointerCount
+ << "; value must be between 1 and " << MAX_POINTERS << ".";
}
std::bitset<MAX_POINTER_ID + 1> pointerIdBits;
for (size_t i = 0; i < pointerCount; i++) {
int32_t id = pointerProperties[i].id;
if (id < 0 || id > MAX_POINTER_ID) {
- ALOGE("Motion event has invalid pointer id %d; value must be between 0 and %d", id,
- MAX_POINTER_ID);
- return false;
+ return Error() << "Motion event has invalid pointer id " << id
+ << "; value must be between 0 and " << MAX_POINTER_ID;
}
if (pointerIdBits.test(id)) {
- ALOGE("Motion event has duplicate pointer id %d", id);
- return false;
+ return Error() << "Motion event has duplicate pointer id " << id;
}
pointerIdBits.set(id);
}
- return true;
+ return {};
+}
+
+Result<void> validateInputEvent(const InputEvent& event) {
+ switch (event.getType()) {
+ case InputEventType::KEY: {
+ const KeyEvent& key = static_cast<const KeyEvent&>(event);
+ const int32_t action = key.getAction();
+ return validateKeyEvent(action);
+ }
+ case InputEventType::MOTION: {
+ const MotionEvent& motion = static_cast<const MotionEvent&>(event);
+ const int32_t action = motion.getAction();
+ const size_t pointerCount = motion.getPointerCount();
+ const PointerProperties* pointerProperties = motion.getPointerProperties();
+ const int32_t actionButton = motion.getActionButton();
+ return validateMotionEvent(action, actionButton, pointerCount, pointerProperties);
+ }
+ default: {
+ return {};
+ }
+ }
}
std::string dumpRegion(const Region& region) {
@@ -676,7 +715,6 @@
SurfaceComposerClient::getDefault()->addWindowInfosListener(mWindowInfoListener);
#endif
mKeyRepeatState.lastKeyEntry = nullptr;
- policy->getDispatcherConfiguration(&mConfig);
}
InputDispatcher::~InputDispatcher() {
@@ -2402,6 +2440,7 @@
const bool isStylus = isPointerFromStylus(entry, /*pointerIndex=*/0);
sp<WindowInfoHandle> oldTouchedWindowHandle =
tempTouchState.getFirstForegroundWindowHandle();
+ LOG_ALWAYS_FATAL_IF(oldTouchedWindowHandle == nullptr);
auto [newTouchedWindowHandle, _] = findTouchedWindowAtLocked(displayId, x, y, isStylus);
// Verify targeted injection.
@@ -2417,13 +2456,11 @@
newTouchedWindowHandle = nullptr;
}
- if (oldTouchedWindowHandle != newTouchedWindowHandle &&
- oldTouchedWindowHandle != nullptr && newTouchedWindowHandle != nullptr) {
- if (DEBUG_FOCUS) {
- ALOGD("Touch is slipping out of window %s into window %s in display %" PRId32,
- oldTouchedWindowHandle->getName().c_str(),
- newTouchedWindowHandle->getName().c_str(), displayId);
- }
+ if (!haveSameToken(oldTouchedWindowHandle, newTouchedWindowHandle)) {
+ ALOGD("Touch is slipping out of window %s into window %s in display %" PRId32,
+ oldTouchedWindowHandle->getName().c_str(),
+ newTouchedWindowHandle->getName().c_str(), displayId);
+
// Make a slippery exit from the old window.
std::bitset<MAX_POINTER_ID + 1> pointerIds;
const int32_t pointerId = entry.pointerProperties[0].id;
@@ -4094,7 +4131,9 @@
args.id, args.eventTime, args.deviceId, inputEventSourceToString(args.source).c_str(),
args.displayId, args.policyFlags, KeyEvent::actionToString(args.action), args.flags,
KeyEvent::getLabel(args.keyCode), args.scanCode, args.metaState, args.downTime);
- if (!validateKeyEvent(args.action)) {
+ Result<void> keyCheck = validateKeyEvent(args.action);
+ if (!keyCheck.ok()) {
+ LOG(ERROR) << "invalid key event: " << keyCheck.error();
return;
}
@@ -4191,9 +4230,10 @@
}
}
- if (!validateMotionEvent(args.action, args.actionButton, args.pointerCount,
- args.pointerProperties)) {
- LOG(ERROR) << "Invalid event: " << args.dump();
+ Result<void> motionCheck = validateMotionEvent(args.action, args.actionButton,
+ args.pointerCount, args.pointerProperties);
+ if (!motionCheck.ok()) {
+ LOG(ERROR) << "Invalid event: " << args.dump() << "; reason: " << motionCheck.error();
return;
}
@@ -4369,6 +4409,12 @@
InputEventInjectionSync syncMode,
std::chrono::milliseconds timeout,
uint32_t policyFlags) {
+ Result<void> eventValidation = validateInputEvent(*event);
+ if (!eventValidation.ok()) {
+ LOG(INFO) << "Injection failed: invalid event: " << eventValidation.error();
+ return InputEventInjectionResult::FAILED;
+ }
+
if (debugInboundEventDetails()) {
LOG(DEBUG) << __func__ << ": targetUid=" << toString(targetUid)
<< ", syncMode=" << ftl::enum_string(syncMode) << ", timeout=" << timeout.count()
@@ -4394,11 +4440,7 @@
switch (event->getType()) {
case InputEventType::KEY: {
const KeyEvent& incomingKey = static_cast<const KeyEvent&>(*event);
- int32_t action = incomingKey.getAction();
- if (!validateKeyEvent(action)) {
- return InputEventInjectionResult::FAILED;
- }
-
+ const int32_t action = incomingKey.getAction();
int32_t flags = incomingKey.getFlags();
if (policyFlags & POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY) {
flags |= AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT;
@@ -4440,20 +4482,13 @@
case InputEventType::MOTION: {
const MotionEvent& motionEvent = static_cast<const MotionEvent&>(*event);
- const int32_t action = motionEvent.getAction();
const bool isPointerEvent =
isFromSource(event->getSource(), AINPUT_SOURCE_CLASS_POINTER);
// If a pointer event has no displayId specified, inject it to the default display.
const uint32_t displayId = isPointerEvent && (event->getDisplayId() == ADISPLAY_ID_NONE)
? ADISPLAY_ID_DEFAULT
: event->getDisplayId();
- const size_t pointerCount = motionEvent.getPointerCount();
- const PointerProperties* pointerProperties = motionEvent.getPointerProperties();
- const int32_t actionButton = motionEvent.getActionButton();
int32_t flags = motionEvent.getFlags();
- if (!validateMotionEvent(action, actionButton, pointerCount, pointerProperties)) {
- return InputEventInjectionResult::FAILED;
- }
if (!(policyFlags & POLICY_FLAG_FILTERED)) {
nsecs_t eventTime = motionEvent.getEventTime();
@@ -4475,8 +4510,9 @@
std::unique_ptr<MotionEntry> injectedEntry =
std::make_unique<MotionEntry>(motionEvent.getId(), *sampleEventTimes,
resolvedDeviceId, motionEvent.getSource(),
- displayId, policyFlags, action, actionButton,
- flags, motionEvent.getMetaState(),
+ displayId, policyFlags, motionEvent.getAction(),
+ motionEvent.getActionButton(), flags,
+ motionEvent.getMetaState(),
motionEvent.getButtonState(),
motionEvent.getClassification(),
motionEvent.getEdgeFlags(),
@@ -4484,18 +4520,22 @@
motionEvent.getYPrecision(),
motionEvent.getRawXCursorPosition(),
motionEvent.getRawYCursorPosition(),
- motionEvent.getDownTime(), uint32_t(pointerCount),
- pointerProperties, samplePointerCoords);
+ motionEvent.getDownTime(),
+ motionEvent.getPointerCount(),
+ motionEvent.getPointerProperties(),
+ samplePointerCoords);
transformMotionEntryForInjectionLocked(*injectedEntry, motionEvent.getTransform());
injectedEntries.push(std::move(injectedEntry));
for (size_t i = motionEvent.getHistorySize(); i > 0; i--) {
sampleEventTimes += 1;
- samplePointerCoords += pointerCount;
+ samplePointerCoords += motionEvent.getPointerCount();
std::unique_ptr<MotionEntry> nextInjectedEntry =
std::make_unique<MotionEntry>(motionEvent.getId(), *sampleEventTimes,
resolvedDeviceId, motionEvent.getSource(),
- displayId, policyFlags, action, actionButton,
- flags, motionEvent.getMetaState(),
+ displayId, policyFlags,
+ motionEvent.getAction(),
+ motionEvent.getActionButton(), flags,
+ motionEvent.getMetaState(),
motionEvent.getButtonState(),
motionEvent.getClassification(),
motionEvent.getEdgeFlags(),
@@ -4504,7 +4544,8 @@
motionEvent.getRawXCursorPosition(),
motionEvent.getRawYCursorPosition(),
motionEvent.getDownTime(),
- uint32_t(pointerCount), pointerProperties,
+ motionEvent.getPointerCount(),
+ motionEvent.getPointerProperties(),
samplePointerCoords);
transformMotionEntryForInjectionLocked(*nextInjectedEntry,
motionEvent.getTransform());
@@ -6607,6 +6648,14 @@
mLooper->wake();
}
+void InputDispatcher::requestRefreshConfiguration() {
+ InputDispatcherConfiguration config;
+ mPolicy->getDispatcherConfiguration(&config);
+
+ std::scoped_lock _l(mLock);
+ mConfig = config;
+}
+
void InputDispatcher::setMonitorDispatchingTimeoutForTest(std::chrono::nanoseconds timeout) {
std::scoped_lock _l(mLock);
mMonitorDispatchingTimeout = timeout;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 7aa1a2d..dd7f7fe 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -149,6 +149,8 @@
void cancelCurrentTouch() override;
+ void requestRefreshConfiguration() override;
+
// Public to allow tests to verify that a Monitor can get ANR.
void setMonitorDispatchingTimeoutForTest(std::chrono::nanoseconds timeout);
@@ -166,7 +168,7 @@
std::unique_ptr<InputThread> mThread;
sp<InputDispatcherPolicyInterface> mPolicy;
- android::InputDispatcherConfiguration mConfig;
+ android::InputDispatcherConfiguration mConfig GUARDED_BY(mLock);
std::mutex mLock;
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index 76dce63..c752ddd 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -225,6 +225,12 @@
* Abort the current touch stream.
*/
virtual void cancelCurrentTouch() = 0;
+
+ /**
+ * Request that the InputDispatcher's configuration, which can be obtained through the policy,
+ * be updated.
+ */
+ virtual void requestRefreshConfiguration() = 0;
};
} // namespace android
diff --git a/services/inputflinger/host/Android.bp b/services/inputflinger/host/Android.bp
index 743587c..4d2839f 100644
--- a/services/inputflinger/host/Android.bp
+++ b/services/inputflinger/host/Android.bp
@@ -23,7 +23,7 @@
cc_library_shared {
name: "libinputflingerhost",
-
+ cpp_std: "c++20",
srcs: [
"InputFlinger.cpp",
"InputDriver.cpp",
@@ -64,14 +64,17 @@
srcs: ["main.cpp"],
- cflags: ["-Wall", "-Werror"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
shared_libs: [
"libbase",
"libbinder",
"libinputflingerhost",
"libutils",
- "libinput"
+ "libinput",
],
static_libs: [
"libarect",
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 27d7b9c..b3c5095 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -5284,6 +5284,7 @@
mFakePolicy = sp<FakeInputDispatcherPolicy>::make();
mFakePolicy->setKeyRepeatConfiguration(KEY_REPEAT_TIMEOUT, KEY_REPEAT_DELAY);
mDispatcher = std::make_unique<InputDispatcher>(mFakePolicy);
+ mDispatcher->requestRefreshConfiguration();
mDispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
ASSERT_EQ(OK, mDispatcher->start());
@@ -6140,6 +6141,28 @@
touchAndAssertPositions(AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints);
}
+/**
+ * When one of the windows is slippery, the touch should not slip into the other window with the
+ * same input channel.
+ */
+TEST_F(InputDispatcherMultiWindowSameTokenTests, TouchDoesNotSlipEvenIfSlippery) {
+ mWindow1->setSlippery(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow1, mWindow2}}});
+
+ // Touch down in window 1
+ mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {{50, 50}}));
+ consumeMotionEvent(mWindow1, ACTION_DOWN, {{50, 50}});
+
+ // Move touch to be above window 2. Even though window 1 is slippery, touch should not slip.
+ // That means the gesture should continue normally, without any ACTION_CANCEL or ACTION_DOWN
+ // getting generated.
+ mDispatcher->notifyMotion(generateMotionArgs(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {{150, 150}}));
+
+ consumeMotionEvent(mWindow1, ACTION_MOVE, {{150, 150}});
+}
+
class InputDispatcherSingleWindowAnr : public InputDispatcherTest {
virtual void SetUp() override {
InputDispatcherTest::SetUp();
diff --git a/services/sensorservice/BatteryService.cpp b/services/sensorservice/BatteryService.cpp
index b0fbe5d..0ea548c 100644
--- a/services/sensorservice/BatteryService.cpp
+++ b/services/sensorservice/BatteryService.cpp
@@ -30,8 +30,8 @@
namespace android {
// ---------------------------------------------------------------------------
-BatteryService::BatteryService() : mBatteryStatService(nullptr) {
-}
+BatteryService::BatteryService()
+ : mBatteryStatService(nullptr), mLastWakeupSensorEventReportedMs(0) {}
bool BatteryService::addSensor(uid_t uid, int handle) {
Mutex::Autolock _l(mActivationsLock);
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index f28bfd4..f7049b9 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -329,14 +329,6 @@
}
}
-void AidlComposer::resetCommands(Display display) {
- mMutex.lock_shared();
- if (auto writer = getWriter(display)) {
- writer->get().reset();
- }
- mMutex.unlock_shared();
-}
-
Error AidlComposer::executeCommands(Display display) {
mMutex.lock_shared();
auto error = execute(display);
@@ -1054,9 +1046,8 @@
return Error::BAD_DISPLAY;
}
- const auto& commands = writer->get().getPendingCommands();
+ auto commands = writer->get().takePendingCommands();
if (commands.empty()) {
- writer->get().reset();
return Error::NONE;
}
@@ -1088,8 +1079,6 @@
}
}
- writer->get().reset();
-
return error;
}
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
index 8313c09..ce05b38 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
@@ -72,10 +72,6 @@
void registerCallback(HWC2::ComposerCallback& callback) override;
- // Reset all pending commands in the command buffer. Useful if you want to
- // skip a frame but have already queued some commands.
- void resetCommands(Display) override;
-
// Explicitly flush all pending commands in the command buffer.
Error executeCommands(Display) override;
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index c65c572..cf67795 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -110,10 +110,6 @@
virtual void registerCallback(HWC2::ComposerCallback& callback) = 0;
- // Reset all pending commands in the command buffer. Useful if you want to
- // skip a frame but have already queued some commands.
- virtual void resetCommands(Display) = 0;
-
// Explicitly flush all pending commands in the command buffer.
virtual Error executeCommands(Display) = 0;
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
index 23de4fa..e0f6c45 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -293,10 +293,6 @@
}
}
-void HidlComposer::resetCommands(Display) {
- mWriter.reset();
-}
-
Error HidlComposer::executeCommands(Display) {
return execute();
}
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
index d04652b..0521acf 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
@@ -174,10 +174,6 @@
void registerCallback(HWC2::ComposerCallback& callback) override;
- // Reset all pending commands in the command buffer. Useful if you want to
- // skip a frame but have already queued some commands.
- void resetCommands(Display) override;
-
// Explicitly flush all pending commands in the command buffer.
Error executeCommands(Display) override;
diff --git a/services/surfaceflinger/DisplayRenderArea.cpp b/services/surfaceflinger/DisplayRenderArea.cpp
index 8f39e26..e55cd3e 100644
--- a/services/surfaceflinger/DisplayRenderArea.cpp
+++ b/services/surfaceflinger/DisplayRenderArea.cpp
@@ -35,21 +35,24 @@
const Rect& sourceCrop, ui::Size reqSize,
ui::Dataspace reqDataSpace,
bool useIdentityTransform,
+ bool hintForSeamlessTransition,
bool allowSecureLayers) {
if (auto display = displayWeak.promote()) {
// Using new to access a private constructor.
return std::unique_ptr<DisplayRenderArea>(
new DisplayRenderArea(std::move(display), sourceCrop, reqSize, reqDataSpace,
- useIdentityTransform, allowSecureLayers));
+ useIdentityTransform, hintForSeamlessTransition,
+ allowSecureLayers));
}
return nullptr;
}
DisplayRenderArea::DisplayRenderArea(sp<const DisplayDevice> display, const Rect& sourceCrop,
ui::Size reqSize, ui::Dataspace reqDataSpace,
- bool useIdentityTransform, bool allowSecureLayers)
- : RenderArea(reqSize, CaptureFill::OPAQUE, reqDataSpace, allowSecureLayers,
- applyDeviceOrientation(useIdentityTransform, *display)),
+ bool useIdentityTransform, bool hintForSeamlessTransition,
+ bool allowSecureLayers)
+ : RenderArea(reqSize, CaptureFill::OPAQUE, reqDataSpace, hintForSeamlessTransition,
+ allowSecureLayers, applyDeviceOrientation(useIdentityTransform, *display)),
mDisplay(std::move(display)),
mSourceCrop(sourceCrop) {}
diff --git a/services/surfaceflinger/DisplayRenderArea.h b/services/surfaceflinger/DisplayRenderArea.h
index ce5410a..9a4981c 100644
--- a/services/surfaceflinger/DisplayRenderArea.h
+++ b/services/surfaceflinger/DisplayRenderArea.h
@@ -30,6 +30,7 @@
static std::unique_ptr<RenderArea> create(wp<const DisplayDevice>, const Rect& sourceCrop,
ui::Size reqSize, ui::Dataspace,
bool useIdentityTransform,
+ bool hintForSeamlessTransition,
bool allowSecureLayers = true);
const ui::Transform& getTransform() const override;
@@ -39,7 +40,8 @@
private:
DisplayRenderArea(sp<const DisplayDevice>, const Rect& sourceCrop, ui::Size reqSize,
- ui::Dataspace, bool useIdentityTransform, bool allowSecureLayers = true);
+ ui::Dataspace, bool useIdentityTransform, bool hintForSeamlessTransition,
+ bool allowSecureLayers = true);
const sp<const DisplayDevice> mDisplay;
const Rect mSourceCrop;
diff --git a/services/surfaceflinger/LayerRenderArea.cpp b/services/surfaceflinger/LayerRenderArea.cpp
index 1b8ff28..f6b5afc 100644
--- a/services/surfaceflinger/LayerRenderArea.cpp
+++ b/services/surfaceflinger/LayerRenderArea.cpp
@@ -40,8 +40,9 @@
LayerRenderArea::LayerRenderArea(SurfaceFlinger& flinger, sp<Layer> layer, const Rect& crop,
ui::Size reqSize, ui::Dataspace reqDataSpace, bool childrenOnly,
bool allowSecureLayers, const ui::Transform& layerTransform,
- const Rect& layerBufferSize)
- : RenderArea(reqSize, CaptureFill::CLEAR, reqDataSpace, allowSecureLayers),
+ const Rect& layerBufferSize, bool hintForSeamlessTransition)
+ : RenderArea(reqSize, CaptureFill::CLEAR, reqDataSpace, hintForSeamlessTransition,
+ allowSecureLayers),
mLayer(std::move(layer)),
mLayerTransform(layerTransform),
mLayerBufferSize(layerBufferSize),
diff --git a/services/surfaceflinger/LayerRenderArea.h b/services/surfaceflinger/LayerRenderArea.h
index 9bb13b3..aa609ee 100644
--- a/services/surfaceflinger/LayerRenderArea.h
+++ b/services/surfaceflinger/LayerRenderArea.h
@@ -34,7 +34,8 @@
public:
LayerRenderArea(SurfaceFlinger& flinger, sp<Layer> layer, const Rect& crop, ui::Size reqSize,
ui::Dataspace reqDataSpace, bool childrenOnly, bool allowSecureLayers,
- const ui::Transform& layerTransform, const Rect& layerBufferSize);
+ const ui::Transform& layerTransform, const Rect& layerBufferSize,
+ bool hintForSeamlessTransition);
const ui::Transform& getTransform() const override;
bool isSecure() const override;
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index 9a4261d..f1fd6db 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -355,6 +355,8 @@
if (isSetByHwc()) {
transaction.setFlags(surface, layer_state_t::eLayerIsRefreshRateIndicator,
layer_state_t::eLayerIsRefreshRateIndicator);
+ // Disable overlay layer caching when refresh rate is updated by the HWC.
+ transaction.setCachingHint(surface, gui::CachingHint::Disabled);
}
transaction.setFrameRate(surface, kFrameRate, kCompatibility, kSeamlessness);
return transaction;
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 531d277..8f658d5 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -277,10 +277,12 @@
const Rect sampledBounds = sampleRegion.bounds();
constexpr bool kUseIdentityTransform = false;
+ constexpr bool kHintForSeamlessTransition = false;
SurfaceFlinger::RenderAreaFuture renderAreaFuture = ftl::defer([=] {
return DisplayRenderArea::create(displayWeak, sampledBounds, sampledBounds.getSize(),
- ui::Dataspace::V0_SRGB, kUseIdentityTransform);
+ ui::Dataspace::V0_SRGB, kUseIdentityTransform,
+ kHintForSeamlessTransition);
});
std::unordered_set<sp<IRegionSamplingListener>, SpHash<IRegionSamplingListener>> listeners;
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
index 910fce0..71b85bd 100644
--- a/services/surfaceflinger/RenderArea.h
+++ b/services/surfaceflinger/RenderArea.h
@@ -25,12 +25,14 @@
static float getCaptureFillValue(CaptureFill captureFill);
RenderArea(ui::Size reqSize, CaptureFill captureFill, ui::Dataspace reqDataSpace,
- bool allowSecureLayers = false, RotationFlags rotation = ui::Transform::ROT_0)
+ bool hintForSeamlessTransition, bool allowSecureLayers = false,
+ RotationFlags rotation = ui::Transform::ROT_0)
: mAllowSecureLayers(allowSecureLayers),
mReqSize(reqSize),
mReqDataSpace(reqDataSpace),
mCaptureFill(captureFill),
- mRotationFlags(rotation) {}
+ mRotationFlags(rotation),
+ mHintForSeamlessTransition(hintForSeamlessTransition) {}
static std::function<std::vector<std::pair<Layer*, sp<LayerFE>>>()> fromTraverseLayersLambda(
std::function<void(const LayerVector::Visitor&)> traverseLayers) {
@@ -90,6 +92,10 @@
// capture operation.
virtual sp<Layer> getParentLayer() const { return nullptr; }
+ // Returns whether the render result may be used for system animations that
+ // must preserve the exact colors of the display.
+ bool getHintForSeamlessTransition() const { return mHintForSeamlessTransition; }
+
protected:
const bool mAllowSecureLayers;
@@ -98,7 +104,7 @@
const ui::Dataspace mReqDataSpace;
const CaptureFill mCaptureFill;
const RotationFlags mRotationFlags;
- const Rect mLayerStackSpaceRect;
+ const bool mHintForSeamlessTransition;
};
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 74665a7..1c0bf0d 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -692,17 +692,27 @@
}
void EventThread::onNewVsyncSchedule(std::shared_ptr<scheduler::VsyncSchedule> schedule) {
+ // Hold onto the old registration until after releasing the mutex to avoid deadlock.
+ scheduler::VSyncCallbackRegistration oldRegistration =
+ onNewVsyncScheduleInternal(std::move(schedule));
+}
+
+scheduler::VSyncCallbackRegistration EventThread::onNewVsyncScheduleInternal(
+ std::shared_ptr<scheduler::VsyncSchedule> schedule) {
std::lock_guard<std::mutex> lock(mMutex);
const bool reschedule = mVsyncRegistration.cancel() == scheduler::CancelResult::Cancelled;
mVsyncSchedule = std::move(schedule);
- mVsyncRegistration =
- scheduler::VSyncCallbackRegistration(mVsyncSchedule->getDispatch(),
- createDispatchCallback(), mThreadName);
+ auto oldRegistration =
+ std::exchange(mVsyncRegistration,
+ scheduler::VSyncCallbackRegistration(mVsyncSchedule->getDispatch(),
+ createDispatchCallback(),
+ mThreadName));
if (reschedule) {
mVsyncRegistration.schedule({.workDuration = mWorkDuration.get().count(),
.readyDuration = mReadyDuration.count(),
.earliestVsync = mLastVsyncCallbackTime.ns()});
}
+ return oldRegistration;
}
scheduler::VSyncDispatch::Callback EventThread::createDispatchCallback() {
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 30869e9..684745b 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -174,7 +174,7 @@
size_t getEventThreadConnectionCount() override;
- void onNewVsyncSchedule(std::shared_ptr<scheduler::VsyncSchedule>) override;
+ void onNewVsyncSchedule(std::shared_ptr<scheduler::VsyncSchedule>) override EXCLUDES(mMutex);
private:
friend EventThreadTest;
@@ -201,6 +201,11 @@
scheduler::VSyncDispatch::Callback createDispatchCallback();
+ // Returns the old registration so it can be destructed outside the lock to
+ // avoid deadlock.
+ scheduler::VSyncCallbackRegistration onNewVsyncScheduleInternal(
+ std::shared_ptr<scheduler::VsyncSchedule>) EXCLUDES(mMutex);
+
const char* const mThreadName;
TracedOrdinal<int> mVsyncTracer;
TracedOrdinal<std::chrono::nanoseconds> mWorkDuration GUARDED_BY(mMutex);
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 63a0173..1e45b41 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -830,81 +830,35 @@
using RankedRefreshRates = RefreshRateSelector::RankedFrameRates;
display::PhysicalDisplayVector<RankedRefreshRates> perDisplayRanking;
-
- // Tallies the score of a refresh rate across `displayCount` displays.
- struct RefreshRateTally {
- explicit RefreshRateTally(float score) : score(score) {}
-
- float score;
- size_t displayCount = 1;
- };
-
- // Chosen to exceed a typical number of refresh rates across displays.
- constexpr size_t kStaticCapacity = 8;
- ftl::SmallMap<Fps, RefreshRateTally, kStaticCapacity, FpsApproxEqual> refreshRateTallies;
-
const auto globalSignals = makeGlobalSignals();
+ Fps pacesetterFps;
for (const auto& [id, display] : mDisplays) {
auto rankedFrameRates =
display.selectorPtr->getRankedFrameRates(mPolicy.contentRequirements,
globalSignals);
-
- for (const auto& [frameRateMode, score] : rankedFrameRates.ranking) {
- const auto [it, inserted] = refreshRateTallies.try_emplace(frameRateMode.fps, score);
-
- if (!inserted) {
- auto& tally = it->second;
- tally.score += score;
- tally.displayCount++;
- }
+ if (id == *mPacesetterDisplayId) {
+ pacesetterFps = rankedFrameRates.ranking.front().frameRateMode.fps;
}
-
perDisplayRanking.push_back(std::move(rankedFrameRates));
}
- auto maxScoreIt = refreshRateTallies.cbegin();
-
- // Find the first refresh rate common to all displays.
- while (maxScoreIt != refreshRateTallies.cend() &&
- maxScoreIt->second.displayCount != mDisplays.size()) {
- ++maxScoreIt;
- }
-
- if (maxScoreIt != refreshRateTallies.cend()) {
- // Choose the highest refresh rate common to all displays, if any.
- for (auto it = maxScoreIt + 1; it != refreshRateTallies.cend(); ++it) {
- const auto [fps, tally] = *it;
-
- if (tally.displayCount == mDisplays.size() && tally.score > maxScoreIt->second.score) {
- maxScoreIt = it;
- }
- }
- }
-
- const std::optional<Fps> chosenFps = maxScoreIt != refreshRateTallies.cend()
- ? std::make_optional(maxScoreIt->first)
- : std::nullopt;
-
DisplayModeChoiceMap modeChoices;
-
using fps_approx_ops::operator==;
- for (auto& [ranking, signals] : perDisplayRanking) {
- if (!chosenFps) {
- const auto& [frameRateMode, _] = ranking.front();
- modeChoices.try_emplace(frameRateMode.modePtr->getPhysicalDisplayId(),
- DisplayModeChoice{frameRateMode, signals});
- continue;
- }
+ for (auto& [rankings, signals] : perDisplayRanking) {
+ const auto chosenFrameRateMode =
+ ftl::find_if(rankings,
+ [&](const auto& ranking) {
+ return ranking.frameRateMode.fps == pacesetterFps;
+ })
+ .transform([](const auto& scoredFrameRate) {
+ return scoredFrameRate.get().frameRateMode;
+ })
+ .value_or(rankings.front().frameRateMode);
- for (auto& [frameRateMode, _] : ranking) {
- if (frameRateMode.fps == *chosenFps) {
- modeChoices.try_emplace(frameRateMode.modePtr->getPhysicalDisplayId(),
- DisplayModeChoice{frameRateMode, signals});
- break;
- }
- }
+ modeChoices.try_emplace(chosenFrameRateMode.modePtr->getPhysicalDisplayId(),
+ DisplayModeChoice{chosenFrameRateMode, signals});
}
return modeChoices;
}
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatch.h b/services/surfaceflinger/Scheduler/VSyncDispatch.h
index 77875e3..c3a952f 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatch.h
+++ b/services/surfaceflinger/Scheduler/VSyncDispatch.h
@@ -155,10 +155,6 @@
VSyncDispatch& operator=(const VSyncDispatch&) = delete;
};
-/*
- * Helper class to operate on registered callbacks. It is up to user of the class to ensure
- * that VsyncDispatch lifetime exceeds the lifetime of VSyncCallbackRegistation.
- */
class VSyncCallbackRegistration {
public:
VSyncCallbackRegistration(std::shared_ptr<VSyncDispatch>, VSyncDispatch::Callback,
@@ -178,9 +174,10 @@
CancelResult cancel();
private:
+ friend class VSyncCallbackRegistrationTest;
+
std::shared_ptr<VSyncDispatch> mDispatch;
- VSyncDispatch::CallbackToken mToken;
- bool mValidToken;
+ std::optional<VSyncDispatch::CallbackToken> mToken;
};
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
index 26389eb..1f922f1 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
@@ -21,12 +21,16 @@
#include <android-base/stringprintf.h>
#include <ftl/concat.h>
#include <utils/Trace.h>
+#include <log/log_main.h>
#include <scheduler/TimeKeeper.h>
#include "VSyncDispatchTimerQueue.h"
#include "VSyncTracker.h"
+#undef LOG_TAG
+#define LOG_TAG "VSyncDispatch"
+
namespace android::scheduler {
using base::StringAppendF;
@@ -225,6 +229,10 @@
VSyncDispatchTimerQueue::~VSyncDispatchTimerQueue() {
std::lock_guard lock(mMutex);
cancelTimer();
+ for (auto& [_, entry] : mCallbacks) {
+ ALOGE("Forgot to unregister a callback on VSyncDispatch!");
+ entry->ensureNotRunning();
+ }
}
void VSyncDispatchTimerQueue::cancelTimer() {
@@ -438,47 +446,44 @@
VSyncDispatch::Callback callback,
std::string callbackName)
: mDispatch(std::move(dispatch)),
- mToken(mDispatch->registerCallback(std::move(callback), std::move(callbackName))),
- mValidToken(true) {}
+ mToken(mDispatch->registerCallback(std::move(callback), std::move(callbackName))) {}
VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncCallbackRegistration&& other)
- : mDispatch(std::move(other.mDispatch)),
- mToken(std::move(other.mToken)),
- mValidToken(std::move(other.mValidToken)) {
- other.mValidToken = false;
-}
+ : mDispatch(std::move(other.mDispatch)), mToken(std::exchange(other.mToken, std::nullopt)) {}
VSyncCallbackRegistration& VSyncCallbackRegistration::operator=(VSyncCallbackRegistration&& other) {
+ if (this == &other) return *this;
+ if (mToken) {
+ mDispatch->unregisterCallback(*mToken);
+ }
mDispatch = std::move(other.mDispatch);
- mToken = std::move(other.mToken);
- mValidToken = std::move(other.mValidToken);
- other.mValidToken = false;
+ mToken = std::exchange(other.mToken, std::nullopt);
return *this;
}
VSyncCallbackRegistration::~VSyncCallbackRegistration() {
- if (mValidToken) mDispatch->unregisterCallback(mToken);
+ if (mToken) mDispatch->unregisterCallback(*mToken);
}
ScheduleResult VSyncCallbackRegistration::schedule(VSyncDispatch::ScheduleTiming scheduleTiming) {
- if (!mValidToken) {
+ if (!mToken) {
return std::nullopt;
}
- return mDispatch->schedule(mToken, scheduleTiming);
+ return mDispatch->schedule(*mToken, scheduleTiming);
}
ScheduleResult VSyncCallbackRegistration::update(VSyncDispatch::ScheduleTiming scheduleTiming) {
- if (!mValidToken) {
+ if (!mToken) {
return std::nullopt;
}
- return mDispatch->update(mToken, scheduleTiming);
+ return mDispatch->update(*mToken, scheduleTiming);
}
CancelResult VSyncCallbackRegistration::cancel() {
- if (!mValidToken) {
+ if (!mToken) {
return CancelResult::Error;
}
- return mDispatch->cancel(mToken);
+ return mDispatch->cancel(*mToken);
}
} // namespace android::scheduler
diff --git a/services/surfaceflinger/ScreenCaptureOutput.cpp b/services/surfaceflinger/ScreenCaptureOutput.cpp
index a1d5cd7..b70b53d 100644
--- a/services/surfaceflinger/ScreenCaptureOutput.cpp
+++ b/services/surfaceflinger/ScreenCaptureOutput.cpp
@@ -36,6 +36,7 @@
output->setLayerFilter({args.layerStack});
output->setRenderSurface(std::make_unique<ScreenCaptureRenderSurface>(std::move(args.buffer)));
output->setDisplayBrightness(args.sdrWhitePointNits, args.displayBrightnessNits);
+ output->editState().clientTargetBrightness = args.targetBrightness;
output->setDisplayColorProfile(std::make_unique<compositionengine::impl::DisplayColorProfile>(
compositionengine::DisplayColorProfileCreationArgsBuilder()
@@ -75,7 +76,6 @@
auto clientCompositionDisplay =
compositionengine::impl::Output::generateClientCompositionDisplaySettings();
clientCompositionDisplay.clip = mRenderArea.getSourceCrop();
- clientCompositionDisplay.targetLuminanceNits = -1;
return clientCompositionDisplay;
}
diff --git a/services/surfaceflinger/ScreenCaptureOutput.h b/services/surfaceflinger/ScreenCaptureOutput.h
index 4e5a0cc..3c307b0 100644
--- a/services/surfaceflinger/ScreenCaptureOutput.h
+++ b/services/surfaceflinger/ScreenCaptureOutput.h
@@ -33,6 +33,8 @@
std::shared_ptr<renderengine::ExternalTexture> buffer;
float sdrWhitePointNits;
float displayBrightnessNits;
+ // Counterintuitively, when targetBrightness > 1.0 then dim the scene.
+ float targetBrightness;
bool regionSampling;
};
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 48b4144..d406aff 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2146,7 +2146,14 @@
}));
}
-auto SurfaceFlinger::getPreviousPresentFence(TimePoint frameTime, Period vsyncPeriod)
+bool SurfaceFlinger::wouldPresentEarly(TimePoint frameTime, Period vsyncPeriod) const {
+ const bool isThreeVsyncsAhead = mExpectedPresentTime - frameTime > 2 * vsyncPeriod;
+ return isThreeVsyncsAhead ||
+ getPreviousPresentFence(frameTime, vsyncPeriod)->getSignalTime() !=
+ Fence::SIGNAL_TIME_PENDING;
+}
+
+auto SurfaceFlinger::getPreviousPresentFence(TimePoint frameTime, Period vsyncPeriod) const
-> const FenceTimePtr& {
const bool isTwoVsyncsAhead = mExpectedPresentTime - frameTime > vsyncPeriod;
const size_t i = static_cast<size_t>(isTwoVsyncsAhead);
@@ -2614,21 +2621,14 @@
refreshArgs.devOptFlashDirtyRegionsDelay = std::chrono::milliseconds(mDebugFlashDelay);
}
- const auto prevVsyncTime = mExpectedPresentTime - mScheduler->getVsyncSchedule()->period();
- const auto hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration;
-
const Period vsyncPeriod = mScheduler->getVsyncSchedule()->period();
- const bool threeVsyncsAhead = mExpectedPresentTime - frameTime > 2 * vsyncPeriod;
- // We should wait for the earliest present time if HWC doesn't support ExpectedPresentTime,
- // and the next vsync is not already taken by the previous frame.
- const bool waitForEarliestPresent =
- !getHwComposer().getComposer()->isSupported(
- Hwc2::Composer::OptionalFeature::ExpectedPresentTime) &&
- (threeVsyncsAhead ||
- mPreviousPresentFences[0].fenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING);
+ if (!getHwComposer().getComposer()->isSupported(
+ Hwc2::Composer::OptionalFeature::ExpectedPresentTime) &&
+ wouldPresentEarly(frameTime, vsyncPeriod)) {
+ const auto prevVsyncTime = mExpectedPresentTime - vsyncPeriod;
+ const auto hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration;
- if (waitForEarliestPresent) {
refreshArgs.earliestPresentTime = prevVsyncTime - hwcMinWorkDuration;
}
@@ -2662,9 +2662,10 @@
// Send a power hint hint after presentation is finished
if (mPowerHintSessionEnabled) {
- mPowerAdvisor->setSfPresentTiming(TimePoint::fromNs(mPreviousPresentFences[0]
- .fenceTime->getSignalTime()),
- TimePoint::now());
+ const nsecs_t pastPresentTime =
+ getPreviousPresentFence(frameTime, vsyncPeriod)->getSignalTime();
+
+ mPowerAdvisor->setSfPresentTiming(TimePoint::fromNs(pastPresentTime), TimePoint::now());
mPowerAdvisor->reportActualWorkDuration();
}
@@ -3718,10 +3719,10 @@
}
void SurfaceFlinger::updateInputFlinger() {
- ATRACE_CALL();
- if (!mInputFlinger) {
+ if (!mInputFlinger || (!mUpdateInputInfo && mInputWindowCommands.empty())) {
return;
}
+ ATRACE_CALL();
std::vector<WindowInfo> windowInfos;
std::vector<DisplayInfo> displayInfos;
@@ -3730,20 +3731,18 @@
mUpdateInputInfo = false;
updateWindowInfo = true;
buildWindowInfos(windowInfos, displayInfos);
- } else if (mInputWindowCommands.empty()) {
- return;
}
- std::unordered_set<Layer*> visibleLayers;
- mDrawingState.traverse([&visibleLayers](Layer* layer) {
- if (layer->isVisibleForInput()) {
- visibleLayers.insert(layer);
+ std::unordered_set<int32_t> visibleWindowIds;
+ for (WindowInfo& windowInfo : windowInfos) {
+ if (!windowInfo.inputConfig.test(WindowInfo::InputConfig::NOT_VISIBLE)) {
+ visibleWindowIds.insert(windowInfo.id);
}
- });
- bool visibleLayersChanged = false;
- if (visibleLayers != mVisibleLayers) {
- visibleLayersChanged = true;
- mVisibleLayers = std::move(visibleLayers);
+ }
+ bool visibleWindowsChanged = false;
+ if (visibleWindowIds != mVisibleWindowIds) {
+ visibleWindowsChanged = true;
+ mVisibleWindowIds = std::move(visibleWindowIds);
}
BackgroundExecutor::getInstance().sendCallbacks({[updateWindowInfo,
@@ -3752,14 +3751,14 @@
inputWindowCommands =
std::move(mInputWindowCommands),
inputFlinger = mInputFlinger, this,
- visibleLayersChanged]() {
+ visibleWindowsChanged]() {
ATRACE_NAME("BackgroundExecutor::updateInputFlinger");
if (updateWindowInfo) {
mWindowInfosListenerInvoker
->windowInfosChanged(std::move(windowInfos), std::move(displayInfos),
std::move(
inputWindowCommands.windowInfosReportedListeners),
- /* forceImmediateCall= */ visibleLayersChanged ||
+ /* forceImmediateCall= */ visibleWindowsChanged ||
!inputWindowCommands.focusRequests.empty());
} else {
// If there are listeners but no changes to input windows, call the listeners
@@ -6916,6 +6915,32 @@
return NO_ERROR;
}
+namespace {
+
+ui::Dataspace pickBestDataspace(ui::Dataspace requestedDataspace, const DisplayDevice* display,
+ bool capturingHdrLayers, bool hintForSeamlessTransition) {
+ if (requestedDataspace != ui::Dataspace::UNKNOWN || display == nullptr) {
+ return requestedDataspace;
+ }
+
+ const auto& state = display->getCompositionDisplay()->getState();
+
+ const auto dataspaceForColorMode = ui::pickDataspaceFor(state.colorMode);
+
+ if (capturingHdrLayers && !hintForSeamlessTransition) {
+ // For now since we only support 8-bit screenshots, just use HLG and
+ // assume that 1.0 >= display max luminance. This isn't quite as future
+ // proof as PQ is, but is good enough.
+ // Consider using PQ once we support 16-bit screenshots and we're able
+ // to consistently supply metadata to image encoders.
+ return ui::Dataspace::BT2020_HLG;
+ }
+
+ return dataspaceForColorMode;
+}
+
+} // namespace
+
status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args,
const sp<IScreenCaptureListener>& captureListener) {
ATRACE_CALL();
@@ -6931,7 +6956,6 @@
ui::LayerStack layerStack;
ui::Size reqSize(args.width, args.height);
std::unordered_set<uint32_t> excludeLayerIds;
- ui::Dataspace dataspace;
{
Mutex::Autolock lock(mStateLock);
sp<DisplayDevice> display = getDisplayDeviceLocked(args.displayToken);
@@ -6953,17 +6977,12 @@
return NAME_NOT_FOUND;
}
}
-
- // Allow the caller to specify a dataspace regardless of the display's color mode, e.g. if
- // it wants sRGB regardless of the display's wide color mode.
- dataspace = args.dataspace == ui::Dataspace::UNKNOWN
- ? ui::pickDataspaceFor(display->getCompositionDisplay()->getState().colorMode)
- : args.dataspace;
}
RenderAreaFuture renderAreaFuture = ftl::defer([=] {
- return DisplayRenderArea::create(displayWeak, args.sourceCrop, reqSize, dataspace,
- args.useIdentityTransform, args.captureSecureLayers);
+ return DisplayRenderArea::create(displayWeak, args.sourceCrop, reqSize,
+ ui::Dataspace::UNKNOWN, args.useIdentityTransform,
+ args.hintForSeamlessTransition, args.captureSecureLayers);
});
GetLayerSnapshotsFunction getLayerSnapshots;
@@ -6989,7 +7008,6 @@
ui::LayerStack layerStack;
wp<const DisplayDevice> displayWeak;
ui::Size size;
- ui::Dataspace dataspace;
{
Mutex::Autolock lock(mStateLock);
@@ -7001,12 +7019,12 @@
displayWeak = display;
layerStack = display->getLayerStack();
size = display->getLayerStackSpaceRect().getSize();
- dataspace = ui::pickDataspaceFor(display->getCompositionDisplay()->getState().colorMode);
}
RenderAreaFuture renderAreaFuture = ftl::defer([=] {
- return DisplayRenderArea::create(displayWeak, Rect(), size, dataspace,
+ return DisplayRenderArea::create(displayWeak, Rect(), size, ui::Dataspace::UNKNOWN,
false /* useIdentityTransform */,
+ false /* hintForSeamlessTransition */,
false /* captureSecureLayers */);
});
@@ -7048,7 +7066,7 @@
sp<Layer> parent;
Rect crop(args.sourceCrop);
std::unordered_set<uint32_t> excludeLayerIds;
- ui::Dataspace dataspace;
+ ui::Dataspace dataspace = args.dataspace;
// Call this before holding mStateLock to avoid any deadlocking.
bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission();
@@ -7095,12 +7113,6 @@
return NAME_NOT_FOUND;
}
}
-
- // The dataspace is depended on the color mode of display, that could use non-native mode
- // (ex. displayP3) to enhance the content, but some cases are checking native RGB in bytes,
- // and failed if display is not in native mode. This provide a way to force using native
- // colors when capture.
- dataspace = args.dataspace;
} // mStateLock
// really small crop or frameScale
@@ -7129,7 +7141,8 @@
return std::make_unique<LayerRenderArea>(*this, parent, crop, reqSize, dataspace,
childrenOnly, args.captureSecureLayers,
- layerTransform, layerBufferSize);
+ layerTransform, layerBufferSize,
+ args.hintForSeamlessTransition);
});
GetLayerSnapshotsFunction getLayerSnapshots;
if (mLayerLifecycleManagerEnabled) {
@@ -7315,29 +7328,48 @@
return ftl::yield<FenceResult>(base::unexpected(PERMISSION_DENIED)).share();
}
- captureResults.buffer = buffer->getBuffer();
- auto dataspace = renderArea->getReqDataSpace();
+ auto capturedBuffer = buffer;
+
+ auto requestedDataspace = 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) {
+ captureResults.capturedDataspace = requestedDataspace;
+
+ {
Mutex::Autolock lock(mStateLock);
- auto display = findDisplay([layerStack = parent->getLayerStack()](const auto& display) {
- return display.getLayerStack() == layerStack;
- });
- if (!display) {
- // If the layer is not on a display, use the dataspace for the default display.
- display = getDefaultDisplayDeviceLocked();
+ const DisplayDevice* display = nullptr;
+ if (parent) {
+ display = findDisplay([layerStack = parent->getLayerStack()](const auto& display) {
+ return display.getLayerStack() == layerStack;
+ }).get();
}
- dataspace = ui::pickDataspaceFor(display->getCompositionDisplay()->getState().colorMode);
- renderIntent = display->getCompositionDisplay()->getState().renderIntent;
- sdrWhitePointNits = display->getCompositionDisplay()->getState().sdrWhitePointNits;
- displayBrightnessNits = display->getCompositionDisplay()->getState().displayBrightnessNits;
+ if (display == nullptr) {
+ display = renderArea->getDisplayDevice().get();
+ }
+
+ if (display == nullptr) {
+ display = getDefaultDisplayDeviceLocked().get();
+ }
+
+ if (display != nullptr) {
+ const auto& state = display->getCompositionDisplay()->getState();
+ captureResults.capturedDataspace =
+ pickBestDataspace(requestedDataspace, display, captureResults.capturedHdrLayers,
+ renderArea->getHintForSeamlessTransition());
+ sdrWhitePointNits = state.sdrWhitePointNits;
+ displayBrightnessNits = state.displayBrightnessNits;
+
+ if (requestedDataspace == ui::Dataspace::UNKNOWN) {
+ renderIntent = state.renderIntent;
+ }
+ }
}
- captureResults.capturedDataspace = dataspace;
+
+ captureResults.buffer = capturedBuffer->getBuffer();
ui::LayerStack layerStack{ui::DEFAULT_LAYER_STACK};
if (!layers.empty()) {
@@ -7354,9 +7386,9 @@
return layerFEs;
};
- auto present = [this, buffer = std::move(buffer), dataspace, sdrWhitePointNits,
- displayBrightnessNits, grayscale, layerFEs = copyLayerFEs(), layerStack,
- regionSampling, renderArea = std::move(renderArea),
+ auto present = [this, buffer = capturedBuffer, dataspace = captureResults.capturedDataspace,
+ sdrWhitePointNits, displayBrightnessNits, grayscale, layerFEs = copyLayerFEs(),
+ layerStack, regionSampling, renderArea = std::move(renderArea),
renderIntent]() -> FenceResult {
std::unique_ptr<compositionengine::CompositionEngine> compositionEngine =
mFactory.createCompositionEngine();
@@ -7365,6 +7397,16 @@
compositionengine::Output::ColorProfile colorProfile{.dataspace = dataspace,
.renderIntent = renderIntent};
+ float targetBrightness = 1.0f;
+ if (dataspace == ui::Dataspace::BT2020_HLG) {
+ const float maxBrightnessNits = displayBrightnessNits / sdrWhitePointNits * 203;
+ // With a low dimming ratio, don't fit the entire curve. Otherwise mixed content
+ // will appear way too bright.
+ if (maxBrightnessNits < 1000.f) {
+ targetBrightness = 1000.f / maxBrightnessNits;
+ }
+ }
+
std::shared_ptr<ScreenCaptureOutput> output = createScreenCaptureOutput(
ScreenCaptureOutputArgs{.compositionEngine = *compositionEngine,
.colorProfile = colorProfile,
@@ -7373,6 +7415,7 @@
.buffer = std::move(buffer),
.sdrWhitePointNits = sdrWhitePointNits,
.displayBrightnessNits = displayBrightnessNits,
+ .targetBrightness = targetBrightness,
.regionSampling = regionSampling});
const float colorSaturation = grayscale ? 0 : 1;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index fffd63a..cd7659b 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -998,7 +998,9 @@
using FenceTimePtr = std::shared_ptr<FenceTime>;
- const FenceTimePtr& getPreviousPresentFence(TimePoint frameTime, Period)
+ bool wouldPresentEarly(TimePoint frameTime, Period) const REQUIRES(kMainThreadContext);
+
+ const FenceTimePtr& getPreviousPresentFence(TimePoint frameTime, Period) const
REQUIRES(kMainThreadContext);
// Blocks the thread waiting for up to graceTimeMs in case the fence is about to signal.
@@ -1428,10 +1430,8 @@
display::DisplayMap<ui::LayerStack, frontend::DisplayInfo> mFrontEndDisplayInfos;
bool mFrontEndDisplayInfosChanged = false;
- // Layers visible during the last commit. This set should only be used for testing set equality
- // and membership. The pointers should not be dereferenced as it's possible the set contains
- // pointers to freed layers.
- std::unordered_set<Layer*> mVisibleLayers;
+ // WindowInfo ids visible during the last commit.
+ std::unordered_set<int32_t> mVisibleWindowIds;
};
class SurfaceComposerAIDL : public gui::BnSurfaceComposer {
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
index a9247fe..9fac14e 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
@@ -327,7 +327,6 @@
invokeComposerHal2_4(&composer, display, outLayer);
composer.executeCommands(display);
- composer.resetCommands(display);
composer.destroyLayer(display, outLayer);
composer.destroyVirtualDisplay(display);
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
index c3dcb85..921cae4 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
@@ -177,7 +177,8 @@
{mFdp.ConsumeIntegral<int32_t>(),
mFdp.ConsumeIntegral<int32_t>()} /*reqSize*/,
mFdp.PickValueInArray(kDataspaces), mFdp.ConsumeBool(),
- mFdp.ConsumeBool(), getFuzzedTransform(), getFuzzedRect());
+ mFdp.ConsumeBool(), getFuzzedTransform(), getFuzzedRect(),
+ mFdp.ConsumeBool());
layerArea.render([]() {} /*drawLayers*/);
if (!ownsHandle) {
diff --git a/services/surfaceflinger/tests/tracing/Android.bp b/services/surfaceflinger/tests/tracing/Android.bp
index aa6c74e..21ebaea 100644
--- a/services/surfaceflinger/tests/tracing/Android.bp
+++ b/services/surfaceflinger/tests/tracing/Android.bp
@@ -30,7 +30,7 @@
],
test_suites: ["device-tests"],
sanitize: {
- address: false,
+ address: true,
},
srcs: [
":libsurfaceflinger_sources",
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 201d37f..3713275 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -128,6 +128,7 @@
"TransactionTracingTest.cpp",
"TunnelModeEnabledReporterTest.cpp",
"StrongTypingTest.cpp",
+ "VSyncCallbackRegistrationTest.cpp",
"VSyncDispatchTimerQueueTest.cpp",
"VSyncDispatchRealtimeTest.cpp",
"VsyncModulatorTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 156007b..6ca21bd 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -200,7 +200,7 @@
constexpr bool regionSampling = false;
auto renderArea = DisplayRenderArea::create(mDisplay, sourceCrop, sourceCrop.getSize(),
- ui::Dataspace::V0_SRGB, ui::Transform::ROT_0);
+ ui::Dataspace::V0_SRGB, true, true);
auto traverseLayers = [this](const LayerVector::Visitor& visitor) {
return mFlinger.traverseLayersInLayerStack(mDisplay->getLayerStack(),
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index dc76b4c..965e378 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -359,7 +359,8 @@
EXPECT_EQ(expectedChoices, actualChoices);
}
{
- // This display does not support 120 Hz, so we should choose 60 Hz despite the touch signal.
+ // The kDisplayId3 does not support 120Hz, The pacesetter display rate is chosen to be 120
+ // Hz. In this case only the display kDisplayId3 choose 60Hz as it does not support 120Hz.
mScheduler
->registerDisplay(kDisplayId3,
std::make_shared<RefreshRateSelector>(kDisplay3Modes,
@@ -371,6 +372,26 @@
expectedChoices = ftl::init::map<
const PhysicalDisplayId&,
+ DisplayModeChoice>(kDisplayId1, FrameRateMode{120_Hz, kDisplay1Mode120},
+ globalSignals)(kDisplayId2,
+ FrameRateMode{120_Hz, kDisplay2Mode120},
+ globalSignals)(kDisplayId3,
+ FrameRateMode{60_Hz,
+ kDisplay3Mode60},
+ globalSignals);
+
+ const auto actualChoices = mScheduler->chooseDisplayModes();
+ EXPECT_EQ(expectedChoices, actualChoices);
+ }
+ {
+ // We should choose 60Hz despite the touch signal as pacesetter only supports 60Hz
+ mScheduler->setPacesetterDisplay(kDisplayId3);
+ const GlobalSignals globalSignals = {.touch = true};
+ mScheduler->replaceTouchTimer(10);
+ mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals);
+
+ expectedChoices = ftl::init::map<
+ const PhysicalDisplayId&,
DisplayModeChoice>(kDisplayId1, FrameRateMode{60_Hz, kDisplay1Mode60},
globalSignals)(kDisplayId2,
FrameRateMode{60_Hz, kDisplay2Mode60},
diff --git a/services/surfaceflinger/tests/unittests/VSyncCallbackRegistrationTest.cpp b/services/surfaceflinger/tests/unittests/VSyncCallbackRegistrationTest.cpp
new file mode 100644
index 0000000..69b3861
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/VSyncCallbackRegistrationTest.cpp
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "Scheduler/VSyncDispatch.h"
+#include "mock/MockVSyncDispatch.h"
+
+using namespace testing;
+
+namespace android::scheduler {
+
+class VSyncCallbackRegistrationTest : public Test {
+protected:
+ VSyncDispatch::Callback mCallback = [](nsecs_t, nsecs_t, nsecs_t) {};
+
+ std::shared_ptr<mock::VSyncDispatch> mVsyncDispatch = std::make_shared<mock::VSyncDispatch>();
+ VSyncDispatch::CallbackToken mCallbackToken{7};
+ std::string mCallbackName = "callback";
+
+ std::shared_ptr<mock::VSyncDispatch> mVsyncDispatch2 = std::make_shared<mock::VSyncDispatch>();
+ VSyncDispatch::CallbackToken mCallbackToken2{42};
+ std::string mCallbackName2 = "callback2";
+
+ void assertDispatch(const VSyncCallbackRegistration& registration,
+ std::shared_ptr<VSyncDispatch> dispatch) {
+ ASSERT_EQ(registration.mDispatch, dispatch);
+ }
+
+ void assertToken(const VSyncCallbackRegistration& registration,
+ const std::optional<VSyncDispatch::CallbackToken>& token) {
+ ASSERT_EQ(registration.mToken, token);
+ }
+};
+
+TEST_F(VSyncCallbackRegistrationTest, unregistersCallbackOnDestruction) {
+ // TODO (b/279581095): With ftl::Function, `_` can be replaced with
+ // `mCallback`, here and in other calls to `registerCallback, since the
+ // ftl version has an operator==, unlike std::function.
+ EXPECT_CALL(*mVsyncDispatch, registerCallback(_, mCallbackName))
+ .WillOnce(Return(mCallbackToken));
+ EXPECT_CALL(*mVsyncDispatch, unregisterCallback(mCallbackToken)).Times(1);
+
+ VSyncCallbackRegistration registration(mVsyncDispatch, mCallback, mCallbackName);
+ ASSERT_NO_FATAL_FAILURE(assertDispatch(registration, mVsyncDispatch));
+ ASSERT_NO_FATAL_FAILURE(assertToken(registration, mCallbackToken));
+}
+
+TEST_F(VSyncCallbackRegistrationTest, unregistersCallbackOnPointerMove) {
+ {
+ InSequence seq;
+ EXPECT_CALL(*mVsyncDispatch, registerCallback(_, mCallbackName))
+ .WillOnce(Return(mCallbackToken));
+ EXPECT_CALL(*mVsyncDispatch2, registerCallback(_, mCallbackName2))
+ .WillOnce(Return(mCallbackToken2));
+ EXPECT_CALL(*mVsyncDispatch2, unregisterCallback(mCallbackToken2)).Times(1);
+ EXPECT_CALL(*mVsyncDispatch, unregisterCallback(mCallbackToken)).Times(1);
+ }
+
+ auto registration =
+ std::make_unique<VSyncCallbackRegistration>(mVsyncDispatch, mCallback, mCallbackName);
+
+ auto registration2 =
+ std::make_unique<VSyncCallbackRegistration>(mVsyncDispatch2, mCallback, mCallbackName2);
+
+ registration2 = std::move(registration);
+
+ ASSERT_NO_FATAL_FAILURE(assertDispatch(*registration2.get(), mVsyncDispatch));
+ ASSERT_NO_FATAL_FAILURE(assertToken(*registration2.get(), mCallbackToken));
+}
+
+TEST_F(VSyncCallbackRegistrationTest, unregistersCallbackOnMoveOperator) {
+ {
+ InSequence seq;
+ EXPECT_CALL(*mVsyncDispatch, registerCallback(_, mCallbackName))
+ .WillOnce(Return(mCallbackToken));
+ EXPECT_CALL(*mVsyncDispatch2, registerCallback(_, mCallbackName2))
+ .WillOnce(Return(mCallbackToken2));
+ EXPECT_CALL(*mVsyncDispatch2, unregisterCallback(mCallbackToken2)).Times(1);
+ EXPECT_CALL(*mVsyncDispatch, unregisterCallback(mCallbackToken)).Times(1);
+ }
+
+ VSyncCallbackRegistration registration(mVsyncDispatch, mCallback, mCallbackName);
+
+ VSyncCallbackRegistration registration2(mVsyncDispatch2, mCallback, mCallbackName2);
+
+ registration2 = std::move(registration);
+
+ ASSERT_NO_FATAL_FAILURE(assertDispatch(registration, nullptr));
+ ASSERT_NO_FATAL_FAILURE(assertToken(registration, std::nullopt));
+
+ ASSERT_NO_FATAL_FAILURE(assertDispatch(registration2, mVsyncDispatch));
+ ASSERT_NO_FATAL_FAILURE(assertToken(registration2, mCallbackToken));
+}
+
+TEST_F(VSyncCallbackRegistrationTest, moveConstructor) {
+ EXPECT_CALL(*mVsyncDispatch, registerCallback(_, mCallbackName))
+ .WillOnce(Return(mCallbackToken));
+ EXPECT_CALL(*mVsyncDispatch, unregisterCallback(mCallbackToken)).Times(1);
+
+ VSyncCallbackRegistration registration(mVsyncDispatch, mCallback, mCallbackName);
+ VSyncCallbackRegistration registration2(std::move(registration));
+
+ ASSERT_NO_FATAL_FAILURE(assertDispatch(registration, nullptr));
+ ASSERT_NO_FATAL_FAILURE(assertToken(registration, std::nullopt));
+
+ ASSERT_NO_FATAL_FAILURE(assertDispatch(registration2, mVsyncDispatch));
+ ASSERT_NO_FATAL_FAILURE(assertToken(registration2, mCallbackToken));
+}
+
+TEST_F(VSyncCallbackRegistrationTest, moveOperatorEqualsSelf) {
+ EXPECT_CALL(*mVsyncDispatch, registerCallback(_, mCallbackName))
+ .WillOnce(Return(mCallbackToken));
+ EXPECT_CALL(*mVsyncDispatch, unregisterCallback(mCallbackToken)).Times(1);
+
+ VSyncCallbackRegistration registration(mVsyncDispatch, mCallback, mCallbackName);
+
+ // Use a reference so the compiler doesn't realize that registration is
+ // being moved to itself.
+ VSyncCallbackRegistration& registrationRef = registration;
+ registration = std::move(registrationRef);
+
+ ASSERT_NO_FATAL_FAILURE(assertDispatch(registration, mVsyncDispatch));
+ ASSERT_NO_FATAL_FAILURE(assertToken(registration, mCallbackToken));
+}
+
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index 5dc3490..d3fb9fc 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -55,7 +55,6 @@
std::vector<aidl::android::hardware::graphics::composer3::Capability>());
MOCK_METHOD0(dumpDebugInfo, std::string());
MOCK_METHOD1(registerCallback, void(HWC2::ComposerCallback&));
- MOCK_METHOD1(resetCommands, void(Display));
MOCK_METHOD1(executeCommands, Error(Display));
MOCK_METHOD0(getMaxVirtualDisplayCount, uint32_t());
MOCK_METHOD4(createVirtualDisplay, Error(uint32_t, uint32_t, PixelFormat*, Display*));