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 #pragma once
18 
19 #include <android-base/thread_annotations.h>
20 #include <utils/Looper.h>
21 #include <wakeup_client.grpc.pb.h>
22 #include <condition_variable>
23 #include <mutex>
24 #include <queue>
25 #include <string>
26 #include <thread>
27 
28 namespace android {
29 namespace hardware {
30 namespace automotive {
31 namespace remoteaccess {
32 
33 // The following are the same as VehicleApPowerBootupReason defined in VHAL.
34 constexpr int32_t BOOTUP_REASON_USER_POWER_ON = 0;
35 constexpr int32_t BOOTUP_REASON_SYSTEM_REMOTE_ACCESS = 2;
36 constexpr int32_t BOOTUP_REASON_SYSTEM_ENTER_GARAGE_MODE = 3;
37 
38 // A class to generate fake task for testing. Not required for real implementation. In real
39 // implementation, the task should come from remote task server. This class is thread-safe.
40 class FakeTaskGenerator final {
41   public:
42     GetRemoteTasksResponse generateTask(const std::string& clientId);
43 
44   private:
45     constexpr static uint8_t DATA[] = {0xde, 0xad, 0xbe, 0xef};
46 };
47 
48 struct TaskInfo {
49     // This is unique per-task. Note that a task might be popped and put back into the task queue,
50     // it will have a new task ID but the same clientId in the task data.
51     int taskId;
52     int64_t timestampInMs;
53     GetRemoteTasksResponse taskData;
54 };
55 
56 struct TaskInfoComparator {
57     // We want the smallest timestamp and smallest task ID on top.
operatorTaskInfoComparator58     bool operator()(const TaskInfo& l, const TaskInfo& r) {
59         return l.timestampInMs > r.timestampInMs ||
60                (l.timestampInMs == r.timestampInMs && l.taskId > r.taskId);
61     }
62 };
63 
64 // forward-declaration.
65 class TaskQueue;
66 
67 class TaskTimeoutMessageHandler final : public android::MessageHandler {
68   public:
69     TaskTimeoutMessageHandler(TaskQueue* taskQueue);
70     void handleMessage(const android::Message& message) override;
71 
72   private:
73     TaskQueue* mTaskQueue;
74 };
75 
76 // TaskQueue is thread-safe.
77 class TaskQueue final {
78   public:
79     TaskQueue(android::sp<Looper> looper);
80 
81     void add(const GetRemoteTasksResponse& response);
82     std::optional<GetRemoteTasksResponse> maybePopOne();
83     void waitForTask();
84     void stopWait();
85     bool isEmpty();
86     bool isStopped();
87 
88   private:
89     friend class TaskTimeoutMessageHandler;
90 
91     std::mutex mLock;
92     std::priority_queue<TaskInfo, std::vector<TaskInfo>, TaskInfoComparator> mTasks
93             GUARDED_BY(mLock);
94     // A variable to notify mTasks is not empty.
95     std::condition_variable mTasksNotEmptyCv;
96     std::atomic<bool> mStopped = false;
97     android::sp<Looper> mLooper;
98     android::sp<TaskTimeoutMessageHandler> mTaskTimeoutMessageHandler;
99     std::atomic<int> mTaskIdCounter = 0;
100 
101     void loop();
102     void handleTaskTimeout();
103 };
104 
105 // forward-declaration
106 class ServiceImpl;
107 
108 class TaskScheduleMsgHandler final : public android::MessageHandler {
109   public:
110     TaskScheduleMsgHandler(ServiceImpl* impl);
111     void handleMessage(const android::Message& message) override;
112 
113   private:
114     ServiceImpl* mImpl;
115 };
116 
117 class ServiceImpl {
118   public:
119     ServiceImpl();
120 
121     virtual ~ServiceImpl() = 0;
122 
123     // Stop the handling for all income requests. Prepare for shutdown.
124     void stopServer();
125 
126     grpc::Status GetRemoteTasks(grpc::ServerContext* context, const GetRemoteTasksRequest* request,
127                                 grpc::ServerWriter<GetRemoteTasksResponse>* writer);
128 
129     grpc::Status NotifyWakeupRequired(grpc::ServerContext* context,
130                                       const NotifyWakeupRequiredRequest* request,
131                                       NotifyWakeupRequiredResponse* response);
132 
133     grpc::Status ScheduleTask(grpc::ServerContext* context, const ScheduleTaskRequest* request,
134                               ScheduleTaskResponse* response);
135 
136     grpc::Status UnscheduleTask(grpc::ServerContext* context, const UnscheduleTaskRequest* request,
137                                 UnscheduleTaskResponse* response);
138 
139     grpc::Status UnscheduleAllTasks(grpc::ServerContext* context,
140                                     const UnscheduleAllTasksRequest* request,
141                                     UnscheduleAllTasksResponse* response);
142 
143     grpc::Status IsTaskScheduled(grpc::ServerContext* context,
144                                  const IsTaskScheduledRequest* request,
145                                  IsTaskScheduledResponse* response);
146 
147     grpc::Status GetAllPendingScheduledTasks(grpc::ServerContext* context,
148                                              const GetAllPendingScheduledTasksRequest* request,
149                                              GetAllPendingScheduledTasksResponse* response);
150 
151     grpc::Status IsVehicleInUse(grpc::ServerContext* context, const IsVehicleInUseRequest* request,
152                                 IsVehicleInUseResponse* response);
153 
154     grpc::Status GetApPowerBootupReason(grpc::ServerContext* context,
155                                         const GetApPowerBootupReasonRequest* request,
156                                         GetApPowerBootupReasonResponse* response);
157 
158     /**
159      * Starts generating fake tasks for the specific client repeatedly.
160      *
161      * The fake task will have {0xDE 0xAD 0xBE 0xEF} as payload. A new fake task will be sent
162      * to the client every 5s.
163      */
164     void startGeneratingFakeTask(const std::string& clientId);
165 
166     /**
167      * stops generating fake tasks.
168      */
169     void stopGeneratingFakeTask();
170 
171     /**
172      * Returns whether we need to wakeup the target device to send remote tasks.
173      */
174     bool isWakeupRequired();
175 
176     /**
177      * Returns whether we have an active connection with the target device.
178      */
179     bool isRemoteTaskConnectionAlive();
180 
181     /**
182      * Injects a fake task with taskData to be sent to the specific client.
183      */
184     void injectTask(const std::string& taskData, const std::string& clientId);
185 
186     /**
187      * Wakes up the target device.
188      *
189      * This must be implemented by child class and contains device specific logic. E.g. this might
190      * be sending QEMU commands for the emulator device.
191      */
192     virtual void wakeupApplicationProcessor(int32_t bootupReason) = 0;
193 
194     /**
195      * Cleans up a scheduled task info.
196      */
197     void cleanupScheduledTaskLocked(const std::string& clientId, const std::string& scheduleId)
198             REQUIRES(mLock);
199 
200     /**
201      * Sets whether vehicle is in use.
202      */
203     void setVehicleInUse(bool vehicleInUse);
204 
205     /**
206      * Sets the bootup reason.
207      */
208     void setBootupReason(int32_t bootupReason);
209 
210   private:
211     friend class TaskScheduleMsgHandler;
212 
213     struct ScheduleInfo {
214         std::unique_ptr<GrpcScheduleInfo> grpcScheduleInfo;
215         // This is a unique ID to represent this schedule. Each repeated tasks will have different
216         // task ID but will have the same scheduleMsgId so that we can use to unschedule. This has
217         // to be an int so we cannot use the scheduleId provided by the client.
218         int scheduleMsgId;
219         int64_t periodicInSeconds;
220         int32_t currentCount;
221         int32_t totalCount;
222     };
223 
224     std::atomic<int> mScheduleMsgCounter = 0;
225     // This is a looper for scheduling tasks to be executed in the future.
226     android::sp<Looper> mLooper;
227     android::sp<TaskScheduleMsgHandler> mTaskScheduleMsgHandler;
228     // This is a thread for generating fake tasks.
229     std::thread mFakeTaskThread;
230     // This is a thread for the looper.
231     std::thread mLooperThread;
232     // A variable to notify server is stopping.
233     std::condition_variable mTaskLoopStoppedCv;
234     // Whether wakeup AP is required for executing tasks.
235     std::atomic<bool> mWakeupRequired = true;
236     // Whether we currently have an active long-live connection to deliver remote tasks.
237     std::atomic<bool> mRemoteTaskConnectionAlive = false;
238     std::mutex mLock;
239     bool mGeneratingFakeTask GUARDED_BY(mLock);
240     std::atomic<bool> mServerStopped = false;
241     std::unordered_map<std::string, std::unordered_map<std::string, ScheduleInfo>>
242             mInfoByScheduleIdByClientId GUARDED_BY(mLock);
243     std::atomic<bool> mVehicleInUse = false;
244     std::atomic<int32_t> mBootupReason = BOOTUP_REASON_USER_POWER_ON;
245 
246     // Thread-safe. For test impl only.
247     FakeTaskGenerator mFakeTaskGenerator;
248     // Thread-safe.
249     std::unique_ptr<TaskQueue> mTaskQueue;
250 
251     void fakeTaskGenerateLoop(const std::string& clientId);
252     void injectTaskResponse(const GetRemoteTasksResponse& response);
253     bool getScheduleInfoLocked(int scheduleMsgId, ScheduleInfo** outScheduleInfoPtr)
254             REQUIRES(mLock);
255     void handleAddTask(int scheduleMsgId);
256     void loop();
257 };
258 
259 class WakeupClientServiceImpl : public WakeupClient::Service {
260   public:
WakeupClientServiceImpl(ServiceImpl * impl)261     WakeupClientServiceImpl(ServiceImpl* impl) { mImpl = impl; }
262 
GetRemoteTasks(grpc::ServerContext * context,const GetRemoteTasksRequest * request,grpc::ServerWriter<GetRemoteTasksResponse> * writer)263     grpc::Status GetRemoteTasks(grpc::ServerContext* context, const GetRemoteTasksRequest* request,
264                                 grpc::ServerWriter<GetRemoteTasksResponse>* writer) override {
265         return mImpl->GetRemoteTasks(context, request, writer);
266     }
267 
NotifyWakeupRequired(grpc::ServerContext * context,const NotifyWakeupRequiredRequest * request,NotifyWakeupRequiredResponse * response)268     grpc::Status NotifyWakeupRequired(grpc::ServerContext* context,
269                                       const NotifyWakeupRequiredRequest* request,
270                                       NotifyWakeupRequiredResponse* response) override {
271         return mImpl->NotifyWakeupRequired(context, request, response);
272     }
273 
ScheduleTask(grpc::ServerContext * context,const ScheduleTaskRequest * request,ScheduleTaskResponse * response)274     grpc::Status ScheduleTask(grpc::ServerContext* context, const ScheduleTaskRequest* request,
275                               ScheduleTaskResponse* response) override {
276         return mImpl->ScheduleTask(context, request, response);
277     }
278 
UnscheduleTask(grpc::ServerContext * context,const UnscheduleTaskRequest * request,UnscheduleTaskResponse * response)279     grpc::Status UnscheduleTask(grpc::ServerContext* context, const UnscheduleTaskRequest* request,
280                                 UnscheduleTaskResponse* response) override {
281         return mImpl->UnscheduleTask(context, request, response);
282     }
283 
UnscheduleAllTasks(grpc::ServerContext * context,const UnscheduleAllTasksRequest * request,UnscheduleAllTasksResponse * response)284     grpc::Status UnscheduleAllTasks(grpc::ServerContext* context,
285                                     const UnscheduleAllTasksRequest* request,
286                                     UnscheduleAllTasksResponse* response) override {
287         return mImpl->UnscheduleAllTasks(context, request, response);
288     }
289 
IsTaskScheduled(grpc::ServerContext * context,const IsTaskScheduledRequest * request,IsTaskScheduledResponse * response)290     grpc::Status IsTaskScheduled(grpc::ServerContext* context,
291                                  const IsTaskScheduledRequest* request,
292                                  IsTaskScheduledResponse* response) override {
293         return mImpl->IsTaskScheduled(context, request, response);
294     }
295 
GetAllPendingScheduledTasks(grpc::ServerContext * context,const GetAllPendingScheduledTasksRequest * request,GetAllPendingScheduledTasksResponse * response)296     grpc::Status GetAllPendingScheduledTasks(
297             grpc::ServerContext* context, const GetAllPendingScheduledTasksRequest* request,
298             GetAllPendingScheduledTasksResponse* response) override {
299         return mImpl->GetAllPendingScheduledTasks(context, request, response);
300     }
301 
302   private:
303     ServiceImpl* mImpl;
304 };
305 
306 class PowerControllerServiceImpl : public PowerController::Service {
307   public:
PowerControllerServiceImpl(ServiceImpl * impl)308     PowerControllerServiceImpl(ServiceImpl* impl) { mImpl = impl; }
309 
IsVehicleInUse(grpc::ServerContext * context,const IsVehicleInUseRequest * request,IsVehicleInUseResponse * response)310     grpc::Status IsVehicleInUse(grpc::ServerContext* context, const IsVehicleInUseRequest* request,
311                                 IsVehicleInUseResponse* response) override {
312         return mImpl->IsVehicleInUse(context, request, response);
313     }
314 
GetApPowerBootupReason(grpc::ServerContext * context,const GetApPowerBootupReasonRequest * request,GetApPowerBootupReasonResponse * response)315     grpc::Status GetApPowerBootupReason(grpc::ServerContext* context,
316                                         const GetApPowerBootupReasonRequest* request,
317                                         GetApPowerBootupReasonResponse* response) override {
318         return mImpl->GetApPowerBootupReason(context, request, response);
319     }
320 
321   private:
322     ServiceImpl* mImpl;
323 };
324 
325 }  // namespace remoteaccess
326 }  // namespace automotive
327 }  // namespace hardware
328 }  // namespace android
329