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::vehicle::VehicleProperty;
43 using ::android::base::Error;
44 using ::android::base::ParseInt;
45 using ::android::base::Result;
46 using ::android::base::ScopedLockAssertion;
47 using ::android::base::StringAppendF;
48 using ::android::base::StringPrintf;
49 using ::android::frameworks::automotive::vhal::IVhalClient;
50 using ::android::hardware::automotive::vehicle::toInt;
51 using ::grpc::ClientContext;
52 using ::grpc::ClientReaderInterface;
53 using ::grpc::Status;
54 using ::grpc::StatusCode;
55 using ::ndk::ScopedAStatus;
56 
57 const std::string WAKEUP_SERVICE_NAME = "com.google.vehicle.wakeup";
58 const std::string PROCESSOR_ID = "application_processor";
59 constexpr char COMMAND_SET_AP_STATE[] = "--set-ap-state";
60 constexpr char COMMAND_START_DEBUG_CALLBACK[] = "--start-debug-callback";
61 constexpr char COMMAND_STOP_DEBUG_CALLBACK[] = "--stop-debug-callback";
62 constexpr char COMMAND_SHOW_TASK[] = "--show-task";
63 constexpr char COMMAND_GET_VEHICLE_ID[] = "--get-vehicle-id";
64 constexpr char COMMAND_INJECT_TASK[] = "--inject-task";
65 constexpr char COMMAND_INJECT_TASK_NEXT_REBOOT[] = "--inject-task-next-reboot";
66 constexpr char COMMAND_STATUS[] = "--status";
67 
68 constexpr char DEBUG_TASK_FILE[] = "/data/vendor/remoteaccess/debugTask";
69 
stringToBytes(std::string_view s)70 std::vector<uint8_t> stringToBytes(std::string_view s) {
71     const char* data = s.data();
72     return std::vector<uint8_t>(data, data + s.size());
73 }
74 
rpcStatusToScopedAStatus(const Status & status,const std::string & errorMsg)75 ScopedAStatus rpcStatusToScopedAStatus(const Status& status, const std::string& errorMsg) {
76     return ScopedAStatus::fromServiceSpecificErrorWithMessage(
77             status.error_code(), (errorMsg + ", error: " + status.error_message()).c_str());
78 }
79 
printBytes(const std::vector<uint8_t> & bytes)80 std::string printBytes(const std::vector<uint8_t>& bytes) {
81     std::string s;
82     for (size_t i = 0; i < bytes.size(); i++) {
83         StringAppendF(&s, "%02x", bytes[i]);
84     }
85     return s;
86 }
87 
checkBoolFlag(const char * flag)88 bool checkBoolFlag(const char* flag) {
89     return !strcmp(flag, "1") || !strcmp(flag, "0");
90 }
91 
dprintErrorStatus(int fd,const char * detail,const ScopedAStatus & status)92 void dprintErrorStatus(int fd, const char* detail, const ScopedAStatus& status) {
93     dprintf(fd, "%s, code: %d, error: %s\n", detail, status.getStatus(), status.getMessage());
94 }
95 
boolToString(bool x)96 std::string boolToString(bool x) {
97     return x ? "true" : "false";
98 }
99 
100 }  // namespace
101 
RemoteAccessService(WakeupClient::StubInterface * grpcStub)102 RemoteAccessService::RemoteAccessService(WakeupClient::StubInterface* grpcStub)
103     : mGrpcStub(grpcStub) {
104     std::ifstream debugTaskFile;
105     debugTaskFile.open(DEBUG_TASK_FILE, std::ios::in);
106     if (!debugTaskFile.is_open()) {
107         ALOGD("No debug task available");
108         return;
109     }
110 
111     char buffer[1024] = {};
112     debugTaskFile.getline(buffer, sizeof(buffer));
113     std::string clientId = std::string(buffer);
114     debugTaskFile.getline(buffer, sizeof(buffer));
115     std::string taskData = std::string(buffer);
116     int latencyInSec;
117     debugTaskFile >> latencyInSec;
118     debugTaskFile.close();
119 
120     ALOGD("Task for client: %s, data: [%s], latency: %d\n", clientId.c_str(), taskData.c_str(),
121           latencyInSec);
122 
123     mInjectDebugTaskThread = std::thread([this, clientId, taskData, latencyInSec] {
124         std::this_thread::sleep_for(std::chrono::seconds(latencyInSec));
125         if (auto result = deliverRemoteTaskThroughCallback(clientId, taskData); !result.ok()) {
126             ALOGE("Failed to inject debug task, clientID: %s, taskData: %s, error: %s",
127                   clientId.c_str(), taskData.c_str(), result.error().message().c_str());
128             return;
129         }
130         ALOGD("Task for client: %s, data: [%s] successfully injected\n", clientId.c_str(),
131               taskData.c_str());
132     });
133 }
134 
~RemoteAccessService()135 RemoteAccessService::~RemoteAccessService() {
136     maybeStopTaskLoop();
137     if (mInjectDebugTaskThread.joinable()) {
138         mInjectDebugTaskThread.join();
139     }
140 }
141 
maybeStartTaskLoop()142 void RemoteAccessService::maybeStartTaskLoop() {
143     std::lock_guard<std::mutex> lockGuard(mStartStopTaskLoopLock);
144     if (mTaskLoopRunning) {
145         return;
146     }
147 
148     mThread = std::thread([this]() { runTaskLoop(); });
149 
150     mTaskLoopRunning = true;
151 }
152 
maybeStopTaskLoop()153 void RemoteAccessService::maybeStopTaskLoop() {
154     std::lock_guard<std::mutex> lockGuard(mStartStopTaskLoopLock);
155     if (!mTaskLoopRunning) {
156         return;
157     }
158 
159     {
160         std::lock_guard<std::mutex> lockGuard(mLock);
161         // Try to stop the reading stream.
162         if (mGetRemoteTasksContext) {
163             mGetRemoteTasksContext->TryCancel();
164             // Don't reset mGetRemoteTaskContext here since the read stream might still be affective
165             // and might still be using it. This will cause reader->Read to return false and
166             // mGetRemoteTasksContext will be cleared after reader->Finish() is called.
167         }
168         mTaskWaitStopped = true;
169         mCv.notify_all();
170     }
171     if (mThread.joinable()) {
172         mThread.join();
173     }
174 
175     mTaskLoopRunning = false;
176 }
177 
updateGrpcConnected(bool connected)178 void RemoteAccessService::updateGrpcConnected(bool connected) {
179     std::lock_guard<std::mutex> lockGuard(mLock);
180     mGrpcConnected = connected;
181 }
182 
deliverRemoteTaskThroughCallback(const std::string & clientId,std::string_view taskData)183 Result<void> RemoteAccessService::deliverRemoteTaskThroughCallback(const std::string& clientId,
184                                                                    std::string_view taskData) {
185     std::shared_ptr<IRemoteTaskCallback> callback;
186     {
187         std::lock_guard<std::mutex> lockGuard(mLock);
188         callback = mRemoteTaskCallback;
189         mClientIdToTaskCount[clientId] += 1;
190     }
191     if (callback == nullptr) {
192         return Error() << "No callback registered, task ignored";
193     }
194     ALOGD("Calling onRemoteTaskRequested callback for client ID: %s", clientId.c_str());
195     ScopedAStatus callbackStatus =
196             callback->onRemoteTaskRequested(clientId, stringToBytes(taskData));
197     if (!callbackStatus.isOk()) {
198         return Error() << "Failed to call onRemoteTaskRequested callback, status: "
199                        << callbackStatus.getStatus()
200                        << ", message: " << callbackStatus.getMessage();
201     }
202     return {};
203 }
204 
runTaskLoop()205 void RemoteAccessService::runTaskLoop() {
206     GetRemoteTasksRequest request = {};
207     std::unique_ptr<ClientReaderInterface<GetRemoteTasksResponse>> reader;
208     while (true) {
209         {
210             std::lock_guard<std::mutex> lockGuard(mLock);
211             mGetRemoteTasksContext.reset(new ClientContext());
212             reader = mGrpcStub->GetRemoteTasks(mGetRemoteTasksContext.get(), request);
213         }
214         updateGrpcConnected(true);
215         GetRemoteTasksResponse response;
216         while (reader->Read(&response)) {
217             ALOGI("Receiving one task from remote task client");
218 
219             if (auto result =
220                         deliverRemoteTaskThroughCallback(response.clientid(), response.data());
221                 !result.ok()) {
222                 ALOGE("%s", result.error().message().c_str());
223                 continue;
224             }
225         }
226         updateGrpcConnected(false);
227         Status status = reader->Finish();
228         mGetRemoteTasksContext.reset();
229 
230         ALOGE("GetRemoteTasks stream breaks, code: %d, message: %s, sleeping for 10s and retry",
231               status.error_code(), status.error_message().c_str());
232         // The long lasting connection should not return. But if the server returns, retry after
233         // 10s.
234         {
235             std::unique_lock lk(mLock);
236             if (mCv.wait_for(lk, std::chrono::milliseconds(mRetryWaitInMs), [this] {
237                     ScopedLockAssertion lockAssertion(mLock);
238                     return mTaskWaitStopped;
239                 })) {
240                 // If the stopped flag is set, we are quitting, exit the loop.
241                 break;
242             }
243         }
244     }
245 }
246 
getVehicleId(std::string * vehicleId)247 ScopedAStatus RemoteAccessService::getVehicleId(std::string* vehicleId) {
248 #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
249     auto vhalClient = IVhalClient::tryCreate();
250     if (vhalClient == nullptr) {
251         ALOGE("Failed to connect to VHAL");
252         return ScopedAStatus::fromServiceSpecificErrorWithMessage(
253                 /*errorCode=*/0, "Failed to connect to VHAL to get vehicle ID");
254     }
255     return getVehicleIdWithClient(*vhalClient.get(), vehicleId);
256 #else
257     // Don't use VHAL client in fuzzing since IPC is not allowed.
258     return ScopedAStatus::ok();
259 #endif
260 }
261 
getVehicleIdWithClient(IVhalClient & vhalClient,std::string * vehicleId)262 ScopedAStatus RemoteAccessService::getVehicleIdWithClient(IVhalClient& vhalClient,
263                                                           std::string* vehicleId) {
264     auto result = vhalClient.getValueSync(
265             *vhalClient.createHalPropValue(toInt(VehicleProperty::INFO_VIN)));
266     if (!result.ok()) {
267         return ScopedAStatus::fromServiceSpecificErrorWithMessage(
268                 /*errorCode=*/0,
269                 ("failed to get INFO_VIN from VHAL: " + result.error().message()).c_str());
270     }
271     *vehicleId = (*result)->getStringValue();
272     return ScopedAStatus::ok();
273 }
274 
getProcessorId(std::string * processorId)275 ScopedAStatus RemoteAccessService::getProcessorId(std::string* processorId) {
276     *processorId = PROCESSOR_ID;
277     return ScopedAStatus::ok();
278 }
279 
getWakeupServiceName(std::string * wakeupServiceName)280 ScopedAStatus RemoteAccessService::getWakeupServiceName(std::string* wakeupServiceName) {
281     *wakeupServiceName = WAKEUP_SERVICE_NAME;
282     return ScopedAStatus::ok();
283 }
284 
setRemoteTaskCallback(const std::shared_ptr<IRemoteTaskCallback> & callback)285 ScopedAStatus RemoteAccessService::setRemoteTaskCallback(
286         const std::shared_ptr<IRemoteTaskCallback>& callback) {
287     std::lock_guard<std::mutex> lockGuard(mLock);
288     mRemoteTaskCallback = callback;
289     return ScopedAStatus::ok();
290 }
291 
clearRemoteTaskCallback()292 ScopedAStatus RemoteAccessService::clearRemoteTaskCallback() {
293     std::lock_guard<std::mutex> lockGuard(mLock);
294     mRemoteTaskCallback.reset();
295     return ScopedAStatus::ok();
296 }
297 
notifyApStateChange(const ApState & newState)298 ScopedAStatus RemoteAccessService::notifyApStateChange(const ApState& newState) {
299     ClientContext context;
300     NotifyWakeupRequiredRequest request = {};
301     request.set_iswakeuprequired(newState.isWakeupRequired);
302     NotifyWakeupRequiredResponse response = {};
303     Status status = mGrpcStub->NotifyWakeupRequired(&context, request, &response);
304     if (!status.ok()) {
305         return rpcStatusToScopedAStatus(status, "Failed to notify isWakeupRequired");
306     }
307 
308     if (newState.isReadyForRemoteTask) {
309         maybeStartTaskLoop();
310     } else {
311         maybeStopTaskLoop();
312     }
313     return ScopedAStatus::ok();
314 }
315 
checkDumpPermission()316 bool RemoteAccessService::checkDumpPermission() {
317     uid_t uid = AIBinder_getCallingUid();
318     return uid == AID_ROOT || uid == AID_SHELL || uid == AID_SYSTEM;
319 }
320 
dumpHelp(int fd)321 void RemoteAccessService::dumpHelp(int fd) {
322     dprintf(fd,
323             "RemoteAccess HAL debug interface, Usage: \n"
324             "%s [0/1](isReadyForRemoteTask) [0/1](isWakeupRequired): Set the new AP state\n"
325             "%s: Start a debug callback that will record the received tasks\n"
326             "%s: Stop the debug callback\n"
327             "%s: Show tasks received by debug callback\n"
328             "%s: Get vehicle id\n"
329             "%s [client_id] [task_data]: Inject a task\n"
330             "%s [client_id] [task_data] [latencyInSec]: "
331             "Inject a task on next reboot after latencyInSec seconds\n"
332             "%s: Show status\n",
333             COMMAND_SET_AP_STATE, COMMAND_START_DEBUG_CALLBACK, COMMAND_STOP_DEBUG_CALLBACK,
334             COMMAND_SHOW_TASK, COMMAND_GET_VEHICLE_ID, COMMAND_INJECT_TASK,
335             COMMAND_INJECT_TASK_NEXT_REBOOT, COMMAND_STATUS);
336 }
337 
dump(int fd,const char ** args,uint32_t numArgs)338 binder_status_t RemoteAccessService::dump(int fd, const char** args, uint32_t numArgs) {
339     if (!checkDumpPermission()) {
340         dprintf(fd, "Caller must be root, system or shell\n");
341         return STATUS_PERMISSION_DENIED;
342     }
343 
344     if (numArgs == 0) {
345         dumpHelp(fd);
346         printCurrentStatus(fd);
347         return STATUS_OK;
348     }
349 
350     if (!strcmp(args[0], COMMAND_SET_AP_STATE)) {
351         if (numArgs < 3) {
352             dumpHelp(fd);
353             return STATUS_OK;
354         }
355         ApState apState = {};
356         const char* remoteTaskFlag = args[1];
357         if (!strcmp(remoteTaskFlag, "1") && !strcmp(remoteTaskFlag, "0")) {
358             dumpHelp(fd);
359             return STATUS_OK;
360         }
361         if (!checkBoolFlag(args[1])) {
362             dumpHelp(fd);
363             return STATUS_OK;
364         }
365         if (!strcmp(args[1], "1")) {
366             apState.isReadyForRemoteTask = true;
367         }
368         if (!checkBoolFlag(args[2])) {
369             dumpHelp(fd);
370             return STATUS_OK;
371         }
372         if (!strcmp(args[2], "1")) {
373             apState.isWakeupRequired = true;
374         }
375         auto status = notifyApStateChange(apState);
376         if (!status.isOk()) {
377             dprintErrorStatus(fd, "Failed to set AP state", status);
378         } else {
379             dprintf(fd, "successfully set the new AP state\n");
380         }
381     } else if (!strcmp(args[0], COMMAND_START_DEBUG_CALLBACK)) {
382         mDebugCallback = ndk::SharedRefBase::make<DebugRemoteTaskCallback>();
383         setRemoteTaskCallback(mDebugCallback);
384         dprintf(fd, "Debug callback registered\n");
385     } else if (!strcmp(args[0], COMMAND_STOP_DEBUG_CALLBACK)) {
386         if (mDebugCallback) {
387             mDebugCallback.reset();
388         }
389         clearRemoteTaskCallback();
390         dprintf(fd, "Debug callback unregistered\n");
391     } else if (!strcmp(args[0], COMMAND_SHOW_TASK)) {
392         if (mDebugCallback) {
393             dprintf(fd, "%s", mDebugCallback->printTasks().c_str());
394         } else {
395             dprintf(fd, "Debug callback is not currently used, use \"%s\" first.\n",
396                     COMMAND_START_DEBUG_CALLBACK);
397         }
398     } else if (!strcmp(args[0], COMMAND_GET_VEHICLE_ID)) {
399         std::string vehicleId;
400         auto status = getVehicleId(&vehicleId);
401         if (!status.isOk()) {
402             dprintErrorStatus(fd, "Failed to get vehicle ID", status);
403         } else {
404             dprintf(fd, "Vehicle Id: %s\n", vehicleId.c_str());
405         }
406     } else if (!strcmp(args[0], COMMAND_INJECT_TASK)) {
407         if (numArgs < 3) {
408             dumpHelp(fd);
409             return STATUS_OK;
410         }
411         debugInjectTask(fd, args[1], args[2]);
412     } else if (!strcmp(args[0], COMMAND_INJECT_TASK_NEXT_REBOOT)) {
413         if (numArgs < 4) {
414             dumpHelp(fd);
415             return STATUS_OK;
416         }
417         debugInjectTaskNextReboot(fd, args[1], args[2], args[3]);
418     } else if (!strcmp(args[0], COMMAND_STATUS)) {
419         printCurrentStatus(fd);
420     } else {
421         dumpHelp(fd);
422     }
423 
424     return STATUS_OK;
425 }
426 
printCurrentStatus(int fd)427 void RemoteAccessService::printCurrentStatus(int fd) {
428     std::lock_guard<std::mutex> lockGuard(mLock);
429     dprintf(fd,
430             "\nRemoteAccess HAL status \n"
431             "Remote task callback registered: %s\n"
432             "Task receiving GRPC connection established: %s\n"
433             "Received task count by clientId: \n%s\n",
434             boolToString(mRemoteTaskCallback.get()).c_str(), boolToString(mGrpcConnected).c_str(),
435             clientIdToTaskCountToStringLocked().c_str());
436 }
437 
debugInjectTask(int fd,std::string_view clientId,std::string_view taskData)438 void RemoteAccessService::debugInjectTask(int fd, std::string_view clientId,
439                                           std::string_view taskData) {
440     std::string clientIdCopy = std::string(clientId);
441     if (auto result = deliverRemoteTaskThroughCallback(clientIdCopy, taskData); !result.ok()) {
442         dprintf(fd, "Failed to inject task: %s\n", result.error().message().c_str());
443         return;
444     }
445     dprintf(fd, "Task for client: %s, data: [%s] successfully injected\n", clientId.data(),
446             taskData.data());
447 }
448 
debugInjectTaskNextReboot(int fd,std::string_view clientId,std::string_view taskData,const char * latencyInSecStr)449 void RemoteAccessService::debugInjectTaskNextReboot(int fd, std::string_view clientId,
450                                                     std::string_view taskData,
451                                                     const char* latencyInSecStr) {
452     int latencyInSec;
453     if (!ParseInt(latencyInSecStr, &latencyInSec)) {
454         dprintf(fd, "The input latency in second is not a valid integer");
455         return;
456     }
457     std::ofstream debugTaskFile;
458     debugTaskFile.open(DEBUG_TASK_FILE, std::ios::out);
459     if (!debugTaskFile.is_open()) {
460         dprintf(fd,
461                 "Failed to open debug task file, please run the command: "
462                 "'adb shell touch %s' first\n",
463                 DEBUG_TASK_FILE);
464         return;
465     }
466     if (taskData.find("\n") != std::string::npos) {
467         dprintf(fd, "Task data must not contain newline\n");
468         return;
469     }
470     debugTaskFile << clientId << "\n" << taskData << "\n" << latencyInSec;
471     debugTaskFile.close();
472     dprintf(fd,
473             "Task with clientId: %s, task data: %s, latency: %d sec scheduled for next reboot\n",
474             clientId.data(), taskData.data(), latencyInSec);
475 }
476 
clientIdToTaskCountToStringLocked()477 std::string RemoteAccessService::clientIdToTaskCountToStringLocked() {
478     // Print the table header
479     std::string output = "| ClientId | Count |\n";
480     for (const auto& [clientId, taskCount] : mClientIdToTaskCount) {
481         output += StringPrintf("  %-9s  %-6zu\n", clientId.c_str(), taskCount);
482     }
483     return output;
484 }
485 
onRemoteTaskRequested(const std::string & clientId,const std::vector<uint8_t> & data)486 ScopedAStatus DebugRemoteTaskCallback::onRemoteTaskRequested(const std::string& clientId,
487                                                              const std::vector<uint8_t>& data) {
488     std::lock_guard<std::mutex> lockGuard(mLock);
489     mTasks.push_back({
490             .clientId = clientId,
491             .data = data,
492     });
493     return ScopedAStatus::ok();
494 }
495 
printTasks()496 std::string DebugRemoteTaskCallback::printTasks() {
497     std::lock_guard<std::mutex> lockGuard(mLock);
498     std::string s = StringPrintf("Received %zu tasks in %f seconds", mTasks.size(),
499                                  (android::uptimeMillis() - mStartTimeMillis) / 1000.);
500     for (size_t i = 0; i < mTasks.size(); i++) {
501         StringAppendF(&s, "Client Id: %s, Data: %s\n", mTasks[i].clientId.c_str(),
502                       printBytes(mTasks[i].data).c_str());
503     }
504     return s;
505 }
506 
507 }  // namespace remoteaccess
508 }  // namespace automotive
509 }  // namespace hardware
510 }  // namespace android
511