1 /*
2 * Copyright 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "LooperStub.h"
18
19 #include <android-base/chrono_utils.h>
20 #include <utils/Looper.h>
21
22 #include <future> // NOLINT(build/c++11)
23
24 namespace android {
25 namespace automotive {
26 namespace watchdog {
27 namespace testing {
28
29 using ::android::Message;
30 using ::android::base::Error;
31 using ::android::base::Result;
32
33 // As the messages, which are to be polled immediately, are enqueued in the underlying looper
34 // handler before calling its poll method, the looper handler doesn't have to wait for any new
35 // messages.
36 const std::chrono::milliseconds kLooperPollTimeout = 0ms;
37
38 // Maximum timeout before giving up on the underlying looper handler. This doesn't block the test
39 // as long as the underlying looper handler processes the enqueued messages quickly and updates
40 // |mShouldPoll|.
41 const std::chrono::milliseconds kStubPollCheckTimeout = 3min;
42
pollAll(int)43 int LooperStub::pollAll(int /*timeoutMillis*/) {
44 {
45 Mutex::Autolock lock(mMutex);
46 if (!mShouldPoll) {
47 return 0;
48 }
49 mElapsedTime = mTimer;
50 while (!mCache.empty() && mCache.front().empty()) {
51 mTimer += 1s; // Each empty entry in the cache is a second elapsed.
52 mCache.erase(mCache.begin());
53 }
54 mElapsedTime = mTimer - mElapsedTime;
55 if (mCache.empty()) {
56 mShouldPoll = false;
57 return 0;
58 }
59 // Send messages from the top of the cache and poll them immediately.
60 const auto messages = mCache.front();
61 for (const auto& m : messages) {
62 mLooper->sendMessage(mHandler, m);
63 }
64 mCache.front().clear();
65 }
66 int result = mLooper->pollAll(kLooperPollTimeout.count());
67 Mutex::Autolock lock(mMutex);
68 mShouldPoll = false;
69 return result;
70 }
71
sendMessage(const android::sp<MessageHandler> & handler,const Message & message)72 void LooperStub::sendMessage(const android::sp<MessageHandler>& handler, const Message& message) {
73 sendMessageAtTime(now(), handler, message);
74 }
75
sendMessageAtTime(nsecs_t uptime,const android::sp<MessageHandler> & handler,const Message & message)76 void LooperStub::sendMessageAtTime(nsecs_t uptime, const android::sp<MessageHandler>& handler,
77 const Message& message) {
78 Mutex::Autolock lock(mMutex);
79 mHandler = handler;
80 nsecs_t uptimeDelay = uptime - now();
81 size_t pos = static_cast<size_t>(ns2s(uptimeDelay));
82 while (mCache.size() < pos + 1) {
83 mCache.emplace_back(LooperStub::CacheEntry());
84 }
85 mCache[pos].emplace_back(message);
86 }
87
removeMessages(const android::sp<MessageHandler> & handler)88 void LooperStub::removeMessages(const android::sp<MessageHandler>& handler) {
89 Mutex::Autolock lock(mMutex);
90 mCache.clear();
91 mLooper->removeMessages(handler);
92 }
93
removeMessages(const android::sp<MessageHandler> & handler,int what)94 void LooperStub::removeMessages(const android::sp<MessageHandler>& handler, int what) {
95 Mutex::Autolock lock(mMutex);
96 for (auto& entry : mCache) {
97 for (auto it = entry.begin(); it != entry.end();) {
98 if (it->what == what) {
99 entry.erase(it);
100 } else {
101 ++it;
102 }
103 }
104 }
105 mLooper->removeMessages(handler, what);
106 }
107
pollCache()108 Result<void> LooperStub::pollCache() {
109 {
110 Mutex::Autolock lock(mMutex);
111 mShouldPoll = true;
112 }
113 auto checkPollCompleted = std::async([&]() {
114 bool shouldPoll = true;
115 while (shouldPoll) {
116 Mutex::Autolock lock(mMutex);
117 shouldPoll = mShouldPoll;
118 }
119 });
120 if (checkPollCompleted.wait_for(kStubPollCheckTimeout) != std::future_status::ready) {
121 mShouldPoll = false;
122 return Error() << "Poll didn't complete before " << kStubPollCheckTimeout.count()
123 << " milliseconds";
124 }
125 return {};
126 }
127
128 } // namespace testing
129 } // namespace watchdog
130 } // namespace automotive
131 } // namespace android
132