1 /*
2 * Copyright (C) 2022 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 "TestWakeupClientServiceImpl.h"
18
19 #include <android-base/stringprintf.h>
20 #include <inttypes.h>
21 #include <utils/Looper.h>
22 #include <utils/SystemClock.h>
23 #include <chrono>
24 #include <thread>
25
26 namespace android {
27 namespace hardware {
28 namespace automotive {
29 namespace remoteaccess {
30
31 namespace {
32
33 using ::android::uptimeMillis;
34 using ::android::base::ScopedLockAssertion;
35 using ::android::base::StringPrintf;
36 using ::grpc::ServerContext;
37 using ::grpc::ServerWriter;
38 using ::grpc::Status;
39
40 constexpr int64_t kTaskIntervalInMs = 5'000;
41 constexpr int64_t kTaskTimeoutInMs = 60'000;
42
msToNs(int64_t ms)43 int64_t msToNs(int64_t ms) {
44 return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::milliseconds(ms))
45 .count();
46 }
47
sToNs(int64_t s)48 int64_t sToNs(int64_t s) {
49 return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(s)).count();
50 }
51
52 } // namespace
53
generateTask(const std::string & clientId)54 GetRemoteTasksResponse FakeTaskGenerator::generateTask(const std::string& clientId) {
55 GetRemoteTasksResponse response;
56 response.set_data(reinterpret_cast<const char*>(DATA), sizeof(DATA));
57 response.set_clientid(clientId);
58 return response;
59 }
60
TaskTimeoutMessageHandler(TaskQueue * taskQueue)61 TaskTimeoutMessageHandler::TaskTimeoutMessageHandler(TaskQueue* taskQueue)
62 : mTaskQueue(taskQueue) {}
63
handleMessage(const android::Message & message)64 void TaskTimeoutMessageHandler::handleMessage(const android::Message& message) {
65 mTaskQueue->handleTaskTimeout();
66 }
67
TaskQueue(android::sp<Looper> looper)68 TaskQueue::TaskQueue(android::sp<Looper> looper) {
69 mTaskTimeoutMessageHandler = android::sp<TaskTimeoutMessageHandler>::make(this);
70 mLooper = looper;
71 }
72
maybePopOne()73 std::optional<GetRemoteTasksResponse> TaskQueue::maybePopOne() {
74 std::lock_guard<std::mutex> lockGuard(mLock);
75 if (mTasks.size() == 0) {
76 return std::nullopt;
77 }
78 TaskInfo response = std::move(mTasks.top());
79 mTasks.pop();
80 mLooper->removeMessages(mTaskTimeoutMessageHandler, response.taskId);
81 return std::move(response.taskData);
82 }
83
add(const GetRemoteTasksResponse & task)84 void TaskQueue::add(const GetRemoteTasksResponse& task) {
85 std::lock_guard<std::mutex> lockGuard(mLock);
86 if (mStopped) {
87 return;
88 }
89 int taskId = mTaskIdCounter++;
90 mTasks.push(TaskInfo{
91 .taskId = taskId,
92 .timestampInMs = uptimeMillis(),
93 .taskData = task,
94 });
95 android::Message message(taskId);
96 mLooper->sendMessageDelayed(msToNs(kTaskTimeoutInMs), mTaskTimeoutMessageHandler, message);
97 mTasksNotEmptyCv.notify_all();
98 }
99
waitForTask()100 void TaskQueue::waitForTask() {
101 std::unique_lock<std::mutex> lock(mLock);
102 mTasksNotEmptyCv.wait(lock, [this] {
103 ScopedLockAssertion lockAssertion(mLock);
104 return mTasks.size() > 0 || mStopped;
105 });
106 }
107
isStopped()108 bool TaskQueue::isStopped() {
109 return mStopped;
110 }
111
stopWait()112 void TaskQueue::stopWait() {
113 mStopped = true;
114 {
115 std::lock_guard<std::mutex> lockGuard(mLock);
116 mTasksNotEmptyCv.notify_all();
117 }
118 }
119
isEmpty()120 bool TaskQueue::isEmpty() {
121 std::lock_guard<std::mutex> lockGuard(mLock);
122 return mTasks.size() == 0 || mStopped;
123 }
124
handleTaskTimeout()125 void TaskQueue::handleTaskTimeout() {
126 // We know which task timed-out from the taskId in the message. However, there is no easy way
127 // to remove a specific task with the task ID from the priority_queue, so we just check from
128 // the top of the queue (which have the oldest tasks).
129 std::lock_guard<std::mutex> lockGuard(mLock);
130 int64_t now = uptimeMillis();
131 while (mTasks.size() > 0) {
132 const TaskInfo& taskInfo = mTasks.top();
133 if (taskInfo.timestampInMs + kTaskTimeoutInMs > now) {
134 break;
135 }
136 // In real implementation, this should report task failure to remote wakeup server.
137 printf("Task for client ID: %s timed-out, added at %" PRId64 " ms, now %" PRId64 " ms\n",
138 taskInfo.taskData.clientid().c_str(), taskInfo.timestampInMs, now);
139 mTasks.pop();
140 }
141 }
142
ServiceImpl()143 ServiceImpl::ServiceImpl() {
144 mTaskScheduleMsgHandler = android::sp<TaskScheduleMsgHandler>::make(this);
145 mLooper = android::sp<Looper>::make(/*opts=*/0);
146 mLooperThread = std::thread([this] { loop(); });
147 mTaskQueue = std::make_unique<TaskQueue>(mLooper);
148 }
149
~ServiceImpl()150 ServiceImpl::~ServiceImpl() {
151 if (mServerStopped) {
152 return;
153 }
154 stopServer();
155 }
156
stopServer()157 void ServiceImpl::stopServer() {
158 mTaskQueue->stopWait();
159 stopGeneratingFakeTask();
160 // Set the flag so that the loop thread will exit.
161 mServerStopped = true;
162 mLooper->wake();
163 if (mLooperThread.joinable()) {
164 mLooperThread.join();
165 }
166 }
167
loop()168 void ServiceImpl::loop() {
169 Looper::setForThread(mLooper);
170
171 while (true) {
172 // Don't use pollAll since it might swallow wake.
173 mLooper->pollOnce(/*timeoutMillis=*/-1);
174 if (mServerStopped) {
175 return;
176 }
177 }
178 }
179
injectTask(const std::string & taskData,const std::string & clientId)180 void ServiceImpl::injectTask(const std::string& taskData, const std::string& clientId) {
181 GetRemoteTasksResponse response;
182 response.set_data(taskData);
183 response.set_clientid(clientId);
184 injectTaskResponse(response);
185 }
186
injectTaskResponse(const GetRemoteTasksResponse & response)187 void ServiceImpl::injectTaskResponse(const GetRemoteTasksResponse& response) {
188 printf("Receive a new task\n");
189 mTaskQueue->add(response);
190 if (mWakeupRequired) {
191 wakeupApplicationProcessor(BOOTUP_REASON_SYSTEM_REMOTE_ACCESS);
192 }
193 }
194
startGeneratingFakeTask(const std::string & clientId)195 void ServiceImpl::startGeneratingFakeTask(const std::string& clientId) {
196 std::lock_guard<std::mutex> lockGuard(mLock);
197 if (mGeneratingFakeTask) {
198 printf("Fake task is already being generated\n");
199 return;
200 }
201 mGeneratingFakeTask = true;
202 mFakeTaskThread = std::thread([this, clientId] { fakeTaskGenerateLoop(clientId); });
203 printf("Started generating fake tasks\n");
204 }
205
stopGeneratingFakeTask()206 void ServiceImpl::stopGeneratingFakeTask() {
207 {
208 std::lock_guard<std::mutex> lockGuard(mLock);
209 if (!mGeneratingFakeTask) {
210 printf("Fake task is not being generated, do nothing\n");
211 return;
212 }
213 mTaskLoopStoppedCv.notify_all();
214 mGeneratingFakeTask = false;
215 }
216 if (mFakeTaskThread.joinable()) {
217 mFakeTaskThread.join();
218 }
219 printf("Stopped generating fake tasks\n");
220 }
221
fakeTaskGenerateLoop(const std::string & clientId)222 void ServiceImpl::fakeTaskGenerateLoop(const std::string& clientId) {
223 // In actual implementation, this should communicate with the remote server and receives tasks
224 // from it. Here we simulate receiving one remote task every {kTaskIntervalInMs}ms.
225 while (true) {
226 injectTaskResponse(mFakeTaskGenerator.generateTask(clientId));
227 printf("Sleeping for %" PRId64 " seconds until next task\n", kTaskIntervalInMs);
228
229 std::unique_lock lk(mLock);
230 if (mTaskLoopStoppedCv.wait_for(lk, std::chrono::milliseconds(kTaskIntervalInMs), [this] {
231 ScopedLockAssertion lockAssertion(mLock);
232 return !mGeneratingFakeTask;
233 })) {
234 // If the stopped flag is set, we are quitting, exit the loop.
235 return;
236 }
237 }
238 }
239
GetRemoteTasks(ServerContext * context,const GetRemoteTasksRequest * request,ServerWriter<GetRemoteTasksResponse> * writer)240 Status ServiceImpl::GetRemoteTasks(ServerContext* context, const GetRemoteTasksRequest* request,
241 ServerWriter<GetRemoteTasksResponse>* writer) {
242 printf("GetRemoteTasks called\n");
243 mRemoteTaskConnectionAlive = true;
244 while (true) {
245 mTaskQueue->waitForTask();
246
247 if (mTaskQueue->isStopped()) {
248 // Server stopped, exit the loop.
249 printf("Server stopped exit loop\n");
250 break;
251 }
252
253 while (true) {
254 auto maybeTask = mTaskQueue->maybePopOne();
255 if (!maybeTask.has_value()) {
256 printf("no task left\n");
257 // No task left, loop again and wait for another task(s).
258 break;
259 }
260 // Loop through all the task in the queue but obtain lock for each element so we don't
261 // hold lock while writing the response.
262 printf("Sending one remote task\n");
263 const GetRemoteTasksResponse& response = maybeTask.value();
264 if (!writer->Write(response)) {
265 // Broken stream, maybe the client is shutting down.
266 printf("Failed to deliver remote task to remote access HAL\n");
267 // The task failed to be sent, add it back to the queue. The order might change, but
268 // it is okay.
269 mTaskQueue->add(response);
270 mRemoteTaskConnectionAlive = false;
271 return Status::CANCELLED;
272 }
273 }
274 }
275 // Server stopped, exit the loop.
276 return Status::CANCELLED;
277 }
278
NotifyWakeupRequired(ServerContext * context,const NotifyWakeupRequiredRequest * request,NotifyWakeupRequiredResponse * response)279 Status ServiceImpl::NotifyWakeupRequired(ServerContext* context,
280 const NotifyWakeupRequiredRequest* request,
281 NotifyWakeupRequiredResponse* response) {
282 printf("NotifyWakeupRequired called\n");
283 if (request->iswakeuprequired() && !mWakeupRequired && !mTaskQueue->isEmpty()) {
284 // If wakeup is now required and previously not required, this means we have finished
285 // shutting down the device. If there are still pending tasks, try waking up AP again
286 // to finish executing those tasks.
287 wakeupApplicationProcessor(BOOTUP_REASON_SYSTEM_REMOTE_ACCESS);
288 }
289 mWakeupRequired = request->iswakeuprequired();
290 if (mWakeupRequired) {
291 // We won't know the connection is down unless we try to send a task over. If wakeup is
292 // required, the connection is very likely already down.
293 mRemoteTaskConnectionAlive = false;
294 }
295 return Status::OK;
296 }
297
cleanupScheduledTaskLocked(const std::string & clientId,const std::string & scheduleId)298 void ServiceImpl::cleanupScheduledTaskLocked(const std::string& clientId,
299 const std::string& scheduleId) {
300 mInfoByScheduleIdByClientId[clientId].erase(scheduleId);
301 if (mInfoByScheduleIdByClientId[clientId].size() == 0) {
302 mInfoByScheduleIdByClientId.erase(clientId);
303 }
304 }
305
TaskScheduleMsgHandler(ServiceImpl * impl)306 TaskScheduleMsgHandler::TaskScheduleMsgHandler(ServiceImpl* impl) : mImpl(impl) {}
307
handleMessage(const android::Message & message)308 void TaskScheduleMsgHandler::handleMessage(const android::Message& message) {
309 mImpl->handleAddTask(message.what);
310 }
311
ScheduleTask(ServerContext * context,const ScheduleTaskRequest * request,ScheduleTaskResponse * response)312 Status ServiceImpl::ScheduleTask(ServerContext* context, const ScheduleTaskRequest* request,
313 ScheduleTaskResponse* response) {
314 std::lock_guard<std::mutex> lockGuard(mLock);
315
316 const GrpcScheduleInfo& grpcScheduleInfo = request->scheduleinfo();
317 const std::string& scheduleId = grpcScheduleInfo.scheduleid();
318 const std::string& clientId = grpcScheduleInfo.clientid();
319 response->set_errorcode(ErrorCode::OK);
320
321 if (mInfoByScheduleIdByClientId.find(clientId) != mInfoByScheduleIdByClientId.end() &&
322 mInfoByScheduleIdByClientId[clientId].find(scheduleId) !=
323 mInfoByScheduleIdByClientId[clientId].end()) {
324 printf("Duplicate schedule Id: %s for client Id: %s\n", scheduleId.c_str(),
325 clientId.c_str());
326 response->set_errorcode(ErrorCode::INVALID_ARG);
327 return Status::OK;
328 }
329
330 int64_t startTimeInEpochSeconds = grpcScheduleInfo.starttimeinepochseconds();
331 int64_t periodicInSeconds = grpcScheduleInfo.periodicinseconds();
332 int32_t count = grpcScheduleInfo.count();
333
334 int scheduleMsgId = mScheduleMsgCounter++;
335 mInfoByScheduleIdByClientId[clientId][scheduleId] = {
336 .grpcScheduleInfo = std::make_unique<GrpcScheduleInfo>(grpcScheduleInfo),
337 .scheduleMsgId = scheduleMsgId,
338 .periodicInSeconds = periodicInSeconds,
339 .currentCount = 0,
340 .totalCount = count,
341 };
342
343 int64_t delayInSeconds =
344 startTimeInEpochSeconds - std::chrono::duration_cast<std::chrono::seconds>(
345 std::chrono::system_clock::now().time_since_epoch())
346 .count();
347 if (delayInSeconds < 0) {
348 delayInSeconds = 0;
349 }
350
351 printf("ScheduleTask called with client Id: %s, schedule Id: %s, delay: %" PRId64 " s\n",
352 clientId.c_str(), scheduleId.c_str(), delayInSeconds);
353
354 mLooper->sendMessageDelayed(sToNs(delayInSeconds), mTaskScheduleMsgHandler,
355 android::Message(scheduleMsgId));
356
357 return Status::OK;
358 }
359
getScheduleInfoLocked(int scheduleMsgId,ScheduleInfo ** outScheduleInfoPtr)360 bool ServiceImpl::getScheduleInfoLocked(int scheduleMsgId, ScheduleInfo** outScheduleInfoPtr) {
361 for (auto& [_, infoByScheduleId] : mInfoByScheduleIdByClientId) {
362 for (auto& [_, scheduleInfo] : infoByScheduleId) {
363 if (scheduleInfo.scheduleMsgId == scheduleMsgId) {
364 *outScheduleInfoPtr = &scheduleInfo;
365 return true;
366 }
367 }
368 }
369 return false;
370 }
371
handleAddTask(int scheduleMsgId)372 void ServiceImpl::handleAddTask(int scheduleMsgId) {
373 std::lock_guard<std::mutex> lockGuard(mLock);
374
375 ScheduleInfo* scheduleInfoPtr;
376 bool found = getScheduleInfoLocked(scheduleMsgId, &scheduleInfoPtr);
377 if (!found) {
378 printf("The schedule msg Id: %d is not found\n", scheduleMsgId);
379 return;
380 }
381
382 const GrpcScheduleInfo& grpcScheduleInfo = *scheduleInfoPtr->grpcScheduleInfo;
383 const std::string scheduleId = grpcScheduleInfo.scheduleid();
384 const std::string clientId = grpcScheduleInfo.clientid();
385 scheduleInfoPtr->currentCount++;
386 ScheduleTaskType taskType = grpcScheduleInfo.tasktype();
387 printf("Sending scheduled tasks for scheduleId: %s, clientId: %s, taskCount: %d, "
388 "taskType: %d\n",
389 scheduleId.c_str(), clientId.c_str(), scheduleInfoPtr->currentCount,
390 static_cast<int>(taskType));
391
392 if (taskType == ScheduleTaskType::ENTER_GARAGE_MODE) {
393 if (mWakeupRequired) {
394 wakeupApplicationProcessor(BOOTUP_REASON_SYSTEM_ENTER_GARAGE_MODE);
395 } else {
396 printf("Ignore ENTER_GARAGE_MODE task type because the head unit is already running");
397 }
398 } else if (grpcScheduleInfo.tasktype() == ScheduleTaskType::CUSTOM) {
399 GetRemoteTasksResponse injectResponse;
400 injectResponse.set_data(grpcScheduleInfo.data().data(), grpcScheduleInfo.data().size());
401 injectResponse.set_clientid(clientId);
402 injectTaskResponse(injectResponse);
403 } else {
404 printf("Unknown task type: %d\n", static_cast<int>(taskType));
405 }
406
407 if (scheduleInfoPtr->totalCount != 0 &&
408 scheduleInfoPtr->currentCount == scheduleInfoPtr->totalCount) {
409 // This schedule is finished.
410 cleanupScheduledTaskLocked(clientId, scheduleId);
411 return;
412 }
413
414 // Schedule the task for the next period.
415 mLooper->sendMessageDelayed(sToNs(scheduleInfoPtr->periodicInSeconds), mTaskScheduleMsgHandler,
416 android::Message(scheduleMsgId));
417 }
418
UnscheduleTask(ServerContext * context,const UnscheduleTaskRequest * request,UnscheduleTaskResponse * response)419 Status ServiceImpl::UnscheduleTask(ServerContext* context, const UnscheduleTaskRequest* request,
420 UnscheduleTaskResponse* response) {
421 std::lock_guard<std::mutex> lockGuard(mLock);
422
423 const std::string& clientId = request->clientid();
424 const std::string& scheduleId = request->scheduleid();
425 printf("UnscheduleTask called with client Id: %s, schedule Id: %s\n", clientId.c_str(),
426 scheduleId.c_str());
427
428 if (mInfoByScheduleIdByClientId.find(clientId) == mInfoByScheduleIdByClientId.end() ||
429 mInfoByScheduleIdByClientId[clientId].find(scheduleId) ==
430 mInfoByScheduleIdByClientId[clientId].end()) {
431 printf("UnscheduleTask: no task associated with clientId: %s, scheduleId: %s\n",
432 clientId.c_str(), scheduleId.c_str());
433 return Status::OK;
434 }
435
436 mLooper->removeMessages(mTaskScheduleMsgHandler,
437 mInfoByScheduleIdByClientId[clientId][scheduleId].scheduleMsgId);
438 cleanupScheduledTaskLocked(clientId, scheduleId);
439 return Status::OK;
440 }
441
UnscheduleAllTasks(ServerContext * context,const UnscheduleAllTasksRequest * request,UnscheduleAllTasksResponse * response)442 Status ServiceImpl::UnscheduleAllTasks(ServerContext* context,
443 const UnscheduleAllTasksRequest* request,
444 UnscheduleAllTasksResponse* response) {
445 std::lock_guard<std::mutex> lockGuard(mLock);
446
447 const std::string& clientId = request->clientid();
448 printf("UnscheduleAllTasks called with client Id: %s\n", clientId.c_str());
449 if (mInfoByScheduleIdByClientId.find(clientId) == mInfoByScheduleIdByClientId.end()) {
450 printf("UnscheduleTask: no task associated with clientId: %s\n", clientId.c_str());
451 return Status::OK;
452 }
453 const auto& infoByScheduleId = mInfoByScheduleIdByClientId[clientId];
454 std::vector<int> scheduleMsgIds;
455 for (const auto& [_, scheduleInfo] : infoByScheduleId) {
456 mLooper->removeMessages(mTaskScheduleMsgHandler, /*what=*/scheduleInfo.scheduleMsgId);
457 }
458
459 mInfoByScheduleIdByClientId.erase(clientId);
460 return Status::OK;
461 }
462
IsTaskScheduled(ServerContext * context,const IsTaskScheduledRequest * request,IsTaskScheduledResponse * response)463 Status ServiceImpl::IsTaskScheduled(ServerContext* context, const IsTaskScheduledRequest* request,
464 IsTaskScheduledResponse* response) {
465 std::lock_guard<std::mutex> lockGuard(mLock);
466
467 const std::string& clientId = request->clientid();
468 const std::string& scheduleId = request->scheduleid();
469 printf("IsTaskScheduled called with client Id: %s, scheduleId: %s\n", clientId.c_str(),
470 scheduleId.c_str());
471
472 if (mInfoByScheduleIdByClientId.find(clientId) == mInfoByScheduleIdByClientId.end()) {
473 response->set_istaskscheduled(false);
474 return Status::OK;
475 }
476 if (mInfoByScheduleIdByClientId[clientId].find(scheduleId) ==
477 mInfoByScheduleIdByClientId[clientId].end()) {
478 response->set_istaskscheduled(false);
479 return Status::OK;
480 }
481 response->set_istaskscheduled(true);
482 return Status::OK;
483 }
484
GetAllPendingScheduledTasks(ServerContext * context,const GetAllPendingScheduledTasksRequest * request,GetAllPendingScheduledTasksResponse * response)485 Status ServiceImpl::GetAllPendingScheduledTasks(ServerContext* context,
486 const GetAllPendingScheduledTasksRequest* request,
487 GetAllPendingScheduledTasksResponse* response) {
488 const std::string& clientId = request->clientid();
489 printf("GetAllPendingScheduledTasks called with client Id: %s\n", clientId.c_str());
490 response->clear_allscheduledtasks();
491 {
492 std::unique_lock lk(mLock);
493 if (mInfoByScheduleIdByClientId.find(clientId) == mInfoByScheduleIdByClientId.end()) {
494 return Status::OK;
495 }
496 for (const auto& [_, scheduleInfo] : mInfoByScheduleIdByClientId[clientId]) {
497 (*response->add_allscheduledtasks()) = *scheduleInfo.grpcScheduleInfo;
498 }
499 }
500 return Status::OK;
501 }
502
IsVehicleInUse(ServerContext * context,const IsVehicleInUseRequest * request,IsVehicleInUseResponse * response)503 Status ServiceImpl::IsVehicleInUse(ServerContext* context, const IsVehicleInUseRequest* request,
504 IsVehicleInUseResponse* response) {
505 response->set_isvehicleinuse(mVehicleInUse);
506 return Status::OK;
507 }
508
GetApPowerBootupReason(ServerContext * context,const GetApPowerBootupReasonRequest * request,GetApPowerBootupReasonResponse * response)509 Status ServiceImpl::GetApPowerBootupReason(ServerContext* context,
510 const GetApPowerBootupReasonRequest* request,
511 GetApPowerBootupReasonResponse* response) {
512 response->set_bootupreason(mBootupReason);
513 return Status::OK;
514 }
515
isWakeupRequired()516 bool ServiceImpl::isWakeupRequired() {
517 return mWakeupRequired;
518 }
519
isRemoteTaskConnectionAlive()520 bool ServiceImpl::isRemoteTaskConnectionAlive() {
521 return mRemoteTaskConnectionAlive;
522 }
523
setVehicleInUse(bool vehicleInUse)524 void ServiceImpl::setVehicleInUse(bool vehicleInUse) {
525 mVehicleInUse = vehicleInUse;
526 }
527
setBootupReason(int32_t bootupReason)528 void ServiceImpl::setBootupReason(int32_t bootupReason) {
529 mBootupReason = bootupReason;
530 }
531
532 } // namespace remoteaccess
533 } // namespace automotive
534 } // namespace hardware
535 } // namespace android
536