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 "RemoteAccessService.h"
18 
19 #include <VehicleUtils.h>
20 #include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h>
21 #include <android-base/parseint.h>
22 #include <android-base/stringprintf.h>
23 #include <android/binder_status.h>
24 #include <grpc++/grpc++.h>
25 #include <private/android_filesystem_config.h>
26 #include <sys/stat.h>
27 #include <utils/Log.h>
28 #include <chrono>
29 #include <fstream>
30 #include <iostream>
31 #include <thread>
32 
33 namespace android {
34 namespace hardware {
35 namespace automotive {
36 namespace remoteaccess {
37 
38 namespace {
39 
40 using ::aidl::android::hardware::automotive::remoteaccess::ApState;
41 using ::aidl::android::hardware::automotive::remoteaccess::IRemoteTaskCallback;
42 using ::aidl::android::hardware::automotive::remoteaccess::ScheduleInfo;
43 using ::aidl::android::hardware::automotive::remoteaccess::TaskType;
44 using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
45 using ::android::base::Error;
46 using ::android::base::ParseInt;
47 using ::android::base::Result;
48 using ::android::base::ScopedLockAssertion;
49 using ::android::base::StringAppendF;
50 using ::android::base::StringPrintf;
51 using ::android::frameworks::automotive::vhal::IVhalClient;
52 using ::android::hardware::automotive::vehicle::toInt;
53 using ::grpc::ClientContext;
54 using ::grpc::ClientReaderInterface;
55 using ::grpc::Status;
56 using ::grpc::StatusCode;
57 using ::ndk::ScopedAStatus;
58 
59 const std::string WAKEUP_SERVICE_NAME = "com.google.vehicle.wakeup";
60 const std::string PROCESSOR_ID = "application_processor";
61 constexpr char COMMAND_SET_AP_STATE[] = "--set-ap-state";
62 constexpr char COMMAND_START_DEBUG_CALLBACK[] = "--start-debug-callback";
63 constexpr char COMMAND_STOP_DEBUG_CALLBACK[] = "--stop-debug-callback";
64 constexpr char COMMAND_SHOW_TASK[] = "--show-task";
65 constexpr char COMMAND_GET_VEHICLE_ID[] = "--get-vehicle-id";
66 constexpr char COMMAND_INJECT_TASK[] = "--inject-task";
67 constexpr char COMMAND_INJECT_TASK_NEXT_REBOOT[] = "--inject-task-next-reboot";
68 constexpr char COMMAND_STATUS[] = "--status";
69 
70 constexpr char DEBUG_TASK_FILE[] = "/data/vendor/remoteaccess/debugTask";
71 
stringToBytes(std::string_view s)72 std::vector<uint8_t> stringToBytes(std::string_view s) {
73     const char* data = s.data();
74     return std::vector<uint8_t>(data, data + s.size());
75 }
76 
rpcStatusToScopedAStatus(const Status & status,const std::string & errorMsg)77 ScopedAStatus rpcStatusToScopedAStatus(const Status& status, const std::string& errorMsg) {
78     return ScopedAStatus::fromServiceSpecificErrorWithMessage(
79             status.error_code(), (errorMsg + ", error: " + status.error_message()).c_str());
80 }
81 
printBytes(const std::vector<uint8_t> & bytes)82 std::string printBytes(const std::vector<uint8_t>& bytes) {
83     std::string s;
84     for (size_t i = 0; i < bytes.size(); i++) {
85         StringAppendF(&s, "%02x", bytes[i]);
86     }
87     return s;
88 }
89 
checkBoolFlag(const char * flag)90 bool checkBoolFlag(const char* flag) {
91     return !strcmp(flag, "1") || !strcmp(flag, "0");
92 }
93 
dprintErrorStatus(int fd,const char * detail,const ScopedAStatus & status)94 void dprintErrorStatus(int fd, const char* detail, const ScopedAStatus& status) {
95     dprintf(fd, "%s, code: %d, error: %s\n", detail, status.getStatus(), status.getMessage());
96 }
97 
boolToString(bool x)98 std::string boolToString(bool x) {
99     return x ? "true" : "false";
100 }
101 
102 }  // namespace
103 
RemoteAccessService(WakeupClient::StubInterface * grpcStub)104 RemoteAccessService::RemoteAccessService(WakeupClient::StubInterface* grpcStub)
105     : mGrpcStub(grpcStub) {
106     if (mGrpcStub != nullptr) {
107         mGrpcServerExist = true;
108     }
109 
110     std::ifstream debugTaskFile;
111     debugTaskFile.open(DEBUG_TASK_FILE, std::ios::in);
112     if (!debugTaskFile.is_open()) {
113         ALOGD("No debug task available");
114         return;
115     }
116 
117     char buffer[1024] = {};
118     debugTaskFile.getline(buffer, sizeof(buffer));
119     std::string clientId = std::string(buffer);
120     debugTaskFile.getline(buffer, sizeof(buffer));
121     std::string taskData = std::string(buffer);
122     int latencyInSec;
123     debugTaskFile >> latencyInSec;
124     debugTaskFile.close();
125 
126     ALOGD("Task for client: %s, data: [%s], latency: %d\n", clientId.c_str(), taskData.c_str(),
127           latencyInSec);
128 
129     mInjectDebugTaskThread = std::thread([this, clientId, taskData, latencyInSec] {
130         std::this_thread::sleep_for(std::chrono::seconds(latencyInSec));
131         if (auto result = deliverRemoteTaskThroughCallback(clientId, taskData); !result.ok()) {
132             ALOGE("Failed to inject debug task, clientID: %s, taskData: %s, error: %s",
133                   clientId.c_str(), taskData.c_str(), result.error().message().c_str());
134             return;
135         }
136         ALOGD("Task for client: %s, data: [%s] successfully injected\n", clientId.c_str(),
137               taskData.c_str());
138     });
139 }
140 
~RemoteAccessService()141 RemoteAccessService::~RemoteAccessService() {
142     maybeStopTaskLoop();
143     if (mInjectDebugTaskThread.joinable()) {
144         mInjectDebugTaskThread.join();
145     }
146 }
147 
maybeStartTaskLoop()148 void RemoteAccessService::maybeStartTaskLoop() {
149     std::lock_guard<std::mutex> lockGuard(mStartStopTaskLoopLock);
150     if (mTaskLoopRunning) {
151         return;
152     }
153 
154     mThread = std::thread([this]() { runTaskLoop(); });
155 
156     mTaskLoopRunning = true;
157 }
158 
maybeStopTaskLoop()159 void RemoteAccessService::maybeStopTaskLoop() {
160     std::lock_guard<std::mutex> lockGuard(mStartStopTaskLoopLock);
161     if (!mTaskLoopRunning) {
162         return;
163     }
164 
165     {
166         std::lock_guard<std::mutex> lockGuard(mLock);
167         // Try to stop the reading stream.
168         if (mGetRemoteTasksContext) {
169             mGetRemoteTasksContext->TryCancel();
170             // Don't reset mGetRemoteTaskContext here since the read stream might still be affective
171             // and might still be using it. This will cause reader->Read to return false and
172             // mGetRemoteTasksContext will be cleared after reader->Finish() is called.
173         }
174         mTaskWaitStopped = true;
175         mCv.notify_all();
176     }
177     if (mThread.joinable()) {
178         mThread.join();
179     }
180 
181     mTaskLoopRunning = false;
182 }
183 
updateGrpcReadChannelOpen(bool grpcReadChannelOpen)184 void RemoteAccessService::updateGrpcReadChannelOpen(bool grpcReadChannelOpen) {
185     std::lock_guard<std::mutex> lockGuard(mLock);
186     mGrpcReadChannelOpen = grpcReadChannelOpen;
187 }
188 
deliverRemoteTaskThroughCallback(const std::string & clientId,std::string_view taskData)189 Result<void> RemoteAccessService::deliverRemoteTaskThroughCallback(const std::string& clientId,
190                                                                    std::string_view taskData) {
191     std::shared_ptr<IRemoteTaskCallback> callback;
192     {
193         std::lock_guard<std::mutex> lockGuard(mLock);
194         callback = mRemoteTaskCallback;
195         mClientIdToTaskCount[clientId] += 1;
196     }
197     if (callback == nullptr) {
198         return Error() << "No callback registered, task ignored";
199     }
200     ALOGD("Calling onRemoteTaskRequested callback for client ID: %s", clientId.c_str());
201     ScopedAStatus callbackStatus =
202             callback->onRemoteTaskRequested(clientId, stringToBytes(taskData));
203     if (!callbackStatus.isOk()) {
204         return Error() << "Failed to call onRemoteTaskRequested callback, status: "
205                        << callbackStatus.getStatus()
206                        << ", message: " << callbackStatus.getMessage();
207     }
208     return {};
209 }
210 
runTaskLoop()211 void RemoteAccessService::runTaskLoop() {
212     GetRemoteTasksRequest request = {};
213     std::unique_ptr<ClientReaderInterface<GetRemoteTasksResponse>> reader;
214     while (true) {
215         {
216             std::lock_guard<std::mutex> lockGuard(mLock);
217             mGetRemoteTasksContext.reset(new ClientContext());
218             reader = mGrpcStub->GetRemoteTasks(mGetRemoteTasksContext.get(), request);
219         }
220         updateGrpcReadChannelOpen(true);
221         GetRemoteTasksResponse response;
222         while (reader->Read(&response)) {
223             ALOGI("Receiving one task from remote task client");
224 
225             if (auto result =
226                         deliverRemoteTaskThroughCallback(response.clientid(), response.data());
227                 !result.ok()) {
228                 ALOGE("%s", result.error().message().c_str());
229                 continue;
230             }
231         }
232         updateGrpcReadChannelOpen(false);
233         Status status = reader->Finish();
234         mGetRemoteTasksContext.reset();
235 
236         ALOGE("GetRemoteTasks stream breaks, code: %d, message: %s, sleeping for 10s and retry",
237               status.error_code(), status.error_message().c_str());
238         // The long lasting connection should not return. But if the server returns, retry after
239         // 10s.
240         {
241             std::unique_lock lk(mLock);
242             if (mCv.wait_for(lk, std::chrono::milliseconds(mRetryWaitInMs), [this] {
243                     ScopedLockAssertion lockAssertion(mLock);
244                     return mTaskWaitStopped;
245                 })) {
246                 // If the stopped flag is set, we are quitting, exit the loop.
247                 break;
248             }
249         }
250     }
251 }
252 
getVehicleId(std::string * vehicleId)253 ScopedAStatus RemoteAccessService::getVehicleId(std::string* vehicleId) {
254 #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
255     auto vhalClient = IVhalClient::tryCreate();
256     if (vhalClient == nullptr) {
257         ALOGE("Failed to connect to VHAL");
258         return ScopedAStatus::fromServiceSpecificErrorWithMessage(
259                 /*errorCode=*/0, "Failed to connect to VHAL to get vehicle ID");
260     }
261     return getVehicleIdWithClient(*vhalClient.get(), vehicleId);
262 #else
263     // Don't use VHAL client in fuzzing since IPC is not allowed.
264     return ScopedAStatus::ok();
265 #endif
266 }
267 
getVehicleIdWithClient(IVhalClient & vhalClient,std::string * vehicleId)268 ScopedAStatus RemoteAccessService::getVehicleIdWithClient(IVhalClient& vhalClient,
269                                                           std::string* vehicleId) {
270     auto result = vhalClient.getValueSync(
271             *vhalClient.createHalPropValue(toInt(VehicleProperty::INFO_VIN)));
272     if (!result.ok()) {
273         return ScopedAStatus::fromServiceSpecificErrorWithMessage(
274                 /*errorCode=*/0,
275                 ("failed to get INFO_VIN from VHAL: " + result.error().message()).c_str());
276     }
277     *vehicleId = (*result)->getStringValue();
278     return ScopedAStatus::ok();
279 }
280 
getProcessorId(std::string * processorId)281 ScopedAStatus RemoteAccessService::getProcessorId(std::string* processorId) {
282     *processorId = PROCESSOR_ID;
283     return ScopedAStatus::ok();
284 }
285 
getWakeupServiceName(std::string * wakeupServiceName)286 ScopedAStatus RemoteAccessService::getWakeupServiceName(std::string* wakeupServiceName) {
287     *wakeupServiceName = WAKEUP_SERVICE_NAME;
288     return ScopedAStatus::ok();
289 }
290 
setRemoteTaskCallback(const std::shared_ptr<IRemoteTaskCallback> & callback)291 ScopedAStatus RemoteAccessService::setRemoteTaskCallback(
292         const std::shared_ptr<IRemoteTaskCallback>& callback) {
293     std::lock_guard<std::mutex> lockGuard(mLock);
294     mRemoteTaskCallback = callback;
295     return ScopedAStatus::ok();
296 }
297 
clearRemoteTaskCallback()298 ScopedAStatus RemoteAccessService::clearRemoteTaskCallback() {
299     std::lock_guard<std::mutex> lockGuard(mLock);
300     mRemoteTaskCallback.reset();
301     return ScopedAStatus::ok();
302 }
303 
notifyApStateChange(const ApState & newState)304 ScopedAStatus RemoteAccessService::notifyApStateChange(const ApState& newState) {
305     if (!mGrpcServerExist) {
306         ALOGW("GRPC server does not exist, do nothing");
307         return ScopedAStatus::ok();
308     }
309 
310     ClientContext context;
311     NotifyWakeupRequiredRequest request = {};
312     request.set_iswakeuprequired(newState.isWakeupRequired);
313     NotifyWakeupRequiredResponse response = {};
314     Status status = mGrpcStub->NotifyWakeupRequired(&context, request, &response);
315     if (!status.ok()) {
316         return rpcStatusToScopedAStatus(status, "Failed to notify isWakeupRequired");
317     }
318 
319     if (newState.isReadyForRemoteTask) {
320         maybeStartTaskLoop();
321     } else {
322         maybeStopTaskLoop();
323     }
324     return ScopedAStatus::ok();
325 }
326 
isTaskScheduleSupported()327 bool RemoteAccessService::isTaskScheduleSupported() {
328     if (!mGrpcServerExist) {
329         ALOGW("GRPC server does not exist, task scheduling not supported");
330         return false;
331     }
332 
333     return true;
334 }
335 
isTaskScheduleSupported(bool * out)336 ScopedAStatus RemoteAccessService::isTaskScheduleSupported(bool* out) {
337     *out = isTaskScheduleSupported();
338     return ScopedAStatus::ok();
339 }
340 
getSupportedTaskTypesForScheduling(std::vector<TaskType> * out)341 ndk::ScopedAStatus RemoteAccessService::getSupportedTaskTypesForScheduling(
342         std::vector<TaskType>* out) {
343     out->clear();
344     if (!isTaskScheduleSupported()) {
345         ALOGW("Task scheduleing is not supported, return empty task types");
346         return ScopedAStatus::ok();
347     }
348 
349     out->push_back(TaskType::CUSTOM);
350     out->push_back(TaskType::ENTER_GARAGE_MODE);
351     return ScopedAStatus::ok();
352 }
353 
scheduleTask(const ScheduleInfo & scheduleInfo)354 ScopedAStatus RemoteAccessService::scheduleTask(const ScheduleInfo& scheduleInfo) {
355     if (!isTaskScheduleSupported()) {
356         ALOGW("Task scheduleing is not supported, return exception");
357         return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
358                                                            "task scheduling is not supported");
359     }
360 
361     ClientContext context;
362     ScheduleTaskRequest request = {};
363     ScheduleTaskResponse response = {};
364 
365     if (scheduleInfo.count < 0) {
366         return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
367                                                            "count must be >= 0");
368     }
369     if (scheduleInfo.startTimeInEpochSeconds < 0) {
370         return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
371                                                            "startTimeInEpochSeconds must be >= 0");
372     }
373     if (scheduleInfo.periodicInSeconds < 0) {
374         return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
375                                                            "periodicInSeconds must be >= 0");
376     }
377     if (scheduleInfo.taskData.size() > scheduleInfo.MAX_TASK_DATA_SIZE_IN_BYTES) {
378         return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
379                                                            "task data too big");
380     }
381 
382     request.mutable_scheduleinfo()->set_clientid(scheduleInfo.clientId);
383     request.mutable_scheduleinfo()->set_tasktype(
384             static_cast<ScheduleTaskType>(scheduleInfo.taskType));
385     request.mutable_scheduleinfo()->set_scheduleid(scheduleInfo.scheduleId);
386     request.mutable_scheduleinfo()->set_data(scheduleInfo.taskData.data(),
387                                              scheduleInfo.taskData.size());
388     request.mutable_scheduleinfo()->set_count(scheduleInfo.count);
389     request.mutable_scheduleinfo()->set_starttimeinepochseconds(
390             scheduleInfo.startTimeInEpochSeconds);
391     request.mutable_scheduleinfo()->set_periodicinseconds(scheduleInfo.periodicInSeconds);
392     Status status = mGrpcStub->ScheduleTask(&context, request, &response);
393     if (!status.ok()) {
394         return rpcStatusToScopedAStatus(status, "Failed to call ScheduleTask");
395     }
396     int errorCode = response.errorcode();
397     switch (errorCode) {
398         case ErrorCode::OK:
399             return ScopedAStatus::ok();
400         case ErrorCode::INVALID_ARG:
401             return ScopedAStatus::fromExceptionCodeWithMessage(
402                     EX_ILLEGAL_ARGUMENT, "received invalid_arg from grpc server");
403         default:
404             // Should not happen.
405             return ScopedAStatus::fromServiceSpecificErrorWithMessage(
406                     -1, ("Got unknown error code: " + ErrorCode_Name(errorCode) +
407                          " from remote access HAL")
408                                 .c_str());
409     }
410 }
411 
unscheduleTask(const std::string & clientId,const std::string & scheduleId)412 ScopedAStatus RemoteAccessService::unscheduleTask(const std::string& clientId,
413                                                   const std::string& scheduleId) {
414     if (!isTaskScheduleSupported()) {
415         ALOGW("Task scheduleing is not supported, do nothing");
416         return ScopedAStatus::ok();
417     }
418 
419     ClientContext context;
420     UnscheduleTaskRequest request = {};
421     UnscheduleTaskResponse response = {};
422     request.set_clientid(clientId);
423     request.set_scheduleid(scheduleId);
424     Status status = mGrpcStub->UnscheduleTask(&context, request, &response);
425     if (!status.ok()) {
426         return rpcStatusToScopedAStatus(status, "Failed to call UnscheduleTask");
427     }
428     return ScopedAStatus::ok();
429 }
430 
unscheduleAllTasks(const std::string & clientId)431 ScopedAStatus RemoteAccessService::unscheduleAllTasks(const std::string& clientId) {
432     if (!isTaskScheduleSupported()) {
433         ALOGW("Task scheduleing is not supported, do nothing");
434         return ScopedAStatus::ok();
435     }
436 
437     ClientContext context;
438     UnscheduleAllTasksRequest request = {};
439     UnscheduleAllTasksResponse response = {};
440     request.set_clientid(clientId);
441     Status status = mGrpcStub->UnscheduleAllTasks(&context, request, &response);
442     if (!status.ok()) {
443         return rpcStatusToScopedAStatus(status, "Failed to call UnscheduleAllTasks");
444     }
445     return ScopedAStatus::ok();
446 }
447 
isTaskScheduled(const std::string & clientId,const std::string & scheduleId,bool * out)448 ScopedAStatus RemoteAccessService::isTaskScheduled(const std::string& clientId,
449                                                    const std::string& scheduleId, bool* out) {
450     if (!isTaskScheduleSupported()) {
451         ALOGW("Task scheduleing is not supported, return false");
452         *out = false;
453         return ScopedAStatus::ok();
454     }
455 
456     ClientContext context;
457     IsTaskScheduledRequest request = {};
458     IsTaskScheduledResponse response = {};
459     request.set_clientid(clientId);
460     request.set_scheduleid(scheduleId);
461     Status status = mGrpcStub->IsTaskScheduled(&context, request, &response);
462     if (!status.ok()) {
463         return rpcStatusToScopedAStatus(status, "Failed to call isTaskScheduled");
464     }
465     *out = response.istaskscheduled();
466     return ScopedAStatus::ok();
467 }
468 
getAllPendingScheduledTasks(const std::string & clientId,std::vector<ScheduleInfo> * out)469 ScopedAStatus RemoteAccessService::getAllPendingScheduledTasks(const std::string& clientId,
470                                                                std::vector<ScheduleInfo>* out) {
471     if (!isTaskScheduleSupported()) {
472         ALOGW("Task scheduleing is not supported, return empty array");
473         out->clear();
474         return ScopedAStatus::ok();
475     }
476 
477     ClientContext context;
478     GetAllPendingScheduledTasksRequest request = {};
479     GetAllPendingScheduledTasksResponse response = {};
480     request.set_clientid(clientId);
481     Status status = mGrpcStub->GetAllPendingScheduledTasks(&context, request, &response);
482     if (!status.ok()) {
483         return rpcStatusToScopedAStatus(status, "Failed to call isTaskScheduled");
484     }
485     out->clear();
486     for (int i = 0; i < response.allscheduledtasks_size(); i++) {
487         const GrpcScheduleInfo& rpcScheduleInfo = response.allscheduledtasks(i);
488         ScheduleInfo scheduleInfo = {
489                 .clientId = rpcScheduleInfo.clientid(),
490                 .taskType = static_cast<TaskType>(rpcScheduleInfo.tasktype()),
491                 .scheduleId = rpcScheduleInfo.scheduleid(),
492                 .taskData = stringToBytes(rpcScheduleInfo.data()),
493                 .count = rpcScheduleInfo.count(),
494                 .startTimeInEpochSeconds = rpcScheduleInfo.starttimeinepochseconds(),
495                 .periodicInSeconds = rpcScheduleInfo.periodicinseconds(),
496         };
497         out->push_back(std::move(scheduleInfo));
498     }
499     return ScopedAStatus::ok();
500 }
501 
checkDumpPermission()502 bool RemoteAccessService::checkDumpPermission() {
503     uid_t uid = AIBinder_getCallingUid();
504     return uid == AID_ROOT || uid == AID_SHELL || uid == AID_SYSTEM;
505 }
506 
dumpHelp(int fd)507 void RemoteAccessService::dumpHelp(int fd) {
508     dprintf(fd,
509             "RemoteAccess HAL debug interface, Usage: \n"
510             "%s [0/1](isReadyForRemoteTask) [0/1](isWakeupRequired): Set the new AP state\n"
511             "%s: Start a debug callback that will record the received tasks\n"
512             "%s: Stop the debug callback\n"
513             "%s: Show tasks received by debug callback\n"
514             "%s: Get vehicle id\n"
515             "%s [client_id] [task_data]: Inject a task\n"
516             "%s [client_id] [task_data] [latencyInSec]: "
517             "Inject a task on next reboot after latencyInSec seconds\n"
518             "%s: Show status\n",
519             COMMAND_SET_AP_STATE, COMMAND_START_DEBUG_CALLBACK, COMMAND_STOP_DEBUG_CALLBACK,
520             COMMAND_SHOW_TASK, COMMAND_GET_VEHICLE_ID, COMMAND_INJECT_TASK,
521             COMMAND_INJECT_TASK_NEXT_REBOOT, COMMAND_STATUS);
522 }
523 
dump(int fd,const char ** args,uint32_t numArgs)524 binder_status_t RemoteAccessService::dump(int fd, const char** args, uint32_t numArgs) {
525     if (!checkDumpPermission()) {
526         dprintf(fd, "Caller must be root, system or shell\n");
527         return STATUS_PERMISSION_DENIED;
528     }
529 
530     if (numArgs == 0) {
531         dumpHelp(fd);
532         printCurrentStatus(fd);
533         return STATUS_OK;
534     }
535 
536     if (!strcmp(args[0], COMMAND_SET_AP_STATE)) {
537         if (numArgs < 3) {
538             dumpHelp(fd);
539             return STATUS_OK;
540         }
541         ApState apState = {};
542         const char* remoteTaskFlag = args[1];
543         if (!strcmp(remoteTaskFlag, "1") && !strcmp(remoteTaskFlag, "0")) {
544             dumpHelp(fd);
545             return STATUS_OK;
546         }
547         if (!checkBoolFlag(args[1])) {
548             dumpHelp(fd);
549             return STATUS_OK;
550         }
551         if (!strcmp(args[1], "1")) {
552             apState.isReadyForRemoteTask = true;
553         }
554         if (!checkBoolFlag(args[2])) {
555             dumpHelp(fd);
556             return STATUS_OK;
557         }
558         if (!strcmp(args[2], "1")) {
559             apState.isWakeupRequired = true;
560         }
561         auto status = notifyApStateChange(apState);
562         if (!status.isOk()) {
563             dprintErrorStatus(fd, "Failed to set AP state", status);
564         } else {
565             dprintf(fd, "successfully set the new AP state\n");
566         }
567     } else if (!strcmp(args[0], COMMAND_START_DEBUG_CALLBACK)) {
568         mDebugCallback = ndk::SharedRefBase::make<DebugRemoteTaskCallback>();
569         setRemoteTaskCallback(mDebugCallback);
570         dprintf(fd, "Debug callback registered\n");
571     } else if (!strcmp(args[0], COMMAND_STOP_DEBUG_CALLBACK)) {
572         if (mDebugCallback) {
573             mDebugCallback.reset();
574         }
575         clearRemoteTaskCallback();
576         dprintf(fd, "Debug callback unregistered\n");
577     } else if (!strcmp(args[0], COMMAND_SHOW_TASK)) {
578         if (mDebugCallback) {
579             dprintf(fd, "%s", mDebugCallback->printTasks().c_str());
580         } else {
581             dprintf(fd, "Debug callback is not currently used, use \"%s\" first.\n",
582                     COMMAND_START_DEBUG_CALLBACK);
583         }
584     } else if (!strcmp(args[0], COMMAND_GET_VEHICLE_ID)) {
585         std::string vehicleId;
586         auto status = getVehicleId(&vehicleId);
587         if (!status.isOk()) {
588             dprintErrorStatus(fd, "Failed to get vehicle ID", status);
589         } else {
590             dprintf(fd, "Vehicle Id: %s\n", vehicleId.c_str());
591         }
592     } else if (!strcmp(args[0], COMMAND_INJECT_TASK)) {
593         if (numArgs < 3) {
594             dumpHelp(fd);
595             return STATUS_OK;
596         }
597         debugInjectTask(fd, args[1], args[2]);
598     } else if (!strcmp(args[0], COMMAND_INJECT_TASK_NEXT_REBOOT)) {
599         if (numArgs < 4) {
600             dumpHelp(fd);
601             return STATUS_OK;
602         }
603         debugInjectTaskNextReboot(fd, args[1], args[2], args[3]);
604     } else if (!strcmp(args[0], COMMAND_STATUS)) {
605         printCurrentStatus(fd);
606     } else {
607         dumpHelp(fd);
608     }
609 
610     return STATUS_OK;
611 }
612 
printCurrentStatus(int fd)613 void RemoteAccessService::printCurrentStatus(int fd) {
614     std::lock_guard<std::mutex> lockGuard(mLock);
615     dprintf(fd,
616             "\nRemoteAccess HAL status \n"
617             "Remote task callback registered: %s\n"
618             "GRPC server exist: %s\n"
619             "GRPC read channel for receiving tasks open: %s\n"
620             "Received task count by clientId: \n%s\n",
621             boolToString(mRemoteTaskCallback.get()).c_str(), boolToString(mGrpcServerExist).c_str(),
622             boolToString(mGrpcReadChannelOpen).c_str(),
623             clientIdToTaskCountToStringLocked().c_str());
624 }
625 
debugInjectTask(int fd,std::string_view clientId,std::string_view taskData)626 void RemoteAccessService::debugInjectTask(int fd, std::string_view clientId,
627                                           std::string_view taskData) {
628     std::string clientIdCopy = std::string(clientId);
629     if (auto result = deliverRemoteTaskThroughCallback(clientIdCopy, taskData); !result.ok()) {
630         dprintf(fd, "Failed to inject task: %s\n", result.error().message().c_str());
631         return;
632     }
633     dprintf(fd, "Task for client: %s, data: [%s] successfully injected\n", clientId.data(),
634             taskData.data());
635 }
636 
debugInjectTaskNextReboot(int fd,std::string_view clientId,std::string_view taskData,const char * latencyInSecStr)637 void RemoteAccessService::debugInjectTaskNextReboot(int fd, std::string_view clientId,
638                                                     std::string_view taskData,
639                                                     const char* latencyInSecStr) {
640     int latencyInSec;
641     if (!ParseInt(latencyInSecStr, &latencyInSec)) {
642         dprintf(fd, "The input latency in second is not a valid integer");
643         return;
644     }
645     std::ofstream debugTaskFile;
646     debugTaskFile.open(DEBUG_TASK_FILE, std::ios::out);
647     if (!debugTaskFile.is_open()) {
648         dprintf(fd,
649                 "Failed to open debug task file, please run the command: "
650                 "'adb shell touch %s' first\n",
651                 DEBUG_TASK_FILE);
652         return;
653     }
654     if (taskData.find("\n") != std::string::npos) {
655         dprintf(fd, "Task data must not contain newline\n");
656         return;
657     }
658     debugTaskFile << clientId << "\n" << taskData << "\n" << latencyInSec;
659     debugTaskFile.close();
660     dprintf(fd,
661             "Task with clientId: %s, task data: %s, latency: %d sec scheduled for next reboot\n",
662             clientId.data(), taskData.data(), latencyInSec);
663 }
664 
clientIdToTaskCountToStringLocked()665 std::string RemoteAccessService::clientIdToTaskCountToStringLocked() {
666     // Print the table header
667     std::string output = "| ClientId | Count |\n";
668     for (const auto& [clientId, taskCount] : mClientIdToTaskCount) {
669         output += StringPrintf("  %-9s  %-6zu\n", clientId.c_str(), taskCount);
670     }
671     return output;
672 }
673 
onRemoteTaskRequested(const std::string & clientId,const std::vector<uint8_t> & data)674 ScopedAStatus DebugRemoteTaskCallback::onRemoteTaskRequested(const std::string& clientId,
675                                                              const std::vector<uint8_t>& data) {
676     std::lock_guard<std::mutex> lockGuard(mLock);
677     mTasks.push_back({
678             .clientId = clientId,
679             .data = data,
680     });
681     return ScopedAStatus::ok();
682 }
683 
printTasks()684 std::string DebugRemoteTaskCallback::printTasks() {
685     std::lock_guard<std::mutex> lockGuard(mLock);
686     std::string s = StringPrintf("Received %zu tasks in %f seconds", mTasks.size(),
687                                  (android::uptimeMillis() - mStartTimeMillis) / 1000.);
688     for (size_t i = 0; i < mTasks.size(); i++) {
689         StringAppendF(&s, "Client Id: %s, Data: %s\n", mTasks[i].clientId.c_str(),
690                       printBytes(mTasks[i].data).c_str());
691     }
692     return s;
693 }
694 
695 }  // namespace remoteaccess
696 }  // namespace automotive
697 }  // namespace hardware
698 }  // namespace android
699