blob: 0944d8699d87c395fac2cc54ccf0db7d1c7db2ca [file] [log] [blame]
Yu Shan7a5283f2022-10-25 18:01:05 -07001/*
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>
Yu Shan194757d2023-04-19 11:44:35 -070021#include <android-base/parseint.h>
Yu Shan7a5283f2022-10-25 18:01:05 -070022#include <android-base/stringprintf.h>
23#include <android/binder_status.h>
24#include <grpc++/grpc++.h>
25#include <private/android_filesystem_config.h>
Yu Shan194757d2023-04-19 11:44:35 -070026#include <sys/stat.h>
Yu Shan7a5283f2022-10-25 18:01:05 -070027#include <utils/Log.h>
28#include <chrono>
Yu Shan194757d2023-04-19 11:44:35 -070029#include <fstream>
30#include <iostream>
Yu Shan7a5283f2022-10-25 18:01:05 -070031#include <thread>
32
33namespace android {
34namespace hardware {
35namespace automotive {
36namespace remoteaccess {
37
38namespace {
39
40using ::aidl::android::hardware::automotive::remoteaccess::ApState;
41using ::aidl::android::hardware::automotive::remoteaccess::IRemoteTaskCallback;
Yu Shan06ddbc62023-08-23 18:05:26 -070042using ::aidl::android::hardware::automotive::remoteaccess::ScheduleInfo;
Yu Shan7a5283f2022-10-25 18:01:05 -070043using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
Yu Shan95493682023-03-21 18:00:17 -070044using ::android::base::Error;
Yu Shan194757d2023-04-19 11:44:35 -070045using ::android::base::ParseInt;
Yu Shan95493682023-03-21 18:00:17 -070046using ::android::base::Result;
Yu Shan7a5283f2022-10-25 18:01:05 -070047using ::android::base::ScopedLockAssertion;
48using ::android::base::StringAppendF;
49using ::android::base::StringPrintf;
50using ::android::frameworks::automotive::vhal::IVhalClient;
51using ::android::hardware::automotive::vehicle::toInt;
52using ::grpc::ClientContext;
53using ::grpc::ClientReaderInterface;
54using ::grpc::Status;
55using ::grpc::StatusCode;
56using ::ndk::ScopedAStatus;
57
58const std::string WAKEUP_SERVICE_NAME = "com.google.vehicle.wakeup";
Eric Jeong6c3a1d82023-03-16 00:45:40 -070059const std::string PROCESSOR_ID = "application_processor";
Yu Shan7a5283f2022-10-25 18:01:05 -070060constexpr char COMMAND_SET_AP_STATE[] = "--set-ap-state";
61constexpr char COMMAND_START_DEBUG_CALLBACK[] = "--start-debug-callback";
62constexpr char COMMAND_STOP_DEBUG_CALLBACK[] = "--stop-debug-callback";
63constexpr char COMMAND_SHOW_TASK[] = "--show-task";
Eric Jeong6c3a1d82023-03-16 00:45:40 -070064constexpr char COMMAND_GET_VEHICLE_ID[] = "--get-vehicle-id";
Yu Shan95493682023-03-21 18:00:17 -070065constexpr char COMMAND_INJECT_TASK[] = "--inject-task";
Yu Shan194757d2023-04-19 11:44:35 -070066constexpr char COMMAND_INJECT_TASK_NEXT_REBOOT[] = "--inject-task-next-reboot";
Yu Shan95493682023-03-21 18:00:17 -070067constexpr char COMMAND_STATUS[] = "--status";
Yu Shan7a5283f2022-10-25 18:01:05 -070068
Yu Shan58ff0912023-05-12 18:00:59 -070069constexpr char DEBUG_TASK_FILE[] = "/data/vendor/remoteaccess/debugTask";
Yu Shan194757d2023-04-19 11:44:35 -070070
Yu Shan95493682023-03-21 18:00:17 -070071std::vector<uint8_t> stringToBytes(std::string_view s) {
Yu Shan7a5283f2022-10-25 18:01:05 -070072 const char* data = s.data();
73 return std::vector<uint8_t>(data, data + s.size());
74}
75
76ScopedAStatus rpcStatusToScopedAStatus(const Status& status, const std::string& errorMsg) {
77 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
78 status.error_code(), (errorMsg + ", error: " + status.error_message()).c_str());
79}
80
81std::string printBytes(const std::vector<uint8_t>& bytes) {
82 std::string s;
83 for (size_t i = 0; i < bytes.size(); i++) {
84 StringAppendF(&s, "%02x", bytes[i]);
85 }
86 return s;
87}
88
89bool checkBoolFlag(const char* flag) {
90 return !strcmp(flag, "1") || !strcmp(flag, "0");
91}
92
93void dprintErrorStatus(int fd, const char* detail, const ScopedAStatus& status) {
94 dprintf(fd, "%s, code: %d, error: %s\n", detail, status.getStatus(), status.getMessage());
95}
96
Yu Shan95493682023-03-21 18:00:17 -070097std::string boolToString(bool x) {
98 return x ? "true" : "false";
99}
100
Yu Shan7a5283f2022-10-25 18:01:05 -0700101} // namespace
102
103RemoteAccessService::RemoteAccessService(WakeupClient::StubInterface* grpcStub)
Yu Shan194757d2023-04-19 11:44:35 -0700104 : mGrpcStub(grpcStub) {
105 std::ifstream debugTaskFile;
106 debugTaskFile.open(DEBUG_TASK_FILE, std::ios::in);
107 if (!debugTaskFile.is_open()) {
108 ALOGD("No debug task available");
109 return;
110 }
111
112 char buffer[1024] = {};
113 debugTaskFile.getline(buffer, sizeof(buffer));
114 std::string clientId = std::string(buffer);
115 debugTaskFile.getline(buffer, sizeof(buffer));
116 std::string taskData = std::string(buffer);
117 int latencyInSec;
118 debugTaskFile >> latencyInSec;
119 debugTaskFile.close();
120
121 ALOGD("Task for client: %s, data: [%s], latency: %d\n", clientId.c_str(), taskData.c_str(),
122 latencyInSec);
123
124 mInjectDebugTaskThread = std::thread([this, clientId, taskData, latencyInSec] {
125 std::this_thread::sleep_for(std::chrono::seconds(latencyInSec));
126 if (auto result = deliverRemoteTaskThroughCallback(clientId, taskData); !result.ok()) {
127 ALOGE("Failed to inject debug task, clientID: %s, taskData: %s, error: %s",
128 clientId.c_str(), taskData.c_str(), result.error().message().c_str());
129 return;
130 }
131 ALOGD("Task for client: %s, data: [%s] successfully injected\n", clientId.c_str(),
132 taskData.c_str());
133 });
134}
Yu Shan7a5283f2022-10-25 18:01:05 -0700135
136RemoteAccessService::~RemoteAccessService() {
137 maybeStopTaskLoop();
Yu Shan194757d2023-04-19 11:44:35 -0700138 if (mInjectDebugTaskThread.joinable()) {
139 mInjectDebugTaskThread.join();
140 }
Yu Shan7a5283f2022-10-25 18:01:05 -0700141}
142
143void RemoteAccessService::maybeStartTaskLoop() {
144 std::lock_guard<std::mutex> lockGuard(mStartStopTaskLoopLock);
145 if (mTaskLoopRunning) {
146 return;
147 }
148
149 mThread = std::thread([this]() { runTaskLoop(); });
150
151 mTaskLoopRunning = true;
152}
153
154void RemoteAccessService::maybeStopTaskLoop() {
155 std::lock_guard<std::mutex> lockGuard(mStartStopTaskLoopLock);
156 if (!mTaskLoopRunning) {
157 return;
158 }
159
160 {
161 std::lock_guard<std::mutex> lockGuard(mLock);
162 // Try to stop the reading stream.
163 if (mGetRemoteTasksContext) {
164 mGetRemoteTasksContext->TryCancel();
Yu Shandf39d6e2022-12-02 17:01:57 -0800165 // Don't reset mGetRemoteTaskContext here since the read stream might still be affective
166 // and might still be using it. This will cause reader->Read to return false and
167 // mGetRemoteTasksContext will be cleared after reader->Finish() is called.
Yu Shan7a5283f2022-10-25 18:01:05 -0700168 }
169 mTaskWaitStopped = true;
170 mCv.notify_all();
171 }
172 if (mThread.joinable()) {
173 mThread.join();
174 }
175
176 mTaskLoopRunning = false;
177}
178
Yu Shan95493682023-03-21 18:00:17 -0700179void RemoteAccessService::updateGrpcConnected(bool connected) {
180 std::lock_guard<std::mutex> lockGuard(mLock);
181 mGrpcConnected = connected;
182}
183
184Result<void> RemoteAccessService::deliverRemoteTaskThroughCallback(const std::string& clientId,
185 std::string_view taskData) {
186 std::shared_ptr<IRemoteTaskCallback> callback;
187 {
188 std::lock_guard<std::mutex> lockGuard(mLock);
189 callback = mRemoteTaskCallback;
190 mClientIdToTaskCount[clientId] += 1;
191 }
192 if (callback == nullptr) {
193 return Error() << "No callback registered, task ignored";
194 }
195 ALOGD("Calling onRemoteTaskRequested callback for client ID: %s", clientId.c_str());
196 ScopedAStatus callbackStatus =
197 callback->onRemoteTaskRequested(clientId, stringToBytes(taskData));
198 if (!callbackStatus.isOk()) {
199 return Error() << "Failed to call onRemoteTaskRequested callback, status: "
200 << callbackStatus.getStatus()
201 << ", message: " << callbackStatus.getMessage();
202 }
203 return {};
204}
205
Yu Shan7a5283f2022-10-25 18:01:05 -0700206void RemoteAccessService::runTaskLoop() {
207 GetRemoteTasksRequest request = {};
208 std::unique_ptr<ClientReaderInterface<GetRemoteTasksResponse>> reader;
209 while (true) {
210 {
211 std::lock_guard<std::mutex> lockGuard(mLock);
212 mGetRemoteTasksContext.reset(new ClientContext());
213 reader = mGrpcStub->GetRemoteTasks(mGetRemoteTasksContext.get(), request);
214 }
Yu Shan95493682023-03-21 18:00:17 -0700215 updateGrpcConnected(true);
Yu Shan7a5283f2022-10-25 18:01:05 -0700216 GetRemoteTasksResponse response;
217 while (reader->Read(&response)) {
218 ALOGI("Receiving one task from remote task client");
219
Yu Shan95493682023-03-21 18:00:17 -0700220 if (auto result =
221 deliverRemoteTaskThroughCallback(response.clientid(), response.data());
222 !result.ok()) {
223 ALOGE("%s", result.error().message().c_str());
Yu Shan7a5283f2022-10-25 18:01:05 -0700224 continue;
225 }
Yu Shan7a5283f2022-10-25 18:01:05 -0700226 }
Yu Shan95493682023-03-21 18:00:17 -0700227 updateGrpcConnected(false);
Yu Shan7a5283f2022-10-25 18:01:05 -0700228 Status status = reader->Finish();
Yu Shandf39d6e2022-12-02 17:01:57 -0800229 mGetRemoteTasksContext.reset();
Yu Shan7a5283f2022-10-25 18:01:05 -0700230
231 ALOGE("GetRemoteTasks stream breaks, code: %d, message: %s, sleeping for 10s and retry",
232 status.error_code(), status.error_message().c_str());
233 // The long lasting connection should not return. But if the server returns, retry after
234 // 10s.
235 {
236 std::unique_lock lk(mLock);
237 if (mCv.wait_for(lk, std::chrono::milliseconds(mRetryWaitInMs), [this] {
238 ScopedLockAssertion lockAssertion(mLock);
239 return mTaskWaitStopped;
240 })) {
241 // If the stopped flag is set, we are quitting, exit the loop.
242 break;
243 }
244 }
245 }
246}
247
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700248ScopedAStatus RemoteAccessService::getVehicleId(std::string* vehicleId) {
Yu Shan7a5283f2022-10-25 18:01:05 -0700249#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
250 auto vhalClient = IVhalClient::tryCreate();
251 if (vhalClient == nullptr) {
252 ALOGE("Failed to connect to VHAL");
253 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700254 /*errorCode=*/0, "Failed to connect to VHAL to get vehicle ID");
Yu Shan7a5283f2022-10-25 18:01:05 -0700255 }
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700256 return getVehicleIdWithClient(*vhalClient.get(), vehicleId);
Yu Shan7a5283f2022-10-25 18:01:05 -0700257#else
258 // Don't use VHAL client in fuzzing since IPC is not allowed.
259 return ScopedAStatus::ok();
260#endif
261}
262
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700263ScopedAStatus RemoteAccessService::getVehicleIdWithClient(IVhalClient& vhalClient,
264 std::string* vehicleId) {
Yu Shan7a5283f2022-10-25 18:01:05 -0700265 auto result = vhalClient.getValueSync(
266 *vhalClient.createHalPropValue(toInt(VehicleProperty::INFO_VIN)));
267 if (!result.ok()) {
268 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
269 /*errorCode=*/0,
270 ("failed to get INFO_VIN from VHAL: " + result.error().message()).c_str());
271 }
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700272 *vehicleId = (*result)->getStringValue();
273 return ScopedAStatus::ok();
274}
275
276ScopedAStatus RemoteAccessService::getProcessorId(std::string* processorId) {
277 *processorId = PROCESSOR_ID;
Yu Shan7a5283f2022-10-25 18:01:05 -0700278 return ScopedAStatus::ok();
279}
280
281ScopedAStatus RemoteAccessService::getWakeupServiceName(std::string* wakeupServiceName) {
282 *wakeupServiceName = WAKEUP_SERVICE_NAME;
283 return ScopedAStatus::ok();
284}
285
286ScopedAStatus RemoteAccessService::setRemoteTaskCallback(
287 const std::shared_ptr<IRemoteTaskCallback>& callback) {
288 std::lock_guard<std::mutex> lockGuard(mLock);
289 mRemoteTaskCallback = callback;
290 return ScopedAStatus::ok();
291}
292
293ScopedAStatus RemoteAccessService::clearRemoteTaskCallback() {
294 std::lock_guard<std::mutex> lockGuard(mLock);
295 mRemoteTaskCallback.reset();
296 return ScopedAStatus::ok();
297}
298
299ScopedAStatus RemoteAccessService::notifyApStateChange(const ApState& newState) {
300 ClientContext context;
301 NotifyWakeupRequiredRequest request = {};
302 request.set_iswakeuprequired(newState.isWakeupRequired);
303 NotifyWakeupRequiredResponse response = {};
304 Status status = mGrpcStub->NotifyWakeupRequired(&context, request, &response);
305 if (!status.ok()) {
306 return rpcStatusToScopedAStatus(status, "Failed to notify isWakeupRequired");
307 }
308
309 if (newState.isReadyForRemoteTask) {
310 maybeStartTaskLoop();
311 } else {
312 maybeStopTaskLoop();
313 }
314 return ScopedAStatus::ok();
315}
316
Yu Shan72d6f892023-08-30 11:44:13 -0700317ScopedAStatus RemoteAccessService::isTaskScheduleSupported(bool* out) {
318 *out = true;
Yu Shan06ddbc62023-08-23 18:05:26 -0700319 return ScopedAStatus::ok();
320}
321
Yu Shan72d6f892023-08-30 11:44:13 -0700322ScopedAStatus RemoteAccessService::scheduleTask(const ScheduleInfo& scheduleInfo) {
323 ClientContext context;
324 ScheduleTaskRequest request = {};
325 ScheduleTaskResponse response = {};
326 request.mutable_scheduleinfo()->set_clientid(scheduleInfo.clientId);
327 request.mutable_scheduleinfo()->set_scheduleid(scheduleInfo.scheduleId);
328 request.mutable_scheduleinfo()->set_data(scheduleInfo.taskData.data(),
329 scheduleInfo.taskData.size());
330 request.mutable_scheduleinfo()->set_count(scheduleInfo.count);
331 request.mutable_scheduleinfo()->set_starttimeinepochseconds(
332 scheduleInfo.startTimeInEpochSeconds);
333 request.mutable_scheduleinfo()->set_periodicinseconds(scheduleInfo.periodicInSeconds);
334 Status status = mGrpcStub->ScheduleTask(&context, request, &response);
335 if (!status.ok()) {
336 return rpcStatusToScopedAStatus(status, "Failed to call ScheduleTask");
337 }
338 int errorCode = response.errorcode();
339 switch (errorCode) {
340 case ErrorCode::OK:
341 return ScopedAStatus::ok();
342 case ErrorCode::INVALID_ARG:
343 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
344 default:
345 // Should not happen.
346 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
347 -1, ("Got unknown error code: " + ErrorCode_Name(errorCode) +
348 " from remote access HAL")
349 .c_str());
350 }
351}
352
353ScopedAStatus RemoteAccessService::unscheduleTask(const std::string& clientId,
354 const std::string& scheduleId) {
355 ClientContext context;
356 UnscheduleTaskRequest request = {};
357 UnscheduleTaskResponse response = {};
358 request.set_clientid(clientId);
359 request.set_scheduleid(scheduleId);
360 Status status = mGrpcStub->UnscheduleTask(&context, request, &response);
361 if (!status.ok()) {
362 return rpcStatusToScopedAStatus(status, "Failed to call UnscheduleTask");
363 }
Yu Shan06ddbc62023-08-23 18:05:26 -0700364 return ScopedAStatus::ok();
365}
366
Yu Shan72d6f892023-08-30 11:44:13 -0700367ScopedAStatus RemoteAccessService::unscheduleAllTasks(const std::string& clientId) {
368 ClientContext context;
369 UnscheduleAllTasksRequest request = {};
370 UnscheduleAllTasksResponse response = {};
371 request.set_clientid(clientId);
372 Status status = mGrpcStub->UnscheduleAllTasks(&context, request, &response);
373 if (!status.ok()) {
374 return rpcStatusToScopedAStatus(status, "Failed to call UnscheduleAllTasks");
375 }
Yu Shan06ddbc62023-08-23 18:05:26 -0700376 return ScopedAStatus::ok();
377}
378
Yu Shan72d6f892023-08-30 11:44:13 -0700379ScopedAStatus RemoteAccessService::isTaskScheduled(const std::string& clientId,
380 const std::string& scheduleId, bool* out) {
381 ClientContext context;
382 IsTaskScheduledRequest request = {};
383 IsTaskScheduledResponse response = {};
384 request.set_clientid(clientId);
385 request.set_scheduleid(scheduleId);
386 Status status = mGrpcStub->IsTaskScheduled(&context, request, &response);
387 if (!status.ok()) {
388 return rpcStatusToScopedAStatus(status, "Failed to call isTaskScheduled");
389 }
390 *out = response.istaskscheduled();
Yu Shan06ddbc62023-08-23 18:05:26 -0700391 return ScopedAStatus::ok();
392}
393
394ScopedAStatus RemoteAccessService::getAllScheduledTasks(const std::string& clientId,
395 std::vector<ScheduleInfo>* out) {
Yu Shan72d6f892023-08-30 11:44:13 -0700396 ClientContext context;
397 GetAllScheduledTasksRequest request = {};
398 GetAllScheduledTasksResponse response = {};
399 request.set_clientid(clientId);
400 Status status = mGrpcStub->GetAllScheduledTasks(&context, request, &response);
401 if (!status.ok()) {
402 return rpcStatusToScopedAStatus(status, "Failed to call isTaskScheduled");
403 }
404 out->clear();
405 for (int i = 0; i < response.allscheduledtasks_size(); i++) {
406 const GrpcScheduleInfo& rpcScheduleInfo = response.allscheduledtasks(i);
407 ScheduleInfo scheduleInfo = {
408 .clientId = rpcScheduleInfo.clientid(),
409 .scheduleId = rpcScheduleInfo.scheduleid(),
410 .taskData = stringToBytes(rpcScheduleInfo.data()),
411 .count = rpcScheduleInfo.count(),
412 .startTimeInEpochSeconds = rpcScheduleInfo.starttimeinepochseconds(),
413 .periodicInSeconds = rpcScheduleInfo.periodicinseconds(),
414 };
415 out->push_back(std::move(scheduleInfo));
416 }
Yu Shan06ddbc62023-08-23 18:05:26 -0700417 return ScopedAStatus::ok();
418}
419
Yu Shan7a5283f2022-10-25 18:01:05 -0700420bool RemoteAccessService::checkDumpPermission() {
421 uid_t uid = AIBinder_getCallingUid();
422 return uid == AID_ROOT || uid == AID_SHELL || uid == AID_SYSTEM;
423}
424
425void RemoteAccessService::dumpHelp(int fd) {
Yu Shan95493682023-03-21 18:00:17 -0700426 dprintf(fd,
427 "RemoteAccess HAL debug interface, Usage: \n"
428 "%s [0/1](isReadyForRemoteTask) [0/1](isWakeupRequired): Set the new AP state\n"
429 "%s: Start a debug callback that will record the received tasks\n"
430 "%s: Stop the debug callback\n"
431 "%s: Show tasks received by debug callback\n"
432 "%s: Get vehicle id\n"
433 "%s [client_id] [task_data]: Inject a task\n"
Yu Shan194757d2023-04-19 11:44:35 -0700434 "%s [client_id] [task_data] [latencyInSec]: "
435 "Inject a task on next reboot after latencyInSec seconds\n"
Yu Shan95493682023-03-21 18:00:17 -0700436 "%s: Show status\n",
437 COMMAND_SET_AP_STATE, COMMAND_START_DEBUG_CALLBACK, COMMAND_STOP_DEBUG_CALLBACK,
Yu Shan194757d2023-04-19 11:44:35 -0700438 COMMAND_SHOW_TASK, COMMAND_GET_VEHICLE_ID, COMMAND_INJECT_TASK,
439 COMMAND_INJECT_TASK_NEXT_REBOOT, COMMAND_STATUS);
Yu Shan7a5283f2022-10-25 18:01:05 -0700440}
441
442binder_status_t RemoteAccessService::dump(int fd, const char** args, uint32_t numArgs) {
443 if (!checkDumpPermission()) {
444 dprintf(fd, "Caller must be root, system or shell\n");
445 return STATUS_PERMISSION_DENIED;
446 }
447
448 if (numArgs == 0) {
449 dumpHelp(fd);
Yu Shan95493682023-03-21 18:00:17 -0700450 printCurrentStatus(fd);
Yu Shan7a5283f2022-10-25 18:01:05 -0700451 return STATUS_OK;
452 }
453
454 if (!strcmp(args[0], COMMAND_SET_AP_STATE)) {
455 if (numArgs < 3) {
456 dumpHelp(fd);
457 return STATUS_OK;
458 }
459 ApState apState = {};
460 const char* remoteTaskFlag = args[1];
461 if (!strcmp(remoteTaskFlag, "1") && !strcmp(remoteTaskFlag, "0")) {
462 dumpHelp(fd);
463 return STATUS_OK;
464 }
465 if (!checkBoolFlag(args[1])) {
466 dumpHelp(fd);
467 return STATUS_OK;
468 }
469 if (!strcmp(args[1], "1")) {
470 apState.isReadyForRemoteTask = true;
471 }
472 if (!checkBoolFlag(args[2])) {
473 dumpHelp(fd);
474 return STATUS_OK;
475 }
476 if (!strcmp(args[2], "1")) {
477 apState.isWakeupRequired = true;
478 }
479 auto status = notifyApStateChange(apState);
480 if (!status.isOk()) {
481 dprintErrorStatus(fd, "Failed to set AP state", status);
482 } else {
483 dprintf(fd, "successfully set the new AP state\n");
484 }
485 } else if (!strcmp(args[0], COMMAND_START_DEBUG_CALLBACK)) {
486 mDebugCallback = ndk::SharedRefBase::make<DebugRemoteTaskCallback>();
487 setRemoteTaskCallback(mDebugCallback);
488 dprintf(fd, "Debug callback registered\n");
489 } else if (!strcmp(args[0], COMMAND_STOP_DEBUG_CALLBACK)) {
490 if (mDebugCallback) {
491 mDebugCallback.reset();
492 }
493 clearRemoteTaskCallback();
494 dprintf(fd, "Debug callback unregistered\n");
495 } else if (!strcmp(args[0], COMMAND_SHOW_TASK)) {
496 if (mDebugCallback) {
497 dprintf(fd, "%s", mDebugCallback->printTasks().c_str());
498 } else {
499 dprintf(fd, "Debug callback is not currently used, use \"%s\" first.\n",
500 COMMAND_START_DEBUG_CALLBACK);
501 }
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700502 } else if (!strcmp(args[0], COMMAND_GET_VEHICLE_ID)) {
503 std::string vehicleId;
504 auto status = getVehicleId(&vehicleId);
Yu Shan7a5283f2022-10-25 18:01:05 -0700505 if (!status.isOk()) {
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700506 dprintErrorStatus(fd, "Failed to get vehicle ID", status);
Yu Shan7a5283f2022-10-25 18:01:05 -0700507 } else {
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700508 dprintf(fd, "Vehicle Id: %s\n", vehicleId.c_str());
Yu Shan7a5283f2022-10-25 18:01:05 -0700509 }
Yu Shan95493682023-03-21 18:00:17 -0700510 } else if (!strcmp(args[0], COMMAND_INJECT_TASK)) {
511 if (numArgs < 3) {
512 dumpHelp(fd);
513 return STATUS_OK;
514 }
515 debugInjectTask(fd, args[1], args[2]);
Yu Shan194757d2023-04-19 11:44:35 -0700516 } else if (!strcmp(args[0], COMMAND_INJECT_TASK_NEXT_REBOOT)) {
517 if (numArgs < 4) {
518 dumpHelp(fd);
519 return STATUS_OK;
520 }
521 debugInjectTaskNextReboot(fd, args[1], args[2], args[3]);
Yu Shan95493682023-03-21 18:00:17 -0700522 } else if (!strcmp(args[0], COMMAND_STATUS)) {
523 printCurrentStatus(fd);
Yu Shan7a5283f2022-10-25 18:01:05 -0700524 } else {
525 dumpHelp(fd);
526 }
527
528 return STATUS_OK;
529}
530
Yu Shan95493682023-03-21 18:00:17 -0700531void RemoteAccessService::printCurrentStatus(int fd) {
532 std::lock_guard<std::mutex> lockGuard(mLock);
533 dprintf(fd,
534 "\nRemoteAccess HAL status \n"
535 "Remote task callback registered: %s\n"
536 "Task receiving GRPC connection established: %s\n"
537 "Received task count by clientId: \n%s\n",
538 boolToString(mRemoteTaskCallback.get()).c_str(), boolToString(mGrpcConnected).c_str(),
539 clientIdToTaskCountToStringLocked().c_str());
540}
541
542void RemoteAccessService::debugInjectTask(int fd, std::string_view clientId,
543 std::string_view taskData) {
544 std::string clientIdCopy = std::string(clientId);
545 if (auto result = deliverRemoteTaskThroughCallback(clientIdCopy, taskData); !result.ok()) {
Yu Shan194757d2023-04-19 11:44:35 -0700546 dprintf(fd, "Failed to inject task: %s\n", result.error().message().c_str());
Yu Shan95493682023-03-21 18:00:17 -0700547 return;
548 }
549 dprintf(fd, "Task for client: %s, data: [%s] successfully injected\n", clientId.data(),
550 taskData.data());
551}
552
Yu Shan194757d2023-04-19 11:44:35 -0700553void RemoteAccessService::debugInjectTaskNextReboot(int fd, std::string_view clientId,
554 std::string_view taskData,
555 const char* latencyInSecStr) {
556 int latencyInSec;
557 if (!ParseInt(latencyInSecStr, &latencyInSec)) {
558 dprintf(fd, "The input latency in second is not a valid integer");
559 return;
560 }
561 std::ofstream debugTaskFile;
562 debugTaskFile.open(DEBUG_TASK_FILE, std::ios::out);
563 if (!debugTaskFile.is_open()) {
564 dprintf(fd,
565 "Failed to open debug task file, please run the command: "
566 "'adb shell touch %s' first\n",
567 DEBUG_TASK_FILE);
568 return;
569 }
570 if (taskData.find("\n") != std::string::npos) {
571 dprintf(fd, "Task data must not contain newline\n");
572 return;
573 }
574 debugTaskFile << clientId << "\n" << taskData << "\n" << latencyInSec;
575 debugTaskFile.close();
576 dprintf(fd,
577 "Task with clientId: %s, task data: %s, latency: %d sec scheduled for next reboot\n",
578 clientId.data(), taskData.data(), latencyInSec);
579}
580
Yu Shan95493682023-03-21 18:00:17 -0700581std::string RemoteAccessService::clientIdToTaskCountToStringLocked() {
582 // Print the table header
583 std::string output = "| ClientId | Count |\n";
584 for (const auto& [clientId, taskCount] : mClientIdToTaskCount) {
585 output += StringPrintf(" %-9s %-6zu\n", clientId.c_str(), taskCount);
586 }
587 return output;
588}
589
Yu Shan7a5283f2022-10-25 18:01:05 -0700590ScopedAStatus DebugRemoteTaskCallback::onRemoteTaskRequested(const std::string& clientId,
591 const std::vector<uint8_t>& data) {
592 std::lock_guard<std::mutex> lockGuard(mLock);
593 mTasks.push_back({
594 .clientId = clientId,
595 .data = data,
596 });
597 return ScopedAStatus::ok();
598}
599
600std::string DebugRemoteTaskCallback::printTasks() {
601 std::lock_guard<std::mutex> lockGuard(mLock);
602 std::string s = StringPrintf("Received %zu tasks in %f seconds", mTasks.size(),
603 (android::uptimeMillis() - mStartTimeMillis) / 1000.);
604 for (size_t i = 0; i < mTasks.size(); i++) {
605 StringAppendF(&s, "Client Id: %s, Data: %s\n", mTasks[i].clientId.c_str(),
606 printBytes(mTasks[i].data).c_str());
607 }
608 return s;
609}
610
611} // namespace remoteaccess
612} // namespace automotive
613} // namespace hardware
614} // namespace android