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