diff options
53 files changed, 950 insertions, 580 deletions
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index b4aa88ee78..a49f563060 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -1957,17 +1957,43 @@ binder::Status InstalldNativeService::freeCache(const std::optional<std::string> #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 6112d5fd0a..eef69f4b32 100644 --- a/include/android/sensor.h +++ b/include/android/sensor.h @@ -267,7 +267,8 @@ enum { * {@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 68b99b034e..61e6657621 100644 --- a/libs/gralloc/types/Gralloc4.cpp +++ b/libs/gralloc/types/Gralloc4.cpp @@ -196,35 +196,6 @@ status_t encodeMetadataType(const MetadataType& input, OutputHidlVec* output); 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 @@ status_t encodeMetadata(const MetadataType& metadataType, const T& input, hidl_v 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; - } - - 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); + if (!input) { + return NO_ERROR; } - - return NO_ERROR; + return encodeMetadata(metadataType, *input, output, encodeHelper); } /** @@ -379,36 +315,45 @@ status_t decodeOptionalMetadata(const MetadataType& metadataType, const hidl_vec 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; + T tmp; + status_t err = decodeMetadata(metadataType, input, &tmp, decodeHelper); + if (!err) { + *output = tmp; } + return err; +} - if (present) { - T tmp; - err = decodeHelper(&inputHidlVec, &tmp); - if (err) { - return err; - } - - *output = tmp; +/** + * 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; } - err = inputHidlVec.hasRemainingData(); - if (err) { + 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; } - return NO_ERROR; + 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 c2793ac5de..dbccf30fae 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -165,6 +165,17 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, bool updateDestinati 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(const std::string& name, const sp<SurfaceCont } BLASTBufferQueue::~BLASTBufferQueue() { + TransactionCompletedListener::getInstance()->removeQueueStallListener(this); if (mPendingTransactions.empty()) { return; } @@ -1113,4 +1125,9 @@ bool BLASTBufferQueue::isSameSurfaceControl(const sp<SurfaceControl>& surfaceCon 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 f7392d4969..e4b8bad8f8 100644 --- a/libs/gui/ITransactionCompletedListener.cpp +++ b/libs/gui/ITransactionCompletedListener.cpp @@ -29,6 +29,7 @@ namespace { // Anonymous 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 @@ public: 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 @@ status_t BnTransactionCompletedListener::onTransact(uint32_t code, const Parcel& &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 6642ec6337..501f8cf15c 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -447,6 +447,27 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener } } +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 65fc04df1a..9328a54184 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -113,6 +113,14 @@ public: 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 @@ private: // 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 a791c665e1..cc136bb40a 100644 --- a/libs/gui/include/gui/ITransactionCompletedListener.h +++ b/libs/gui/include/gui/ITransactionCompletedListener.h @@ -194,6 +194,7 @@ public: 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 0cc43d85bf..efbdb36fef 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -772,6 +772,7 @@ protected: // 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 @@ public: 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 @@ public: // 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 34f10ec00e..3bc7068f3c 100644 --- a/libs/input/android/os/InputEventInjectionResult.aidl +++ b/libs/input/android/os/InputEventInjectionResult.aidl @@ -29,9 +29,8 @@ enum InputEventInjectionResult { /* 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 995dba1422..db001184b4 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 f0d45c2123..62745dc8d5 100644 --- a/libs/shaders/shaders.cpp +++ b/libs/shaders/shaders.cpp @@ -78,7 +78,7 @@ void generateEOTF(ui::Dataspace dataspace, std::string& shader) { 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 beca7f191a..86c788d3b3 100644 --- a/opengl/libs/EGL/BlobCache.cpp +++ b/opengl/libs/EGL/BlobCache.cpp @@ -52,35 +52,37 @@ BlobCache::BlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize 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 @@ void BlobCache::set(const void* key, size_t keySize, const void* value, size_t v 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 @@ void BlobCache::set(const void* key, size_t keySize, const void* value, size_t v 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 @@ void BlobCache::set(const void* key, size_t keySize, const void* value, size_t v "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 50b4e4c6d0..ff03d30099 100644 --- a/opengl/libs/EGL/BlobCache.h +++ b/opengl/libs/EGL/BlobCache.h @@ -39,6 +39,26 @@ public: // (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 @@ public: // 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 d31373b37a..ceea0fb979 100644 --- a/opengl/libs/EGL/BlobCache_test.cpp +++ b/opengl/libs/EGL/BlobCache_test.cpp @@ -49,7 +49,7 @@ protected: 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, CacheSingleValueSucceeds) { 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, CacheTwoValuesSucceeds) { 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, GetOnlyWritesInsideBounds) { 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, GetOnlyWritesIfBufferIsLargeEnough) { } 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, MultipleSetsCacheLatestValue) { 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 @@ TEST_F(BlobCacheTest, DoesntCacheIfKeyIsTooBig) { 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 @@ TEST_F(BlobCacheTest, DoesntCacheIfValueIsTooBig) { 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 @@ TEST_F(BlobCacheTest, DoesntCacheIfKeyValuePairIsTooBig) { 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 @@ TEST_F(BlobCacheTest, CacheMaxKeySizeSucceeds) { 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 @@ TEST_F(BlobCacheTest, CacheMaxValueSizeSucceeds) { 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 @@ TEST_F(BlobCacheTest, CacheMaxKeyValuePairSizeSucceeds) { 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 @@ TEST_F(BlobCacheTest, ExceedingTotalLimitHalvesCacheSize) { 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 @@ TEST_F(BlobCacheTest, ExceedingTotalLimitHalvesCacheSize) { 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 9b72ff4b19..b4b617e188 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 32eec291cb..a2e60c4e6f 100644 --- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp +++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp @@ -31,11 +31,11 @@ using android::os::InputEventInjectionSync; 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 @@ private: 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 @@ public: 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 @@ static void benchmarkInjectMotion(benchmark::State& state) { 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 4636820538..d1c8b8a10e 100644 --- a/services/inputflinger/dispatcher/DragState.h +++ b/services/inputflinger/dispatcher/DragState.h @@ -26,7 +26,8 @@ namespace android { 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 @@ struct DragState { 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 c8024a61a9..c2d3ad6b9d 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 0bfafb1d19..90cf150ac3 100644 --- a/services/inputflinger/dispatcher/InjectionState.h +++ b/services/inputflinger/dispatcher/InjectionState.h @@ -27,13 +27,12 @@ namespace inputdispatcher { 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 5d8df5fdf0..b5a3825fc3 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -578,6 +578,27 @@ bool isWindowOwnedBy(const sp<WindowInfoHandle>& windowHandle, int32_t pid, int3 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 @@ bool InputDispatcher::enqueueInboundEventLocked(std::unique_ptr<EventEntry> newE 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 @@ bool InputDispatcher::enqueueInboundEventLocked(std::unique_ptr<EventEntry> newE } 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 @@ bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, std::shared_ptr< } 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 @@ bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, std::shared_ptr< } 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 @@ InputEventInjectionResult InputDispatcher::findFocusedWindowTargetsLocked( // 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 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( 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 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( // 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 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( "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 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( 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 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( 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 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( 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 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( 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 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( 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 @@ void InputDispatcher::finishDragAndDrop(int32_t displayId, float x, float y) { 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 @@ void InputDispatcher::addDragEventLocked(const MotionEntry& entry) { (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; } + } + + 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; + } - // 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 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(); - 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); + 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; } - mDragState->dragHoverWindowHandle = hoverWindowHandle; + + // 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; } - // enqueue drag location if needed. - if (hoverWindowHandle != nullptr) { - enqueueDragEventLocked(hoverWindowHandle, false /*isExiting*/, entry); + + 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; } - } else if (maskedAction == AMOTION_EVENT_ACTION_UP) { - finishDragAndDrop(entry.displayId, x, y); - } else if (maskedAction == AMOTION_EVENT_ACTION_CANCEL) { - sendDropWindowCommandLocked(nullptr, 0, 0); - mDragState.reset(); } } @@ -2657,26 +2719,6 @@ void InputDispatcher::addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& } } -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 @@ void InputDispatcher::notifyPointerCaptureChanged(const NotifyPointerCaptureChan } } -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 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( 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 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( } // 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 @@ std::unique_ptr<VerifiedInputEvent> InputDispatcher::verifyInputEvent(const Inpu 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 @@ void InputDispatcher::setInjectionResult(EventEntry& entry, 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 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp< // 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 f3dac19fa4..ed89ed0b0f 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -104,7 +104,7 @@ public: 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 @@ private: 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 @@ private: // 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 @@ private: 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 d7bc5fbfe9..67fed8b4f1 100644 --- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h +++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h @@ -68,10 +68,16 @@ public: * 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 de0b6da884..575b3d7059 100644 --- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h +++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h @@ -125,15 +125,6 @@ public: /* 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 b688898022..91a666c699 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -45,10 +45,10 @@ namespace android::inputdispatcher { 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_2_DOWN = 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 @@ private: 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 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) { /*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 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) { 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 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { 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 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { 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 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { 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 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { 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 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { 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 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { 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 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { 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 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { 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 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { 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 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { 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 @@ public: 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 @@ static InputEventInjectionResult injectKey( 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 @@ static InputEventInjectionResult injectKey( 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 @@ private: 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 @@ static InputEventInjectionResult injectMotionEvent( 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 @@ static InputEventInjectionResult injectMotionEvent( .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 @@ TEST_F(InputDispatcherTest, DisplayRemoved) { * 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 @@ protected: 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 @@ protected: 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 @@ TEST_F(InputDispatcherSingleWindowAnr, StaleKeyEventDoesNotAnr) { 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 @@ protected: 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 @@ protected: // 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 @@ protected: {{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 @@ TEST_F(InputDispatcherDragTests, StylusDragAndDrop) { mSecondWindow->assertNoEvents(); } -TEST_F(InputDispatcherDragTests, DragAndDrop_InvalidWindow) { +TEST_F(InputDispatcherDragTests, DragAndDropOnInvalidWindow) { performDrag(); // Set second window invisible. @@ -6312,6 +6324,89 @@ TEST_F(InputDispatcherDragTests, DragAndDrop_InvalidWindow) { 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 @@ protected: 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 @@ TEST_F(InputDispatcherStylusInterceptorTest, StylusHandwritingScenario) { 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 14f9a12553..94de55c124 100644 --- a/services/sensorservice/BatteryService.cpp +++ b/services/sensorservice/BatteryService.cpp @@ -74,23 +74,6 @@ void BatteryService::disableSensorImpl(uid_t uid, int handle) { } } -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 09eb2c1d10..13fc58aadb 100644 --- a/services/sensorservice/BatteryService.h +++ b/services/sensorservice/BatteryService.h @@ -32,7 +32,6 @@ class BatteryService : public Singleton<BatteryService> { 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 @@ public: 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 53a3025779..de050e02d0 100644 --- a/services/sensorservice/SensorDevice.cpp +++ b/services/sensorservice/SensorDevice.cpp @@ -612,8 +612,10 @@ int SensorDevice::getHalDeviceVersion() const { 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 @@ void SensorDevice::disableAllSensors() { 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 fae16f66b2..2dd12e9446 100644 --- a/services/sensorservice/SensorDirectConnection.cpp +++ b/services/sensorservice/SensorDirectConnection.cpp @@ -157,7 +157,7 @@ int32_t SensorService::SensorDirectConnection::configureChannel(int handle, int } 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 6948895835..f06f9472bd 100644 --- a/services/sensorservice/SensorEventConnection.cpp +++ b/services/sensorservice/SensorEventConnection.cpp @@ -162,7 +162,8 @@ bool SensorService::SensorEventConnection::addSensor(int32_t handle) { 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 8b81d4817e..948692bd47 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -814,6 +814,12 @@ status_t SensorService::shellCommand(int in, int out, int err, Vector<String16>& 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::getSensorList(const String16& opPackageName) { 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 @@ void SensorService::cleanupConnection(SensorEventConnection* c) { } 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 @@ void SensorService::cleanupConnection(SensorEventConnection* c) { } c->updateLooperRegistration(mLooper); mConnectionHolder.removeEventConnection(connection); - BatteryService::cleanup(c->getUid()); if (c->needsWakeLock()) { checkWakeLockStateLocked(&connLock); } @@ -1988,6 +1995,20 @@ status_t SensorService::flushSensor(const sp<SensorEventConnection>& connection, 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 b18d20418f..234dc9cd7d 100644 --- a/services/sensorservice/SensorService.h +++ b/services/sensorservice/SensorService.h @@ -373,7 +373,7 @@ private: 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 @@ private: 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 635b0884d9..f8c53c338e 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -315,11 +315,7 @@ void BufferLayer::preparePerFrameCompositionState() { 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 @@ void BufferLayer::onPostComposition(const DisplayDevice* display, 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 @@ bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, 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 3e70493101..4c70eb58bf 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -192,7 +192,7 @@ private: 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 9ae45fc4cb..7361a4fdef 100644 --- a/services/surfaceflinger/BufferLayerConsumer.cpp +++ b/services/surfaceflinger/BufferLayerConsumer.cpp @@ -471,18 +471,6 @@ void BufferLayerConsumer::onBufferAvailable(const BufferItem& item) { } } -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 9ed80b46bd..23ad2a3f91 100644 --- a/services/surfaceflinger/BufferLayerConsumer.h +++ b/services/surfaceflinger/BufferLayerConsumer.h @@ -236,8 +236,7 @@ private: // 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 6a1a38b39c..f487aab9ce 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -66,20 +66,10 @@ void BufferQueueLayer::setTransformHint(ui::Transform::RotationFlags displayTran 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 @@ status_t BufferQueueLayer::updateActiveBuffer() { 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 4587b5e27c..649da2c8cb 100644 --- a/services/surfaceflinger/BufferQueueLayer.h +++ b/services/surfaceflinger/BufferQueueLayer.h @@ -102,7 +102,7 @@ private: 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 c88511049b..e58b65ec06 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -178,15 +178,6 @@ void BufferStateLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) { } 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 @@ bool BufferStateLayer::setPosition(float x, float y) { 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 @@ bool BufferStateLayer::setBuffer(std::shared_ptr<renderengine::ExternalTexture>& 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 @@ status_t BufferStateLayer::updateActiveBuffer() { 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 cc510d8c74..bbf058c298 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -66,8 +66,6 @@ public: 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 @@ private: 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 c65d467b0d..7709b967b6 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h @@ -164,6 +164,9 @@ struct OutputCompositionState { 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 742332ca24..2d2b3dfb39 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -763,6 +763,7 @@ void Output::writeCompositionState(const compositionengine::CompositionRefreshAr 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 @@ void Output::writeCompositionState(const compositionengine::CompositionRefreshAr 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 @@ void Output::writeCompositionState(const compositionengine::CompositionRefreshAr 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 @@ void Output::setTreat170mAsSrgb(bool enable) { } 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 @@ bool Output::canPredictCompositionStrategy(const CompositionRefreshArgs& refresh 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 @@ bool Output::canPredictCompositionStrategy(const CompositionRefreshArgs& refresh 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 784abeac29..b907129dba 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -850,14 +850,20 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, updatesLayerContentForAllLayers 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 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, updatesLayerGeometryAndContentF 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 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, forcesClientCompositionForAllLa 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 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, peekThroughLayerChangesOrder) { 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 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, peekThroughLayerChangesOrder) { 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 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, peekThroughLayerChangesOrder) { 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 @@ struct OutputComposeSurfacesTest : public testing::Test { 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 @@ struct OutputComposeSurfacesTest_UsesExpectedDisplaySettings : public OutputComp 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 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forHdrMixedComposi {.physicalDisplay = kDefaultOutputDestinationClip, .clip = kDefaultOutputViewport, .maxLuminance = kDefaultMaxLuminance, - .currentLuminanceNits = kDefaultMaxLuminance, + .currentLuminanceNits = kDisplayLuminance, .outputDataspace = kDefaultOutputDataspace, .colorTransform = kDefaultColorTransformMat, .deviceHandlesColorTransform = true, @@ -3806,7 +3834,7 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forHdrMixedCompositionWithDimmingStage) { verify().ifMixedCompositionIs(true) .andIfUsesHdr(true) - .withDisplayBrightnessNits(kUnknownLuminance) + .withDisplayBrightnessNits(kDisplayLuminance) .withDimmingStage( aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF) .withRenderIntent( @@ -3816,7 +3844,7 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, {.physicalDisplay = kDefaultOutputDestinationClip, .clip = kDefaultOutputViewport, .maxLuminance = kDefaultMaxLuminance, - .currentLuminanceNits = kDefaultMaxLuminance, + .currentLuminanceNits = kDisplayLuminance, .outputDataspace = kDefaultOutputDataspace, .colorTransform = kDefaultColorTransformMat, .deviceHandlesColorTransform = true, @@ -3834,7 +3862,7 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, 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 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, {.physicalDisplay = kDefaultOutputDestinationClip, .clip = kDefaultOutputViewport, .maxLuminance = kDefaultMaxLuminance, - .currentLuminanceNits = kDefaultMaxLuminance, + .currentLuminanceNits = kDisplayLuminance, .outputDataspace = kDefaultOutputDataspace, .colorTransform = kDefaultColorTransformMat, .deviceHandlesColorTransform = true, @@ -3859,7 +3887,7 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, 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 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forNonHdrMixedComp {.physicalDisplay = kDefaultOutputDestinationClip, .clip = kDefaultOutputViewport, .maxLuminance = kDefaultMaxLuminance, - .currentLuminanceNits = kDefaultMaxLuminance, + .currentLuminanceNits = kDisplayLuminance, .outputDataspace = kDefaultOutputDataspace, .colorTransform = kDefaultColorTransformMat, .deviceHandlesColorTransform = true, @@ -3885,7 +3913,7 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forNonHdrMixedComp 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 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forHdrOnlyClientCo {.physicalDisplay = kDefaultOutputDestinationClip, .clip = kDefaultOutputViewport, .maxLuminance = kDefaultMaxLuminance, - .currentLuminanceNits = kDefaultMaxLuminance, + .currentLuminanceNits = kDisplayLuminance, .outputDataspace = kDefaultOutputDataspace, .colorTransform = kDefaultColorTransformMat, .deviceHandlesColorTransform = false, @@ -3911,7 +3939,7 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forHdrOnlyClientCo 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 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forNonHdrOnlyClien {.physicalDisplay = kDefaultOutputDestinationClip, .clip = kDefaultOutputViewport, .maxLuminance = kDefaultMaxLuminance, - .currentLuminanceNits = kDefaultMaxLuminance, + .currentLuminanceNits = kDisplayLuminance, .outputDataspace = kDefaultOutputDataspace, .colorTransform = kDefaultColorTransformMat, .deviceHandlesColorTransform = false, @@ -3938,7 +3966,7 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, 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 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, {.physicalDisplay = kDefaultOutputDestinationClip, .clip = kDefaultOutputViewport, .maxLuminance = kDefaultMaxLuminance, - .currentLuminanceNits = kDefaultMaxLuminance, + .currentLuminanceNits = kDisplayLuminance, .outputDataspace = kDefaultOutputDataspace, .colorTransform = kDefaultColorTransformMat, .deviceHandlesColorTransform = true, @@ -4785,10 +4813,14 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, noBackgroundBlurWhenOpaque) { 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 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, handlesBackgroundBlurRequests) 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 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, handlesBlurRegionRequests) { 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 659efd8636..bfdf667629 100644 --- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp +++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp @@ -80,22 +80,33 @@ void traceExpensiveRendering(bool enabled) { } // 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 @@ void PowerAdvisor::notifyDisplayUpdateImminent() { return; } - if (mSendUpdateImminent.load()) { + if (mSendUpdateImminent.exchange(false)) { std::lock_guard lock(mPowerHalMutex); HalWrapper* const halWrapper = getPowerHal(); if (halWrapper == nullptr) { @@ -147,10 +158,18 @@ void PowerAdvisor::notifyDisplayUpdateImminent() { 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 61bb32b8bd..7c10e19e11 100644 --- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h +++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h @@ -114,9 +114,9 @@ private: 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 2298f038e9..39686e0a07 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -151,10 +151,8 @@ Layer::Layer(const LayerCreationArgs& args) 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 @@ void Layer::getFrameStats(FrameStats* outStats) const { 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 100704369e..ca46abc54d 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -432,10 +432,6 @@ public: 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 @@ public: 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 @@ protected: // 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 3aa0a5f15c..37f0fec425 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -167,18 +167,19 @@ impl::EventThread::ThrottleVsyncCallback Scheduler::makeThrottleVsyncCallback() 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 d8a2696ef0..787ccd71df 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2415,27 +2415,22 @@ void SurfaceFlinger::postComposition() { 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 @@ int SurfaceFlinger::flushPendingTransactionQueues( 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 @@ bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) { return TransactionReadiness::NotReady; } - return transactionIsReadyToBeApplied(transaction.frameTimelineInfo, + return transactionIsReadyToBeApplied(transaction, transaction.frameTimelineInfo, transaction.isAutoTimestamp, transaction.desiredPresentTime, transaction.originUid, transaction.states, @@ -3965,7 +3961,7 @@ bool SurfaceFlinger::shouldLatchUnsignaled(const sp<Layer>& layer, const layer_s 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 @@ auto SurfaceFlinger::transactionIsReadyToBeApplied( } 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 @@ auto SurfaceFlinger::transactionIsReadyToBeApplied( 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 @@ auto SurfaceFlinger::transactionIsReadyToBeApplied( } 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 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) { {"--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 @@ void SurfaceFlinger::dumpStaticScreenStats(std::string& result) const { 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 @@ std::shared_future<FenceResult> SurfaceFlinger::renderScreenImpl( 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 @@ std::shared_future<FenceResult> SurfaceFlinger::renderScreenImpl( 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 dc54ac245b..aeaa01e539 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -167,9 +167,6 @@ enum class LatchUnsignaledConfig { using DisplayColorSetting = compositionengine::OutputColorSetting; struct SurfaceFlingerBE { - FenceTimeline mGlCompositionDoneTimeline; - FenceTimeline mDisplayTimeline; - // protected by mCompositorTimingLock; mutable std::mutex mCompositorTimingLock; CompositorTiming mCompositorTiming; @@ -810,7 +807,7 @@ private: 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 @@ private: 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 bab5326093..900d566942 100644 --- a/services/surfaceflinger/TransactionState.h +++ b/services/surfaceflinger/TransactionState.h @@ -98,6 +98,8 @@ struct TransactionState { 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 a80aca2f73..867a1985bd 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h @@ -456,9 +456,6 @@ public: 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 bd8081f863..34cf90628a 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp @@ -147,8 +147,6 @@ void LayerFuzzer::invokeBufferStateLayer() { 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(); |