Merge "SF: Do not duplicate fences per layer per frame" into tm-dev
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index b4aa88e..a49f563 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -1957,17 +1957,43 @@
#endif // GRANULAR_LOCKS
FTS *fts;
FTSENT *p;
+
+ // Create a list of data paths whose children have cache directories
auto ce_path = create_data_user_ce_path(uuid_, userId);
auto de_path = create_data_user_de_path(uuid_, userId);
auto media_path = findDataMediaPath(uuid, userId) + "/Android/data/";
- char *argv[] = { (char*) ce_path.c_str(), (char*) de_path.c_str(),
- (char*) media_path.c_str(), nullptr };
+ auto ce_sdk_path = create_data_misc_sdk_sandbox_path(uuid_, /*isCeData=*/true, userId);
+ auto de_sdk_path = create_data_misc_sdk_sandbox_path(uuid_, /*isCeData=*/false, userId);
+
+ std::vector<std::string> dataPaths = {ce_path, de_path, media_path};
+ foreach_subdir(ce_sdk_path, [&ce_sdk_path, &dataPaths](const std::string subDir) {
+ const auto fullpath = ce_sdk_path + "/" + subDir;
+ dataPaths.push_back(fullpath);
+ });
+ foreach_subdir(de_sdk_path, [&de_sdk_path, &dataPaths](const std::string subDir) {
+ const auto fullpath = de_sdk_path + "/" + subDir;
+ dataPaths.push_back((char*)fullpath.c_str());
+ });
+
+ char* argv[dataPaths.size() + 1];
+ for (unsigned int i = 0; i < dataPaths.size(); i++) {
+ argv[i] = (char*)dataPaths[i].c_str();
+ }
+ argv[dataPaths.size()] = nullptr;
+
if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
return error("Failed to fts_open");
}
while ((p = fts_read(fts)) != nullptr) {
if (p->fts_info == FTS_D && p->fts_level == 1) {
uid_t uid = p->fts_statp->st_uid;
+
+ // If uid belongs to sdk sandbox, then the cache should be attributed to the
+ // original client app.
+ const auto client_uid = multiuser_convert_sdk_sandbox_to_app_uid(uid);
+ const bool isSandboxUid = (client_uid != (uid_t)-1);
+ if (isSandboxUid) uid = client_uid;
+
if (multiuser_get_app_id(uid) == AID_MEDIA_RW) {
uid = (multiuser_get_app_id(p->fts_statp->st_gid) - AID_EXT_GID_START)
+ AID_APP_START;
diff --git a/include/android/sensor.h b/include/android/sensor.h
index 6112d5f..eef69f4 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -267,7 +267,8 @@
* {@link ASENSOR_TYPE_HEAD_TRACKER}
* reporting-mode: continuous
*
- * Measures the orientation and rotational velocity of a user's head.
+ * Measures the orientation and rotational velocity of a user's head. Only for internal use
+ * within the Android system.
*/
ASENSOR_TYPE_HEAD_TRACKER = 37,
/**
diff --git a/libs/gralloc/types/Gralloc4.cpp b/libs/gralloc/types/Gralloc4.cpp
index 68b99b0..61e6657 100644
--- a/libs/gralloc/types/Gralloc4.cpp
+++ b/libs/gralloc/types/Gralloc4.cpp
@@ -196,35 +196,6 @@
status_t validateMetadataType(InputHidlVec* input, const MetadataType& expectedMetadataType);
/**
- * Private helper functions
- */
-template <class T>
-status_t encodeInteger(const T& input, OutputHidlVec* output) {
- static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
- std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
- std::is_same<T, float>::value || std::is_same<T, double>::value);
- if (!output) {
- return BAD_VALUE;
- }
-
- const uint8_t* tmp = reinterpret_cast<const uint8_t*>(&input);
- return output->encode(tmp, sizeof(input));
-}
-
-template <class T>
-status_t decodeInteger(InputHidlVec* input, T* output) {
- static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
- std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
- std::is_same<T, float>::value || std::is_same<T, double>::value);
- if (!output) {
- return BAD_VALUE;
- }
-
- uint8_t* tmp = reinterpret_cast<uint8_t*>(output);
- return input->decode(tmp, sizeof(*output));
-}
-
-/**
* encode/encodeMetadata are the main encoding functions. They take in T and uses the encodeHelper
* function to turn T into the hidl_vec byte stream.
*
@@ -280,45 +251,10 @@
template <class T>
status_t encodeOptionalMetadata(const MetadataType& metadataType, const std::optional<T>& input,
hidl_vec<uint8_t>* output, EncodeHelper<T> encodeHelper) {
- OutputHidlVec outputHidlVec{output};
-
- status_t err = encodeMetadataType(metadataType, &outputHidlVec);
- if (err) {
- return err;
+ if (!input) {
+ return NO_ERROR;
}
-
- err = encodeInteger<uint32_t>(input.has_value() ? 1 : 0, &outputHidlVec);
- if (err) {
- return err;
- }
-
- if (input) {
- err = encodeHelper(*input, &outputHidlVec);
- if (err) {
- return err;
- }
- }
-
- err = outputHidlVec.resize();
- if (err) {
- return err;
- }
-
- err = encodeMetadataType(metadataType, &outputHidlVec);
- if (err) {
- return err;
- }
-
- err = encodeInteger<uint32_t>(input.has_value() ? 1 : 0, &outputHidlVec);
- if (err) {
- return err;
- }
-
- if (input) {
- return encodeHelper(*input, &outputHidlVec);
- }
-
- return NO_ERROR;
+ return encodeMetadata(metadataType, *input, output, encodeHelper);
}
/**
@@ -379,36 +315,45 @@
if (!output) {
return BAD_VALUE;
}
-
- InputHidlVec inputHidlVec{&input};
-
- status_t err = validateMetadataType(&inputHidlVec, metadataType);
- if (err) {
- return err;
+ if (input.size() <= 0) {
+ output->reset();
+ return NO_ERROR;
}
-
- uint32_t present = 0;
- err = decodeInteger<uint32_t>(&inputHidlVec, &present);
- if (err) {
- return err;
- }
-
- if (present) {
- T tmp;
- err = decodeHelper(&inputHidlVec, &tmp);
- if (err) {
- return err;
- }
-
+ T tmp;
+ status_t err = decodeMetadata(metadataType, input, &tmp, decodeHelper);
+ if (!err) {
*output = tmp;
}
+ return err;
+}
- err = inputHidlVec.hasRemainingData();
- if (err) {
+/**
+ * Private helper functions
+ */
+template <class T>
+status_t encodeInteger(const T& input, OutputHidlVec* output) {
+ static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
+ std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
+ std::is_same<T, float>::value || std::is_same<T, double>::value);
+ if (!output) {
return BAD_VALUE;
}
- return NO_ERROR;
+ const uint8_t* tmp = reinterpret_cast<const uint8_t*>(&input);
+ return output->encode(tmp, sizeof(input));
+}
+
+template <class T>
+status_t decodeInteger(InputHidlVec* input, T* output) {
+ static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
+ std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
+ std::is_same<T, float>::value || std::is_same<T, double>::value);
+ if (!output) {
+ return BAD_VALUE;
+ }
+
+ uint8_t* tmp = reinterpret_cast<uint8_t*>(output);
+ return input->decode(tmp, sizeof(*output));
}
status_t encodeString(const std::string& input, OutputHidlVec* output) {
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index c2793ac..dbccf30 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -165,6 +165,17 @@
mCurrentMaxAcquiredBufferCount = mMaxAcquiredBuffers;
mNumAcquired = 0;
mNumFrameAvailable = 0;
+
+ TransactionCompletedListener::getInstance()->addQueueStallListener(
+ [&]() {
+ std::function<void(bool)> callbackCopy;
+ {
+ std::unique_lock _lock{mMutex};
+ callbackCopy = mTransactionHangCallback;
+ }
+ if (callbackCopy) callbackCopy(true);
+ }, this);
+
BQA_LOGV("BLASTBufferQueue created");
}
@@ -175,6 +186,7 @@
}
BLASTBufferQueue::~BLASTBufferQueue() {
+ TransactionCompletedListener::getInstance()->removeQueueStallListener(this);
if (mPendingTransactions.empty()) {
return;
}
@@ -1113,4 +1125,9 @@
return SurfaceControl::isSameSurface(mSurfaceControl, surfaceControl);
}
+void BLASTBufferQueue::setTransactionHangCallback(std::function<void(bool)> callback) {
+ std::unique_lock _lock{mMutex};
+ mTransactionHangCallback = callback;
+}
+
} // namespace android
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index f7392d4..e4b8bad 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -29,6 +29,7 @@
enum class Tag : uint32_t {
ON_TRANSACTION_COMPLETED = IBinder::FIRST_CALL_TRANSACTION,
ON_RELEASE_BUFFER,
+ ON_TRANSACTION_QUEUE_STALLED,
LAST = ON_RELEASE_BUFFER,
};
@@ -277,6 +278,11 @@
callbackId, releaseFence,
currentMaxAcquiredBufferCount);
}
+
+ void onTransactionQueueStalled() override {
+ callRemoteAsync<decltype(&ITransactionCompletedListener::onTransactionQueueStalled)>(
+ Tag::ON_TRANSACTION_QUEUE_STALLED);
+ }
};
// Out-of-line virtual method definitions to trigger vtable emission in this translation unit (see
@@ -297,6 +303,9 @@
&ITransactionCompletedListener::onTransactionCompleted);
case Tag::ON_RELEASE_BUFFER:
return callLocalAsync(data, reply, &ITransactionCompletedListener::onReleaseBuffer);
+ case Tag::ON_TRANSACTION_QUEUE_STALLED:
+ return callLocalAsync(data, reply,
+ &ITransactionCompletedListener::onTransactionQueueStalled);
}
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 6642ec6..501f8cf 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -447,6 +447,27 @@
}
}
+void TransactionCompletedListener::onTransactionQueueStalled() {
+ std::unordered_map<void*, std::function<void()>> callbackCopy;
+ {
+ std::scoped_lock<std::mutex> lock(mMutex);
+ callbackCopy = mQueueStallListeners;
+ }
+ for (auto const& it : callbackCopy) {
+ it.second();
+ }
+}
+
+void TransactionCompletedListener::addQueueStallListener(std::function<void()> stallListener,
+ void* id) {
+ std::scoped_lock<std::mutex> lock(mMutex);
+ mQueueStallListeners[id] = stallListener;
+}
+void TransactionCompletedListener::removeQueueStallListener(void *id) {
+ std::scoped_lock<std::mutex> lock(mMutex);
+ mQueueStallListeners.erase(id);
+}
+
void TransactionCompletedListener::onReleaseBuffer(ReleaseCallbackId callbackId,
sp<Fence> releaseFence,
uint32_t currentMaxAcquiredBufferCount) {
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 65fc04d..9328a54 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -113,6 +113,14 @@
uint64_t getLastAcquiredFrameNum();
void abandon();
+ /**
+ * Set a callback to be invoked when we are hung. The boolean parameter
+ * indicates whether the hang is due to an unfired fence.
+ * TODO: The boolean is always true atm, unfired fence is
+ * the only case we detect.
+ */
+ void setTransactionHangCallback(std::function<void(bool)> callback);
+
virtual ~BLASTBufferQueue();
private:
@@ -269,6 +277,8 @@
// transaction that will be applied by some sync consumer.
bool mAppliedLastTransaction = false;
uint64_t mLastAppliedFrameNumber = 0;
+
+ std::function<void(bool)> mTransactionHangCallback;
};
} // namespace android
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
index a791c66..cc136bb 100644
--- a/libs/gui/include/gui/ITransactionCompletedListener.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -194,6 +194,7 @@
virtual void onReleaseBuffer(ReleaseCallbackId callbackId, sp<Fence> releaseFence,
uint32_t currentMaxAcquiredBufferCount) = 0;
+ virtual void onTransactionQueueStalled() = 0;
};
class BnTransactionCompletedListener : public SafeBnInterface<ITransactionCompletedListener> {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 0cc43d8..efbdb36 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -772,6 +772,7 @@
// This is protected by mSurfaceStatsListenerMutex, but GUARDED_BY isn't supported for
// std::recursive_mutex
std::multimap<int32_t, SurfaceStatsCallbackEntry> mSurfaceStatsListeners;
+ std::unordered_map<void*, std::function<void()>> mQueueStallListeners;
public:
static sp<TransactionCompletedListener> getInstance();
@@ -789,6 +790,9 @@
const sp<SurfaceControl>& surfaceControl,
const std::unordered_set<CallbackId, CallbackIdHash>& callbackIds);
+ void addQueueStallListener(std::function<void()> stallListener, void* id);
+ void removeQueueStallListener(void *id);
+
/*
* Adds a jank listener to be informed about SurfaceFlinger's jank classification for a specific
* surface. Jank classifications arrive as part of the transaction callbacks about previous
@@ -817,6 +821,8 @@
// For Testing Only
static void setInstance(const sp<TransactionCompletedListener>&);
+ void onTransactionQueueStalled() override;
+
private:
ReleaseBufferCallback popReleaseBufferCallbackLocked(const ReleaseCallbackId&);
static sp<TransactionCompletedListener> sInstance;
diff --git a/libs/input/android/os/InputEventInjectionResult.aidl b/libs/input/android/os/InputEventInjectionResult.aidl
index 34f10ec..3bc7068 100644
--- a/libs/input/android/os/InputEventInjectionResult.aidl
+++ b/libs/input/android/os/InputEventInjectionResult.aidl
@@ -29,9 +29,8 @@
/* Injection succeeded. */
SUCCEEDED = 0,
- /* Injection failed because the injector did not have permission to inject
- * into the application with input focus. */
- PERMISSION_DENIED = 1,
+ /* Injection failed because the injected event did not target the appropriate window. */
+ TARGET_MISMATCH = 1,
/* Injection failed because there were no available input targets. */
FAILED = 2,
diff --git a/libs/renderengine/TEST_MAPPING b/libs/renderengine/TEST_MAPPING
index 995dba1..db00118 100644
--- a/libs/renderengine/TEST_MAPPING
+++ b/libs/renderengine/TEST_MAPPING
@@ -3,5 +3,11 @@
{
"name": "librenderengine_test"
}
+ ],
+
+ "imports": [
+ {
+ "path": "frameworks/native/services/surfaceflinger"
+ }
]
}
diff --git a/libs/shaders/shaders.cpp b/libs/shaders/shaders.cpp
index f0d45c2..62745dc 100644
--- a/libs/shaders/shaders.cpp
+++ b/libs/shaders/shaders.cpp
@@ -78,7 +78,7 @@
shader.append(R"(
float EOTF_sRGB(float srgb) {
- return srgb <= 0.08125 ? srgb / 4.50 : pow((srgb + 0.099) / 1.099, 0.45);
+ return srgb <= 0.08125 ? srgb / 4.50 : pow((srgb + 0.099) / 1.099, 1 / 0.45);
}
float3 EOTF_sRGB(float3 srgb) {
diff --git a/opengl/libs/EGL/BlobCache.cpp b/opengl/libs/EGL/BlobCache.cpp
index beca7f1..86c788d 100644
--- a/opengl/libs/EGL/BlobCache.cpp
+++ b/opengl/libs/EGL/BlobCache.cpp
@@ -52,35 +52,37 @@
ALOGV("initializing random seed using %lld", (unsigned long long)now);
}
-void BlobCache::set(const void* key, size_t keySize, const void* value, size_t valueSize) {
+BlobCache::InsertResult BlobCache::set(const void* key, size_t keySize, const void* value,
+ size_t valueSize) {
if (mMaxKeySize < keySize) {
ALOGV("set: not caching because the key is too large: %zu (limit: %zu)", keySize,
mMaxKeySize);
- return;
+ return InsertResult::kKeyTooBig;
}
if (mMaxValueSize < valueSize) {
ALOGV("set: not caching because the value is too large: %zu (limit: %zu)", valueSize,
mMaxValueSize);
- return;
+ return InsertResult::kValueTooBig;
}
if (mMaxTotalSize < keySize + valueSize) {
ALOGV("set: not caching because the combined key/value size is too "
"large: %zu (limit: %zu)",
keySize + valueSize, mMaxTotalSize);
- return;
+ return InsertResult::kCombinedTooBig;
}
if (keySize == 0) {
ALOGW("set: not caching because keySize is 0");
- return;
+ return InsertResult::kInvalidKeySize;
}
- if (valueSize <= 0) {
+ if (valueSize == 0) {
ALOGW("set: not caching because valueSize is 0");
- return;
+ return InsertResult::kInvalidValueSize;
}
std::shared_ptr<Blob> cacheKey(new Blob(key, keySize, false));
CacheEntry cacheEntry(cacheKey, nullptr);
+ bool didClean = false;
while (true) {
auto index = std::lower_bound(mCacheEntries.begin(), mCacheEntries.end(), cacheEntry);
if (index == mCacheEntries.end() || cacheEntry < *index) {
@@ -92,13 +94,14 @@
if (isCleanable()) {
// Clean the cache and try again.
clean();
+ didClean = true;
continue;
} else {
ALOGV("set: not caching new key/value pair because the "
"total cache size limit would be exceeded: %zu "
"(limit: %zu)",
keySize + valueSize, mMaxTotalSize);
- break;
+ return InsertResult::kNotEnoughSpace;
}
}
mCacheEntries.insert(index, CacheEntry(keyBlob, valueBlob));
@@ -114,12 +117,13 @@
if (isCleanable()) {
// Clean the cache and try again.
clean();
+ didClean = true;
continue;
} else {
ALOGV("set: not caching new value because the total cache "
"size limit would be exceeded: %zu (limit: %zu)",
keySize + valueSize, mMaxTotalSize);
- break;
+ return InsertResult::kNotEnoughSpace;
}
}
index->setValue(valueBlob);
@@ -128,7 +132,7 @@
"value",
keySize, valueSize);
}
- break;
+ return didClean ? InsertResult::kDidClean : InsertResult::kInserted;
}
}
diff --git a/opengl/libs/EGL/BlobCache.h b/opengl/libs/EGL/BlobCache.h
index 50b4e4c..ff03d30 100644
--- a/opengl/libs/EGL/BlobCache.h
+++ b/opengl/libs/EGL/BlobCache.h
@@ -39,6 +39,26 @@
// (key sizes plus value sizes) will not exceed maxTotalSize.
BlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize);
+ // Return value from set(), below.
+ enum class InsertResult {
+ // The key is larger than maxKeySize specified in the constructor.
+ kKeyTooBig,
+ // The value is larger than maxValueSize specified in the constructor.
+ kValueTooBig,
+ // The combined key + value is larger than maxTotalSize specified in the constructor.
+ kCombinedTooBig,
+ // keySize is 0
+ kInvalidKeySize,
+ // valueSize is 0
+ kInvalidValueSize,
+ // Unable to free enough space to fit the new entry.
+ kNotEnoughSpace,
+ // The new entry was inserted, but an old entry had to be evicted.
+ kDidClean,
+ // There was enough room in the cache and the new entry was inserted.
+ kInserted,
+
+ };
// set inserts a new binary value into the cache and associates it with the
// given binary key. If the key or value are too large for the cache then
// the cache remains unchanged. This includes the case where a different
@@ -54,7 +74,7 @@
// 0 < keySize
// value != NULL
// 0 < valueSize
- void set(const void* key, size_t keySize, const void* value, size_t valueSize);
+ InsertResult set(const void* key, size_t keySize, const void* value, size_t valueSize);
// get retrieves from the cache the binary value associated with a given
// binary key. If the key is present in the cache then the length of the
diff --git a/opengl/libs/EGL/BlobCache_test.cpp b/opengl/libs/EGL/BlobCache_test.cpp
index d31373b..ceea0fb 100644
--- a/opengl/libs/EGL/BlobCache_test.cpp
+++ b/opengl/libs/EGL/BlobCache_test.cpp
@@ -49,7 +49,7 @@
TEST_F(BlobCacheTest, CacheSingleValueSucceeds) {
unsigned char buf[4] = {0xee, 0xee, 0xee, 0xee};
- mBC->set("abcd", 4, "efgh", 4);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
ASSERT_EQ('e', buf[0]);
ASSERT_EQ('f', buf[1]);
@@ -59,8 +59,8 @@
TEST_F(BlobCacheTest, CacheTwoValuesSucceeds) {
unsigned char buf[2] = {0xee, 0xee};
- mBC->set("ab", 2, "cd", 2);
- mBC->set("ef", 2, "gh", 2);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("ab", 2, "cd", 2));
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("ef", 2, "gh", 2));
ASSERT_EQ(size_t(2), mBC->get("ab", 2, buf, 2));
ASSERT_EQ('c', buf[0]);
ASSERT_EQ('d', buf[1]);
@@ -71,7 +71,7 @@
TEST_F(BlobCacheTest, GetOnlyWritesInsideBounds) {
unsigned char buf[6] = {0xee, 0xee, 0xee, 0xee, 0xee, 0xee};
- mBC->set("abcd", 4, "efgh", 4);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf + 1, 4));
ASSERT_EQ(0xee, buf[0]);
ASSERT_EQ('e', buf[1]);
@@ -83,7 +83,7 @@
TEST_F(BlobCacheTest, GetOnlyWritesIfBufferIsLargeEnough) {
unsigned char buf[3] = {0xee, 0xee, 0xee};
- mBC->set("abcd", 4, "efgh", 4);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 3));
ASSERT_EQ(0xee, buf[0]);
ASSERT_EQ(0xee, buf[1]);
@@ -91,14 +91,14 @@
}
TEST_F(BlobCacheTest, GetDoesntAccessNullBuffer) {
- mBC->set("abcd", 4, "efgh", 4);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
ASSERT_EQ(size_t(4), mBC->get("abcd", 4, nullptr, 0));
}
TEST_F(BlobCacheTest, MultipleSetsCacheLatestValue) {
unsigned char buf[4] = {0xee, 0xee, 0xee, 0xee};
- mBC->set("abcd", 4, "efgh", 4);
- mBC->set("abcd", 4, "ijkl", 4);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "ijkl", 4));
ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
ASSERT_EQ('i', buf[0]);
ASSERT_EQ('j', buf[1]);
@@ -108,8 +108,8 @@
TEST_F(BlobCacheTest, SecondSetKeepsFirstValueIfTooLarge) {
unsigned char buf[MAX_VALUE_SIZE + 1] = {0xee, 0xee, 0xee, 0xee};
- mBC->set("abcd", 4, "efgh", 4);
- mBC->set("abcd", 4, buf, MAX_VALUE_SIZE + 1);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
+ ASSERT_EQ(BlobCache::InsertResult::kValueTooBig, mBC->set("abcd", 4, buf, MAX_VALUE_SIZE + 1));
ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
ASSERT_EQ('e', buf[0]);
ASSERT_EQ('f', buf[1]);
@@ -123,7 +123,7 @@
for (int i = 0; i < MAX_KEY_SIZE + 1; i++) {
key[i] = 'a';
}
- mBC->set(key, MAX_KEY_SIZE + 1, "bbbb", 4);
+ ASSERT_EQ(BlobCache::InsertResult::kKeyTooBig, mBC->set(key, MAX_KEY_SIZE + 1, "bbbb", 4));
ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE + 1, buf, 4));
ASSERT_EQ(0xee, buf[0]);
ASSERT_EQ(0xee, buf[1]);
@@ -136,7 +136,7 @@
for (int i = 0; i < MAX_VALUE_SIZE + 1; i++) {
buf[i] = 'b';
}
- mBC->set("abcd", 4, buf, MAX_VALUE_SIZE + 1);
+ ASSERT_EQ(BlobCache::InsertResult::kValueTooBig, mBC->set("abcd", 4, buf, MAX_VALUE_SIZE + 1));
for (int i = 0; i < MAX_VALUE_SIZE + 1; i++) {
buf[i] = 0xee;
}
@@ -163,7 +163,8 @@
buf[i] = 'b';
}
- mBC->set(key, MAX_KEY_SIZE, buf, MAX_VALUE_SIZE);
+ ASSERT_EQ(BlobCache::InsertResult::kCombinedTooBig,
+ mBC->set(key, MAX_KEY_SIZE, buf, MAX_VALUE_SIZE));
ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE, nullptr, 0));
}
@@ -173,7 +174,7 @@
for (int i = 0; i < MAX_KEY_SIZE; i++) {
key[i] = 'a';
}
- mBC->set(key, MAX_KEY_SIZE, "wxyz", 4);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set(key, MAX_KEY_SIZE, "wxyz", 4));
ASSERT_EQ(size_t(4), mBC->get(key, MAX_KEY_SIZE, buf, 4));
ASSERT_EQ('w', buf[0]);
ASSERT_EQ('x', buf[1]);
@@ -186,7 +187,7 @@
for (int i = 0; i < MAX_VALUE_SIZE; i++) {
buf[i] = 'b';
}
- mBC->set("abcd", 4, buf, MAX_VALUE_SIZE);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, buf, MAX_VALUE_SIZE));
for (int i = 0; i < MAX_VALUE_SIZE; i++) {
buf[i] = 0xee;
}
@@ -212,13 +213,45 @@
buf[i] = 'b';
}
- mBC->set(key, MAX_KEY_SIZE, buf, bufSize);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set(key, MAX_KEY_SIZE, buf, bufSize));
ASSERT_EQ(size_t(bufSize), mBC->get(key, MAX_KEY_SIZE, nullptr, 0));
}
+// Verify that kNotEnoughSpace is returned from BlobCache::set when expected.
+// Note: This relies on internal knowledge of how BlobCache works.
+TEST_F(BlobCacheTest, NotEnoughSpace) {
+ // Insert a small entry into the cache.
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("x", 1, "y", 1));
+
+ // Attempt to put a max size entry into the cache. If the cache were empty,
+ // as in CacheMaxKeyValuePairSizeSucceeds, this would succeed. Based on the
+ // current logic of BlobCache, the small entry is not big enough to allow it
+ // to be cleaned to insert the new entry.
+ ASSERT_TRUE(MAX_KEY_SIZE < MAX_TOTAL_SIZE);
+
+ enum { bufSize = MAX_TOTAL_SIZE - MAX_KEY_SIZE };
+
+ char key[MAX_KEY_SIZE];
+ char buf[bufSize];
+ for (int i = 0; i < MAX_KEY_SIZE; i++) {
+ key[i] = 'a';
+ }
+ for (int i = 0; i < bufSize; i++) {
+ buf[i] = 'b';
+ }
+
+ ASSERT_EQ(BlobCache::InsertResult::kNotEnoughSpace, mBC->set(key, MAX_KEY_SIZE, buf, bufSize));
+ ASSERT_EQ(0, mBC->get(key, MAX_KEY_SIZE, nullptr, 0));
+
+ // The original entry remains in the cache.
+ unsigned char buf2[1] = {0xee};
+ ASSERT_EQ(size_t(1), mBC->get("x", 1, buf2, 1));
+ ASSERT_EQ('y', buf2[0]);
+}
+
TEST_F(BlobCacheTest, CacheMinKeyAndValueSizeSucceeds) {
unsigned char buf[1] = {0xee};
- mBC->set("x", 1, "y", 1);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("x", 1, "y", 1));
ASSERT_EQ(size_t(1), mBC->get("x", 1, buf, 1));
ASSERT_EQ('y', buf[0]);
}
@@ -243,12 +276,12 @@
const int maxEntries = MAX_TOTAL_SIZE / 2;
for (int i = 0; i < maxEntries; i++) {
uint8_t k = i;
- mBC->set(&k, 1, "x", 1);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set(&k, 1, "x", 1));
}
// Insert one more entry, causing a cache overflow.
{
uint8_t k = maxEntries;
- mBC->set(&k, 1, "x", 1);
+ ASSERT_EQ(BlobCache::InsertResult::kDidClean, mBC->set(&k, 1, "x", 1));
}
// Count the number of entries in the cache.
int numCached = 0;
@@ -261,6 +294,14 @@
ASSERT_EQ(maxEntries / 2 + 1, numCached);
}
+TEST_F(BlobCacheTest, InvalidKeySize) {
+ ASSERT_EQ(BlobCache::InsertResult::kInvalidKeySize, mBC->set("", 0, "efgh", 4));
+}
+
+TEST_F(BlobCacheTest, InvalidValueSize) {
+ ASSERT_EQ(BlobCache::InsertResult::kInvalidValueSize, mBC->set("abcd", 4, "", 0));
+}
+
class BlobCacheFlattenTest : public BlobCacheTest {
protected:
virtual void SetUp() {
diff --git a/services/inputflinger/TEST_MAPPING b/services/inputflinger/TEST_MAPPING
index 9b72ff4..b4b617e 100644
--- a/services/inputflinger/TEST_MAPPING
+++ b/services/inputflinger/TEST_MAPPING
@@ -24,6 +24,14 @@
"name": "libinputservice_test"
},
{
+ "name": "CtsHardwareTestCases",
+ "options": [
+ {
+ "include-filter": "android.hardware.input.cts.tests"
+ }
+ ]
+ },
+ {
"name": "CtsInputTestCases"
},
{
@@ -31,6 +39,7 @@
"options": [
{
"include-filter": "android.view.cts.MotionEventTest",
+ "include-filter": "android.view.cts.PointerCaptureTest",
"include-filter": "android.view.cts.VerifyInputEventTest"
}
]
@@ -45,6 +54,14 @@
]
},
{
+ "name": "FrameworksServicesTests",
+ "options": [
+ {
+ "include-filter": "com.android.server.input"
+ }
+ ]
+ },
+ {
"name": "CtsSecurityTestCases",
"options": [
{
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index 32eec29..a2e60c4 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -31,11 +31,11 @@
namespace android::inputdispatcher {
// An arbitrary device id.
-static const int32_t DEVICE_ID = 1;
+constexpr int32_t DEVICE_ID = 1;
-// An arbitrary injector pid / uid pair that has permission to inject events.
-static const int32_t INJECTOR_PID = 999;
-static const int32_t INJECTOR_UID = 1001;
+// The default pid and uid for windows created by the test.
+constexpr int32_t WINDOW_PID = 999;
+constexpr int32_t WINDOW_UID = 1001;
static constexpr std::chrono::duration INJECT_EVENT_TIMEOUT = 5s;
static constexpr std::chrono::nanoseconds DISPATCHING_TIMEOUT = 100ms;
@@ -108,8 +108,6 @@
void pokeUserActivity(nsecs_t, int32_t, int32_t) override {}
- bool checkInjectEventsPermissionNonReentrant(int32_t, int32_t) override { return false; }
-
void onPointerDownOutsideFocus(const sp<IBinder>& newToken) override {}
void setPointerCapture(const PointerCaptureRequest&) override {}
@@ -196,8 +194,8 @@
mInfo.globalScaleFactor = 1.0;
mInfo.touchableRegion.clear();
mInfo.addTouchableRegion(mFrame);
- mInfo.ownerPid = INJECTOR_PID;
- mInfo.ownerUid = INJECTOR_UID;
+ mInfo.ownerPid = WINDOW_PID;
+ mInfo.ownerUid = WINDOW_UID;
mInfo.displayId = ADISPLAY_ID_DEFAULT;
}
@@ -310,14 +308,14 @@
for (auto _ : state) {
MotionEvent event = generateMotionEvent();
// Send ACTION_DOWN
- dispatcher.injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, INJECT_EVENT_TIMEOUT,
+ dispatcher.injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ INJECT_EVENT_TIMEOUT,
POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
// Send ACTION_UP
event.setAction(AMOTION_EVENT_ACTION_UP);
- dispatcher.injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, INJECT_EVENT_TIMEOUT,
+ dispatcher.injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ INJECT_EVENT_TIMEOUT,
POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
window->consumeEvent();
diff --git a/services/inputflinger/dispatcher/DragState.h b/services/inputflinger/dispatcher/DragState.h
index 4636820..d1c8b8a 100644
--- a/services/inputflinger/dispatcher/DragState.h
+++ b/services/inputflinger/dispatcher/DragState.h
@@ -26,7 +26,8 @@
namespace inputdispatcher {
struct DragState {
- DragState(const sp<android::gui::WindowInfoHandle>& windowHandle) : dragWindow(windowHandle) {}
+ DragState(const sp<android::gui::WindowInfoHandle>& windowHandle, int32_t pointerId)
+ : dragWindow(windowHandle), pointerId(pointerId) {}
void dump(std::string& dump, const char* prefix = "");
// The window being dragged.
@@ -37,6 +38,8 @@
bool isStartDrag = false;
// Indicate if the stylus button is down at the start of the drag.
bool isStylusButtonDownAtStart = false;
+ // Indicate which pointer id is tracked by the drag and drop.
+ const int32_t pointerId;
};
} // namespace inputdispatcher
diff --git a/services/inputflinger/dispatcher/InjectionState.cpp b/services/inputflinger/dispatcher/InjectionState.cpp
index c8024a6..c2d3ad6 100644
--- a/services/inputflinger/dispatcher/InjectionState.cpp
+++ b/services/inputflinger/dispatcher/InjectionState.cpp
@@ -20,10 +20,9 @@
namespace android::inputdispatcher {
-InjectionState::InjectionState(int32_t injectorPid, int32_t injectorUid)
+InjectionState::InjectionState(const std::optional<int32_t>& targetUid)
: refCount(1),
- injectorPid(injectorPid),
- injectorUid(injectorUid),
+ targetUid(targetUid),
injectionResult(android::os::InputEventInjectionResult::PENDING),
injectionIsAsync(false),
pendingForegroundDispatches(0) {}
diff --git a/services/inputflinger/dispatcher/InjectionState.h b/services/inputflinger/dispatcher/InjectionState.h
index 0bfafb1..90cf150 100644
--- a/services/inputflinger/dispatcher/InjectionState.h
+++ b/services/inputflinger/dispatcher/InjectionState.h
@@ -27,13 +27,12 @@
struct InjectionState {
mutable int32_t refCount;
- int32_t injectorPid;
- int32_t injectorUid;
+ std::optional<int32_t> targetUid;
android::os::InputEventInjectionResult injectionResult; // initially PENDING
bool injectionIsAsync; // set to true if injection is not waiting for the result
int32_t pendingForegroundDispatches; // the number of foreground dispatches in progress
- InjectionState(int32_t injectorPid, int32_t injectorUid);
+ explicit InjectionState(const std::optional<int32_t>& targetUid);
void release();
private:
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 5d8df5f..b5a3825 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -578,6 +578,27 @@
return false;
}
+// Checks targeted injection using the window's owner's uid.
+// Returns an empty string if an entry can be sent to the given window, or an error message if the
+// entry is a targeted injection whose uid target doesn't match the window owner.
+std::optional<std::string> verifyTargetedInjection(const sp<WindowInfoHandle>& window,
+ const EventEntry& entry) {
+ if (entry.injectionState == nullptr || !entry.injectionState->targetUid) {
+ // The event was not injected, or the injected event does not target a window.
+ return {};
+ }
+ const int32_t uid = *entry.injectionState->targetUid;
+ if (window == nullptr) {
+ return StringPrintf("No valid window target for injection into uid %d.", uid);
+ }
+ if (entry.injectionState->targetUid != window->getInfo()->ownerUid) {
+ return StringPrintf("Injected event targeted at uid %d would be dispatched to window '%s' "
+ "owned by uid %d.",
+ uid, window->getName().c_str(), window->getInfo()->ownerUid);
+ }
+ return {};
+}
+
} // namespace
// --- InputDispatcher ---
@@ -1036,6 +1057,8 @@
switch (entry.type) {
case EventEntry::Type::KEY: {
+ LOG_ALWAYS_FATAL_IF((entry.policyFlags & POLICY_FLAG_TRUSTED) == 0,
+ "Unexpected untrusted event.");
// Optimize app switch latency.
// If the application takes too long to catch up then we drop all events preceding
// the app switch key.
@@ -1073,6 +1096,8 @@
}
case EventEntry::Type::MOTION: {
+ LOG_ALWAYS_FATAL_IF((entry.policyFlags & POLICY_FLAG_TRUSTED) == 0,
+ "Unexpected untrusted event.");
if (shouldPruneInboundQueueLocked(static_cast<MotionEntry&>(entry))) {
mNextUnblockedEvent = mInboundQueue.back();
needWake = true;
@@ -1720,8 +1745,7 @@
}
setInjectionResult(*entry, injectionResult);
- if (injectionResult == InputEventInjectionResult::PERMISSION_DENIED) {
- ALOGW("Permission denied, dropping the motion (isPointer=%s)", toString(isPointerEvent));
+ if (injectionResult == InputEventInjectionResult::TARGET_MISMATCH) {
return true;
}
if (injectionResult != InputEventInjectionResult::SUCCEEDED) {
@@ -1747,18 +1771,12 @@
}
void InputDispatcher::enqueueDragEventLocked(const sp<WindowInfoHandle>& windowHandle,
- bool isExiting, const MotionEntry& motionEntry) {
- // If the window needs enqueue a drag event, the pointerCount should be 1 and the action should
- // be AMOTION_EVENT_ACTION_MOVE, that could guarantee the first pointer is always valid.
- LOG_ALWAYS_FATAL_IF(motionEntry.pointerCount != 1);
- PointerCoords pointerCoords;
- pointerCoords.copyFrom(motionEntry.pointerCoords[0]);
- pointerCoords.transform(windowHandle->getInfo()->transform);
-
+ bool isExiting, const int32_t rawX,
+ const int32_t rawY) {
+ const vec2 xy = windowHandle->getInfo()->transform.transform(vec2(rawX, rawY));
std::unique_ptr<DragEntry> dragEntry =
- std::make_unique<DragEntry>(mIdGenerator.nextId(), motionEntry.eventTime,
- windowHandle->getToken(), isExiting, pointerCoords.getX(),
- pointerCoords.getY());
+ std::make_unique<DragEntry>(mIdGenerator.nextId(), now(), windowHandle->getToken(),
+ isExiting, xy.x, xy.y);
enqueueInboundEventLocked(std::move(dragEntry));
}
@@ -1978,9 +1996,10 @@
// we have a valid, non-null focused window
resetNoFocusedWindowTimeoutLocked();
- // Check permissions.
- if (!checkInjectionPermission(focusedWindowHandle, entry.injectionState)) {
- return InputEventInjectionResult::PERMISSION_DENIED;
+ // Verify targeted injection.
+ if (const auto err = verifyTargetedInjection(focusedWindowHandle, entry); err) {
+ ALOGW("Dropping injected event: %s", (*err).c_str());
+ return InputEventInjectionResult::TARGET_MISMATCH;
}
if (focusedWindowHandle->getInfo()->inputConfig.test(
@@ -2046,11 +2065,6 @@
nsecs_t currentTime, const MotionEntry& entry, std::vector<InputTarget>& inputTargets,
nsecs_t* nextWakeupTime, bool* outConflictingPointerActions) {
ATRACE_CALL();
- enum InjectionPermission {
- INJECTION_PERMISSION_UNKNOWN,
- INJECTION_PERMISSION_GRANTED,
- INJECTION_PERMISSION_DENIED
- };
// For security reasons, we defer updating the touch state until we are sure that
// event injection will be allowed.
@@ -2060,7 +2074,6 @@
// Update the touch state as needed based on the properties of the touch event.
InputEventInjectionResult injectionResult = InputEventInjectionResult::PENDING;
- InjectionPermission injectionPermission = INJECTION_PERMISSION_UNKNOWN;
sp<WindowInfoHandle> newHoverWindowHandle(mLastHoverWindowHandle);
sp<WindowInfoHandle> newTouchedWindowHandle;
@@ -2109,7 +2122,7 @@
"in display %" PRId32,
displayId);
// TODO: test multiple simultaneous input streams.
- injectionResult = InputEventInjectionResult::PERMISSION_DENIED;
+ injectionResult = InputEventInjectionResult::FAILED;
switchedDevice = false;
wrongDevice = true;
goto Failed;
@@ -2142,6 +2155,14 @@
newTouchedWindowHandle = tempTouchState.getFirstForegroundWindowHandle();
}
+ // Verify targeted injection.
+ if (const auto err = verifyTargetedInjection(newTouchedWindowHandle, entry); err) {
+ ALOGW("Dropping injected touch event: %s", (*err).c_str());
+ injectionResult = os::InputEventInjectionResult::TARGET_MISMATCH;
+ newTouchedWindowHandle = nullptr;
+ goto Failed;
+ }
+
// Figure out whether splitting will be allowed for this window.
if (newTouchedWindowHandle != nullptr) {
if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) {
@@ -2185,6 +2206,11 @@
for (const sp<WindowInfoHandle>& windowHandle : newTouchedWindows) {
const WindowInfo& info = *windowHandle->getInfo();
+ // Skip spy window targets that are not valid for targeted injection.
+ if (const auto err = verifyTargetedInjection(windowHandle, entry); err) {
+ continue;
+ }
+
if (info.inputConfig.test(WindowInfo::InputConfig::PAUSE_DISPATCHING)) {
ALOGI("Not sending touch event to %s because it is paused",
windowHandle->getName().c_str());
@@ -2278,6 +2304,14 @@
newTouchedWindowHandle =
findTouchedWindowAtLocked(displayId, x, y, &tempTouchState, isStylus);
+ // Verify targeted injection.
+ if (const auto err = verifyTargetedInjection(newTouchedWindowHandle, entry); err) {
+ ALOGW("Dropping injected event: %s", (*err).c_str());
+ injectionResult = os::InputEventInjectionResult::TARGET_MISMATCH;
+ newTouchedWindowHandle = nullptr;
+ goto Failed;
+ }
+
// Drop touch events if requested by input feature
if (newTouchedWindowHandle != nullptr &&
shouldDropInput(entry, newTouchedWindowHandle)) {
@@ -2369,19 +2403,26 @@
goto Failed;
}
- // Check permission to inject into all touched foreground windows.
- if (std::any_of(tempTouchState.windows.begin(), tempTouchState.windows.end(),
- [this, &entry](const TouchedWindow& touchedWindow) {
- return (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) != 0 &&
- !checkInjectionPermission(touchedWindow.windowHandle,
- entry.injectionState);
- })) {
- injectionResult = InputEventInjectionResult::PERMISSION_DENIED;
- injectionPermission = INJECTION_PERMISSION_DENIED;
- goto Failed;
+ // Ensure that all touched windows are valid for injection.
+ if (entry.injectionState != nullptr) {
+ std::string errs;
+ for (const TouchedWindow& touchedWindow : tempTouchState.windows) {
+ if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
+ // Allow ACTION_OUTSIDE events generated by targeted injection to be
+ // dispatched to any uid, since the coords will be zeroed out later.
+ continue;
+ }
+ const auto err = verifyTargetedInjection(touchedWindow.windowHandle, entry);
+ if (err) errs += "\n - " + *err;
+ }
+ if (!errs.empty()) {
+ ALOGW("Dropping targeted injection: At least one touched window is not owned by uid "
+ "%d:%s",
+ *entry.injectionState->targetUid, errs.c_str());
+ injectionResult = InputEventInjectionResult::TARGET_MISMATCH;
+ goto Failed;
+ }
}
- // Permission granted to inject into all touched foreground windows.
- injectionPermission = INJECTION_PERMISSION_GRANTED;
// Check whether windows listening for outside touches are owned by the same UID. If it is
// set the policy flag that we will not reveal coordinate information to this window.
@@ -2447,19 +2488,6 @@
tempTouchState.filterNonAsIsTouchWindows();
Failed:
- // Check injection permission once and for all.
- if (injectionPermission == INJECTION_PERMISSION_UNKNOWN) {
- if (checkInjectionPermission(nullptr, entry.injectionState)) {
- injectionPermission = INJECTION_PERMISSION_GRANTED;
- } else {
- injectionPermission = INJECTION_PERMISSION_DENIED;
- }
- }
-
- if (injectionPermission != INJECTION_PERMISSION_GRANTED) {
- return injectionResult;
- }
-
// Update final pieces of touch state if the injector had permission.
if (!wrongDevice) {
if (switchedDevice) {
@@ -2546,13 +2574,14 @@
vec2 local = dropWindow->getInfo()->transform.transform(x, y);
sendDropWindowCommandLocked(dropWindow->getToken(), local.x, local.y);
} else {
+ ALOGW("No window found when drop.");
sendDropWindowCommandLocked(nullptr, 0, 0);
}
mDragState.reset();
}
void InputDispatcher::addDragEventLocked(const MotionEntry& entry) {
- if (entry.pointerCount != 1 || !mDragState) {
+ if (!mDragState) {
return;
}
@@ -2562,42 +2591,75 @@
(entry.buttonState & AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) != 0;
}
- int32_t maskedAction = entry.action & AMOTION_EVENT_ACTION_MASK;
- int32_t x = static_cast<int32_t>(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));
- int32_t y = static_cast<int32_t>(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
- if (maskedAction == AMOTION_EVENT_ACTION_MOVE) {
- // Handle the special case : stylus button no longer pressed.
- bool isStylusButtonDown = (entry.buttonState & AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) != 0;
- if (mDragState->isStylusButtonDownAtStart && !isStylusButtonDown) {
- finishDragAndDrop(entry.displayId, x, y);
- return;
+ // Find the pointer index by id.
+ int32_t pointerIndex = 0;
+ for (; static_cast<uint32_t>(pointerIndex) < entry.pointerCount; pointerIndex++) {
+ const PointerProperties& pointerProperties = entry.pointerProperties[pointerIndex];
+ if (pointerProperties.id == mDragState->pointerId) {
+ break;
}
+ }
- // Prevent stylus interceptor windows from affecting drag and drop behavior for now, until
- // we have an explicit reason to support it.
- constexpr bool isStylus = false;
-
- const sp<WindowInfoHandle> hoverWindowHandle =
- findTouchedWindowAtLocked(entry.displayId, x, y, nullptr /*touchState*/, isStylus,
- false /*addOutsideTargets*/, true /*ignoreDragWindow*/);
- // enqueue drag exit if needed.
- if (hoverWindowHandle != mDragState->dragHoverWindowHandle &&
- !haveSameToken(hoverWindowHandle, mDragState->dragHoverWindowHandle)) {
- if (mDragState->dragHoverWindowHandle != nullptr) {
- enqueueDragEventLocked(mDragState->dragHoverWindowHandle, true /*isExiting*/,
- entry);
- }
- mDragState->dragHoverWindowHandle = hoverWindowHandle;
- }
- // enqueue drag location if needed.
- if (hoverWindowHandle != nullptr) {
- enqueueDragEventLocked(hoverWindowHandle, false /*isExiting*/, entry);
- }
- } else if (maskedAction == AMOTION_EVENT_ACTION_UP) {
- finishDragAndDrop(entry.displayId, x, y);
- } else if (maskedAction == AMOTION_EVENT_ACTION_CANCEL) {
+ if (uint32_t(pointerIndex) == entry.pointerCount) {
+ LOG_ALWAYS_FATAL("Should find a valid pointer index by id %d", mDragState->pointerId);
sendDropWindowCommandLocked(nullptr, 0, 0);
mDragState.reset();
+ return;
+ }
+
+ const int32_t maskedAction = entry.action & AMOTION_EVENT_ACTION_MASK;
+ const int32_t x = entry.pointerCoords[pointerIndex].getX();
+ const int32_t y = entry.pointerCoords[pointerIndex].getY();
+
+ switch (maskedAction) {
+ case AMOTION_EVENT_ACTION_MOVE: {
+ // Handle the special case : stylus button no longer pressed.
+ bool isStylusButtonDown =
+ (entry.buttonState & AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) != 0;
+ if (mDragState->isStylusButtonDownAtStart && !isStylusButtonDown) {
+ finishDragAndDrop(entry.displayId, x, y);
+ return;
+ }
+
+ // Prevent stylus interceptor windows from affecting drag and drop behavior for now,
+ // until we have an explicit reason to support it.
+ constexpr bool isStylus = false;
+
+ const sp<WindowInfoHandle> hoverWindowHandle =
+ findTouchedWindowAtLocked(entry.displayId, x, y, nullptr /*touchState*/,
+ isStylus, false /*addOutsideTargets*/,
+ true /*ignoreDragWindow*/);
+ // enqueue drag exit if needed.
+ if (hoverWindowHandle != mDragState->dragHoverWindowHandle &&
+ !haveSameToken(hoverWindowHandle, mDragState->dragHoverWindowHandle)) {
+ if (mDragState->dragHoverWindowHandle != nullptr) {
+ enqueueDragEventLocked(mDragState->dragHoverWindowHandle, true /*isExiting*/, x,
+ y);
+ }
+ mDragState->dragHoverWindowHandle = hoverWindowHandle;
+ }
+ // enqueue drag location if needed.
+ if (hoverWindowHandle != nullptr) {
+ enqueueDragEventLocked(hoverWindowHandle, false /*isExiting*/, x, y);
+ }
+ break;
+ }
+
+ case AMOTION_EVENT_ACTION_POINTER_UP:
+ if (getMotionEventActionPointerIndex(entry.action) != pointerIndex) {
+ break;
+ }
+ // The drag pointer is up.
+ [[fallthrough]];
+ case AMOTION_EVENT_ACTION_UP:
+ finishDragAndDrop(entry.displayId, x, y);
+ break;
+ case AMOTION_EVENT_ACTION_CANCEL: {
+ ALOGD("Receiving cancel when drag and drop.");
+ sendDropWindowCommandLocked(nullptr, 0, 0);
+ mDragState.reset();
+ break;
+ }
}
}
@@ -2657,26 +2719,6 @@
}
}
-bool InputDispatcher::checkInjectionPermission(const sp<WindowInfoHandle>& windowHandle,
- const InjectionState* injectionState) {
- if (injectionState &&
- (windowHandle == nullptr ||
- windowHandle->getInfo()->ownerUid != injectionState->injectorUid) &&
- !hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) {
- if (windowHandle != nullptr) {
- ALOGW("Permission denied: injecting event from pid %d uid %d to window %s "
- "owned by uid %d",
- injectionState->injectorPid, injectionState->injectorUid,
- windowHandle->getName().c_str(), windowHandle->getInfo()->ownerUid);
- } else {
- ALOGW("Permission denied: injecting event from pid %d uid %d",
- injectionState->injectorPid, injectionState->injectorUid);
- }
- return false;
- }
- return true;
-}
-
/**
* Indicate whether one window handle should be considered as obscuring
* another window handle. We only check a few preconditions. Actually
@@ -4195,20 +4237,20 @@
}
}
-InputEventInjectionResult InputDispatcher::injectInputEvent(
- const InputEvent* event, int32_t injectorPid, int32_t injectorUid,
- InputEventInjectionSync syncMode, std::chrono::milliseconds timeout, uint32_t policyFlags) {
+InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* event,
+ std::optional<int32_t> targetUid,
+ InputEventInjectionSync syncMode,
+ std::chrono::milliseconds timeout,
+ uint32_t policyFlags) {
if (DEBUG_INBOUND_EVENT_DETAILS) {
- ALOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, "
- "syncMode=%d, timeout=%lld, policyFlags=0x%08x",
- event->getType(), injectorPid, injectorUid, syncMode, timeout.count(), policyFlags);
+ ALOGD("injectInputEvent - eventType=%d, targetUid=%s, syncMode=%d, timeout=%lld, "
+ "policyFlags=0x%08x",
+ event->getType(), targetUid ? std::to_string(*targetUid).c_str() : "none", syncMode,
+ timeout.count(), policyFlags);
}
nsecs_t endTime = now() + std::chrono::duration_cast<std::chrono::nanoseconds>(timeout).count();
- policyFlags |= POLICY_FLAG_INJECTED;
- if (hasInjectionPermission(injectorPid, injectorUid)) {
- policyFlags |= POLICY_FLAG_TRUSTED;
- }
+ policyFlags |= POLICY_FLAG_INJECTED | POLICY_FLAG_TRUSTED;
// For all injected events, set device id = VIRTUAL_KEYBOARD_ID. The only exception is events
// that have gone through the InputFilter. If the event passed through the InputFilter, assign
@@ -4349,7 +4391,7 @@
return InputEventInjectionResult::FAILED;
}
- InjectionState* injectionState = new InjectionState(injectorPid, injectorUid);
+ InjectionState* injectionState = new InjectionState(targetUid);
if (syncMode == InputEventInjectionSync::NONE) {
injectionState->injectionIsAsync = true;
}
@@ -4421,8 +4463,7 @@
} // release lock
if (DEBUG_INJECTION) {
- ALOGD("injectInputEvent - Finished with result %d. injectorPid=%d, injectorUid=%d",
- injectionResult, injectorPid, injectorUid);
+ ALOGD("injectInputEvent - Finished with result %d.", injectionResult);
}
return injectionResult;
@@ -4461,19 +4502,12 @@
return result;
}
-bool InputDispatcher::hasInjectionPermission(int32_t injectorPid, int32_t injectorUid) {
- return injectorUid == 0 ||
- mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid);
-}
-
void InputDispatcher::setInjectionResult(EventEntry& entry,
InputEventInjectionResult injectionResult) {
InjectionState* injectionState = entry.injectionState;
if (injectionState) {
if (DEBUG_INJECTION) {
- ALOGD("Setting input event injection result to %d. "
- "injectorPid=%d, injectorUid=%d",
- injectionResult, injectionState->injectorPid, injectionState->injectorUid);
+ ALOGD("Setting input event injection result to %d.", injectionResult);
}
if (injectionState->injectionIsAsync && !(entry.policyFlags & POLICY_FLAG_FILTERED)) {
@@ -4482,12 +4516,12 @@
case InputEventInjectionResult::SUCCEEDED:
ALOGV("Asynchronous input event injection succeeded.");
break;
+ case InputEventInjectionResult::TARGET_MISMATCH:
+ ALOGV("Asynchronous input event injection target mismatch.");
+ break;
case InputEventInjectionResult::FAILED:
ALOGW("Asynchronous input event injection failed.");
break;
- case InputEventInjectionResult::PERMISSION_DENIED:
- ALOGW("Asynchronous input event injection permission denied.");
- break;
case InputEventInjectionResult::TIMED_OUT:
ALOGW("Asynchronous input event injection timed out.");
break;
@@ -5117,7 +5151,15 @@
// Store the dragging window.
if (isDragDrop) {
- mDragState = std::make_unique<DragState>(toWindowHandle);
+ if (pointerIds.count() > 1) {
+ ALOGW("The drag and drop cannot be started when there is more than 1 pointer on the"
+ " window.");
+ return false;
+ }
+ // If the window didn't not support split or the source is mouse, the pointerIds count
+ // would be 0, so we have to track the pointer 0.
+ const int32_t id = pointerIds.count() == 0 ? 0 : pointerIds.firstMarkedBit();
+ mDragState = std::make_unique<DragState>(toWindowHandle, id);
}
// Synthesize cancel for old window and down for new window.
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index f3dac19..ed89ed0 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -104,7 +104,7 @@
void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
android::os::InputEventInjectionResult injectInputEvent(
- const InputEvent* event, int32_t injectorPid, int32_t injectorUid,
+ const InputEvent* event, std::optional<int32_t> targetUid,
android::os::InputEventInjectionSync syncMode, std::chrono::milliseconds timeout,
uint32_t policyFlags) override;
@@ -221,7 +221,8 @@
const std::string& reason) REQUIRES(mLock);
// Enqueues a drag event.
void enqueueDragEventLocked(const sp<android::gui::WindowInfoHandle>& windowToken,
- bool isExiting, const MotionEntry& motionEntry) REQUIRES(mLock);
+ bool isExiting, const int32_t rawX, const int32_t rawY)
+ REQUIRES(mLock);
// Adds an event to a queue of recent events for debugging purposes.
void addRecentEventLocked(std::shared_ptr<EventEntry> entry) REQUIRES(mLock);
@@ -278,7 +279,6 @@
// Event injection and synchronization.
std::condition_variable mInjectionResultAvailable;
- bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid);
void setInjectionResult(EventEntry& entry,
android::os::InputEventInjectionResult injectionResult);
void transformMotionEntryForInjectionLocked(MotionEntry&,
@@ -554,8 +554,6 @@
void addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets, int32_t displayId)
REQUIRES(mLock);
void pokeUserActivityLocked(const EventEntry& eventEntry) REQUIRES(mLock);
- bool checkInjectionPermission(const sp<android::gui::WindowInfoHandle>& windowHandle,
- const InjectionState* injectionState);
// Enqueue a drag event if needed, and update the touch state.
// Uses findTouchedWindowTargetsLocked to make the decision
void addDragEventLocked(const MotionEntry& entry) REQUIRES(mLock);
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index d7bc5fb..67fed8b 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -68,10 +68,16 @@
* input injection to proceed.
* Returns one of the INPUT_EVENT_INJECTION_XXX constants.
*
- * This method may be called on any thread (usually by the input manager).
+ * If a targetUid is provided, InputDispatcher will only consider injecting the input event into
+ * windows owned by the provided uid. If the input event is targeted at a window that is not
+ * owned by the provided uid, input injection will fail. If no targetUid is provided, the input
+ * event will be dispatched as-is.
+ *
+ * This method may be called on any thread (usually by the input manager). The caller must
+ * perform all necessary permission checks prior to injecting events.
*/
virtual android::os::InputEventInjectionResult injectInputEvent(
- const InputEvent* event, int32_t injectorPid, int32_t injectorUid,
+ const InputEvent* event, std::optional<int32_t> targetUid,
android::os::InputEventInjectionSync syncMode, std::chrono::milliseconds timeout,
uint32_t policyFlags) = 0;
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
index de0b6da..575b3d7 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
@@ -125,15 +125,6 @@
/* Poke user activity for an event dispatched to a window. */
virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType, int32_t displayId) = 0;
- /* Checks whether a given application pid/uid has permission to inject input events
- * into other applications.
- *
- * This method is special in that its implementation promises to be non-reentrant and
- * is safe to call while holding other locks. (Most other methods make no such guarantees!)
- */
- virtual bool checkInjectEventsPermissionNonReentrant(int32_t injectorPid,
- int32_t injectorUid) = 0;
-
/* Notifies the policy that a pointer down event has occurred outside the current focused
* window.
*
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index b688898..91a666c 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -45,10 +45,10 @@
using namespace ftl::flag_operators;
// An arbitrary time value.
-static const nsecs_t ARBITRARY_TIME = 1234;
+static constexpr nsecs_t ARBITRARY_TIME = 1234;
// An arbitrary device id.
-static const int32_t DEVICE_ID = 1;
+static constexpr int32_t DEVICE_ID = 1;
// An arbitrary display id.
static constexpr int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT;
@@ -61,9 +61,12 @@
static constexpr int32_t POINTER_1_UP =
AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
-// An arbitrary injector pid / uid pair that has permission to inject events.
-static const int32_t INJECTOR_PID = 999;
-static const int32_t INJECTOR_UID = 1001;
+// The default pid and uid for windows created by the test.
+static constexpr int32_t WINDOW_PID = 999;
+static constexpr int32_t WINDOW_UID = 1001;
+
+// The default policy flags to use for event injection by tests.
+static constexpr uint32_t DEFAULT_POLICY_FLAGS = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER;
// An arbitrary pid of the gesture monitor window
static constexpr int32_t MONITOR_PID = 2001;
@@ -472,10 +475,6 @@
void pokeUserActivity(nsecs_t, int32_t, int32_t) override {}
- bool checkInjectEventsPermissionNonReentrant(int32_t pid, int32_t uid) override {
- return pid == INJECTOR_PID && uid == INJECTOR_UID;
- }
-
void onPointerDownOutsideFocus(const sp<IBinder>& newToken) override {
std::scoped_lock lock(mLock);
mOnPointerDownToken = newToken;
@@ -560,8 +559,8 @@
/*action*/ -1, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME,
ARBITRARY_TIME);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject key events with undefined action.";
// Rejects ACTION_MULTIPLE since it is not supported despite being defined in the API.
@@ -569,8 +568,8 @@
INVALID_HMAC, AKEY_EVENT_ACTION_MULTIPLE, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0,
ARBITRARY_TIME, ARBITRARY_TIME);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject key events with ACTION_MULTIPLE.";
}
@@ -599,8 +598,8 @@
ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject motion events with undefined action.";
// Rejects pointer down with invalid index.
@@ -611,8 +610,8 @@
ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject motion events with pointer down index too large.";
event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
@@ -623,8 +622,8 @@
identityTransform, ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject motion events with pointer down index too small.";
// Rejects pointer up with invalid index.
@@ -635,8 +634,8 @@
ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject motion events with pointer up index too large.";
event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
@@ -647,8 +646,8 @@
identityTransform, ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject motion events with pointer up index too small.";
// Rejects motion events with invalid number of pointers.
@@ -659,8 +658,8 @@
ARBITRARY_TIME,
/*pointerCount*/ 0, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject motion events with 0 pointers.";
event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
@@ -670,8 +669,8 @@
ARBITRARY_TIME,
/*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject motion events with more than MAX_POINTERS pointers.";
// Rejects motion events with invalid pointer ids.
@@ -683,8 +682,8 @@
ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject motion events with pointer ids less than 0.";
pointerProperties[0].id = MAX_POINTER_ID + 1;
@@ -695,8 +694,8 @@
ARBITRARY_TIME,
/*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject motion events with pointer ids greater than MAX_POINTER_ID.";
// Rejects motion events with duplicate pointer ids.
@@ -709,8 +708,8 @@
ARBITRARY_TIME,
/*pointerCount*/ 2, pointerProperties, pointerCoords);
ASSERT_EQ(InputEventInjectionResult::FAILED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
- InputEventInjectionSync::NONE, 0ms, 0))
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/, InputEventInjectionSync::NONE,
+ 0ms, 0))
<< "Should reject motion events with duplicate pointer ids.";
}
@@ -1013,8 +1012,8 @@
mInfo.globalScaleFactor = 1.0;
mInfo.touchableRegion.clear();
mInfo.addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT));
- mInfo.ownerPid = INJECTOR_PID;
- mInfo.ownerUid = INJECTOR_UID;
+ mInfo.ownerPid = WINDOW_PID;
+ mInfo.ownerUid = WINDOW_UID;
mInfo.displayId = displayId;
mInfo.inputConfig = WindowInfo::InputConfig::DEFAULT;
}
@@ -1296,7 +1295,8 @@
int32_t displayId = ADISPLAY_ID_NONE,
InputEventInjectionSync syncMode = InputEventInjectionSync::WAIT_FOR_RESULT,
std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
- bool allowKeyRepeat = true) {
+ bool allowKeyRepeat = true, std::optional<int32_t> targetUid = {},
+ uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
KeyEvent event;
nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
@@ -1305,13 +1305,11 @@
INVALID_HMAC, action, /* flags */ 0, AKEYCODE_A, KEY_A, AMETA_NONE,
repeatCount, currentTime, currentTime);
- int32_t policyFlags = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER;
if (!allowKeyRepeat) {
policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
}
// Inject event until dispatch out.
- return dispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, syncMode,
- injectionTimeout, policyFlags);
+ return dispatcher->injectInputEvent(&event, targetUid, syncMode, injectionTimeout, policyFlags);
}
static InputEventInjectionResult injectKeyDown(const std::unique_ptr<InputDispatcher>& dispatcher,
@@ -1454,10 +1452,10 @@
static InputEventInjectionResult injectMotionEvent(
const std::unique_ptr<InputDispatcher>& dispatcher, const MotionEvent& event,
std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
- InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT) {
- return dispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, injectionMode,
- injectionTimeout,
- POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
+ InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT,
+ std::optional<int32_t> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
+ return dispatcher->injectInputEvent(&event, targetUid, injectionMode, injectionTimeout,
+ policyFlags);
}
static InputEventInjectionResult injectMotionEvent(
@@ -1467,7 +1465,8 @@
AMOTION_EVENT_INVALID_CURSOR_POSITION},
std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT,
- nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC)) {
+ nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC),
+ std::optional<int32_t> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
MotionEvent event = MotionEventBuilder(action, source)
.displayId(displayId)
.eventTime(eventTime)
@@ -1479,7 +1478,8 @@
.build();
// Inject event until dispatch out.
- return injectMotionEvent(dispatcher, event, injectionTimeout, injectionMode);
+ return injectMotionEvent(dispatcher, event, injectionTimeout, injectionMode, targetUid,
+ policyFlags);
}
static InputEventInjectionResult injectMotionDown(
@@ -3574,8 +3574,8 @@
* FLAG_WINDOW_IS_PARTIALLY_OBSCURED.
*/
TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) {
- constexpr int32_t SLIPPERY_PID = INJECTOR_PID + 1;
- constexpr int32_t SLIPPERY_UID = INJECTOR_UID + 1;
+ constexpr int32_t SLIPPERY_PID = WINDOW_PID + 1;
+ constexpr int32_t SLIPPERY_UID = WINDOW_UID + 1;
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -4102,7 +4102,7 @@
const int32_t additionalPolicyFlags =
POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_DISABLE_KEY_REPEAT;
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/,
InputEventInjectionSync::WAIT_FOR_RESULT, 10ms,
policyFlags | additionalPolicyFlags));
@@ -4137,7 +4137,7 @@
const int32_t additionalPolicyFlags = POLICY_FLAG_PASS_TO_USER;
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ mDispatcher->injectInputEvent(&event, {} /*targetUid*/,
InputEventInjectionSync::WAIT_FOR_RESULT, 10ms,
policyFlags | additionalPolicyFlags));
@@ -4644,7 +4644,7 @@
const int32_t policyFlags = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER;
InputEventInjectionResult result =
- mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ mDispatcher->injectInputEvent(&event, {} /* targetUid */,
InputEventInjectionSync::WAIT_FOR_RESULT,
INJECT_EVENT_TIMEOUT, policyFlags);
ASSERT_EQ(InputEventInjectionResult::FAILED, result)
@@ -6110,8 +6110,7 @@
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}}});
}
- // Start performing drag, we will create a drag window and transfer touch to it.
- void performDrag() {
+ void injectDown() {
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
{50, 50}))
@@ -6119,6 +6118,15 @@
// Window should receive motion event.
mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ }
+
+ // Start performing drag, we will create a drag window and transfer touch to it.
+ // @param sendDown : if true, send a motion down on first window before perform drag and drop.
+ // Returns true on success.
+ bool performDrag(bool sendDown = true) {
+ if (sendDown) {
+ injectDown();
+ }
// The drag window covers the entire display
mDragWindow = new FakeWindowHandle(mApp, mDispatcher, "DragWindow", ADISPLAY_ID_DEFAULT);
@@ -6126,10 +6134,14 @@
{{ADISPLAY_ID_DEFAULT, {mDragWindow, mWindow, mSecondWindow}}});
// Transfer touch focus to the drag window
- mDispatcher->transferTouchFocus(mWindow->getToken(), mDragWindow->getToken(),
- true /* isDragDrop */);
- mWindow->consumeMotionCancel();
- mDragWindow->consumeMotionDown();
+ bool transferred =
+ mDispatcher->transferTouchFocus(mWindow->getToken(), mDragWindow->getToken(),
+ true /* isDragDrop */);
+ if (transferred) {
+ mWindow->consumeMotionCancel();
+ mDragWindow->consumeMotionDown();
+ }
+ return transferred;
}
// Start performing drag, we will create a drag window and transfer touch to it.
@@ -6276,7 +6288,7 @@
mSecondWindow->assertNoEvents();
}
-TEST_F(InputDispatcherDragTests, DragAndDrop_InvalidWindow) {
+TEST_F(InputDispatcherDragTests, DragAndDropOnInvalidWindow) {
performDrag();
// Set second window invisible.
@@ -6312,6 +6324,89 @@
mSecondWindow->assertNoEvents();
}
+TEST_F(InputDispatcherDragTests, NoDragAndDropWhenMultiFingers) {
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {50, 50}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+
+ const MotionEvent secondFingerDownEvent =
+ MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+ .displayId(ADISPLAY_ID_DEFAULT)
+ .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+ .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
+ .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(75).y(50))
+ .build();
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
+ InputEventInjectionSync::WAIT_FOR_RESULT))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ mWindow->consumeMotionPointerDown(1 /* pointerIndex */);
+
+ // Should not perform drag and drop when window has multi fingers.
+ ASSERT_FALSE(performDrag(false));
+}
+
+TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouch) {
+ // First down on second window.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {150, 50}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+ mSecondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+
+ // Second down on first window.
+ const MotionEvent secondFingerDownEvent =
+ MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+ .displayId(ADISPLAY_ID_DEFAULT)
+ .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+ .pointer(
+ PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(50))
+ .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
+ .build();
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
+ InputEventInjectionSync::WAIT_FOR_RESULT))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+
+ // Perform drag and drop from first window.
+ ASSERT_TRUE(performDrag(false));
+
+ // Move on window.
+ const MotionEvent secondFingerMoveEvent =
+ MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
+ .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+ .pointer(
+ PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(50))
+ .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
+ .build();
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT,
+ InputEventInjectionSync::WAIT_FOR_RESULT));
+ mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT);
+ mWindow->consumeDragEvent(false, 50, 50);
+ mSecondWindow->consumeMotionMove();
+
+ // Release the drag pointer should perform drop.
+ const MotionEvent secondFingerUpEvent =
+ MotionEventBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
+ .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+ .pointer(
+ PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(50))
+ .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
+ .build();
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT,
+ InputEventInjectionSync::WAIT_FOR_RESULT));
+ mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT);
+ mFakePolicy->assertDropTargetEquals(mWindow->getToken());
+ mWindow->assertNoEvents();
+ mSecondWindow->consumeMotionMove();
+}
+
class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {};
TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) {
@@ -6463,8 +6558,8 @@
mWindow->consumeFocusEvent(true);
// Set initial touch mode to InputDispatcher::kDefaultInTouchMode.
- if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, INJECTOR_PID,
- INJECTOR_UID, /* hasPermission */ true)) {
+ if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, WINDOW_PID,
+ WINDOW_UID, /* hasPermission */ true)) {
mWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
mSecondWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
}
@@ -7095,4 +7190,149 @@
window->assertNoEvents();
}
+struct User {
+ int32_t mPid;
+ int32_t mUid;
+ uint32_t mPolicyFlags{DEFAULT_POLICY_FLAGS};
+ std::unique_ptr<InputDispatcher>& mDispatcher;
+
+ User(std::unique_ptr<InputDispatcher>& dispatcher, int32_t pid, int32_t uid)
+ : mPid(pid), mUid(uid), mDispatcher(dispatcher) {}
+
+ InputEventInjectionResult injectTargetedMotion(int32_t action) const {
+ return injectMotionEvent(mDispatcher, action, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {100, 200},
+ {AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION},
+ INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT,
+ systemTime(SYSTEM_TIME_MONOTONIC), {mUid}, mPolicyFlags);
+ }
+
+ InputEventInjectionResult injectTargetedKey(int32_t action) const {
+ return inputdispatcher::injectKey(mDispatcher, action, 0 /* repeatCount*/, ADISPLAY_ID_NONE,
+ InputEventInjectionSync::WAIT_FOR_RESULT,
+ INJECT_EVENT_TIMEOUT, false /*allowKeyRepeat*/, {mUid},
+ mPolicyFlags);
+ }
+
+ sp<FakeWindowHandle> createWindow() const {
+ std::shared_ptr<FakeApplicationHandle> overlayApplication =
+ std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window = new FakeWindowHandle(overlayApplication, mDispatcher,
+ "Owned Window", ADISPLAY_ID_DEFAULT);
+ window->setOwnerInfo(mPid, mUid);
+ return window;
+ }
+};
+
+using InputDispatcherTargetedInjectionTest = InputDispatcherTest;
+
+TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedWindow) {
+ auto owner = User(mDispatcher, 10, 11);
+ auto window = owner.createWindow();
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+
+ EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
+ owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
+ window->consumeMotionDown();
+
+ setFocusedWindow(window);
+ window->consumeFocusEvent(true);
+
+ EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
+ owner.injectTargetedKey(AKEY_EVENT_ACTION_DOWN));
+ window->consumeKeyDown(ADISPLAY_ID_NONE);
+}
+
+TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedWindow) {
+ auto owner = User(mDispatcher, 10, 11);
+ auto window = owner.createWindow();
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+
+ auto rando = User(mDispatcher, 20, 21);
+ EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH,
+ rando.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
+
+ setFocusedWindow(window);
+ window->consumeFocusEvent(true);
+
+ EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH,
+ rando.injectTargetedKey(AKEY_EVENT_ACTION_DOWN));
+ window->assertNoEvents();
+}
+
+TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedSpyWindow) {
+ auto owner = User(mDispatcher, 10, 11);
+ auto window = owner.createWindow();
+ auto spy = owner.createWindow();
+ spy->setSpy(true);
+ spy->setTrustedOverlay(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
+
+ EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
+ owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
+ spy->consumeMotionDown();
+ window->consumeMotionDown();
+}
+
+TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedSpyWindow) {
+ auto owner = User(mDispatcher, 10, 11);
+ auto window = owner.createWindow();
+
+ auto rando = User(mDispatcher, 20, 21);
+ auto randosSpy = rando.createWindow();
+ randosSpy->setSpy(true);
+ randosSpy->setTrustedOverlay(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {randosSpy, window}}});
+
+ // The event is targeted at owner's window, so injection should succeed, but the spy should
+ // not receive the event.
+ EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
+ owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
+ randosSpy->assertNoEvents();
+ window->consumeMotionDown();
+}
+
+TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoAnyWindowWhenNotTargeting) {
+ auto owner = User(mDispatcher, 10, 11);
+ auto window = owner.createWindow();
+
+ auto rando = User(mDispatcher, 20, 21);
+ auto randosSpy = rando.createWindow();
+ randosSpy->setSpy(true);
+ randosSpy->setTrustedOverlay(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {randosSpy, window}}});
+
+ // A user that has injection permission can inject into any window.
+ EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT));
+ randosSpy->consumeMotionDown();
+ window->consumeMotionDown();
+
+ setFocusedWindow(randosSpy);
+ randosSpy->consumeFocusEvent(true);
+
+ EXPECT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher));
+ randosSpy->consumeKeyDown(ADISPLAY_ID_NONE);
+ window->assertNoEvents();
+}
+
+TEST_F(InputDispatcherTargetedInjectionTest, CanGenerateActionOutsideToOtherUids) {
+ auto owner = User(mDispatcher, 10, 11);
+ auto window = owner.createWindow();
+
+ auto rando = User(mDispatcher, 20, 21);
+ auto randosWindow = rando.createWindow();
+ randosWindow->setFrame(Rect{-10, -10, -5, -5});
+ randosWindow->setWatchOutsideTouch(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {randosWindow, window}}});
+
+ // We allow generation of ACTION_OUTSIDE events into windows owned by different uids.
+ EXPECT_EQ(InputEventInjectionResult::SUCCEEDED,
+ owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
+ window->consumeMotionDown();
+ randosWindow->consumeMotionOutside();
+}
+
} // namespace android::inputdispatcher
diff --git a/services/sensorservice/BatteryService.cpp b/services/sensorservice/BatteryService.cpp
index 14f9a12..94de55c 100644
--- a/services/sensorservice/BatteryService.cpp
+++ b/services/sensorservice/BatteryService.cpp
@@ -74,23 +74,6 @@
}
}
-void BatteryService::cleanupImpl(uid_t uid) {
- if (checkService()) {
- Mutex::Autolock _l(mActivationsLock);
- int64_t identity = IPCThreadState::self()->clearCallingIdentity();
- for (size_t i=0 ; i<mActivations.size() ; ) {
- const Info& info(mActivations[i]);
- if (info.uid == uid) {
- mBatteryStatService->noteStopSensor(info.uid, info.handle);
- mActivations.removeAt(i);
- } else {
- i++;
- }
- }
- IPCThreadState::self()->restoreCallingIdentity(identity);
- }
-}
-
bool BatteryService::checkService() {
if (mBatteryStatService == nullptr) {
const sp<IServiceManager> sm(defaultServiceManager());
diff --git a/services/sensorservice/BatteryService.h b/services/sensorservice/BatteryService.h
index 09eb2c1..13fc58a 100644
--- a/services/sensorservice/BatteryService.h
+++ b/services/sensorservice/BatteryService.h
@@ -32,7 +32,6 @@
void enableSensorImpl(uid_t uid, int handle);
void disableSensorImpl(uid_t uid, int handle);
- void cleanupImpl(uid_t uid);
struct Info {
uid_t uid;
@@ -58,9 +57,6 @@
static void disableSensor(uid_t uid, int handle) {
BatteryService::getInstance().disableSensorImpl(uid, handle);
}
- static void cleanup(uid_t uid) {
- BatteryService::getInstance().cleanupImpl(uid);
- }
};
// ---------------------------------------------------------------------------
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 53a3025..de050e0 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -612,8 +612,10 @@
return SENSORS_DEVICE_API_VERSION_1_4;
}
-status_t SensorDevice::flush(void* /*ident*/, int handle) {
+status_t SensorDevice::flush(void* ident, int handle) {
if (mHalWrapper == nullptr) return NO_INIT;
+ if (isClientDisabled(ident)) return INVALID_OPERATION;
+ ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w flush %d", handle);
return mHalWrapper->flush(handle);
}
@@ -754,6 +756,13 @@
status_t SensorDevice::injectSensorData(const sensors_event_t* injected_sensor_event) {
if (mHalWrapper == nullptr) return NO_INIT;
+ ALOGD_IF(DEBUG_CONNECTIONS,
+ "sensor_event handle=%d ts=%" PRId64 " data=%.2f, %.2f, %.2f %.2f %.2f %.2f",
+ injected_sensor_event->sensor, injected_sensor_event->timestamp,
+ injected_sensor_event->data[0], injected_sensor_event->data[1],
+ injected_sensor_event->data[2], injected_sensor_event->data[3],
+ injected_sensor_event->data[4], injected_sensor_event->data[5]);
+
return mHalWrapper->injectSensorData(injected_sensor_event);
}
diff --git a/services/sensorservice/SensorDirectConnection.cpp b/services/sensorservice/SensorDirectConnection.cpp
index fae16f6..2dd12e9 100644
--- a/services/sensorservice/SensorDirectConnection.cpp
+++ b/services/sensorservice/SensorDirectConnection.cpp
@@ -157,7 +157,7 @@
}
const Sensor& s = si->getSensor();
- if (!SensorService::canAccessSensor(s, "config direct channel", mOpPackageName)) {
+ if (!mService->canAccessSensor(s, "config direct channel", mOpPackageName)) {
return PERMISSION_DENIED;
}
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index 6948895..f06f947 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -162,7 +162,8 @@
Mutex::Autolock _l(mConnectionLock);
sp<SensorInterface> si = mService->getSensorInterfaceFromHandle(handle);
if (si == nullptr ||
- !canAccessSensor(si->getSensor(), "Add to SensorEventConnection: ", mOpPackageName) ||
+ !mService->canAccessSensor(si->getSensor(), "Add to SensorEventConnection: ",
+ mOpPackageName) ||
mSensorInfo.count(handle) > 0) {
return false;
}
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 8b81d48..948692b 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -814,6 +814,12 @@
return handleResetUidState(args, err);
} else if (args[0] == String16("get-uid-state")) {
return handleGetUidState(args, out, err);
+ } else if (args[0] == String16("unrestrict-ht")) {
+ mHtRestricted = false;
+ return NO_ERROR;
+ } else if (args[0] == String16("restrict-ht")) {
+ mHtRestricted = true;
+ return NO_ERROR;
} else if (args.size() == 1 && args[0] == String16("help")) {
printHelp(out);
return NO_ERROR;
@@ -1338,11 +1344,11 @@
Vector<Sensor> SensorService::getDynamicSensorList(const String16& opPackageName) {
Vector<Sensor> accessibleSensorList;
mSensors.forEachSensor(
- [&opPackageName, &accessibleSensorList] (const Sensor& sensor) -> bool {
+ [this, &opPackageName, &accessibleSensorList] (const Sensor& sensor) -> bool {
if (sensor.isDynamicSensor()) {
- if (canAccessSensor(sensor, "getDynamicSensorList", opPackageName)) {
+ if (canAccessSensor(sensor, "can't see", opPackageName)) {
accessibleSensorList.add(sensor);
- } else {
+ } else if (sensor.getType() != SENSOR_TYPE_HEAD_TRACKER) {
ALOGI("Skipped sensor %s because it requires permission %s and app op %" PRId32,
sensor.getName().string(),
sensor.getRequiredPermission().string(),
@@ -1611,7 +1617,9 @@
} else {
ALOGE("sensor interface of handle=0x%08x is null!", handle);
}
- c->removeSensor(handle);
+ if (c->removeSensor(handle)) {
+ BatteryService::disableSensor(c->getUid(), handle);
+ }
}
SensorRecord* rec = mActiveSensors.valueAt(i);
ALOGE_IF(!rec, "mActiveSensors[%zu] is null (handle=0x%08x)!", i, handle);
@@ -1631,7 +1639,6 @@
}
c->updateLooperRegistration(mLooper);
mConnectionHolder.removeEventConnection(connection);
- BatteryService::cleanup(c->getUid());
if (c->needsWakeLock()) {
checkWakeLockStateLocked(&connLock);
}
@@ -1988,6 +1995,20 @@
bool SensorService::canAccessSensor(const Sensor& sensor, const char* operation,
const String16& opPackageName) {
+ // Special case for Head Tracker sensor type: currently restricted to system usage only, unless
+ // the restriction is specially lifted for testing
+ if (sensor.getType() == SENSOR_TYPE_HEAD_TRACKER &&
+ !isAudioServerOrSystemServerUid(IPCThreadState::self()->getCallingUid())) {
+ if (!mHtRestricted) {
+ ALOGI("Permitting access to HT sensor type outside system (%s)",
+ String8(opPackageName).string());
+ } else {
+ ALOGW("%s %s a sensor (%s) as a non-system client", String8(opPackageName).string(),
+ operation, sensor.getName().string());
+ return false;
+ }
+ }
+
// Check if a permission is required for this sensor
if (sensor.getRequiredPermission().length() <= 0) {
return true;
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index b18d204..234dc9c 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -373,7 +373,7 @@
status_t cleanupWithoutDisableLocked(const sp<SensorEventConnection>& connection, int handle);
void cleanupAutoDisabledSensorLocked(const sp<SensorEventConnection>& connection,
sensors_event_t const* buffer, const int count);
- static bool canAccessSensor(const Sensor& sensor, const char* operation,
+ bool canAccessSensor(const Sensor& sensor, const char* operation,
const String16& opPackageName);
static bool hasPermissionForSensor(const Sensor& sensor);
static int getTargetSdkVersion(const String16& opPackageName);
@@ -492,6 +492,10 @@
std::unordered_map<int, SensorServiceUtil::RecentEventLogger*> mRecentEvent;
Mode mCurrentOperatingMode;
+ // true if the head tracker sensor type is currently restricted to system usage only
+ // (can only be unrestricted for testing, via shell cmd)
+ bool mHtRestricted = true;
+
// This packagaName is set when SensorService is in RESTRICTED or DATA_INJECTION mode. Only
// applications with this packageName are allowed to activate/deactivate or call flush on
// sensors. To run CTS this is can be set to ".cts." and only CTS tests will get access to
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 635b088..f8c53c3 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -315,11 +315,7 @@
compositionState->sidebandStreamHasFrame = false;
}
-bool BufferLayer::onPreComposition(nsecs_t refreshStartTime) {
- if (mBufferInfo.mBuffer != nullptr) {
- Mutex::Autolock lock(mFrameEventHistoryMutex);
- mFrameEventHistory.addPreComposition(mCurrentFrameNumber, refreshStartTime);
- }
+bool BufferLayer::onPreComposition(nsecs_t) {
return hasReadyFrame();
}
namespace {
@@ -365,12 +361,7 @@
mAlreadyDisplayedThisCompose = false;
// Update mFrameEventHistory.
- {
- Mutex::Autolock lock(mFrameEventHistoryMutex);
- mFrameEventHistory.addPostComposition(mCurrentFrameNumber, glDoneFence, presentFence,
- compositorTiming);
- finalizeFrameEventHistory(glDoneFence, compositorTiming);
- }
+ finalizeFrameEventHistory(glDoneFence, compositorTiming);
// Update mFrameTracker.
nsecs_t desiredPresentTime = mBufferInfo.mDesiredPresentTime;
@@ -500,7 +491,7 @@
return false;
}
- err = updateFrameNumber(latchTime);
+ err = updateFrameNumber();
if (err != NO_ERROR) {
return false;
}
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 3e70493..4c70eb5 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -192,7 +192,7 @@
nsecs_t expectedPresentTime) = 0;
virtual status_t updateActiveBuffer() = 0;
- virtual status_t updateFrameNumber(nsecs_t latchTime) = 0;
+ virtual status_t updateFrameNumber() = 0;
// We generate InputWindowHandles for all non-cursor buffered layers regardless of whether they
// have an InputChannel. This is to enable the InputDispatcher to do PID based occlusion
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 9ae45fc..7361a4f 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -471,18 +471,6 @@
}
}
-void BufferLayerConsumer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
- FrameEventHistoryDelta* outDelta) {
- Mutex::Autolock lock(mMutex);
-
- if (mAbandoned) {
- // Nothing to do if we're already abandoned.
- return;
- }
-
- mLayer->addAndGetFrameTimestamps(newTimestamps, outDelta);
-}
-
void BufferLayerConsumer::abandonLocked() {
BLC_LOGV("abandonLocked");
mCurrentTextureBuffer = nullptr;
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index 9ed80b4..23ad2a3 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -236,8 +236,7 @@
// IConsumerListener interface
void onDisconnect() override;
void onSidebandStreamChanged() override;
- void addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
- FrameEventHistoryDelta* outDelta) override;
+ void addAndGetFrameTimestamps(const NewFrameEventsEntry*, FrameEventHistoryDelta*) override {}
// computeCurrentTransformMatrixLocked computes the transform matrix for the
// current texture. It uses mCurrentTransform and the current GraphicBuffer
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 6a1a38b..f487aab 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -66,20 +66,10 @@
mConsumer->setTransformHint(mTransformHint);
}
-void BufferQueueLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
+void BufferQueueLayer::releasePendingBuffer(nsecs_t) {
if (!mConsumer->releasePendingBuffer()) {
return;
}
-
- auto releaseFenceTime = std::make_shared<FenceTime>(mConsumer->getPrevFinalReleaseFence());
- mReleaseTimeline.updateSignalTimes();
- mReleaseTimeline.push(releaseFenceTime);
-
- Mutex::Autolock lock(mFrameEventHistoryMutex);
- if (mPreviousFrameNumber != 0) {
- mFrameEventHistory.addRelease(mPreviousFrameNumber, dequeueReadyTime,
- std::move(releaseFenceTime));
- }
}
void BufferQueueLayer::setDefaultBufferSize(uint32_t w, uint32_t h) {
@@ -319,14 +309,9 @@
return NO_ERROR;
}
-status_t BufferQueueLayer::updateFrameNumber(nsecs_t latchTime) {
+status_t BufferQueueLayer::updateFrameNumber() {
mPreviousFrameNumber = mCurrentFrameNumber;
mCurrentFrameNumber = mConsumer->getFrameNumber();
-
- {
- Mutex::Autolock lock(mFrameEventHistoryMutex);
- mFrameEventHistory.addLatch(mCurrentFrameNumber, latchTime);
- }
return NO_ERROR;
}
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 4587b5e..649da2c 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -102,7 +102,7 @@
nsecs_t expectedPresentTime) override;
status_t updateActiveBuffer() override;
- status_t updateFrameNumber(nsecs_t latchTime) override;
+ status_t updateFrameNumber() override;
void setFrameTimelineInfoForBuffer(const FrameTimelineInfo& frameTimelineInfo) override;
sp<Layer> createClone() override;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index c885110..e58b65e 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -178,15 +178,6 @@
}
mDrawingState.callbackHandles = {};
-
- std::shared_ptr<FenceTime> releaseFenceTime = std::make_shared<FenceTime>(releaseFence);
- {
- Mutex::Autolock lock(mFrameEventHistoryMutex);
- if (mPreviousFrameNumber != 0) {
- mFrameEventHistory.addRelease(mPreviousFrameNumber, dequeueReadyTime,
- std::move(releaseFenceTime));
- }
- }
}
void BufferStateLayer::finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& glDoneFence,
@@ -346,19 +337,6 @@
return true;
}
-bool BufferStateLayer::addFrameEvent(const sp<Fence>& acquireFence, nsecs_t postedTime,
- nsecs_t desiredPresentTime) {
- Mutex::Autolock lock(mFrameEventHistoryMutex);
- mAcquireTimeline.updateSignalTimes();
- std::shared_ptr<FenceTime> acquireFenceTime =
- std::make_shared<FenceTime>((acquireFence ? acquireFence : Fence::NO_FENCE));
- NewFrameEventsEntry newTimestamps = {mDrawingState.frameNumber, postedTime, desiredPresentTime,
- acquireFenceTime};
- mFrameEventHistory.setProducerWantsEvents();
- mFrameEventHistory.addQueue(newTimestamps);
- return true;
-}
-
bool BufferStateLayer::setBuffer(std::shared_ptr<renderengine::ExternalTexture>& buffer,
const BufferData& bufferData, nsecs_t postTime,
nsecs_t desiredPresentTime, bool isAutoTimestamp,
@@ -445,8 +423,6 @@
using LayerUpdateType = scheduler::LayerHistory::LayerUpdateType;
mFlinger->mScheduler->recordLayerHistory(this, presentTime, LayerUpdateType::Buffer);
- addFrameEvent(mDrawingState.acquireFence, postTime, isAutoTimestamp ? 0 : desiredPresentTime);
-
setFrameTimelineVsyncForBufferTransaction(info, postTime);
if (dequeueTime && *dequeueTime != 0) {
@@ -726,14 +702,10 @@
return NO_ERROR;
}
-status_t BufferStateLayer::updateFrameNumber(nsecs_t latchTime) {
+status_t BufferStateLayer::updateFrameNumber() {
// TODO(marissaw): support frame history events
mPreviousFrameNumber = mCurrentFrameNumber;
mCurrentFrameNumber = mDrawingState.frameNumber;
- {
- Mutex::Autolock lock(mFrameEventHistoryMutex);
- mFrameEventHistory.addLatch(mCurrentFrameNumber, latchTime);
- }
return NO_ERROR;
}
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index cc510d8..bbf058c 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -66,8 +66,6 @@
bool setApi(int32_t api) override;
bool setSidebandStream(const sp<NativeHandle>& sidebandStream) override;
bool setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& handles) override;
- bool addFrameEvent(const sp<Fence>& acquireFence, nsecs_t postedTime,
- nsecs_t requestedPresentTime) override;
bool setPosition(float /*x*/, float /*y*/) override;
bool setMatrix(const layer_state_t::matrix22_t& /*matrix*/);
@@ -124,7 +122,7 @@
nsecs_t expectedPresentTime) override;
status_t updateActiveBuffer() override;
- status_t updateFrameNumber(nsecs_t latchTime) override;
+ status_t updateFrameNumber() override;
sp<Layer> createClone() override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index c65d467..7709b96 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -164,6 +164,9 @@
bool treat170mAsSrgb = false;
+ uint64_t lastOutputLayerHash = 0;
+ uint64_t outputLayerHash = 0;
+
// Debugging
void dump(std::string& result) const;
};
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 742332c..2d2b3df 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -763,6 +763,7 @@
bool includeGeometry = refreshArgs.updatingGeometryThisFrame;
uint32_t z = 0;
bool overrideZ = false;
+ uint64_t outputLayerHash = 0;
for (auto* layer : getOutputLayersOrderedByZ()) {
if (layer == peekThroughLayer) {
// No longer needed, although it should not show up again, so
@@ -789,6 +790,10 @@
constexpr bool isPeekingThrough = true;
peekThroughLayer->writeStateToHWC(includeGeometry, false, z++, overrideZ,
isPeekingThrough);
+ outputLayerHash ^= android::hashCombine(
+ reinterpret_cast<uint64_t>(&peekThroughLayer->getLayerFE()),
+ z, includeGeometry, overrideZ, isPeekingThrough,
+ peekThroughLayer->requiresClientComposition());
}
previousOverride = overrideInfo.buffer->getBuffer();
@@ -797,7 +802,14 @@
constexpr bool isPeekingThrough = false;
layer->writeStateToHWC(includeGeometry, skipLayer, z++, overrideZ, isPeekingThrough);
+ if (!skipLayer) {
+ outputLayerHash ^= android::hashCombine(
+ reinterpret_cast<uint64_t>(&layer->getLayerFE()),
+ z, includeGeometry, overrideZ, isPeekingThrough,
+ layer->requiresClientComposition());
+ }
}
+ editState().outputLayerHash = outputLayerHash;
}
compositionengine::OutputLayer* Output::findLayerRequestingBackgroundComposition() const {
@@ -1486,6 +1498,10 @@
}
bool Output::canPredictCompositionStrategy(const CompositionRefreshArgs& refreshArgs) {
+ uint64_t lastOutputLayerHash = getState().lastOutputLayerHash;
+ uint64_t outputLayerHash = getState().outputLayerHash;
+ editState().lastOutputLayerHash = outputLayerHash;
+
if (!getState().isEnabled || !mHwComposerAsyncWorker) {
ALOGV("canPredictCompositionStrategy disabled");
return false;
@@ -1506,6 +1522,11 @@
return false;
}
+ if (lastOutputLayerHash != outputLayerHash) {
+ ALOGV("canPredictCompositionStrategy output layers changed");
+ return false;
+ }
+
// If no layer uses clientComposition, then don't predict composition strategy
// because we have less work to do in parallel.
if (!anyLayersRequireClientComposition()) {
@@ -1513,12 +1534,7 @@
return false;
}
- if (!refreshArgs.updatingOutputGeometryThisFrame) {
- return true;
- }
-
- ALOGV("canPredictCompositionStrategy updatingOutputGeometryThisFrame");
- return false;
+ return true;
}
bool Output::anyLayersRequireClientComposition() const {
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 784abea..b907129 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -850,14 +850,20 @@
EXPECT_CALL(*layer1.outputLayer,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+ EXPECT_CALL(*layer1.outputLayer, requiresClientComposition())
+ .WillRepeatedly(Return(false));
EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180));
EXPECT_CALL(*layer2.outputLayer,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+ EXPECT_CALL(*layer2.outputLayer, requiresClientComposition())
+ .WillRepeatedly(Return(false));
EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180));
EXPECT_CALL(*layer3.outputLayer,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+ EXPECT_CALL(*layer3.outputLayer, requiresClientComposition())
+ .WillRepeatedly(Return(false));
injectOutputLayer(layer1);
injectOutputLayer(layer2);
@@ -884,14 +890,20 @@
EXPECT_CALL(*layer1.outputLayer,
writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+ EXPECT_CALL(*layer1.outputLayer, requiresClientComposition())
+ .WillRepeatedly(Return(false));
EXPECT_CALL(*layer2.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
EXPECT_CALL(*layer2.outputLayer,
writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+ EXPECT_CALL(*layer2.outputLayer, requiresClientComposition())
+ .WillRepeatedly(Return(false));
EXPECT_CALL(*layer3.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
EXPECT_CALL(*layer3.outputLayer,
writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+ EXPECT_CALL(*layer3.outputLayer, requiresClientComposition())
+ .WillRepeatedly(Return(false));
injectOutputLayer(layer1);
injectOutputLayer(layer2);
@@ -917,14 +929,20 @@
EXPECT_CALL(*layer1.outputLayer,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+ EXPECT_CALL(*layer1.outputLayer, requiresClientComposition())
+ .WillRepeatedly(Return(false));
EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
EXPECT_CALL(*layer2.outputLayer,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+ EXPECT_CALL(*layer2.outputLayer, requiresClientComposition())
+ .WillRepeatedly(Return(false));
EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
EXPECT_CALL(*layer3.outputLayer,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+ EXPECT_CALL(*layer3.outputLayer, requiresClientComposition())
+ .WillRepeatedly(Return(false));
injectOutputLayer(layer1);
injectOutputLayer(layer2);
@@ -950,6 +968,8 @@
InSequence seq;
EXPECT_CALL(*layer0.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
EXPECT_CALL(*layer1.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
+ EXPECT_CALL(*layer1.outputLayer, requiresClientComposition())
+ .WillRepeatedly(Return(false));
EXPECT_CALL(*layer2.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
EXPECT_CALL(*layer3.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0));
@@ -957,6 +977,9 @@
EXPECT_CALL(*layer0.outputLayer,
writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+ EXPECT_CALL(*layer0.outputLayer, requiresClientComposition())
+ .WillRepeatedly(Return(false));
+
// After calling planComposition (which clears overrideInfo), this test sets
// layer3 to be the peekThroughLayer for layer1 and layer2. As a result, it
@@ -966,12 +989,18 @@
writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++,
/*zIsOverridden*/ true, /*isPeekingThrough*/
true));
+ EXPECT_CALL(*layer3.outputLayer, requiresClientComposition())
+ .WillRepeatedly(Return(false));
EXPECT_CALL(*layer1.outputLayer,
writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++,
/*zIsOverridden*/ true, /*isPeekingThrough*/ false));
+ EXPECT_CALL(*layer1.outputLayer, requiresClientComposition())
+ .WillRepeatedly(Return(false));
EXPECT_CALL(*layer2.outputLayer,
writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ true, z++,
/*zIsOverridden*/ true, /*isPeekingThrough*/ false));
+ EXPECT_CALL(*layer2.outputLayer, requiresClientComposition())
+ .WillRepeatedly(Return(false));
injectOutputLayer(layer0);
injectOutputLayer(layer1);
@@ -3354,7 +3383,6 @@
static constexpr float kDefaultMaxLuminance = 0.9f;
static constexpr float kDefaultAvgLuminance = 0.7f;
static constexpr float kDefaultMinLuminance = 0.1f;
- static constexpr float kUnknownLuminance = -1.f;
static constexpr float kDisplayLuminance = 400.f;
static constexpr float kClientTargetLuminanceNits = 200.f;
static constexpr float kClientTargetBrightness = 0.5f;
@@ -3752,7 +3780,7 @@
TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forHdrMixedComposition) {
verify().ifMixedCompositionIs(true)
.andIfUsesHdr(true)
- .withDisplayBrightnessNits(kUnknownLuminance)
+ .withDisplayBrightnessNits(kDisplayLuminance)
.withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
.withRenderIntent(
aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
@@ -3761,7 +3789,7 @@
{.physicalDisplay = kDefaultOutputDestinationClip,
.clip = kDefaultOutputViewport,
.maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDisplayLuminance,
.outputDataspace = kDefaultOutputDataspace,
.colorTransform = kDefaultColorTransformMat,
.deviceHandlesColorTransform = true,
@@ -3806,7 +3834,7 @@
forHdrMixedCompositionWithDimmingStage) {
verify().ifMixedCompositionIs(true)
.andIfUsesHdr(true)
- .withDisplayBrightnessNits(kUnknownLuminance)
+ .withDisplayBrightnessNits(kDisplayLuminance)
.withDimmingStage(
aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF)
.withRenderIntent(
@@ -3816,7 +3844,7 @@
{.physicalDisplay = kDefaultOutputDestinationClip,
.clip = kDefaultOutputViewport,
.maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDisplayLuminance,
.outputDataspace = kDefaultOutputDataspace,
.colorTransform = kDefaultColorTransformMat,
.deviceHandlesColorTransform = true,
@@ -3834,7 +3862,7 @@
forHdrMixedCompositionWithRenderIntent) {
verify().ifMixedCompositionIs(true)
.andIfUsesHdr(true)
- .withDisplayBrightnessNits(kUnknownLuminance)
+ .withDisplayBrightnessNits(kDisplayLuminance)
.withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
.withRenderIntent(aidl::android::hardware::graphics::composer3::RenderIntent::ENHANCE)
.andIfSkipColorTransform(false)
@@ -3842,7 +3870,7 @@
{.physicalDisplay = kDefaultOutputDestinationClip,
.clip = kDefaultOutputViewport,
.maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDisplayLuminance,
.outputDataspace = kDefaultOutputDataspace,
.colorTransform = kDefaultColorTransformMat,
.deviceHandlesColorTransform = true,
@@ -3859,7 +3887,7 @@
TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forNonHdrMixedComposition) {
verify().ifMixedCompositionIs(true)
.andIfUsesHdr(false)
- .withDisplayBrightnessNits(kUnknownLuminance)
+ .withDisplayBrightnessNits(kDisplayLuminance)
.withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
.withRenderIntent(
aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
@@ -3868,7 +3896,7 @@
{.physicalDisplay = kDefaultOutputDestinationClip,
.clip = kDefaultOutputViewport,
.maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDisplayLuminance,
.outputDataspace = kDefaultOutputDataspace,
.colorTransform = kDefaultColorTransformMat,
.deviceHandlesColorTransform = true,
@@ -3885,7 +3913,7 @@
TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forHdrOnlyClientComposition) {
verify().ifMixedCompositionIs(false)
.andIfUsesHdr(true)
- .withDisplayBrightnessNits(kUnknownLuminance)
+ .withDisplayBrightnessNits(kDisplayLuminance)
.withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
.withRenderIntent(
aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
@@ -3894,7 +3922,7 @@
{.physicalDisplay = kDefaultOutputDestinationClip,
.clip = kDefaultOutputViewport,
.maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDisplayLuminance,
.outputDataspace = kDefaultOutputDataspace,
.colorTransform = kDefaultColorTransformMat,
.deviceHandlesColorTransform = false,
@@ -3911,7 +3939,7 @@
TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forNonHdrOnlyClientComposition) {
verify().ifMixedCompositionIs(false)
.andIfUsesHdr(false)
- .withDisplayBrightnessNits(kUnknownLuminance)
+ .withDisplayBrightnessNits(kDisplayLuminance)
.withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
.withRenderIntent(
aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
@@ -3920,7 +3948,7 @@
{.physicalDisplay = kDefaultOutputDestinationClip,
.clip = kDefaultOutputViewport,
.maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDisplayLuminance,
.outputDataspace = kDefaultOutputDataspace,
.colorTransform = kDefaultColorTransformMat,
.deviceHandlesColorTransform = false,
@@ -3938,7 +3966,7 @@
usesExpectedDisplaySettingsForHdrOnlyClientCompositionWithSkipClientTransform) {
verify().ifMixedCompositionIs(false)
.andIfUsesHdr(true)
- .withDisplayBrightnessNits(kUnknownLuminance)
+ .withDisplayBrightnessNits(kDisplayLuminance)
.withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
.withRenderIntent(
aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
@@ -3947,7 +3975,7 @@
{.physicalDisplay = kDefaultOutputDestinationClip,
.clip = kDefaultOutputViewport,
.maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDisplayLuminance,
.outputDataspace = kDefaultOutputDataspace,
.colorTransform = kDefaultColorTransformMat,
.deviceHandlesColorTransform = true,
@@ -4785,10 +4813,14 @@
EXPECT_CALL(*layer1.outputLayer,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+ EXPECT_CALL(*layer1.outputLayer, requiresClientComposition())
+ .WillRepeatedly(Return(false));
EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0));
EXPECT_CALL(*layer2.outputLayer,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+ EXPECT_CALL(*layer2.outputLayer, requiresClientComposition())
+ .WillRepeatedly(Return(false));
layer2.layerFEState.backgroundBlurRadius = 10;
layer2.layerFEState.isOpaque = true;
@@ -4817,14 +4849,20 @@
EXPECT_CALL(*layer1.outputLayer,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+ EXPECT_CALL(*layer1.outputLayer, requiresClientComposition())
+ .WillRepeatedly(Return(false));
EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
EXPECT_CALL(*layer2.outputLayer,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+ EXPECT_CALL(*layer2.outputLayer, requiresClientComposition())
+ .WillRepeatedly(Return(false));
EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0));
EXPECT_CALL(*layer3.outputLayer,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+ EXPECT_CALL(*layer3.outputLayer, requiresClientComposition())
+ .WillRepeatedly(Return(false));
layer2.layerFEState.backgroundBlurRadius = 10;
layer2.layerFEState.isOpaque = false;
@@ -4854,14 +4892,20 @@
EXPECT_CALL(*layer1.outputLayer,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+ EXPECT_CALL(*layer1.outputLayer, requiresClientComposition())
+ .WillRepeatedly(Return(false));
EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
EXPECT_CALL(*layer2.outputLayer,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+ EXPECT_CALL(*layer2.outputLayer, requiresClientComposition())
+ .WillRepeatedly(Return(false));
EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0));
EXPECT_CALL(*layer3.outputLayer,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
+ EXPECT_CALL(*layer3.outputLayer, requiresClientComposition())
+ .WillRepeatedly(Return(false));
BlurRegion region;
layer2.layerFEState.blurRegions.push_back(region);
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 659efd8..bfdf667 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -80,22 +80,33 @@
} // namespace
-PowerAdvisor::PowerAdvisor(SurfaceFlinger& flinger)
- : mFlinger(flinger),
- mUseScreenUpdateTimer(getUpdateTimeout() > 0),
- mScreenUpdateTimer(
- "UpdateImminentTimer", OneShotTimer::Interval(getUpdateTimeout()),
- /* resetCallback */ [this] { mSendUpdateImminent.store(false); },
- /* timeoutCallback */
- [this] {
- mSendUpdateImminent.store(true);
- mFlinger.disableExpensiveRendering();
- }) {}
+PowerAdvisor::PowerAdvisor(SurfaceFlinger& flinger) : mFlinger(flinger) {
+ if (getUpdateTimeout()) {
+ mScreenUpdateTimer.emplace("UpdateImminentTimer",
+ OneShotTimer::Interval(getUpdateTimeout()),
+ /* resetCallback */ nullptr,
+ /* timeoutCallback */
+ [this] {
+ const nsecs_t timeSinceLastUpdate =
+ systemTime() - mLastScreenUpdatedTime.load();
+ if (timeSinceLastUpdate < getUpdateTimeout()) {
+ // We may try to disable expensive rendering and allow
+ // for sending DISPLAY_UPDATE_IMMINENT hints too early if
+ // we idled very shortly after updating the screen, so
+ // make sure we wait enough time.
+ std::this_thread::sleep_for(std::chrono::nanoseconds(
+ getUpdateTimeout() - timeSinceLastUpdate));
+ }
+ mSendUpdateImminent.store(true);
+ mFlinger.disableExpensiveRendering();
+ });
+ }
+}
void PowerAdvisor::init() {
// Defer starting the screen update timer until SurfaceFlinger finishes construction.
- if (mUseScreenUpdateTimer) {
- mScreenUpdateTimer.start();
+ if (mScreenUpdateTimer) {
+ mScreenUpdateTimer->start();
}
}
@@ -135,7 +146,7 @@
return;
}
- if (mSendUpdateImminent.load()) {
+ if (mSendUpdateImminent.exchange(false)) {
std::lock_guard lock(mPowerHalMutex);
HalWrapper* const halWrapper = getPowerHal();
if (halWrapper == nullptr) {
@@ -147,10 +158,18 @@
mReconnectPowerHal = true;
return;
}
+
+ if (mScreenUpdateTimer) {
+ mScreenUpdateTimer->reset();
+ } else {
+ // If we don't have a screen update timer, then we don't throttle power hal calls so
+ // flip this bit back to allow for calling into power hal again.
+ mSendUpdateImminent.store(true);
+ }
}
- if (mUseScreenUpdateTimer) {
- mScreenUpdateTimer.reset();
+ if (mScreenUpdateTimer) {
+ mLastScreenUpdatedTime.store(systemTime());
}
}
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
index 61bb32b..7c10e19 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
@@ -114,9 +114,9 @@
bool mNotifiedExpensiveRendering = false;
SurfaceFlinger& mFlinger;
- const bool mUseScreenUpdateTimer;
std::atomic_bool mSendUpdateImminent = true;
- scheduler::OneShotTimer mScreenUpdateTimer;
+ std::atomic<nsecs_t> mLastScreenUpdatedTime = 0;
+ std::optional<scheduler::OneShotTimer> mScreenUpdateTimer;
};
class AidlPowerHalWrapper : public PowerAdvisor::HalWrapper {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 2298f03..39686e0 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -151,10 +151,8 @@
mDrawingState.color.g = -1.0_hf;
mDrawingState.color.b = -1.0_hf;
}
-
CompositorTiming compositorTiming;
args.flinger->getCompositorTiming(&compositorTiming);
- mFrameEventHistory.initializeCompositorTiming(compositorTiming);
mFrameTracker.setDisplayRefreshPeriod(compositorTiming.interval);
mCallingPid = args.callingPid;
@@ -1531,53 +1529,17 @@
mFrameTracker.getStats(outStats);
}
-void Layer::dumpFrameEvents(std::string& result) {
- StringAppendF(&result, "- Layer %s (%s, %p)\n", getName().c_str(), getType(), this);
- Mutex::Autolock lock(mFrameEventHistoryMutex);
- mFrameEventHistory.checkFencesForCompletion();
- mFrameEventHistory.dump(result);
-}
-
void Layer::dumpCallingUidPid(std::string& result) const {
StringAppendF(&result, "Layer %s (%s) callingPid:%d callingUid:%d ownerUid:%d\n",
getName().c_str(), getType(), mCallingPid, mCallingUid, mOwnerUid);
}
void Layer::onDisconnect() {
- Mutex::Autolock lock(mFrameEventHistoryMutex);
- mFrameEventHistory.onDisconnect();
const int32_t layerId = getSequence();
mFlinger->mTimeStats->onDestroy(layerId);
mFlinger->mFrameTracer->onDestroy(layerId);
}
-void Layer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
- FrameEventHistoryDelta* outDelta) {
- if (newTimestamps) {
- mFlinger->mTimeStats->setPostTime(getSequence(), newTimestamps->frameNumber,
- getName().c_str(), mOwnerUid, newTimestamps->postedTime,
- getGameMode());
- mFlinger->mTimeStats->setAcquireFence(getSequence(), newTimestamps->frameNumber,
- newTimestamps->acquireFence);
- }
-
- Mutex::Autolock lock(mFrameEventHistoryMutex);
- if (newTimestamps) {
- // If there are any unsignaled fences in the aquire timeline at this
- // point, the previously queued frame hasn't been latched yet. Go ahead
- // and try to get the signal time here so the syscall is taken out of
- // the main thread's critical path.
- mAcquireTimeline.updateSignalTimes();
- // Push the new fence after updating since it's likely still pending.
- mAcquireTimeline.push(newTimestamps->acquireFence);
- mFrameEventHistory.addQueue(*newTimestamps);
- }
-
- if (outDelta) {
- mFrameEventHistory.getAndResetDelta(outDelta);
- }
-}
-
size_t Layer::getChildrenCount() const {
size_t count = 0;
for (const sp<Layer>& child : mCurrentChildren) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 1007043..ca46abc 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -432,10 +432,6 @@
virtual bool setSidebandStream(const sp<NativeHandle>& /*sidebandStream*/) { return false; };
virtual bool setTransactionCompletedListeners(
const std::vector<sp<CallbackHandle>>& /*handles*/);
- virtual bool addFrameEvent(const sp<Fence>& /*acquireFence*/, nsecs_t /*postedTime*/,
- nsecs_t /*requestedPresentTime*/) {
- return false;
- }
virtual bool setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace);
virtual bool setColorSpaceAgnostic(const bool agnostic);
virtual bool setDimmingEnabled(const bool dimmingEnabled);
@@ -742,14 +738,11 @@
void miniDump(std::string& result, const DisplayDevice&) const;
void dumpFrameStats(std::string& result) const;
- void dumpFrameEvents(std::string& result);
void dumpCallingUidPid(std::string& result) const;
void clearFrameStats();
void logFrameStats();
void getFrameStats(FrameStats* outStats) const;
void onDisconnect();
- void addAndGetFrameTimestamps(const NewFrameEventsEntry* newEntry,
- FrameEventHistoryDelta* outDelta);
ui::Transform getTransform() const;
bool isTransformValid() const;
@@ -994,13 +987,6 @@
// Timestamp history for UIAutomation. Thread safe.
FrameTracker mFrameTracker;
- // Timestamp history for the consumer to query.
- // Accessed by both consumer and producer on main and binder threads.
- Mutex mFrameEventHistoryMutex;
- ConsumerFrameEventHistory mFrameEventHistory;
- FenceTimeline mAcquireTimeline;
- FenceTimeline mReleaseTimeline;
-
// main thread
sp<NativeHandle> mSidebandStream;
// False if the buffer and its contents have been previously used for GPU
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 3aa0a5f..37f0fec 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -167,18 +167,19 @@
impl::EventThread::GetVsyncPeriodFunction Scheduler::makeGetVsyncPeriodFunction() const {
return [this](uid_t uid) {
const Fps refreshRate = holdRefreshRateConfigs()->getActiveMode()->getFps();
- const nsecs_t basePeriod = refreshRate.getPeriodNsecs();
+ const auto currentPeriod =
+ mVsyncSchedule->getTracker().currentPeriod() ?: refreshRate.getPeriodNsecs();
const auto frameRate = getFrameRateOverride(uid);
if (!frameRate.has_value()) {
- return basePeriod;
+ return currentPeriod;
}
const auto divisor = RefreshRateConfigs::getFrameRateDivisor(refreshRate, *frameRate);
if (divisor <= 1) {
- return basePeriod;
+ return currentPeriod;
}
- return basePeriod * divisor;
+ return currentPeriod * divisor;
};
}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index d8a2696..787ccd7 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2415,27 +2415,22 @@
const auto* display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()).get();
- getBE().mGlCompositionDoneTimeline.updateSignalTimes();
std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
if (display && display->getCompositionDisplay()->getState().usesClientComposition) {
glCompositionDoneFenceTime =
std::make_shared<FenceTime>(display->getCompositionDisplay()
->getRenderSurface()
->getClientTargetAcquireFence());
- getBE().mGlCompositionDoneTimeline.push(glCompositionDoneFenceTime);
} else {
glCompositionDoneFenceTime = FenceTime::NO_FENCE;
}
- getBE().mDisplayTimeline.updateSignalTimes();
mPreviousPresentFences[1] = mPreviousPresentFences[0];
mPreviousPresentFences[0].fence =
display ? getHwComposer().getPresentFence(display->getPhysicalId()) : Fence::NO_FENCE;
mPreviousPresentFences[0].fenceTime =
std::make_shared<FenceTime>(mPreviousPresentFences[0].fence);
- getBE().mDisplayTimeline.push(mPreviousPresentFences[0].fenceTime);
-
nsecs_t now = systemTime();
// Set presentation information before calling Layer::releasePendingBuffer, such that jank
@@ -3721,12 +3716,13 @@
auto& transaction = transactionQueue.front();
const auto ready =
- transactionIsReadyToBeApplied(transaction.frameTimelineInfo,
- transaction.isAutoTimestamp,
- transaction.desiredPresentTime,
- transaction.originUid, transaction.states,
- bufferLayersReadyToPresent, transactions.size(),
- tryApplyUnsignaled);
+ transactionIsReadyToBeApplied(transaction,
+ transaction.frameTimelineInfo,
+ transaction.isAutoTimestamp,
+ transaction.desiredPresentTime,
+ transaction.originUid, transaction.states,
+ bufferLayersReadyToPresent, transactions.size(),
+ tryApplyUnsignaled);
ATRACE_INT("TransactionReadiness", static_cast<int>(ready));
if (ready == TransactionReadiness::NotReady) {
setTransactionFlags(eTransactionFlushNeeded);
@@ -3803,7 +3799,7 @@
return TransactionReadiness::NotReady;
}
- return transactionIsReadyToBeApplied(transaction.frameTimelineInfo,
+ return transactionIsReadyToBeApplied(transaction, transaction.frameTimelineInfo,
transaction.isAutoTimestamp,
transaction.desiredPresentTime,
transaction.originUid, transaction.states,
@@ -3965,7 +3961,7 @@
return true;
}
-auto SurfaceFlinger::transactionIsReadyToBeApplied(
+auto SurfaceFlinger::transactionIsReadyToBeApplied(TransactionState& transaction,
const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime,
uid_t originUid, const Vector<ComposerState>& states,
const std::unordered_map<
@@ -3994,8 +3990,10 @@
}
bool fenceUnsignaled = false;
+ auto queueProcessTime = systemTime();
for (const ComposerState& state : states) {
const layer_state_t& s = state.state;
+
sp<Layer> layer = nullptr;
if (s.surface) {
layer = fromHandle(s.surface).promote();
@@ -4031,6 +4029,15 @@
s.bufferData->acquireFence->getStatus() == Fence::Status::Unsignaled);
if (fenceUnsignaled && !allowLatchUnsignaled) {
+ if (!transaction.sentFenceTimeoutWarning &&
+ queueProcessTime - transaction.queueTime > std::chrono::nanoseconds(4s).count()) {
+ transaction.sentFenceTimeoutWarning = true;
+ auto listener = s.bufferData->releaseBufferListener;
+ if (listener) {
+ listener->onTransactionQueueStalled();
+ }
+ }
+
ATRACE_NAME("fence unsignaled");
return TransactionReadiness::NotReady;
}
@@ -4050,6 +4057,8 @@
}
void SurfaceFlinger::queueTransaction(TransactionState& state) {
+ state.queueTime = systemTime();
+
Mutex::Autolock lock(mQueueLock);
// Generate a CountDownLatch pending state if this is a synchronous transaction.
@@ -4960,7 +4969,6 @@
{"--displays"s, dumper(&SurfaceFlinger::dumpDisplays)},
{"--dispsync"s, dumper([this](std::string& s) { mScheduler->dumpVsync(s); })},
{"--edid"s, argsDumper(&SurfaceFlinger::dumpRawDisplayIdentificationData)},
- {"--frame-events"s, dumper(&SurfaceFlinger::dumpFrameEventsLocked)},
{"--latency"s, argsDumper(&SurfaceFlinger::dumpStatsLocked)},
{"--latency-clear"s, argsDumper(&SurfaceFlinger::clearStatsLocked)},
{"--list"s, dumper(&SurfaceFlinger::listLayersLocked)},
@@ -5127,13 +5135,6 @@
bucketTimeSec, percent);
}
-void SurfaceFlinger::dumpFrameEventsLocked(std::string& result) {
- result.append("Layer frame timestamps:\n");
- // Traverse all layers to dump frame-events for each layer
- mCurrentState.traverseInZOrder(
- [&] (Layer* layer) { layer->dumpFrameEvents(result); });
-}
-
void SurfaceFlinger::dumpCompositionDisplays(std::string& result) const {
for (const auto& [token, display] : mDisplays) {
display->getCompositionDisplay()->dump(result);
@@ -6785,7 +6786,7 @@
BlurSetting::Disabled
: compositionengine::LayerFE::ClientCompositionTargetSettings::
BlurSetting::Enabled,
- isHdrDataspace(dataspace) ? displayBrightnessNits : sdrWhitePointNits,
+ isHdrLayer(layer) ? displayBrightnessNits : sdrWhitePointNits,
};
std::vector<compositionengine::LayerFE::LayerSettings> results =
@@ -6800,7 +6801,7 @@
if (regionSampling) {
settings.backgroundBlurRadius = 0;
}
- captureResults.capturedHdrLayers |= isHdrDataspace(settings.sourceDataspace);
+ captureResults.capturedHdrLayers |= isHdrLayer(layer);
}
clientCompositionLayers.insert(clientCompositionLayers.end(),
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index dc54ac2..aeaa01e 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -167,9 +167,6 @@
using DisplayColorSetting = compositionengine::OutputColorSetting;
struct SurfaceFlingerBE {
- FenceTimeline mGlCompositionDoneTimeline;
- FenceTimeline mDisplayTimeline;
-
// protected by mCompositorTimingLock;
mutable std::mutex mCompositorTimingLock;
CompositorTiming mCompositorTiming;
@@ -810,7 +807,7 @@
Ready,
ReadyUnsignaled,
};
- TransactionReadiness transactionIsReadyToBeApplied(
+ TransactionReadiness transactionIsReadyToBeApplied(TransactionState& state,
const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime,
uid_t originUid, const Vector<ComposerState>& states,
const std::unordered_map<
@@ -1100,8 +1097,6 @@
void dumpVSync(std::string& result) const REQUIRES(mStateLock);
void dumpStaticScreenStats(std::string& result) const;
- // Not const because each Layer needs to query Fences and cache timestamps.
- void dumpFrameEventsLocked(std::string& result);
void dumpCompositionDisplays(std::string& result) const REQUIRES(mStateLock);
void dumpDisplays(std::string& result) const REQUIRES(mStateLock);
diff --git a/services/surfaceflinger/TransactionState.h b/services/surfaceflinger/TransactionState.h
index bab5326..900d566 100644
--- a/services/surfaceflinger/TransactionState.h
+++ b/services/surfaceflinger/TransactionState.h
@@ -98,6 +98,8 @@
int originUid;
uint64_t id;
std::shared_ptr<CountDownLatch> transactionCommittedSignal;
+ int64_t queueTime = 0;
+ bool sentFenceTimeoutWarning = false;
};
class CountDownLatch {
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index a80aca2..867a198 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -456,9 +456,6 @@
mFlinger->dumpStaticScreenStats(result);
result = fdp->ConsumeRandomLengthString().c_str();
- mFlinger->dumpFrameEventsLocked(result);
-
- result = fdp->ConsumeRandomLengthString().c_str();
mFlinger->dumpRawDisplayIdentificationData(dumpArgs, result);
LayersProto layersProto = mFlinger->dumpDrawingStateProto(fdp->ConsumeIntegral<uint32_t>());
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
index bd8081f..34cf906 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
@@ -147,8 +147,6 @@
const bool ownsHandle = mFdp.ConsumeBool();
sp<NativeHandle> nativeHandle = sp<NativeHandle>::make(testHandle, ownsHandle);
layer->setSidebandStream(nativeHandle);
- layer->addFrameEvent(fence, mFdp.ConsumeIntegral<int64_t>() /*postedTime*/,
- mFdp.ConsumeIntegral<int64_t>() /*requestedTime*/);
layer->computeSourceBounds(getFuzzedFloatRect(&mFdp));
layer->fenceHasSignaled();