diff options
49 files changed, 1060 insertions, 321 deletions
diff --git a/include/input/Input.h b/include/input/Input.h index cf0814cf2f..14a7288d19 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -73,6 +73,19 @@ enum { AMOTION_EVENT_FLAG_TAINTED = 0x80000000, }; +/** + * Allowed VerifiedKeyEvent flags. All other flags from KeyEvent do not get verified. + * These values must be kept in sync with VerifiedKeyEvent.java + */ +constexpr int32_t VERIFIED_KEY_EVENT_FLAGS = AKEY_EVENT_FLAG_CANCELED; + +/** + * Allowed VerifiedMotionEventFlags. All other flags from MotionEvent do not get verified. + * These values must be kept in sync with VerifiedMotionEvent.java + */ +constexpr int32_t VERIFIED_MOTION_EVENT_FLAGS = + AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; + enum { /* Used when a motion event is not associated with any display. * Typically used for non-pointer events. */ @@ -718,6 +731,55 @@ protected: bool mInTouchMode; }; +/** + * Base class for verified events. + * Do not create a VerifiedInputEvent explicitly. + * Use helper functions to create them from InputEvents. + */ +struct __attribute__((__packed__)) VerifiedInputEvent { + enum class Type : int32_t { + KEY = AINPUT_EVENT_TYPE_KEY, + MOTION = AINPUT_EVENT_TYPE_MOTION, + }; + + Type type; + int32_t deviceId; + nsecs_t eventTimeNanos; + uint32_t source; + int32_t displayId; +}; + +/** + * Same as KeyEvent, but only contains the data that can be verified. + * If you update this class, you must also update VerifiedKeyEvent.java + */ +struct __attribute__((__packed__)) VerifiedKeyEvent : public VerifiedInputEvent { + int32_t action; + nsecs_t downTimeNanos; + int32_t flags; + int32_t keyCode; + int32_t scanCode; + int32_t metaState; + int32_t repeatCount; +}; + +/** + * Same as MotionEvent, but only contains the data that can be verified. + * If you update this class, you must also update VerifiedMotionEvent.java + */ +struct __attribute__((__packed__)) VerifiedMotionEvent : public VerifiedInputEvent { + float rawX; + float rawY; + int32_t actionMasked; + nsecs_t downTimeNanos; + int32_t flags; + int32_t metaState; + int32_t buttonState; +}; + +VerifiedKeyEvent verifiedKeyEventFromKeyEvent(const KeyEvent& event); +VerifiedMotionEvent verifiedMotionEventFromMotionEvent(const MotionEvent& event); + /* * Input event factory. */ diff --git a/libs/binderthreadstate/Android.bp b/libs/binderthreadstate/Android.bp index 4655e1d8f4..c1861104d3 100644 --- a/libs/binderthreadstate/Android.bp +++ b/libs/binderthreadstate/Android.bp @@ -63,15 +63,3 @@ cc_test { ], require_root: true, } - -// TODO(b/148692216): remove empty lib -cc_library { - name: "libbinderthreadstate", - recovery_available: true, - vendor_available: false, - vndk: { - enabled: true, - support_system_process: true, - }, - host_supported: true, -} diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp index 31a399bd3f..b6b81bbba6 100644 --- a/libs/cputimeinstate/cputimeinstate.cpp +++ b/libs/cputimeinstate/cputimeinstate.cpp @@ -58,6 +58,7 @@ static std::vector<std::vector<uint32_t>> gPolicyCpus; static std::set<uint32_t> gAllFreqs; static unique_fd gTisMapFd; static unique_fd gConcurrentMapFd; +static unique_fd gUidLastUpdateMapFd; static std::optional<std::vector<uint32_t>> readNumbersFromFile(const std::string &path) { std::string data; @@ -144,6 +145,10 @@ static bool initGlobals() { unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_concurrent_times_map")}; if (gConcurrentMapFd < 0) return false; + gUidLastUpdateMapFd = + unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_last_update_map")}; + if (gUidLastUpdateMapFd < 0) return false; + gInitialized = true; return true; } @@ -263,6 +268,18 @@ std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t ui return out; } +static std::optional<bool> uidUpdatedSince(uint32_t uid, uint64_t lastUpdate, + uint64_t *newLastUpdate) { + uint64_t uidLastUpdate; + if (findMapEntry(gUidLastUpdateMapFd, &uid, &uidLastUpdate)) return {}; + // Updates that occurred during the previous read may have been missed. To mitigate + // this, don't ignore entries updated up to 1s before *lastUpdate + constexpr uint64_t NSEC_PER_SEC = 1000000000; + if (uidLastUpdate + NSEC_PER_SEC < lastUpdate) return false; + if (uidLastUpdate > *newLastUpdate) *newLastUpdate = uidLastUpdate; + return true; +} + // Retrieve the times in ns that each uid spent running at each CPU freq. // Return contains no value on error, otherwise it contains a map from uids to vectors of vectors // using the format: @@ -271,6 +288,14 @@ std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t ui // where ti_j_k is the ns uid i spent running on the jth cluster at the cluster's kth lowest freq. std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>> getUidsCpuFreqTimes() { + return getUidsUpdatedCpuFreqTimes(nullptr); +} + +// Retrieve the times in ns that each uid spent running at each CPU freq, excluding UIDs that have +// not run since before lastUpdate. +// Return format is the same as getUidsCpuFreqTimes() +std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>> +getUidsUpdatedCpuFreqTimes(uint64_t *lastUpdate) { if (!gInitialized && !initGlobals()) return {}; time_key_t key, prevKey; std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> map; @@ -282,8 +307,14 @@ getUidsCpuFreqTimes() { std::vector<std::vector<uint64_t>> mapFormat; for (const auto &freqList : gPolicyFreqs) mapFormat.emplace_back(freqList.size(), 0); + uint64_t newLastUpdate = lastUpdate ? *lastUpdate : 0; std::vector<tis_val_t> vals(gNCpus); do { + if (lastUpdate) { + auto uidUpdated = uidUpdatedSince(key.uid, *lastUpdate, &newLastUpdate); + if (!uidUpdated.has_value()) return {}; + if (!*uidUpdated) continue; + } if (findMapEntry(gTisMapFd, &key, vals.data())) return {}; if (map.find(key.uid) == map.end()) map.emplace(key.uid, mapFormat); @@ -299,8 +330,9 @@ getUidsCpuFreqTimes() { } } prevKey = key; - } while (!getNextMapKey(gTisMapFd, &prevKey, &key)); + } while (prevKey = key, !getNextMapKey(gTisMapFd, &prevKey, &key)); if (errno != ENOENT) return {}; + if (lastUpdate && newLastUpdate > *lastUpdate) *lastUpdate = newLastUpdate; return map; } @@ -365,6 +397,15 @@ std::optional<concurrent_time_t> getUidConcurrentTimes(uint32_t uid, bool retry) // where ai is the ns spent running concurrently with tasks on i other cpus and pi_j is the ns spent // running on the ith cluster, concurrently with tasks on j other cpus in the same cluster. std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsConcurrentTimes() { + return getUidsUpdatedConcurrentTimes(nullptr); +} + +// Retrieve the times in ns that each uid spent running concurrently with each possible number of +// other tasks on each cluster (policy times) and overall (active times), excluding UIDs that have +// not run since before lastUpdate. +// Return format is the same as getUidsConcurrentTimes() +std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsUpdatedConcurrentTimes( + uint64_t *lastUpdate) { if (!gInitialized && !initGlobals()) return {}; time_key_t key, prevKey; std::unordered_map<uint32_t, concurrent_time_t> ret; @@ -379,7 +420,13 @@ std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsConcurrent std::vector<concurrent_val_t> vals(gNCpus); std::vector<uint64_t>::iterator activeBegin, activeEnd, policyBegin, policyEnd; + uint64_t newLastUpdate = lastUpdate ? *lastUpdate : 0; do { + if (lastUpdate) { + auto uidUpdated = uidUpdatedSince(key.uid, *lastUpdate, &newLastUpdate); + if (!uidUpdated.has_value()) return {}; + if (!*uidUpdated) continue; + } if (findMapEntry(gConcurrentMapFd, &key, vals.data())) return {}; if (ret.find(key.uid) == ret.end()) ret.emplace(key.uid, retFormat); @@ -405,8 +452,7 @@ std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsConcurrent std::plus<uint64_t>()); } } - prevKey = key; - } while (!getNextMapKey(gConcurrentMapFd, &prevKey, &key)); + } while (prevKey = key, !getNextMapKey(gConcurrentMapFd, &prevKey, &key)); if (errno != ENOENT) return {}; for (const auto &[key, value] : ret) { if (!verifyConcurrentTimes(value)) { @@ -414,6 +460,7 @@ std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsConcurrent if (val.has_value()) ret[key] = val.value(); } } + if (lastUpdate && newLastUpdate > *lastUpdate) *lastUpdate = newLastUpdate; return ret; } @@ -446,6 +493,8 @@ bool clearUidTimes(uint32_t uid) { return false; if (deleteMapEntry(gConcurrentMapFd, &key) && errno != ENOENT) return false; } + + if (deleteMapEntry(gUidLastUpdateMapFd, &uid) && errno != ENOENT) return false; return true; } diff --git a/libs/cputimeinstate/cputimeinstate.h b/libs/cputimeinstate/cputimeinstate.h index 49469d8e04..b7600f59e0 100644 --- a/libs/cputimeinstate/cputimeinstate.h +++ b/libs/cputimeinstate/cputimeinstate.h @@ -26,6 +26,8 @@ bool startTrackingUidTimes(); std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t uid); std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>> getUidsCpuFreqTimes(); +std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>> + getUidsUpdatedCpuFreqTimes(uint64_t *lastUpdate); std::optional<std::vector<std::vector<uint32_t>>> getCpuFreqs(); struct concurrent_time_t { @@ -35,6 +37,8 @@ struct concurrent_time_t { std::optional<concurrent_time_t> getUidConcurrentTimes(uint32_t uid, bool retry = true); std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsConcurrentTimes(); +std::optional<std::unordered_map<uint32_t, concurrent_time_t>> + getUidsUpdatedConcurrentTimes(uint64_t *lastUpdate); bool clearUidTimes(unsigned int uid); } // namespace bpf diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp index 23d87fd646..ea2a2008b7 100644 --- a/libs/cputimeinstate/testtimeinstate.cpp +++ b/libs/cputimeinstate/testtimeinstate.cpp @@ -115,71 +115,169 @@ TEST(TimeInStateTest, SingleUidTimesConsistent) { } TEST(TimeInStateTest, AllUidTimeInState) { - vector<size_t> sizes; - auto map = getUidsCpuFreqTimes(); - ASSERT_TRUE(map.has_value()); + uint64_t zero = 0; + auto maps = {getUidsCpuFreqTimes(), getUidsUpdatedCpuFreqTimes(&zero)}; + for (const auto &map : maps) { + ASSERT_TRUE(map.has_value()); - ASSERT_FALSE(map->empty()); + ASSERT_FALSE(map->empty()); - auto firstEntry = map->begin()->second; - for (const auto &subEntry : firstEntry) sizes.emplace_back(subEntry.size()); + vector<size_t> sizes; + auto firstEntry = map->begin()->second; + for (const auto &subEntry : firstEntry) sizes.emplace_back(subEntry.size()); - for (const auto &vec : *map) { - ASSERT_EQ(vec.second.size(), sizes.size()); - for (size_t i = 0; i < vec.second.size(); ++i) ASSERT_EQ(vec.second[i].size(), sizes[i]); + for (const auto &vec : *map) { + ASSERT_EQ(vec.second.size(), sizes.size()); + for (size_t i = 0; i < vec.second.size(); ++i) ASSERT_EQ(vec.second[i].size(), sizes[i]); + } } } -TEST(TimeInStateTest, SingleAndAllUidTimeInStateConsistent) { - auto map = getUidsCpuFreqTimes(); - ASSERT_TRUE(map.has_value()); - ASSERT_FALSE(map->empty()); +void TestCheckUpdate(const std::vector<std::vector<uint64_t>> &before, + const std::vector<std::vector<uint64_t>> &after) { + ASSERT_EQ(before.size(), after.size()); + uint64_t sumBefore = 0, sumAfter = 0; + for (size_t i = 0; i < before.size(); ++i) { + ASSERT_EQ(before[i].size(), after[i].size()); + for (size_t j = 0; j < before[i].size(); ++j) { + // Times should never decrease + ASSERT_LE(before[i][j], after[i][j]); + } + sumBefore += std::accumulate(before[i].begin(), before[i].end(), (uint64_t)0); + sumAfter += std::accumulate(after[i].begin(), after[i].end(), (uint64_t)0); + } + ASSERT_LE(sumBefore, sumAfter); + ASSERT_LE(sumAfter - sumBefore, NSEC_PER_SEC); +} - for (const auto &kv : *map) { - uint32_t uid = kv.first; - auto times1 = kv.second; - auto times2 = getUidCpuFreqTimes(uid); - ASSERT_TRUE(times2.has_value()); - - ASSERT_EQ(times1.size(), times2->size()); - for (uint32_t i = 0; i < times1.size(); ++i) { - ASSERT_EQ(times1[i].size(), (*times2)[i].size()); - for (uint32_t j = 0; j < times1[i].size(); ++j) { - ASSERT_LE((*times2)[i][j] - times1[i][j], NSEC_PER_SEC); +TEST(TimeInStateTest, AllUidUpdatedTimeInState) { + uint64_t lastUpdate = 0; + auto map1 = getUidsUpdatedCpuFreqTimes(&lastUpdate); + ASSERT_TRUE(map1.has_value()); + ASSERT_FALSE(map1->empty()); + ASSERT_NE(lastUpdate, (uint64_t)0); + uint64_t oldLastUpdate = lastUpdate; + + // Sleep briefly to trigger a context switch, ensuring we see at least one update. + struct timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = 1000000; + nanosleep (&ts, NULL); + + auto map2 = getUidsUpdatedCpuFreqTimes(&lastUpdate); + ASSERT_TRUE(map2.has_value()); + ASSERT_FALSE(map2->empty()); + ASSERT_NE(lastUpdate, oldLastUpdate); + + bool someUidsExcluded = false; + for (const auto &[uid, v] : *map1) { + if (map2->find(uid) == map2->end()) { + someUidsExcluded = true; + break; + } + } + ASSERT_TRUE(someUidsExcluded); + + for (const auto &[uid, newTimes] : *map2) { + ASSERT_NE(map1->find(uid), map1->end()); + ASSERT_NO_FATAL_FAILURE(TestCheckUpdate((*map1)[uid], newTimes)); + } +} + +TEST(TimeInStateTest, SingleAndAllUidTimeInStateConsistent) { + uint64_t zero = 0; + auto maps = {getUidsCpuFreqTimes(), getUidsUpdatedCpuFreqTimes(&zero)}; + for (const auto &map : maps) { + ASSERT_TRUE(map.has_value()); + ASSERT_FALSE(map->empty()); + + for (const auto &kv : *map) { + uint32_t uid = kv.first; + auto times1 = kv.second; + auto times2 = getUidCpuFreqTimes(uid); + ASSERT_TRUE(times2.has_value()); + + ASSERT_EQ(times1.size(), times2->size()); + for (uint32_t i = 0; i < times1.size(); ++i) { + ASSERT_EQ(times1[i].size(), (*times2)[i].size()); + for (uint32_t j = 0; j < times1[i].size(); ++j) { + ASSERT_LE((*times2)[i][j] - times1[i][j], NSEC_PER_SEC); + } } } } } TEST(TimeInStateTest, AllUidConcurrentTimes) { - auto map = getUidsConcurrentTimes(); - ASSERT_TRUE(map.has_value()); - ASSERT_FALSE(map->empty()); - - auto firstEntry = map->begin()->second; - for (const auto &kv : *map) { - ASSERT_EQ(kv.second.active.size(), firstEntry.active.size()); - ASSERT_EQ(kv.second.policy.size(), firstEntry.policy.size()); - for (size_t i = 0; i < kv.second.policy.size(); ++i) { - ASSERT_EQ(kv.second.policy[i].size(), firstEntry.policy[i].size()); + uint64_t zero = 0; + auto maps = {getUidsConcurrentTimes(), getUidsUpdatedConcurrentTimes(&zero)}; + for (const auto &map : maps) { + ASSERT_TRUE(map.has_value()); + ASSERT_FALSE(map->empty()); + + auto firstEntry = map->begin()->second; + for (const auto &kv : *map) { + ASSERT_EQ(kv.second.active.size(), firstEntry.active.size()); + ASSERT_EQ(kv.second.policy.size(), firstEntry.policy.size()); + for (size_t i = 0; i < kv.second.policy.size(); ++i) { + ASSERT_EQ(kv.second.policy[i].size(), firstEntry.policy[i].size()); + } } } } -TEST(TimeInStateTest, SingleAndAllUidConcurrentTimesConsistent) { - auto map = getUidsConcurrentTimes(); - ASSERT_TRUE(map.has_value()); - for (const auto &kv : *map) { - uint32_t uid = kv.first; - auto times1 = kv.second; - auto times2 = getUidConcurrentTimes(uid); - ASSERT_TRUE(times2.has_value()); - for (uint32_t i = 0; i < times1.active.size(); ++i) { - ASSERT_LE(times2->active[i] - times1.active[i], NSEC_PER_SEC); +TEST(TimeInStateTest, AllUidUpdatedConcurrentTimes) { + uint64_t lastUpdate = 0; + auto map1 = getUidsUpdatedConcurrentTimes(&lastUpdate); + ASSERT_TRUE(map1.has_value()); + ASSERT_FALSE(map1->empty()); + ASSERT_NE(lastUpdate, (uint64_t)0); + + // Sleep briefly to trigger a context switch, ensuring we see at least one update. + struct timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = 1000000; + nanosleep (&ts, NULL); + + uint64_t oldLastUpdate = lastUpdate; + auto map2 = getUidsUpdatedConcurrentTimes(&lastUpdate); + ASSERT_TRUE(map2.has_value()); + ASSERT_FALSE(map2->empty()); + ASSERT_NE(lastUpdate, oldLastUpdate); + + bool someUidsExcluded = false; + for (const auto &[uid, v] : *map1) { + if (map2->find(uid) == map2->end()) { + someUidsExcluded = true; + break; } - for (uint32_t i = 0; i < times1.policy.size(); ++i) { - for (uint32_t j = 0; j < times1.policy[i].size(); ++j) { - ASSERT_LE(times2->policy[i][j] - times1.policy[i][j], NSEC_PER_SEC); + } + ASSERT_TRUE(someUidsExcluded); + + for (const auto &[uid, newTimes] : *map2) { + ASSERT_NE(map1->find(uid), map1->end()); + ASSERT_NO_FATAL_FAILURE(TestCheckUpdate({(*map1)[uid].active},{newTimes.active})); + ASSERT_NO_FATAL_FAILURE(TestCheckUpdate((*map1)[uid].policy, newTimes.policy)); + } +} + +TEST(TimeInStateTest, SingleAndAllUidConcurrentTimesConsistent) { + uint64_t zero = 0; + auto maps = {getUidsConcurrentTimes(), getUidsUpdatedConcurrentTimes(&zero)}; + for (const auto &map : maps) { + ASSERT_TRUE(map.has_value()); + for (const auto &kv : *map) { + uint32_t uid = kv.first; + auto times1 = kv.second; + auto times2 = getUidConcurrentTimes(uid); + ASSERT_TRUE(times2.has_value()); + for (uint32_t i = 0; i < times1.active.size(); ++i) { + ASSERT_LE(times2->active[i] - times1.active[i], NSEC_PER_SEC); + } + for (uint32_t i = 0; i < times1.policy.size(); ++i) { + for (uint32_t j = 0; j < times1.policy[i].size(); ++j) { + ASSERT_LE(times2->policy[i][j] - times1.policy[i][j], NSEC_PER_SEC); + } } } } @@ -242,45 +340,51 @@ TEST(TimeInStateTest, AllUidConcurrentTimesMonotonic) { } TEST(TimeInStateTest, AllUidTimeInStateSanityCheck) { - auto map = getUidsCpuFreqTimes(); - ASSERT_TRUE(map.has_value()); - - bool foundLargeValue = false; - for (const auto &kv : *map) { - for (const auto &timeVec : kv.second) { - for (const auto &time : timeVec) { - ASSERT_LE(time, NSEC_PER_YEAR); - if (time > UINT32_MAX) foundLargeValue = true; + uint64_t zero = 0; + auto maps = {getUidsCpuFreqTimes(), getUidsUpdatedCpuFreqTimes(&zero)}; + for (const auto &map : maps) { + ASSERT_TRUE(map.has_value()); + + bool foundLargeValue = false; + for (const auto &kv : *map) { + for (const auto &timeVec : kv.second) { + for (const auto &time : timeVec) { + ASSERT_LE(time, NSEC_PER_YEAR); + if (time > UINT32_MAX) foundLargeValue = true; + } } } + // UINT32_MAX nanoseconds is less than 5 seconds, so if every part of our pipeline is using + // uint64_t as expected, we should have some times higher than that. + ASSERT_TRUE(foundLargeValue); } - // UINT32_MAX nanoseconds is less than 5 seconds, so if every part of our pipeline is using - // uint64_t as expected, we should have some times higher than that. - ASSERT_TRUE(foundLargeValue); } TEST(TimeInStateTest, AllUidConcurrentTimesSanityCheck) { - auto concurrentMap = getUidsConcurrentTimes(); - ASSERT_TRUE(concurrentMap); - - bool activeFoundLargeValue = false; - bool policyFoundLargeValue = false; - for (const auto &kv : *concurrentMap) { - for (const auto &time : kv.second.active) { - ASSERT_LE(time, NSEC_PER_YEAR); - if (time > UINT32_MAX) activeFoundLargeValue = true; - } - for (const auto &policyTimeVec : kv.second.policy) { - for (const auto &time : policyTimeVec) { + uint64_t zero = 0; + auto maps = {getUidsConcurrentTimes(), getUidsUpdatedConcurrentTimes(&zero)}; + for (const auto &concurrentMap : maps) { + ASSERT_TRUE(concurrentMap); + + bool activeFoundLargeValue = false; + bool policyFoundLargeValue = false; + for (const auto &kv : *concurrentMap) { + for (const auto &time : kv.second.active) { ASSERT_LE(time, NSEC_PER_YEAR); - if (time > UINT32_MAX) policyFoundLargeValue = true; + if (time > UINT32_MAX) activeFoundLargeValue = true; + } + for (const auto &policyTimeVec : kv.second.policy) { + for (const auto &time : policyTimeVec) { + ASSERT_LE(time, NSEC_PER_YEAR); + if (time > UINT32_MAX) policyFoundLargeValue = true; + } } } + // UINT32_MAX nanoseconds is less than 5 seconds, so if every part of our pipeline is using + // uint64_t as expected, we should have some times higher than that. + ASSERT_TRUE(activeFoundLargeValue); + ASSERT_TRUE(policyFoundLargeValue); } - // UINT32_MAX nanoseconds is less than 5 seconds, so if every part of our pipeline is using - // uint64_t as expected, we should have some times higher than that. - ASSERT_TRUE(activeFoundLargeValue); - ASSERT_TRUE(policyFoundLargeValue); } TEST(TimeInStateTest, AllUidTimesConsistent) { diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h index 2b65d2f42d..6366529a10 100644 --- a/libs/gui/include/gui/ISurfaceComposerClient.h +++ b/libs/gui/include/gui/ISurfaceComposerClient.h @@ -44,7 +44,7 @@ public: eCursorWindow = 0x00002000, eFXSurfaceBufferQueue = 0x00000000, - eFXSurfaceColor = 0x00020000, + eFXSurfaceEffect = 0x00020000, eFXSurfaceBufferState = 0x00040000, eFXSurfaceContainer = 0x00080000, eFXSurfaceMask = 0x000F0000, diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index e184c7f33b..a87ccd664e 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -403,7 +403,7 @@ TEST_F(BLASTBufferQueueTest, SetCrop_ScalingModeScaleCrop) { int32_t finalCropSideLength = bufferSideLength / 2; auto bg = mClient->createSurface(String8("BGTest"), 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor); + ISurfaceComposerClient::eFXSurfaceEffect); ASSERT_NE(nullptr, bg.get()); Transaction t; t.setLayerStack(bg, 0) diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index 1a623e21dc..c59afba87c 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -82,7 +82,8 @@ public: int width, int height) { sp<SurfaceControl> surfaceControl = scc->createSurface(String8("Test Surface"), 0 /* bufHeight */, 0 /* bufWidth */, - PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor); + PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceEffect); return std::make_unique<InputSurface>(surfaceControl, width, height); } diff --git a/libs/gui/tests/RegionSampling_test.cpp b/libs/gui/tests/RegionSampling_test.cpp index c9de37d957..dbd4ef9d7e 100644 --- a/libs/gui/tests/RegionSampling_test.cpp +++ b/libs/gui/tests/RegionSampling_test.cpp @@ -183,7 +183,7 @@ protected: mBackgroundLayer = mSurfaceComposerClient->createSurface(String8("Background RegionSamplingTest"), 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor); + ISurfaceComposerClient::eFXSurfaceEffect); uint32_t layerPositionBottom = 0x7E000000; SurfaceComposerClient::Transaction{} .setLayer(mBackgroundLayer, layerPositionBottom) diff --git a/libs/gui/tests/SamplingDemo.cpp b/libs/gui/tests/SamplingDemo.cpp index 9891587fe2..5c1bebb960 100644 --- a/libs/gui/tests/SamplingDemo.cpp +++ b/libs/gui/tests/SamplingDemo.cpp @@ -39,7 +39,7 @@ public: sp<SurfaceComposerClient> client = new SurfaceComposerClient; mButton = client->createSurface(String8(name), 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor); + ISurfaceComposerClient::eFXSurfaceEffect); const int32_t width = samplingArea.getWidth(); const int32_t height = samplingArea.getHeight(); @@ -55,7 +55,7 @@ public: .apply(); mButtonBlend = client->createSurface(String8(name) + "Blend", 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor); + ISurfaceComposerClient::eFXSurfaceEffect); SurfaceComposerClient::Transaction{} .setLayer(mButtonBlend, 0x7ffffffe) @@ -73,7 +73,7 @@ public: if (HIGHLIGHT_SAMPLING_AREA) { mSamplingArea = client->createSurface(String8("SamplingArea"), 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor); + ISurfaceComposerClient::eFXSurfaceEffect); SurfaceComposerClient::Transaction{} .setLayer(mSamplingArea, 0x7ffffffd) diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 85b0fd0ec7..2a73dc0149 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -57,6 +57,30 @@ const char* inputEventTypeToString(int32_t type) { return "UNKNOWN"; } +VerifiedKeyEvent verifiedKeyEventFromKeyEvent(const KeyEvent& event) { + return {{VerifiedInputEvent::Type::KEY, event.getDeviceId(), event.getEventTime(), + event.getSource(), event.getDisplayId()}, + event.getAction(), + event.getDownTime(), + event.getFlags() & VERIFIED_KEY_EVENT_FLAGS, + event.getKeyCode(), + event.getScanCode(), + event.getMetaState(), + event.getRepeatCount()}; +} + +VerifiedMotionEvent verifiedMotionEventFromMotionEvent(const MotionEvent& event) { + return {{VerifiedInputEvent::Type::MOTION, event.getDeviceId(), event.getEventTime(), + event.getSource(), event.getDisplayId()}, + event.getRawX(0), + event.getRawY(0), + event.getActionMasked(), + event.getDownTime(), + event.getFlags() & VERIFIED_MOTION_EVENT_FLAGS, + event.getMetaState(), + event.getButtonState()}; +} + void InputEvent::initialize(int32_t deviceId, uint32_t source, int32_t displayId, std::array<uint8_t, 32> hmac) { mDeviceId = deviceId; diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp index c1c35e1b89..fb21d5e3b1 100644 --- a/libs/input/tests/Android.bp +++ b/libs/input/tests/Android.bp @@ -10,12 +10,12 @@ cc_test { "LatencyStatistics_test.cpp", "TouchVideoFrame_test.cpp", "VelocityTracker_test.cpp", + "VerifiedInputEvent_test.cpp", ], cflags: [ "-Wall", "-Wextra", "-Werror", - "-Wno-unused-variable", ], shared_libs: [ "libinput", diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp index dce1f29124..d0f761887a 100644 --- a/libs/input/tests/InputEvent_test.cpp +++ b/libs/input/tests/InputEvent_test.cpp @@ -46,7 +46,6 @@ TEST_F(PointerCoordsTest, ClearSetsBitsToZero) { } TEST_F(PointerCoordsTest, AxisValues) { - float* valuePtr; PointerCoords coords; coords.clear(); diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp index d4bbf6c6ac..885196f3f3 100644 --- a/libs/input/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp @@ -38,6 +38,7 @@ protected: virtual void SetUp() { status_t result = InputChannel::openInputChannelPair("channel name", serverChannel, clientChannel); + ASSERT_EQ(OK, result); mPublisher = new InputPublisher(serverChannel); mConsumer = new InputConsumer(clientChannel); diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp index aa8a2d488f..dd127fcabd 100644 --- a/libs/input/tests/StructLayout_test.cpp +++ b/libs/input/tests/StructLayout_test.cpp @@ -98,4 +98,34 @@ void TestBodySize() { static_assert(sizeof(InputMessage::Body::Focus) == 8); } +// --- VerifiedInputEvent --- +// Ensure that VerifiedInputEvent, VerifiedKeyEvent, VerifiedMotionEvent are packed. +// We will treat them as byte collections when signing them. There should not be any uninitialized +// data in-between fields. Otherwise, the padded data will affect the hmac value and verifications +// will fail. + +void TestVerifiedEventSize() { + // VerifiedInputEvent + constexpr size_t VERIFIED_INPUT_EVENT_SIZE = sizeof(VerifiedInputEvent::type) + + sizeof(VerifiedInputEvent::deviceId) + sizeof(VerifiedInputEvent::eventTimeNanos) + + sizeof(VerifiedInputEvent::source) + sizeof(VerifiedInputEvent::displayId); + static_assert(sizeof(VerifiedInputEvent) == VERIFIED_INPUT_EVENT_SIZE); + + // VerifiedKeyEvent + constexpr size_t VERIFIED_KEY_EVENT_SIZE = VERIFIED_INPUT_EVENT_SIZE + + sizeof(VerifiedKeyEvent::action) + sizeof(VerifiedKeyEvent::downTimeNanos) + + sizeof(VerifiedKeyEvent::flags) + sizeof(VerifiedKeyEvent::keyCode) + + sizeof(VerifiedKeyEvent::scanCode) + sizeof(VerifiedKeyEvent::metaState) + + sizeof(VerifiedKeyEvent::repeatCount); + static_assert(sizeof(VerifiedKeyEvent) == VERIFIED_KEY_EVENT_SIZE); + + // VerifiedMotionEvent + constexpr size_t VERIFIED_MOTION_EVENT_SIZE = VERIFIED_INPUT_EVENT_SIZE + + sizeof(VerifiedMotionEvent::rawX) + sizeof(VerifiedMotionEvent::rawY) + + sizeof(VerifiedMotionEvent::actionMasked) + sizeof(VerifiedMotionEvent::downTimeNanos) + + sizeof(VerifiedMotionEvent::flags) + sizeof(VerifiedMotionEvent::metaState) + + sizeof(VerifiedMotionEvent::buttonState); + static_assert(sizeof(VerifiedMotionEvent) == VERIFIED_MOTION_EVENT_SIZE); +} + } // namespace android diff --git a/libs/input/tests/VerifiedInputEvent_test.cpp b/libs/input/tests/VerifiedInputEvent_test.cpp new file mode 100644 index 0000000000..a59dbe5987 --- /dev/null +++ b/libs/input/tests/VerifiedInputEvent_test.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <gtest/gtest.h> +#include <input/Input.h> + +namespace android { + +static KeyEvent getKeyEventWithFlags(int32_t flags) { + KeyEvent event; + event.initialize(2 /*deviceId*/, AINPUT_SOURCE_GAMEPAD, ADISPLAY_ID_DEFAULT, INVALID_HMAC, + AKEY_EVENT_ACTION_DOWN, flags, AKEYCODE_BUTTON_X, 121 /*scanCode*/, + AMETA_ALT_ON, 1 /*repeatCount*/, 1000 /*downTime*/, 2000 /*eventTime*/); + return event; +} + +static MotionEvent getMotionEventWithFlags(int32_t flags) { + MotionEvent event; + constexpr size_t pointerCount = 1; + PointerProperties pointerProperties[pointerCount]; + PointerCoords pointerCoords[pointerCount]; + for (size_t i = 0; i < pointerCount; i++) { + pointerProperties[i].clear(); + pointerProperties[i].id = i; + pointerCoords[i].clear(); + } + + event.initialize(0 /*deviceId*/, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_DEFAULT, INVALID_HMAC, + AMOTION_EVENT_ACTION_DOWN, 0 /*actionButton*/, flags, + AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/, + MotionClassification::NONE, 2 /*xScale*/, 3 /*yScale*/, 4 /*xOffset*/, + 5 /*yOffset*/, 0.1 /*xPrecision*/, 0.2 /*yPrecision*/, 280 /*xCursorPosition*/, + 540 /*yCursorPosition*/, 100 /*downTime*/, 200 /*eventTime*/, pointerCount, + pointerProperties, pointerCoords); + return event; +} + +TEST(VerifiedKeyEventTest, ConvertKeyEventToVerifiedKeyEvent) { + KeyEvent event = getKeyEventWithFlags(0); + VerifiedKeyEvent verified = verifiedKeyEventFromKeyEvent(event); + + ASSERT_EQ(VerifiedInputEvent::Type::KEY, verified.type); + + ASSERT_EQ(event.getDeviceId(), verified.deviceId); + ASSERT_EQ(event.getEventTime(), verified.eventTimeNanos); + ASSERT_EQ(event.getSource(), verified.source); + ASSERT_EQ(event.getDisplayId(), verified.displayId); + + ASSERT_EQ(event.getAction(), verified.action); + ASSERT_EQ(event.getDownTime(), verified.downTimeNanos); + ASSERT_EQ(event.getFlags() & VERIFIED_KEY_EVENT_FLAGS, verified.flags); + ASSERT_EQ(event.getKeyCode(), verified.keyCode); + ASSERT_EQ(event.getScanCode(), verified.scanCode); + ASSERT_EQ(event.getMetaState(), verified.metaState); + ASSERT_EQ(event.getRepeatCount(), verified.repeatCount); +} + +TEST(VerifiedKeyEventTest, VerifiedKeyEventContainsOnlyVerifiedFlags) { + KeyEvent event = getKeyEventWithFlags(AKEY_EVENT_FLAG_CANCELED | AKEY_EVENT_FLAG_FALLBACK); + VerifiedKeyEvent verified = verifiedKeyEventFromKeyEvent(event); + ASSERT_EQ(AKEY_EVENT_FLAG_CANCELED, verified.flags); +} + +TEST(VerifiedKeyEventTest, VerifiedKeyEventDoesNotContainUnverifiedFlags) { + KeyEvent event = getKeyEventWithFlags(AKEY_EVENT_FLAG_EDITOR_ACTION); + VerifiedKeyEvent verified = verifiedKeyEventFromKeyEvent(event); + ASSERT_EQ(0, verified.flags); +} + +TEST(VerifiedMotionEventTest, ConvertMotionEventToVerifiedMotionEvent) { + MotionEvent event = getMotionEventWithFlags(0); + VerifiedMotionEvent verified = verifiedMotionEventFromMotionEvent(event); + + ASSERT_EQ(VerifiedInputEvent::Type::MOTION, verified.type); + + ASSERT_EQ(event.getDeviceId(), verified.deviceId); + ASSERT_EQ(event.getEventTime(), verified.eventTimeNanos); + ASSERT_EQ(event.getSource(), verified.source); + ASSERT_EQ(event.getDisplayId(), verified.displayId); + + ASSERT_EQ(event.getRawX(0), verified.rawX); + ASSERT_EQ(event.getRawY(0), verified.rawY); + ASSERT_EQ(event.getAction(), verified.actionMasked); + ASSERT_EQ(event.getDownTime(), verified.downTimeNanos); + ASSERT_EQ(event.getFlags() & VERIFIED_MOTION_EVENT_FLAGS, verified.flags); + ASSERT_EQ(event.getMetaState(), verified.metaState); + ASSERT_EQ(event.getButtonState(), verified.buttonState); +} + +TEST(VerifiedMotionEventTest, VerifiedMotionEventContainsOnlyVerifiedFlags) { + MotionEvent event = getMotionEventWithFlags(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | + AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE); + VerifiedMotionEvent verified = verifiedMotionEventFromMotionEvent(event); + ASSERT_EQ(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, verified.flags); +} + +TEST(VerifiedMotionEventTest, VerifiedMotionEventDoesNotContainUnverifiedFlags) { + MotionEvent event = getMotionEventWithFlags(AMOTION_EVENT_FLAG_TAINTED); + VerifiedMotionEvent verified = verifiedMotionEventFromMotionEvent(event); + ASSERT_EQ(0, verified.flags); +} + +} // namespace android diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index 308e93aa48..5c80d551b8 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -40,6 +40,7 @@ cc_library_shared { "libinputreporter", "libinputreader", "libbinder", + "libcrypto", "libcutils", "libhidlbase", "libinput", diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp index a556aad553..3f956a88fb 100644 --- a/services/inputflinger/dispatcher/Android.bp +++ b/services/inputflinger/dispatcher/Android.bp @@ -28,6 +28,7 @@ cc_library_static { ], shared_libs: [ "libbase", + "libcrypto", "libcutils", "libinput", "libinputreporter", diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index f2b95e7f7a..75bc0aa7c8 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -60,7 +60,10 @@ static constexpr bool DEBUG_FOCUS = false; #include <android-base/chrono_utils.h> #include <android-base/stringprintf.h> #include <binder/Binder.h> +#include <input/InputDevice.h> #include <log/log.h> +#include <openssl/hmac.h> +#include <openssl/rand.h> #include <powermanager/PowerManager.h> #include <utils/Trace.h> @@ -325,6 +328,55 @@ static std::unique_ptr<DispatchEntry> createDispatchEntry(const InputTarget& inp return dispatchEntry; } +static std::array<uint8_t, 128> getRandomKey() { + std::array<uint8_t, 128> key; + if (RAND_bytes(key.data(), key.size()) != 1) { + LOG_ALWAYS_FATAL("Can't generate HMAC key"); + } + return key; +} + +// --- HmacKeyManager --- + +HmacKeyManager::HmacKeyManager() : mHmacKey(getRandomKey()) {} + +std::array<uint8_t, 32> HmacKeyManager::sign(const VerifiedInputEvent& event) const { + size_t size; + switch (event.type) { + case VerifiedInputEvent::Type::KEY: { + size = sizeof(VerifiedKeyEvent); + break; + } + case VerifiedInputEvent::Type::MOTION: { + size = sizeof(VerifiedMotionEvent); + break; + } + } + std::vector<uint8_t> data; + const uint8_t* start = reinterpret_cast<const uint8_t*>(&event); + data.assign(start, start + size); + return sign(data); +} + +std::array<uint8_t, 32> HmacKeyManager::sign(const std::vector<uint8_t>& data) const { + // SHA256 always generates 32-bytes result + std::array<uint8_t, 32> hash; + unsigned int hashLen = 0; + uint8_t* result = HMAC(EVP_sha256(), mHmacKey.data(), mHmacKey.size(), data.data(), data.size(), + hash.data(), &hashLen); + if (result == nullptr) { + ALOGE("Could not sign the data using HMAC"); + return INVALID_HMAC; + } + + if (hashLen != hash.size()) { + ALOGE("HMAC-SHA256 has unexpected length"); + return INVALID_HMAC; + } + + return hash; +} + // --- InputDispatcher --- InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) @@ -3153,22 +3205,22 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injec std::queue<EventEntry*> injectedEntries; switch (event->getType()) { case AINPUT_EVENT_TYPE_KEY: { - KeyEvent keyEvent; - keyEvent.initialize(*static_cast<const KeyEvent*>(event)); - int32_t action = keyEvent.getAction(); + const KeyEvent& incomingKey = static_cast<const KeyEvent&>(*event); + int32_t action = incomingKey.getAction(); if (!validateKeyEvent(action)) { return INPUT_EVENT_INJECTION_FAILED; } - int32_t flags = keyEvent.getFlags(); - int32_t keyCode = keyEvent.getKeyCode(); - int32_t metaState = keyEvent.getMetaState(); - accelerateMetaShortcuts(keyEvent.getDeviceId(), action, + int32_t flags = incomingKey.getFlags(); + int32_t keyCode = incomingKey.getKeyCode(); + int32_t metaState = incomingKey.getMetaState(); + accelerateMetaShortcuts(VIRTUAL_KEYBOARD_ID, action, /*byref*/ keyCode, /*byref*/ metaState); - keyEvent.initialize(keyEvent.getDeviceId(), keyEvent.getSource(), - keyEvent.getDisplayId(), INVALID_HMAC, action, flags, keyCode, - keyEvent.getScanCode(), metaState, keyEvent.getRepeatCount(), - keyEvent.getDownTime(), keyEvent.getEventTime()); + KeyEvent keyEvent; + keyEvent.initialize(VIRTUAL_KEYBOARD_ID, incomingKey.getSource(), + incomingKey.getDisplayId(), INVALID_HMAC, action, flags, keyCode, + incomingKey.getScanCode(), metaState, incomingKey.getRepeatCount(), + incomingKey.getDownTime(), incomingKey.getEventTime()); if (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY) { policyFlags |= POLICY_FLAG_VIRTUAL; @@ -3186,11 +3238,10 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injec mLock.lock(); KeyEntry* injectedEntry = new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, keyEvent.getEventTime(), - keyEvent.getDeviceId(), keyEvent.getSource(), - keyEvent.getDisplayId(), policyFlags, action, flags, - keyEvent.getKeyCode(), keyEvent.getScanCode(), - keyEvent.getMetaState(), keyEvent.getRepeatCount(), - keyEvent.getDownTime()); + VIRTUAL_KEYBOARD_ID, keyEvent.getSource(), keyEvent.getDisplayId(), + policyFlags, action, flags, keyEvent.getKeyCode(), + keyEvent.getScanCode(), keyEvent.getMetaState(), + keyEvent.getRepeatCount(), keyEvent.getDownTime()); injectedEntries.push(injectedEntry); break; } @@ -3221,7 +3272,7 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injec const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords(); MotionEntry* injectedEntry = new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes, - motionEvent->getDeviceId(), motionEvent->getSource(), + VIRTUAL_KEYBOARD_ID, motionEvent->getSource(), motionEvent->getDisplayId(), policyFlags, action, actionButton, motionEvent->getFlags(), motionEvent->getMetaState(), motionEvent->getButtonState(), motionEvent->getClassification(), @@ -3238,7 +3289,7 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injec samplePointerCoords += pointerCount; MotionEntry* nextInjectedEntry = new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes, - motionEvent->getDeviceId(), motionEvent->getSource(), + VIRTUAL_KEYBOARD_ID, motionEvent->getSource(), motionEvent->getDisplayId(), policyFlags, action, actionButton, motionEvent->getFlags(), motionEvent->getMetaState(), motionEvent->getButtonState(), @@ -3340,6 +3391,10 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injec return injectionResult; } +std::unique_ptr<VerifiedInputEvent> InputDispatcher::verifyInputEvent(const InputEvent& event) { + return nullptr; +} + bool InputDispatcher::hasInjectionPermission(int32_t injectorPid, int32_t injectorUid) { return injectorUid == 0 || mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid); diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index d2aea80069..ded59a595c 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -56,6 +56,16 @@ namespace android::inputdispatcher { class Connection; +class HmacKeyManager { +public: + HmacKeyManager(); + std::array<uint8_t, 32> sign(const VerifiedInputEvent& event) const; + +private: + std::array<uint8_t, 32> sign(const std::vector<uint8_t>& data) const; + const std::array<uint8_t, 128> mHmacKey; +}; + /* Dispatches events to input targets. Some functions of the input dispatcher, such as * identifying input targets, are controlled by a separate policy object. * @@ -96,6 +106,8 @@ public: int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, uint32_t policyFlags) override; + virtual std::unique_ptr<VerifiedInputEvent> verifyInputEvent(const InputEvent& event) override; + virtual void setInputWindows( const std::vector<sp<InputWindowHandle>>& inputWindowHandles, int32_t displayId, const sp<ISetInputWindowsListener>& setInputWindowsListener = nullptr) override; diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h index 3424f4ce84..6e986768fc 100644 --- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h +++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h @@ -92,6 +92,13 @@ public: int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, uint32_t policyFlags) = 0; + /* + * Check whether InputEvent actually happened by checking the signature of the event. + * + * Return nullptr if the event cannot be verified. + */ + virtual std::unique_ptr<VerifiedInputEvent> verifyInputEvent(const InputEvent& event) = 0; + /* Sets the list of input windows. * * This method may be called on any thread (usually by the input manager). diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp index 09ecb13b0a..f913d826bc 100644 --- a/services/inputflinger/tests/Android.bp +++ b/services/inputflinger/tests/Android.bp @@ -10,6 +10,7 @@ cc_test { "InputClassifierConverter_test.cpp", "InputDispatcher_test.cpp", "InputReader_test.cpp", + "UinputDevice.cpp", ], cflags: [ "-Wall", diff --git a/services/inputflinger/tests/EventHub_test.cpp b/services/inputflinger/tests/EventHub_test.cpp index 6504738fc7..be2e19e7df 100644 --- a/services/inputflinger/tests/EventHub_test.cpp +++ b/services/inputflinger/tests/EventHub_test.cpp @@ -16,7 +16,8 @@ #include "EventHub.h" -#include <android-base/stringprintf.h> +#include "UinputDevice.h" + #include <gtest/gtest.h> #include <inttypes.h> #include <linux/uinput.h> @@ -25,16 +26,16 @@ #define TAG "EventHub_test" +using android::createUinputDevice; using android::EventHub; using android::EventHubInterface; using android::InputDeviceIdentifier; using android::RawEvent; using android::sp; -using android::base::StringPrintf; +using android::UinputHomeKey; using std::chrono_literals::operator""ms; static constexpr bool DEBUG = false; -static const char* DEVICE_NAME = "EventHub Test Device"; static void dumpEvents(const std::vector<RawEvent>& events) { for (const RawEvent& event : events) { @@ -62,27 +63,26 @@ class EventHubTest : public testing::Test { protected: std::unique_ptr<EventHubInterface> mEventHub; // We are only going to emulate a single input device currently. - android::base::unique_fd mDeviceFd; + std::unique_ptr<UinputHomeKey> mKeyboard; int32_t mDeviceId; + virtual void SetUp() override { mEventHub = std::make_unique<EventHub>(); consumeInitialDeviceAddedEvents(); - createDevice(); + mKeyboard = createUinputDevice<UinputHomeKey>(); mDeviceId = waitForDeviceCreation(); } virtual void TearDown() override { - mDeviceFd.reset(); + mKeyboard.reset(); waitForDeviceClose(mDeviceId); } - void createDevice(); /** * Return the device id of the created device. */ int32_t waitForDeviceCreation(); void waitForDeviceClose(int32_t deviceId); void consumeInitialDeviceAddedEvents(); - void sendEvent(uint16_t type, uint16_t code, int32_t value); std::vector<RawEvent> getEvents(std::chrono::milliseconds timeout = 5ms); }; @@ -105,48 +105,6 @@ std::vector<RawEvent> EventHubTest::getEvents(std::chrono::milliseconds timeout) return events; } -void EventHubTest::createDevice() { - mDeviceFd = android::base::unique_fd(open("/dev/uinput", O_WRONLY | O_NONBLOCK)); - if (mDeviceFd < 0) { - FAIL() << "Can't open /dev/uinput :" << strerror(errno); - } - - /** - * Signal which type of events this input device supports. - * We will emulate a keyboard here. - */ - // enable key press/release event - if (ioctl(mDeviceFd, UI_SET_EVBIT, EV_KEY)) { - ADD_FAILURE() << "Error in ioctl : UI_SET_EVBIT : EV_KEY: " << strerror(errno); - } - - // enable set of KEY events - if (ioctl(mDeviceFd, UI_SET_KEYBIT, KEY_HOME)) { - ADD_FAILURE() << "Error in ioctl : UI_SET_KEYBIT : KEY_HOME: " << strerror(errno); - } - - // enable synchronization event - if (ioctl(mDeviceFd, UI_SET_EVBIT, EV_SYN)) { - ADD_FAILURE() << "Error in ioctl : UI_SET_EVBIT : EV_SYN: " << strerror(errno); - } - - struct uinput_user_dev keyboard = {}; - strlcpy(keyboard.name, DEVICE_NAME, UINPUT_MAX_NAME_SIZE); - keyboard.id.bustype = BUS_USB; - keyboard.id.vendor = 0x01; - keyboard.id.product = 0x01; - keyboard.id.version = 1; - - if (write(mDeviceFd, &keyboard, sizeof(keyboard)) < 0) { - FAIL() << "Could not write uinput_user_dev struct into uinput file descriptor: " - << strerror(errno); - } - - if (ioctl(mDeviceFd, UI_DEV_CREATE)) { - FAIL() << "Error in ioctl : UI_DEV_CREATE: " << strerror(errno); - } -} - /** * Since the test runs on a real platform, there will be existing devices * in addition to the test devices being added. Therefore, when EventHub is first created, @@ -176,7 +134,7 @@ int32_t EventHubTest::waitForDeviceCreation() { EXPECT_EQ(static_cast<int32_t>(EventHubInterface::DEVICE_ADDED), deviceAddedEvent.type); InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceAddedEvent.deviceId); const int32_t deviceId = deviceAddedEvent.deviceId; - EXPECT_EQ(identifier.name, DEVICE_NAME); + EXPECT_EQ(identifier.name, mKeyboard->getName()); const RawEvent& finishedDeviceScanEvent = events[1]; EXPECT_EQ(static_cast<int32_t>(EventHubInterface::FINISHED_DEVICE_SCAN), finishedDeviceScanEvent.type); @@ -194,22 +152,6 @@ void EventHubTest::waitForDeviceClose(int32_t deviceId) { finishedDeviceScanEvent.type); } -void EventHubTest::sendEvent(uint16_t type, uint16_t code, int32_t value) { - struct input_event event = {}; - event.type = type; - event.code = code; - event.value = value; - event.time = {}; // uinput ignores the timestamp - - if (write(mDeviceFd, &event, sizeof(input_event)) < 0) { - std::string msg = StringPrintf("Could not write event %" PRIu16 " %" PRIu16 - " with value %" PRId32 " : %s", - type, code, value, strerror(errno)); - ALOGE("%s", msg.c_str()); - ADD_FAILURE() << msg.c_str(); - } -} - /** * Ensure that input_events are generated with monotonic clock. * That means input_event should receive a timestamp that is in the future of the time @@ -218,13 +160,7 @@ void EventHubTest::sendEvent(uint16_t type, uint16_t code, int32_t value) { */ TEST_F(EventHubTest, InputEvent_TimestampIsMonotonic) { nsecs_t lastEventTime = systemTime(SYSTEM_TIME_MONOTONIC); - // key press - sendEvent(EV_KEY, KEY_HOME, 1); - sendEvent(EV_SYN, SYN_REPORT, 0); - - // key release - sendEvent(EV_KEY, KEY_HOME, 0); - sendEvent(EV_SYN, SYN_REPORT, 0); + ASSERT_NO_FATAL_FAILURE(mKeyboard->pressAndReleaseHomeKey()); std::vector<RawEvent> events = getEvents(); ASSERT_EQ(4U, events.size()) << "Expected to receive 2 keys and 2 syncs, total of 4 events"; diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 27db8f5534..c4092cd696 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -43,6 +43,18 @@ struct PointF { float y; }; +/** + * Return a DOWN key event with KEYCODE_A. + */ +static KeyEvent getTestKeyEvent() { + KeyEvent event; + + event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, INVALID_HMAC, + AKEY_EVENT_ACTION_DOWN, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, + ARBITRARY_TIME); + return event; +} + // --- FakeInputDispatcherPolicy --- class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface { @@ -197,6 +209,69 @@ private: } }; +// --- HmacKeyManagerTest --- + +class HmacKeyManagerTest : public testing::Test { +protected: + HmacKeyManager mHmacKeyManager; +}; + +/** + * Ensure that separate calls to sign the same data are generating the same key. + * We avoid asserting against INVALID_HMAC. Since the key is random, there is a non-zero chance + * that a specific key and data combination would produce INVALID_HMAC, which would cause flaky + * tests. + */ +TEST_F(HmacKeyManagerTest, GeneratedHmac_IsConsistent) { + KeyEvent event = getTestKeyEvent(); + VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event); + + std::array<uint8_t, 32> hmac1 = mHmacKeyManager.sign(verifiedEvent); + std::array<uint8_t, 32> hmac2 = mHmacKeyManager.sign(verifiedEvent); + ASSERT_EQ(hmac1, hmac2); +} + +/** + * Ensure that changes in VerifiedKeyEvent produce a different hmac. + */ +TEST_F(HmacKeyManagerTest, GeneratedHmac_ChangesWhenFieldsChange) { + KeyEvent event = getTestKeyEvent(); + VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event); + std::array<uint8_t, 32> initialHmac = mHmacKeyManager.sign(verifiedEvent); + + verifiedEvent.deviceId += 1; + ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent)); + + verifiedEvent.source += 1; + ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent)); + + verifiedEvent.eventTimeNanos += 1; + ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent)); + + verifiedEvent.displayId += 1; + ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent)); + + verifiedEvent.action += 1; + ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent)); + + verifiedEvent.downTimeNanos += 1; + ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent)); + + verifiedEvent.flags += 1; + ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent)); + + verifiedEvent.keyCode += 1; + ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent)); + + verifiedEvent.scanCode += 1; + ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent)); + + verifiedEvent.metaState += 1; + ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent)); + + verifiedEvent.repeatCount += 1; + ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent)); +} // --- InputDispatcherTest --- diff --git a/services/inputflinger/tests/UinputDevice.cpp b/services/inputflinger/tests/UinputDevice.cpp new file mode 100644 index 0000000000..2775d21ce2 --- /dev/null +++ b/services/inputflinger/tests/UinputDevice.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "UinputDevice.h" + +#include <android-base/stringprintf.h> + +namespace android { + +// --- UinputDevice --- + +UinputDevice::UinputDevice(const char* name) : mName(name) {} + +UinputDevice::~UinputDevice() { + if (ioctl(mDeviceFd, UI_DEV_DESTROY)) { + ALOGE("Error while destroying uinput device: %s", strerror(errno)); + } + mDeviceFd.reset(); +} + +void UinputDevice::init() { + mDeviceFd = android::base::unique_fd(open("/dev/uinput", O_WRONLY | O_NONBLOCK)); + if (mDeviceFd < 0) { + FAIL() << "Can't open /dev/uinput :" << strerror(errno); + } + + struct uinput_user_dev device = {}; + strlcpy(device.name, mName, UINPUT_MAX_NAME_SIZE); + device.id.bustype = BUS_USB; + device.id.vendor = 0x01; + device.id.product = 0x01; + device.id.version = 1; + + // Using EXPECT instead of ASSERT to allow the device creation to continue even when + // some failures are reported when configuring the device. + EXPECT_NO_FATAL_FAILURE(configureDevice(mDeviceFd, &device)); + + if (write(mDeviceFd, &device, sizeof(device)) < 0) { + FAIL() << "Could not write uinput_user_dev struct into uinput file descriptor: " + << strerror(errno); + } + + if (ioctl(mDeviceFd, UI_DEV_CREATE)) { + FAIL() << "Error in ioctl : UI_DEV_CREATE: " << strerror(errno); + } +} + +void UinputDevice::injectEvent(uint16_t type, uint16_t code, int32_t value) { + struct input_event event = {}; + event.type = type; + event.code = code; + event.value = value; + event.time = {}; // uinput ignores the timestamp + + if (write(mDeviceFd, &event, sizeof(input_event)) < 0) { + std::string msg = base::StringPrintf("Could not write event %" PRIu16 " %" PRIu16 + " with value %" PRId32 " : %s", + type, code, value, strerror(errno)); + ALOGE("%s", msg.c_str()); + ADD_FAILURE() << msg.c_str(); + } +} + +// --- UinputKeyboard --- + +UinputKeyboard::UinputKeyboard(std::initializer_list<int> keys) + : UinputDevice(UinputKeyboard::KEYBOARD_NAME), mKeys(keys.begin(), keys.end()) {} + +void UinputKeyboard::configureDevice(int fd, uinput_user_dev* device) { + // enable key press/release event + if (ioctl(fd, UI_SET_EVBIT, EV_KEY)) { + ADD_FAILURE() << "Error in ioctl : UI_SET_EVBIT : EV_KEY: " << strerror(errno); + } + + // enable set of KEY events + std::for_each(mKeys.begin(), mKeys.end(), [fd](int key) { + if (ioctl(fd, UI_SET_KEYBIT, key)) { + ADD_FAILURE() << "Error in ioctl : UI_SET_KEYBIT : " << key << " : " << strerror(errno); + } + }); + + // enable synchronization event + if (ioctl(fd, UI_SET_EVBIT, EV_SYN)) { + ADD_FAILURE() << "Error in ioctl : UI_SET_EVBIT : EV_SYN: " << strerror(errno); + } +} + +void UinputKeyboard::pressKey(int key) { + if (mKeys.find(key) == mKeys.end()) { + ADD_FAILURE() << mName << ": Cannot inject key press: Key not found: " << key; + } + EXPECT_NO_FATAL_FAILURE(injectEvent(EV_KEY, key, 1)); + EXPECT_NO_FATAL_FAILURE(injectEvent(EV_SYN, SYN_REPORT, 0)); +} + +void UinputKeyboard::releaseKey(int key) { + if (mKeys.find(key) == mKeys.end()) { + ADD_FAILURE() << mName << ": Cannot inject key release: Key not found: " << key; + } + EXPECT_NO_FATAL_FAILURE(injectEvent(EV_KEY, key, 0)); + EXPECT_NO_FATAL_FAILURE(injectEvent(EV_SYN, SYN_REPORT, 0)); +} + +void UinputKeyboard::pressAndReleaseKey(int key) { + EXPECT_NO_FATAL_FAILURE(pressKey(key)); + EXPECT_NO_FATAL_FAILURE(releaseKey(key)); +} + +// --- UinputHomeKey--- + +UinputHomeKey::UinputHomeKey() : UinputKeyboard({KEY_HOME}) {} + +void UinputHomeKey::pressAndReleaseHomeKey() { + EXPECT_NO_FATAL_FAILURE(pressAndReleaseKey(KEY_HOME)); +} + +} // namespace android diff --git a/services/inputflinger/tests/UinputDevice.h b/services/inputflinger/tests/UinputDevice.h new file mode 100644 index 0000000000..57d9011695 --- /dev/null +++ b/services/inputflinger/tests/UinputDevice.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _UI_TEST_INPUT_UINPUT_INJECTOR_H +#define _UI_TEST_INPUT_UINPUT_INJECTOR_H + +#include <android-base/unique_fd.h> +#include <gtest/gtest.h> +#include <inttypes.h> +#include <linux/uinput.h> +#include <log/log.h> + +#include <memory> + +namespace android { + +// This is the factory method that must be used to create a UinputDevice. +template <class D, class... Ts> +std::unique_ptr<D> createUinputDevice(Ts... args) { + // Using `new` to access non-public constructors. + std::unique_ptr<D> dev(new D(&args...)); + EXPECT_NO_FATAL_FAILURE(dev->init()); + return dev; +} + +// --- UinputDevice --- + +class UinputDevice { +public: + virtual ~UinputDevice(); + + inline const char* getName() const { return mName; } + + // Subclasses must either provide a public constructor or must be-friend the factory method. + template <class D, class... Ts> + friend std::unique_ptr<D> createUinputDevice(Ts... args); + +protected: + const char* mName; + + UinputDevice(const char* name); + + // Signals which types of events this device supports before it is created. + // This must be overridden by subclasses. + virtual void configureDevice(int fd, uinput_user_dev* device) = 0; + + void injectEvent(uint16_t type, uint16_t code, int32_t value); + +private: + base::unique_fd mDeviceFd; + + // This is called once by the factory method createUinputDevice(). + void init(); +}; + +// --- UinputKeyboard --- + +class UinputKeyboard : public UinputDevice { +public: + static constexpr const char* KEYBOARD_NAME = "Test Keyboard Device"; + + // Injects key press and sync. + void pressKey(int key); + // Injects key release and sync. + void releaseKey(int key); + // Injects 4 events: key press, sync, key release, and sync. + void pressAndReleaseKey(int key); + + template <class D, class... Ts> + friend std::unique_ptr<D> createUinputDevice(Ts... args); + +protected: + UinputKeyboard(std::initializer_list<int> keys = {}); + +private: + void configureDevice(int fd, uinput_user_dev* device) override; + + std::set<int> mKeys; +}; + +// --- UinputHomeKey--- + +// A keyboard device that has a single HOME key. +class UinputHomeKey : public UinputKeyboard { +public: + // Injects 4 events: key press, sync, key release, and sync. + void pressAndReleaseHomeKey(); + + template <class D, class... Ts> + friend std::unique_ptr<D> createUinputDevice(Ts... args); + +private: + UinputHomeKey(); +}; + +} // namespace android + +#endif // _UI_TEST_INPUT_UINPUT_INJECTOR_H diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 1b1e8890ab..4ffdf9761e 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -136,7 +136,7 @@ filegroup { "BufferStateLayer.cpp", "ClientCache.cpp", "Client.cpp", - "ColorLayer.cpp", + "EffectLayer.cpp", "ContainerLayer.cpp", "DisplayDevice.cpp", "DisplayHardware/ComposerHal.cpp", diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 371b80227b..1188dfeec2 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -32,7 +32,7 @@ #include <private/gui/SyncFeatures.h> #include <renderengine/Image.h> -#include "ColorLayer.h" +#include "EffectLayer.h" #include "FrameTracer/FrameTracer.h" #include "TimeStats/TimeStats.h" diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/EffectLayer.cpp index 83050c4774..e928c57929 100644 --- a/services/surfaceflinger/ColorLayer.cpp +++ b/services/surfaceflinger/EffectLayer.cpp @@ -20,9 +20,9 @@ // #define LOG_NDEBUG 0 #undef LOG_TAG -#define LOG_TAG "ColorLayer" +#define LOG_TAG "EffectLayer" -#include "ColorLayer.h" +#include "EffectLayer.h" #include <stdint.h> #include <stdlib.h> @@ -41,13 +41,13 @@ namespace android { // --------------------------------------------------------------------------- -ColorLayer::ColorLayer(const LayerCreationArgs& args) +EffectLayer::EffectLayer(const LayerCreationArgs& args) : Layer(args), mCompositionState{mFlinger->getCompositionEngine().createLayerFECompositionState()} {} -ColorLayer::~ColorLayer() = default; +EffectLayer::~EffectLayer() = default; -std::optional<compositionengine::LayerFE::LayerSettings> ColorLayer::prepareClientComposition( +std::optional<compositionengine::LayerFE::LayerSettings> EffectLayer::prepareClientComposition( compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) { auto result = Layer::prepareClientComposition(targetSettings); if (!result) { @@ -57,11 +57,11 @@ std::optional<compositionengine::LayerFE::LayerSettings> ColorLayer::prepareClie return result; } -bool ColorLayer::isVisible() const { +bool EffectLayer::isVisible() const { return !isHiddenByPolicy() && getAlpha() > 0.0_hf; } -bool ColorLayer::setColor(const half3& color) { +bool EffectLayer::setColor(const half3& color) { if (mCurrentState.color.r == color.r && mCurrentState.color.g == color.g && mCurrentState.color.b == color.b) { return false; @@ -76,7 +76,7 @@ bool ColorLayer::setColor(const half3& color) { return true; } -bool ColorLayer::setDataspace(ui::Dataspace dataspace) { +bool EffectLayer::setDataspace(ui::Dataspace dataspace) { if (mCurrentState.dataspace == dataspace) { return false; } @@ -88,7 +88,7 @@ bool ColorLayer::setDataspace(ui::Dataspace dataspace) { return true; } -void ColorLayer::preparePerFrameCompositionState() { +void EffectLayer::preparePerFrameCompositionState() { Layer::preparePerFrameCompositionState(); auto* compositionState = editCompositionState(); @@ -96,30 +96,30 @@ void ColorLayer::preparePerFrameCompositionState() { compositionState->compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR; } -sp<compositionengine::LayerFE> ColorLayer::getCompositionEngineLayerFE() const { +sp<compositionengine::LayerFE> EffectLayer::getCompositionEngineLayerFE() const { return asLayerFE(); } -compositionengine::LayerFECompositionState* ColorLayer::editCompositionState() { +compositionengine::LayerFECompositionState* EffectLayer::editCompositionState() { return mCompositionState.get(); } -const compositionengine::LayerFECompositionState* ColorLayer::getCompositionState() const { +const compositionengine::LayerFECompositionState* EffectLayer::getCompositionState() const { return mCompositionState.get(); } -bool ColorLayer::isOpaque(const Layer::State& s) const { +bool EffectLayer::isOpaque(const Layer::State& s) const { // Consider the layer to be opaque if its opaque flag is set or its effective // alpha (considering the alpha of its parents as well) is 1.0; return (s.flags & layer_state_t::eLayerOpaque) != 0 || getAlpha() == 1.0_hf; } -ui::Dataspace ColorLayer::getDataSpace() const { +ui::Dataspace EffectLayer::getDataSpace() const { return mDrawingState.dataspace; } -sp<Layer> ColorLayer::createClone() { - sp<ColorLayer> layer = mFlinger->getFactory().createColorLayer( +sp<Layer> EffectLayer::createClone() { + sp<EffectLayer> layer = mFlinger->getFactory().createEffectLayer( LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, 0, 0, LayerMetadata())); layer->setInitialValuesForClone(this); diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/EffectLayer.h index 4deb162191..8694283760 100644 --- a/services/surfaceflinger/ColorLayer.h +++ b/services/surfaceflinger/EffectLayer.h @@ -23,15 +23,19 @@ namespace android { -class ColorLayer : public Layer { +// A layer that can render a combination of the following effects. +// * fill the bounds of the layer with a color +// * render a shadow cast by the bounds of the layer +// If no effects are enabled, the layer is considered to be invisible. +class EffectLayer : public Layer { public: - explicit ColorLayer(const LayerCreationArgs&); - ~ColorLayer() override; + explicit EffectLayer(const LayerCreationArgs&); + ~EffectLayer() override; sp<compositionengine::LayerFE> getCompositionEngineLayerFE() const override; compositionengine::LayerFECompositionState* editCompositionState() override; - const char* getType() const override { return "ColorLayer"; } + const char* getType() const override { return "EffectLayer"; } bool isVisible() const override; bool setColor(const half3& color) override; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 6ff23c5f51..fd86da85a0 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -56,10 +56,10 @@ #include <sstream> #include "BufferLayer.h" -#include "ColorLayer.h" #include "Colorizer.h" #include "DisplayDevice.h" #include "DisplayHardware/HWComposer.h" +#include "EffectLayer.h" #include "FrameTracer/FrameTracer.h" #include "LayerProtoHelper.h" #include "LayerRejecter.h" @@ -164,7 +164,7 @@ LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, const sp<Client> c /* * onLayerDisplayed is only meaningful for BufferLayer, but, is called through * Layer. So, the implementation is done in BufferLayer. When called on a - * ColorLayer object, it's essentially a NOP. + * EffectLayer object, it's essentially a NOP. */ void Layer::onLayerDisplayed(const sp<Fence>& /*releaseFence*/) {} @@ -1091,9 +1091,9 @@ bool Layer::setBackgroundColor(const half3& color, float alpha, ui::Dataspace da if (!mCurrentState.bgColorLayer && alpha != 0) { // create background color layer if one does not yet exist - uint32_t flags = ISurfaceComposerClient::eFXSurfaceColor; + uint32_t flags = ISurfaceComposerClient::eFXSurfaceEffect; std::string name = mName + "BackgroundColorLayer"; - mCurrentState.bgColorLayer = mFlinger->getFactory().createColorLayer( + mCurrentState.bgColorLayer = mFlinger->getFactory().createEffectLayer( LayerCreationArgs(mFlinger.get(), nullptr, std::move(name), 0, 0, flags, LayerMetadata())); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index c110462d61..c2dbd142b4 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -212,7 +212,7 @@ public: InputWindowInfo inputInfo; wp<Layer> touchableRegionCrop; - // dataspace is only used by BufferStateLayer and ColorLayer + // dataspace is only used by BufferStateLayer and EffectLayer ui::Dataspace dataspace; // The fields below this point are only used by BufferStateLayer diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp index b467f24207..399da19c75 100644 --- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp @@ -53,15 +53,15 @@ inline void VSyncPredictor::traceInt64If(const char* name, int64_t value) const } inline size_t VSyncPredictor::next(int i) const { - return (i + 1) % timestamps.size(); + return (i + 1) % mTimestamps.size(); } bool VSyncPredictor::validate(nsecs_t timestamp) const { - if (lastTimestampIndex < 0 || timestamps.empty()) { + if (mLastTimestampIndex < 0 || mTimestamps.empty()) { return true; } - auto const aValidTimestamp = timestamps[lastTimestampIndex]; + auto const aValidTimestamp = mTimestamps[mLastTimestampIndex]; auto const percent = (timestamp - aValidTimestamp) % mIdealPeriod * kMaxPercent / mIdealPeriod; return percent < kOutlierTolerancePercent || percent > (kMaxPercent - kOutlierTolerancePercent); } @@ -79,15 +79,15 @@ bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { return false; } - if (timestamps.size() != kHistorySize) { - timestamps.push_back(timestamp); - lastTimestampIndex = next(lastTimestampIndex); + if (mTimestamps.size() != kHistorySize) { + mTimestamps.push_back(timestamp); + mLastTimestampIndex = next(mLastTimestampIndex); } else { - lastTimestampIndex = next(lastTimestampIndex); - timestamps[lastTimestampIndex] = timestamp; + mLastTimestampIndex = next(mLastTimestampIndex); + mTimestamps[mLastTimestampIndex] = timestamp; } - if (timestamps.size() < kMinimumSamplesForPrediction) { + if (mTimestamps.size() < kMinimumSamplesForPrediction) { mRateMap[mIdealPeriod] = {mIdealPeriod, 0}; return true; } @@ -107,11 +107,11 @@ bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { // // intercept = mean(Y) - slope * mean(X) // - std::vector<nsecs_t> vsyncTS(timestamps.size()); - std::vector<nsecs_t> ordinals(timestamps.size()); + std::vector<nsecs_t> vsyncTS(mTimestamps.size()); + std::vector<nsecs_t> ordinals(mTimestamps.size()); // normalizing to the oldest timestamp cuts down on error in calculating the intercept. - auto const oldest_ts = *std::min_element(timestamps.begin(), timestamps.end()); + auto const oldest_ts = *std::min_element(mTimestamps.begin(), mTimestamps.end()); auto it = mRateMap.find(mIdealPeriod); auto const currentPeriod = std::get<0>(it->second); // TODO (b/144707443): its important that there's some precision in the mean of the ordinals @@ -120,10 +120,10 @@ bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { // scheduler::utils::calculate_mean to have a fixed point fractional part. static constexpr int kScalingFactor = 10; - for (auto i = 0u; i < timestamps.size(); i++) { - traceInt64If("VSP-ts", timestamps[i]); + for (auto i = 0u; i < mTimestamps.size(); i++) { + traceInt64If("VSP-ts", mTimestamps[i]); - vsyncTS[i] = timestamps[i] - oldest_ts; + vsyncTS[i] = mTimestamps[i] - oldest_ts; ordinals[i] = ((vsyncTS[i] + (currentPeriod / 2)) / currentPeriod) * kScalingFactor; } @@ -143,12 +143,20 @@ bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { if (CC_UNLIKELY(bottom == 0)) { it->second = {mIdealPeriod, 0}; + clearTimestamps(); return false; } nsecs_t const anticipatedPeriod = top / bottom * kScalingFactor; nsecs_t const intercept = meanTS - (anticipatedPeriod * meanOrdinal / kScalingFactor); + auto const percent = std::abs(anticipatedPeriod - mIdealPeriod) * kMaxPercent / mIdealPeriod; + if (percent >= kOutlierTolerancePercent) { + it->second = {mIdealPeriod, 0}; + clearTimestamps(); + return false; + } + traceInt64If("VSP-period", anticipatedPeriod); traceInt64If("VSP-intercept", intercept); @@ -164,14 +172,14 @@ nsecs_t VSyncPredictor::nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const { auto const [slope, intercept] = getVSyncPredictionModel(lk); - if (timestamps.empty()) { + if (mTimestamps.empty()) { traceInt64If("VSP-mode", 1); auto const knownTimestamp = mKnownTimestamp ? *mKnownTimestamp : timePoint; auto const numPeriodsOut = ((timePoint - knownTimestamp) / mIdealPeriod) + 1; return knownTimestamp + numPeriodsOut * mIdealPeriod; } - auto const oldest = *std::min_element(timestamps.begin(), timestamps.end()); + auto const oldest = *std::min_element(mTimestamps.begin(), mTimestamps.end()); // See b/145667109, the ordinal calculation must take into account the intercept. auto const zeroPoint = oldest + intercept; @@ -225,10 +233,10 @@ void VSyncPredictor::setPeriod(nsecs_t period) { } void VSyncPredictor::clearTimestamps() { - if (!timestamps.empty()) { - mKnownTimestamp = *std::max_element(timestamps.begin(), timestamps.end()); - timestamps.clear(); - lastTimestampIndex = 0; + if (!mTimestamps.empty()) { + mKnownTimestamp = *std::max_element(mTimestamps.begin(), mTimestamps.end()); + mTimestamps.clear(); + mLastTimestampIndex = 0; } } @@ -236,11 +244,11 @@ bool VSyncPredictor::needsMoreSamples(nsecs_t now) const { using namespace std::literals::chrono_literals; std::lock_guard<std::mutex> lk(mMutex); bool needsMoreSamples = true; - if (timestamps.size() >= kMinimumSamplesForPrediction) { + if (mTimestamps.size() >= kMinimumSamplesForPrediction) { nsecs_t constexpr aLongTime = std::chrono::duration_cast<std::chrono::nanoseconds>(500ms).count(); - if (!(lastTimestampIndex < 0 || timestamps.empty())) { - auto const lastTimestamp = timestamps[lastTimestampIndex]; + if (!(mLastTimestampIndex < 0 || mTimestamps.empty())) { + auto const lastTimestamp = mTimestamps[mLastTimestampIndex]; needsMoreSamples = !((lastTimestamp + aLongTime) > now); } } diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h index 532fe9e928..ef1d88ac27 100644 --- a/services/surfaceflinger/Scheduler/VSyncPredictor.h +++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h @@ -83,8 +83,8 @@ private: std::unordered_map<nsecs_t, std::tuple<nsecs_t, nsecs_t>> mutable mRateMap GUARDED_BY(mMutex); - int lastTimestampIndex GUARDED_BY(mMutex) = 0; - std::vector<nsecs_t> timestamps GUARDED_BY(mMutex); + int mLastTimestampIndex GUARDED_BY(mMutex) = 0; + std::vector<nsecs_t> mTimestamps GUARDED_BY(mMutex); }; } // namespace android::scheduler diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index d971625ef4..67c3d52f81 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -83,10 +83,10 @@ #include "BufferQueueLayer.h" #include "BufferStateLayer.h" #include "Client.h" -#include "ColorLayer.h" #include "Colorizer.h" #include "ContainerLayer.h" #include "DisplayDevice.h" +#include "EffectLayer.h" #include "Layer.h" #include "LayerVector.h" #include "MonitoredProducer.h" @@ -2081,7 +2081,8 @@ void SurfaceFlinger::postComposition() } }); - if (presentFenceTime->isValid()) { + if (displayDevice && displayDevice->isPrimary() && + displayDevice->getPowerMode() == HWC_POWER_MODE_NORMAL && presentFenceTime->isValid()) { mScheduler->addPresentFence(presentFenceTime); } @@ -3699,7 +3700,7 @@ status_t SurfaceFlinger::createLayer(const String8& name, const sp<Client>& clie result = createBufferStateLayer(client, std::move(uniqueName), w, h, flags, std::move(metadata), handle, outTransformHint, &layer); break; - case ISurfaceComposerClient::eFXSurfaceColor: + case ISurfaceComposerClient::eFXSurfaceEffect: // check if buffer size is set for color layer. if (w > 0 || h > 0) { ALOGE("createLayer() failed, w or h cannot be set for color layer (w=%d, h=%d)", @@ -3707,8 +3708,8 @@ status_t SurfaceFlinger::createLayer(const String8& name, const sp<Client>& clie return BAD_VALUE; } - result = createColorLayer(client, std::move(uniqueName), w, h, flags, - std::move(metadata), handle, &layer); + result = createEffectLayer(client, std::move(uniqueName), w, h, flags, + std::move(metadata), handle, &layer); break; case ISurfaceComposerClient::eFXSurfaceContainer: // check if buffer size is set for container layer. @@ -3826,10 +3827,10 @@ status_t SurfaceFlinger::createBufferStateLayer(const sp<Client>& client, std::s return NO_ERROR; } -status_t SurfaceFlinger::createColorLayer(const sp<Client>& client, std::string name, uint32_t w, - uint32_t h, uint32_t flags, LayerMetadata metadata, - sp<IBinder>* handle, sp<Layer>* outLayer) { - *outLayer = getFactory().createColorLayer( +status_t SurfaceFlinger::createEffectLayer(const sp<Client>& client, std::string name, uint32_t w, + uint32_t h, uint32_t flags, LayerMetadata metadata, + sp<IBinder>* handle, sp<Layer>* outLayer) { + *outLayer = getFactory().createEffectLayer( {this, client, std::move(name), w, h, flags, std::move(metadata)}); *handle = (*outLayer)->getHandle(); return NO_ERROR; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 8cabcf0ef6..0d43215ba5 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -653,9 +653,9 @@ private: sp<IBinder>* outHandle, uint32_t* outTransformHint, sp<Layer>* outLayer); - status_t createColorLayer(const sp<Client>& client, std::string name, uint32_t w, uint32_t h, - uint32_t flags, LayerMetadata metadata, sp<IBinder>* outHandle, - sp<Layer>* outLayer); + status_t createEffectLayer(const sp<Client>& client, std::string name, uint32_t w, uint32_t h, + uint32_t flags, LayerMetadata metadata, sp<IBinder>* outHandle, + sp<Layer>* outLayer); status_t createContainerLayer(const sp<Client>& client, std::string name, uint32_t w, uint32_t h, uint32_t flags, LayerMetadata metadata, diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp index f9658a78d6..d49133d1fc 100644 --- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp +++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp @@ -25,9 +25,9 @@ #include "BufferLayerConsumer.h" #include "BufferQueueLayer.h" #include "BufferStateLayer.h" -#include "ColorLayer.h" #include "ContainerLayer.h" #include "DisplayDevice.h" +#include "EffectLayer.h" #include "Layer.h" #include "MonitoredProducer.h" #include "NativeWindowSurface.h" @@ -139,8 +139,8 @@ sp<BufferStateLayer> DefaultFactory::createBufferStateLayer(const LayerCreationA return new BufferStateLayer(args); } -sp<ColorLayer> DefaultFactory::createColorLayer(const LayerCreationArgs& args) { - return new ColorLayer(args); +sp<EffectLayer> DefaultFactory::createEffectLayer(const LayerCreationArgs& args) { + return new EffectLayer(args); } } // namespace android::surfaceflinger diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h index 36fae217ce..89194c7ad1 100644 --- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h +++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h @@ -55,7 +55,7 @@ public: std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine() override; sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs& args) override; sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) override; - sp<ColorLayer> createColorLayer(const LayerCreationArgs& args) override; + sp<EffectLayer> createEffectLayer(const LayerCreationArgs& args) override; sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) override; }; diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h index c7da730c64..209bd0caba 100644 --- a/services/surfaceflinger/SurfaceFlingerFactory.h +++ b/services/surfaceflinger/SurfaceFlingerFactory.h @@ -31,7 +31,7 @@ typedef int32_t PixelFormat; class BufferQueueLayer; class BufferStateLayer; class BufferLayerConsumer; -class ColorLayer; +class EffectLayer; class ContainerLayer; class DisplayDevice; class DispSync; @@ -104,7 +104,7 @@ public: virtual sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs& args) = 0; virtual sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) = 0; - virtual sp<ColorLayer> createColorLayer(const LayerCreationArgs& args) = 0; + virtual sp<EffectLayer> createEffectLayer(const LayerCreationArgs& args) = 0; virtual sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) = 0; protected: diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp index 24874b010b..6c8eb27bd0 100644 --- a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp @@ -531,7 +531,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetColorBasic) { ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32)); ASSERT_NO_FATAL_FAILURE(colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor)); + ISurfaceComposerClient::eFXSurfaceEffect)); Transaction() .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)) @@ -570,7 +570,7 @@ void LayerRenderTypeTransactionTest::setBackgroundColorHelper(uint32_t layerType Color priorBgColor = Color::BLUE; Color expectedColor = Color::BLACK; switch (layerType) { - case ISurfaceComposerClient::eFXSurfaceColor: + case ISurfaceComposerClient::eFXSurfaceEffect: ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 0, 0, layerType)); Transaction() .setCrop_legacy(layer, Rect(0, 0, width, height)) @@ -599,7 +599,7 @@ void LayerRenderTypeTransactionTest::setBackgroundColorHelper(uint32_t layerType return; } - if (priorColor && layerType != ISurfaceComposerClient::eFXSurfaceColor) { + if (priorColor && layerType != ISurfaceComposerClient::eFXSurfaceEffect) { Transaction() .setBackgroundColor(layer, half3(0, 0, 1.0f), 1.0f, ui::Dataspace::UNKNOWN) .apply(); @@ -628,7 +628,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetBackgroundColor_Color_NoEffect) { bool bufferFill = false; float alpha = 1.0f; Color finalColor = Color::RED; - ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceColor, + ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceEffect, priorColor, bufferFill, alpha, finalColor)); } @@ -744,7 +744,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetColorClamped) { sp<SurfaceControl> colorLayer; ASSERT_NO_FATAL_FAILURE(colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor)); + ISurfaceComposerClient::eFXSurfaceEffect)); Transaction() .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)) .setColor(colorLayer, half3(2.0f, -1.0f, 0.0f)) @@ -760,7 +760,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetColorWithAlpha) { ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32)); ASSERT_NO_FATAL_FAILURE(colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor)); + ISurfaceComposerClient::eFXSurfaceEffect)); Transaction().setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)).apply(); const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f); @@ -787,7 +787,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetColorWithParentAlpha_Bug74220420) { ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32)); ASSERT_NO_FATAL_FAILURE(colorLayer = createLayer("childWithColor", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor)); + ISurfaceComposerClient::eFXSurfaceEffect)); Transaction().setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)).apply(); const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f); const float alpha = 0.25f; @@ -1663,7 +1663,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetColorTransformBasic) { sp<SurfaceControl> colorLayer; ASSERT_NO_FATAL_FAILURE(colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor)); + ISurfaceComposerClient::eFXSurfaceEffect)); Transaction() .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)) .setLayer(colorLayer, mLayerZBase + 1) @@ -1719,7 +1719,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetColorTransformOnParent) { ISurfaceComposerClient::eFXSurfaceContainer)); ASSERT_NO_FATAL_FAILURE( colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor, parentLayer.get())); + ISurfaceComposerClient::eFXSurfaceEffect, parentLayer.get())); Transaction() .setCrop_legacy(parentLayer, Rect(0, 0, 100, 100)) @@ -1780,7 +1780,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetColorTransformOnChildAndParent) { ISurfaceComposerClient::eFXSurfaceContainer)); ASSERT_NO_FATAL_FAILURE( colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor, parentLayer.get())); + ISurfaceComposerClient::eFXSurfaceEffect, parentLayer.get())); Transaction() .setCrop_legacy(parentLayer, Rect(0, 0, 100, 100)) diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h index 5eb1739219..932c7c86fa 100644 --- a/services/surfaceflinger/tests/LayerTransactionTest.h +++ b/services/surfaceflinger/tests/LayerTransactionTest.h @@ -89,7 +89,7 @@ protected: SurfaceControl* parent = nullptr) { auto colorLayer = createSurface(mClient, name, 0 /* buffer width */, 0 /* buffer height */, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor, parent); + ISurfaceComposerClient::eFXSurfaceEffect, parent); asTransaction([&](Transaction& t) { t.setColor(colorLayer, half3{color.r / 255.0f, color.g / 255.0f, color.b / 255.0f}); t.setAlpha(colorLayer, color.a / 255.0f); @@ -268,7 +268,7 @@ private: mBlackBgSurface = createSurface(mClient, "BaseSurface", 0 /* buffer width */, 0 /* buffer height */, - PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor); + PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect); // set layer stack (b/68888219) Transaction t; diff --git a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp index 7e9202bb82..84780ba73b 100644 --- a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp @@ -69,13 +69,13 @@ TEST_P(LayerTypeTransactionTest, SetRelativeZNegative) { TEST_P(LayerTypeTransactionTest, SetLayerAndRelative) { sp<SurfaceControl> parent = LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor); + ISurfaceComposerClient::eFXSurfaceEffect); sp<SurfaceControl> childLayer; ASSERT_NO_FATAL_FAILURE( childLayer = LayerTransactionTest::createLayer("childLayer", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor, + ISurfaceComposerClient::eFXSurfaceEffect, parent.get())); Transaction() .setColor(childLayer, half3{1.0f, 0.0f, 0.0f}) @@ -116,17 +116,17 @@ TEST_P(LayerTypeTransactionTest, SetLayerAndRelative) { TEST_P(LayerTypeTransactionTest, HideRelativeParentHidesLayer) { sp<SurfaceControl> parent = LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor); + ISurfaceComposerClient::eFXSurfaceEffect); sp<SurfaceControl> relativeParent = LayerTransactionTest::createLayer("RelativeParent", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor); + ISurfaceComposerClient::eFXSurfaceEffect); sp<SurfaceControl> childLayer; ASSERT_NO_FATAL_FAILURE( childLayer = LayerTransactionTest::createLayer("childLayer", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor, + ISurfaceComposerClient::eFXSurfaceEffect, parent.get())); Transaction() .setColor(childLayer, half3{1.0f, 0.0f, 0.0f}) diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp index a1c412801d..cf3f8e8865 100644 --- a/services/surfaceflinger/tests/LayerUpdate_test.cpp +++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp @@ -1114,7 +1114,7 @@ TEST_F(BoundlessLayerTest, BufferLayerIgnoresSize) { TEST_F(BoundlessLayerTest, BoundlessColorLayerFillsParentBufferBounds) { sp<SurfaceControl> colorLayer = createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor, mFGSurfaceControl.get()); + ISurfaceComposerClient::eFXSurfaceEffect, mFGSurfaceControl.get()); ASSERT_TRUE(colorLayer->isValid()); asTransaction([&](Transaction& t) { t.setColor(colorLayer, half3{0, 0, 0}); @@ -1139,7 +1139,7 @@ TEST_F(BoundlessLayerTest, BoundlessColorLayerFillsParentCropBounds) { ASSERT_TRUE(cropLayer->isValid()); sp<SurfaceControl> colorLayer = createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor, cropLayer.get()); + ISurfaceComposerClient::eFXSurfaceEffect, cropLayer.get()); ASSERT_TRUE(colorLayer->isValid()); asTransaction([&](Transaction& t) { t.setCrop_legacy(cropLayer, Rect(5, 5, 10, 10)); @@ -1164,7 +1164,7 @@ TEST_F(BoundlessLayerTest, BoundlessColorLayerFillsParentCropBounds) { TEST_F(BoundlessLayerTest, BoundlessColorLayerTransformHasNoEffect) { sp<SurfaceControl> colorLayer = createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor, mFGSurfaceControl.get()); + ISurfaceComposerClient::eFXSurfaceEffect, mFGSurfaceControl.get()); ASSERT_TRUE(colorLayer->isValid()); asTransaction([&](Transaction& t) { t.setPosition(colorLayer, 320, 320); @@ -1195,7 +1195,7 @@ TEST_F(BoundlessLayerTest, IntermediateBoundlessLayerCanSetTransform) { ASSERT_TRUE(boundlessLayerDownShift->isValid()); sp<SurfaceControl> colorLayer = createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor, boundlessLayerDownShift.get()); + ISurfaceComposerClient::eFXSurfaceEffect, boundlessLayerDownShift.get()); ASSERT_TRUE(colorLayer->isValid()); asTransaction([&](Transaction& t) { t.setPosition(boundlessLayerRightShift, 32, 0); @@ -1229,7 +1229,7 @@ TEST_F(BoundlessLayerTest, IntermediateBoundlessLayerDoNotCrop) { ASSERT_TRUE(boundlessLayer->isValid()); sp<SurfaceControl> colorLayer = mClient->createSurface(String8("ColorLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor, boundlessLayer.get()); + ISurfaceComposerClient::eFXSurfaceEffect, boundlessLayer.get()); ASSERT_TRUE(colorLayer != nullptr); ASSERT_TRUE(colorLayer->isValid()); asTransaction([&](Transaction& t) { @@ -1261,7 +1261,7 @@ TEST_F(BoundlessLayerTest, RootBoundlessLayerCanSetTransform) { ASSERT_TRUE(rootBoundlessLayer->isValid()); sp<SurfaceControl> colorLayer = createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor, rootBoundlessLayer.get()); + ISurfaceComposerClient::eFXSurfaceEffect, rootBoundlessLayer.get()); ASSERT_TRUE(colorLayer->isValid()); asTransaction([&](Transaction& t) { diff --git a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp index c9fdc3b799..f8a5b4094d 100644 --- a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp +++ b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp @@ -66,7 +66,7 @@ protected: void createColorLayer(uint32_t layerStack) { mColorLayer = createSurface(mClient, "ColorLayer", 0 /* buffer width */, 0 /* buffer height */, - PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor); + PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect); ASSERT_TRUE(mColorLayer != nullptr); ASSERT_TRUE(mColorLayer->isValid()); asTransaction([&](Transaction& t) { diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp index e75149653c..32c58ad390 100644 --- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp +++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp @@ -1827,10 +1827,11 @@ class ChildColorLayerTest : public ChildLayerTest<FakeComposerService> { protected: void SetUp() override { Base::SetUp(); - Base::mChild = Base::mComposerClient->createSurface(String8("Child surface"), 0, 0, - PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor, - Base::mFGSurfaceControl.get()); + Base::mChild = + Base::mComposerClient->createSurface(String8("Child surface"), 0, 0, + PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceEffect, + Base::mFGSurfaceControl.get()); { TransactionScope ts(*Base::sFakeComposer); ts.setColor(Base::mChild, diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 888e009282..6e83166a80 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -35,7 +35,7 @@ #include <utils/String8.h> #include "BufferQueueLayer.h" -#include "ColorLayer.h" +#include "EffectLayer.h" #include "Layer.h" #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockComposer.h" @@ -713,7 +713,7 @@ struct BaseLayerProperties { struct DefaultLayerProperties : public BaseLayerProperties<DefaultLayerProperties> {}; -struct ColorLayerProperties : public BaseLayerProperties<ColorLayerProperties> { +struct EffectLayerProperties : public BaseLayerProperties<EffectLayerProperties> { static constexpr IComposerClient::BlendMode BLENDMODE = IComposerClient::BlendMode::NONE; }; @@ -866,16 +866,16 @@ struct BaseLayerVariant { }; template <typename LayerProperties> -struct ColorLayerVariant : public BaseLayerVariant<LayerProperties> { +struct EffectLayerVariant : public BaseLayerVariant<LayerProperties> { using Base = BaseLayerVariant<LayerProperties>; - using FlingerLayerType = sp<ColorLayer>; + using FlingerLayerType = sp<EffectLayer>; static FlingerLayerType createLayer(CompositionTest* test) { - FlingerLayerType layer = Base::template createLayerWithFactory<ColorLayer>(test, [test]() { - return new ColorLayer(LayerCreationArgs(test->mFlinger.mFlinger.get(), sp<Client>(), - "test-layer", LayerProperties::WIDTH, - LayerProperties::HEIGHT, - LayerProperties::LAYER_FLAGS, LayerMetadata())); + FlingerLayerType layer = Base::template createLayerWithFactory<EffectLayer>(test, [test]() { + return new EffectLayer( + LayerCreationArgs(test->mFlinger.mFlinger.get(), sp<Client>(), "test-layer", + LayerProperties::WIDTH, LayerProperties::HEIGHT, + LayerProperties::LAYER_FLAGS, LayerMetadata())); }); auto& layerDrawingState = test->mFlinger.mutableLayerDrawingState(layer); @@ -1228,31 +1228,31 @@ TEST_F(CompositionTest, captureScreenNormalBufferLayer) { * Single-color layers */ -TEST_F(CompositionTest, HWCComposedColorLayerWithDirtyGeometry) { +TEST_F(CompositionTest, HWCComposedEffectLayerWithDirtyGeometry) { displayRefreshCompositionDirtyGeometry< - CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>, + CompositionCase<DefaultDisplaySetupVariant, EffectLayerVariant<EffectLayerProperties>, KeepCompositionTypeVariant<IComposerClient::Composition::SOLID_COLOR>, HwcCompositionResultVariant>>(); } -TEST_F(CompositionTest, HWCComposedColorLayerWithDirtyFrame) { +TEST_F(CompositionTest, HWCComposedEffectLayerWithDirtyFrame) { displayRefreshCompositionDirtyFrame< - CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>, + CompositionCase<DefaultDisplaySetupVariant, EffectLayerVariant<EffectLayerProperties>, KeepCompositionTypeVariant<IComposerClient::Composition::SOLID_COLOR>, HwcCompositionResultVariant>>(); } -TEST_F(CompositionTest, REComposedColorLayer) { +TEST_F(CompositionTest, REComposedEffectLayer) { displayRefreshCompositionDirtyFrame< - CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>, + CompositionCase<DefaultDisplaySetupVariant, EffectLayerVariant<EffectLayerProperties>, ChangeCompositionTypeVariant<IComposerClient::Composition::SOLID_COLOR, IComposerClient::Composition::CLIENT>, RECompositionResultVariant>>(); } -TEST_F(CompositionTest, captureScreenColorLayer) { +TEST_F(CompositionTest, captureScreenEffectLayer) { captureScreenComposition< - CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>, + CompositionCase<DefaultDisplaySetupVariant, EffectLayerVariant<EffectLayerProperties>, NoCompositionTypeVariant, REScreenshotResultVariant>>(); } diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp index cffdc14df7..edd9de46ab 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp @@ -27,7 +27,7 @@ #include "BufferQueueLayer.h" #include "BufferStateLayer.h" -#include "ColorLayer.h" +#include "EffectLayer.h" #include "Layer.h" #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockComposer.h" @@ -68,7 +68,7 @@ protected: void setupComposer(int virtualDisplayCount); sp<BufferQueueLayer> createBufferQueueLayer(); sp<BufferStateLayer> createBufferStateLayer(); - sp<ColorLayer> createColorLayer(); + sp<EffectLayer> createEffectLayer(); void setParent(Layer* child, Layer* parent); void commitTransaction(Layer* layer); @@ -111,11 +111,11 @@ sp<BufferStateLayer> RefreshRateSelectionTest::createBufferStateLayer() { return new BufferStateLayer(args); } -sp<ColorLayer> RefreshRateSelectionTest::createColorLayer() { +sp<EffectLayer> RefreshRateSelectionTest::createEffectLayer() { sp<Client> client; LayerCreationArgs args(mFlinger.flinger(), client, "color-layer", WIDTH, HEIGHT, LAYER_FLAGS, LayerMetadata()); - return new ColorLayer(args); + return new EffectLayer(args); } void RefreshRateSelectionTest::setParent(Layer* child, Layer* parent) { @@ -244,11 +244,11 @@ TEST_F(RefreshRateSelectionTest, testPriorityOnBufferStateLayers) { ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority()); } -TEST_F(RefreshRateSelectionTest, testPriorityOnColorLayers) { - mParent = createColorLayer(); - mChild = createColorLayer(); +TEST_F(RefreshRateSelectionTest, testPriorityOnEffectLayers) { + mParent = createEffectLayer(); + mChild = createEffectLayer(); setParent(mChild.get(), mParent.get()); - mGrandChild = createColorLayer(); + mGrandChild = createEffectLayer(); setParent(mGrandChild.get(), mChild.get()); ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority()); diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 798ba766fc..685cfaf450 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -25,9 +25,9 @@ #include "BufferQueueLayer.h" #include "BufferStateLayer.h" -#include "ColorLayer.h" #include "ContainerLayer.h" #include "DisplayDevice.h" +#include "EffectLayer.h" #include "FakePhaseOffsets.h" #include "Layer.h" #include "NativeWindowSurface.h" @@ -147,9 +147,7 @@ public: return nullptr; } - sp<ColorLayer> createColorLayer(const LayerCreationArgs&) override { - return nullptr; - } + sp<EffectLayer> createEffectLayer(const LayerCreationArgs&) override { return nullptr; } sp<ContainerLayer> createContainerLayer(const LayerCreationArgs&) override { return nullptr; diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp index 6ec3844f25..f834af895c 100644 --- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp @@ -36,7 +36,7 @@ using namespace std::literals; namespace android::scheduler { MATCHER_P2(IsCloseTo, value, tolerance, "is within tolerance") { - return arg <= value + tolerance && value >= value - tolerance; + return arg <= value + tolerance && arg >= value - tolerance; } std::vector<nsecs_t> generateVsyncTimestamps(size_t count, nsecs_t period, nsecs_t bias) { @@ -370,6 +370,26 @@ TEST_F(VSyncPredictorTest, resetsWhenInstructed) { IsCloseTo(idealPeriod, mMaxRoundingError)); } +TEST_F(VSyncPredictorTest, slopeAlwaysValid) { + constexpr auto kNumVsyncs = 100; + auto invalidPeriod = mPeriod; + auto now = 0; + for (int i = 0; i < kNumVsyncs; i++) { + tracker.addVsyncTimestamp(now); + now += invalidPeriod; + invalidPeriod *= 0.9f; + + auto [slope, intercept] = tracker.getVSyncPredictionModel(); + EXPECT_THAT(slope, IsCloseTo(mPeriod, mPeriod * kOutlierTolerancePercent / 100.f)); + + // When VsyncPredictor returns the period it means that it doesn't know how to predict and + // it needs to get more samples + if (slope == mPeriod && intercept == 0) { + EXPECT_TRUE(tracker.needsMoreSamples(now)); + } + } +} + } // namespace android::scheduler // TODO(b/129481165): remove the #pragma below and fix conversion issues |