blob: 1b42a1f091ba0208fa72d8b87fa2d99c7252aca4 [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 Shan8459a062023-12-13 17:49:37 -080043using ::aidl::android::hardware::automotive::remoteaccess::TaskType;
Yu Shan7a5283f2022-10-25 18:01:05 -070044using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
Yu Shan95493682023-03-21 18:00:17 -070045using ::android::base::Error;
Yu Shan194757d2023-04-19 11:44:35 -070046using ::android::base::ParseInt;
Yu Shan95493682023-03-21 18:00:17 -070047using ::android::base::Result;
Yu Shan7a5283f2022-10-25 18:01:05 -070048using ::android::base::ScopedLockAssertion;
49using ::android::base::StringAppendF;
50using ::android::base::StringPrintf;
51using ::android::frameworks::automotive::vhal::IVhalClient;
52using ::android::hardware::automotive::vehicle::toInt;
53using ::grpc::ClientContext;
54using ::grpc::ClientReaderInterface;
55using ::grpc::Status;
56using ::grpc::StatusCode;
57using ::ndk::ScopedAStatus;
58
59const std::string WAKEUP_SERVICE_NAME = "com.google.vehicle.wakeup";
Eric Jeong6c3a1d82023-03-16 00:45:40 -070060const std::string PROCESSOR_ID = "application_processor";
Yu Shan7a5283f2022-10-25 18:01:05 -070061constexpr char COMMAND_SET_AP_STATE[] = "--set-ap-state";
62constexpr char COMMAND_START_DEBUG_CALLBACK[] = "--start-debug-callback";
63constexpr char COMMAND_STOP_DEBUG_CALLBACK[] = "--stop-debug-callback";
64constexpr char COMMAND_SHOW_TASK[] = "--show-task";
Eric Jeong6c3a1d82023-03-16 00:45:40 -070065constexpr char COMMAND_GET_VEHICLE_ID[] = "--get-vehicle-id";
Yu Shan95493682023-03-21 18:00:17 -070066constexpr char COMMAND_INJECT_TASK[] = "--inject-task";
Yu Shan194757d2023-04-19 11:44:35 -070067constexpr char COMMAND_INJECT_TASK_NEXT_REBOOT[] = "--inject-task-next-reboot";
Yu Shan95493682023-03-21 18:00:17 -070068constexpr char COMMAND_STATUS[] = "--status";
Yu Shan7a5283f2022-10-25 18:01:05 -070069
Yu Shan58ff0912023-05-12 18:00:59 -070070constexpr char DEBUG_TASK_FILE[] = "/data/vendor/remoteaccess/debugTask";
Yu Shan194757d2023-04-19 11:44:35 -070071
Yu Shan95493682023-03-21 18:00:17 -070072std::vector<uint8_t> stringToBytes(std::string_view s) {
Yu Shan7a5283f2022-10-25 18:01:05 -070073 const char* data = s.data();
74 return std::vector<uint8_t>(data, data + s.size());
75}
76
77ScopedAStatus 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
82std::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
90bool checkBoolFlag(const char* flag) {
91 return !strcmp(flag, "1") || !strcmp(flag, "0");
92}
93
94void 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
Yu Shan95493682023-03-21 18:00:17 -070098std::string boolToString(bool x) {
99 return x ? "true" : "false";
100}
101
Yu Shan7a5283f2022-10-25 18:01:05 -0700102} // namespace
103
104RemoteAccessService::RemoteAccessService(WakeupClient::StubInterface* grpcStub)
Yu Shan194757d2023-04-19 11:44:35 -0700105 : mGrpcStub(grpcStub) {
106 std::ifstream debugTaskFile;
107 debugTaskFile.open(DEBUG_TASK_FILE, std::ios::in);
108 if (!debugTaskFile.is_open()) {
109 ALOGD("No debug task available");
110 return;
111 }
112
113 char buffer[1024] = {};
114 debugTaskFile.getline(buffer, sizeof(buffer));
115 std::string clientId = std::string(buffer);
116 debugTaskFile.getline(buffer, sizeof(buffer));
117 std::string taskData = std::string(buffer);
118 int latencyInSec;
119 debugTaskFile >> latencyInSec;
120 debugTaskFile.close();
121
122 ALOGD("Task for client: %s, data: [%s], latency: %d\n", clientId.c_str(), taskData.c_str(),
123 latencyInSec);
124
125 mInjectDebugTaskThread = std::thread([this, clientId, taskData, latencyInSec] {
126 std::this_thread::sleep_for(std::chrono::seconds(latencyInSec));
127 if (auto result = deliverRemoteTaskThroughCallback(clientId, taskData); !result.ok()) {
128 ALOGE("Failed to inject debug task, clientID: %s, taskData: %s, error: %s",
129 clientId.c_str(), taskData.c_str(), result.error().message().c_str());
130 return;
131 }
132 ALOGD("Task for client: %s, data: [%s] successfully injected\n", clientId.c_str(),
133 taskData.c_str());
134 });
135}
Yu Shan7a5283f2022-10-25 18:01:05 -0700136
137RemoteAccessService::~RemoteAccessService() {
138 maybeStopTaskLoop();
Yu Shan194757d2023-04-19 11:44:35 -0700139 if (mInjectDebugTaskThread.joinable()) {
140 mInjectDebugTaskThread.join();
141 }
Yu Shan7a5283f2022-10-25 18:01:05 -0700142}
143
144void RemoteAccessService::maybeStartTaskLoop() {
145 std::lock_guard<std::mutex> lockGuard(mStartStopTaskLoopLock);
146 if (mTaskLoopRunning) {
147 return;
148 }
149
150 mThread = std::thread([this]() { runTaskLoop(); });
151
152 mTaskLoopRunning = true;
153}
154
155void RemoteAccessService::maybeStopTaskLoop() {
156 std::lock_guard<std::mutex> lockGuard(mStartStopTaskLoopLock);
157 if (!mTaskLoopRunning) {
158 return;
159 }
160
161 {
162 std::lock_guard<std::mutex> lockGuard(mLock);
163 // Try to stop the reading stream.
164 if (mGetRemoteTasksContext) {
165 mGetRemoteTasksContext->TryCancel();
Yu Shandf39d6e2022-12-02 17:01:57 -0800166 // Don't reset mGetRemoteTaskContext here since the read stream might still be affective
167 // and might still be using it. This will cause reader->Read to return false and
168 // mGetRemoteTasksContext will be cleared after reader->Finish() is called.
Yu Shan7a5283f2022-10-25 18:01:05 -0700169 }
170 mTaskWaitStopped = true;
171 mCv.notify_all();
172 }
173 if (mThread.joinable()) {
174 mThread.join();
175 }
176
177 mTaskLoopRunning = false;
178}
179
Yu Shan95493682023-03-21 18:00:17 -0700180void RemoteAccessService::updateGrpcConnected(bool connected) {
181 std::lock_guard<std::mutex> lockGuard(mLock);
182 mGrpcConnected = connected;
183}
184
185Result<void> RemoteAccessService::deliverRemoteTaskThroughCallback(const std::string& clientId,
186 std::string_view taskData) {
187 std::shared_ptr<IRemoteTaskCallback> callback;
188 {
189 std::lock_guard<std::mutex> lockGuard(mLock);
190 callback = mRemoteTaskCallback;
191 mClientIdToTaskCount[clientId] += 1;
192 }
193 if (callback == nullptr) {
194 return Error() << "No callback registered, task ignored";
195 }
196 ALOGD("Calling onRemoteTaskRequested callback for client ID: %s", clientId.c_str());
197 ScopedAStatus callbackStatus =
198 callback->onRemoteTaskRequested(clientId, stringToBytes(taskData));
199 if (!callbackStatus.isOk()) {
200 return Error() << "Failed to call onRemoteTaskRequested callback, status: "
201 << callbackStatus.getStatus()
202 << ", message: " << callbackStatus.getMessage();
203 }
204 return {};
205}
206
Yu Shan7a5283f2022-10-25 18:01:05 -0700207void RemoteAccessService::runTaskLoop() {
208 GetRemoteTasksRequest request = {};
209 std::unique_ptr<ClientReaderInterface<GetRemoteTasksResponse>> reader;
210 while (true) {
211 {
212 std::lock_guard<std::mutex> lockGuard(mLock);
213 mGetRemoteTasksContext.reset(new ClientContext());
214 reader = mGrpcStub->GetRemoteTasks(mGetRemoteTasksContext.get(), request);
215 }
Yu Shan95493682023-03-21 18:00:17 -0700216 updateGrpcConnected(true);
Yu Shan7a5283f2022-10-25 18:01:05 -0700217 GetRemoteTasksResponse response;
218 while (reader->Read(&response)) {
219 ALOGI("Receiving one task from remote task client");
220
Yu Shan95493682023-03-21 18:00:17 -0700221 if (auto result =
222 deliverRemoteTaskThroughCallback(response.clientid(), response.data());
223 !result.ok()) {
224 ALOGE("%s", result.error().message().c_str());
Yu Shan7a5283f2022-10-25 18:01:05 -0700225 continue;
226 }
Yu Shan7a5283f2022-10-25 18:01:05 -0700227 }
Yu Shan95493682023-03-21 18:00:17 -0700228 updateGrpcConnected(false);
Yu Shan7a5283f2022-10-25 18:01:05 -0700229 Status status = reader->Finish();
Yu Shandf39d6e2022-12-02 17:01:57 -0800230 mGetRemoteTasksContext.reset();
Yu Shan7a5283f2022-10-25 18:01:05 -0700231
232 ALOGE("GetRemoteTasks stream breaks, code: %d, message: %s, sleeping for 10s and retry",
233 status.error_code(), status.error_message().c_str());
234 // The long lasting connection should not return. But if the server returns, retry after
235 // 10s.
236 {
237 std::unique_lock lk(mLock);
238 if (mCv.wait_for(lk, std::chrono::milliseconds(mRetryWaitInMs), [this] {
239 ScopedLockAssertion lockAssertion(mLock);
240 return mTaskWaitStopped;
241 })) {
242 // If the stopped flag is set, we are quitting, exit the loop.
243 break;
244 }
245 }
246 }
247}
248
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700249ScopedAStatus RemoteAccessService::getVehicleId(std::string* vehicleId) {
Yu Shan7a5283f2022-10-25 18:01:05 -0700250#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
251 auto vhalClient = IVhalClient::tryCreate();
252 if (vhalClient == nullptr) {
253 ALOGE("Failed to connect to VHAL");
254 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700255 /*errorCode=*/0, "Failed to connect to VHAL to get vehicle ID");
Yu Shan7a5283f2022-10-25 18:01:05 -0700256 }
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700257 return getVehicleIdWithClient(*vhalClient.get(), vehicleId);
Yu Shan7a5283f2022-10-25 18:01:05 -0700258#else
259 // Don't use VHAL client in fuzzing since IPC is not allowed.
260 return ScopedAStatus::ok();
261#endif
262}
263
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700264ScopedAStatus RemoteAccessService::getVehicleIdWithClient(IVhalClient& vhalClient,
265 std::string* vehicleId) {
Yu Shan7a5283f2022-10-25 18:01:05 -0700266 auto result = vhalClient.getValueSync(
267 *vhalClient.createHalPropValue(toInt(VehicleProperty::INFO_VIN)));
268 if (!result.ok()) {
269 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
270 /*errorCode=*/0,
271 ("failed to get INFO_VIN from VHAL: " + result.error().message()).c_str());
272 }
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700273 *vehicleId = (*result)->getStringValue();
274 return ScopedAStatus::ok();
275}
276
277ScopedAStatus RemoteAccessService::getProcessorId(std::string* processorId) {
278 *processorId = PROCESSOR_ID;
Yu Shan7a5283f2022-10-25 18:01:05 -0700279 return ScopedAStatus::ok();
280}
281
282ScopedAStatus RemoteAccessService::getWakeupServiceName(std::string* wakeupServiceName) {
283 *wakeupServiceName = WAKEUP_SERVICE_NAME;
284 return ScopedAStatus::ok();
285}
286
287ScopedAStatus RemoteAccessService::setRemoteTaskCallback(
288 const std::shared_ptr<IRemoteTaskCallback>& callback) {
289 std::lock_guard<std::mutex> lockGuard(mLock);
290 mRemoteTaskCallback = callback;
291 return ScopedAStatus::ok();
292}
293
294ScopedAStatus RemoteAccessService::clearRemoteTaskCallback() {
295 std::lock_guard<std::mutex> lockGuard(mLock);
296 mRemoteTaskCallback.reset();
297 return ScopedAStatus::ok();
298}
299
300ScopedAStatus RemoteAccessService::notifyApStateChange(const ApState& newState) {
301 ClientContext context;
302 NotifyWakeupRequiredRequest request = {};
303 request.set_iswakeuprequired(newState.isWakeupRequired);
304 NotifyWakeupRequiredResponse response = {};
305 Status status = mGrpcStub->NotifyWakeupRequired(&context, request, &response);
306 if (!status.ok()) {
307 return rpcStatusToScopedAStatus(status, "Failed to notify isWakeupRequired");
308 }
309
310 if (newState.isReadyForRemoteTask) {
311 maybeStartTaskLoop();
312 } else {
313 maybeStopTaskLoop();
314 }
315 return ScopedAStatus::ok();
316}
317
Yu Shan72d6f892023-08-30 11:44:13 -0700318ScopedAStatus RemoteAccessService::isTaskScheduleSupported(bool* out) {
319 *out = true;
Yu Shan06ddbc62023-08-23 18:05:26 -0700320 return ScopedAStatus::ok();
321}
322
Yu Shan8459a062023-12-13 17:49:37 -0800323ndk::ScopedAStatus RemoteAccessService::getSupportedTaskTypesForScheduling(
324 std::vector<TaskType>* out) {
325 // TODO(b/316233421): support ENTER_GARAGE_MODE type.
326 out->push_back(TaskType::CUSTOM);
327 return ScopedAStatus::ok();
328}
329
Yu Shan72d6f892023-08-30 11:44:13 -0700330ScopedAStatus RemoteAccessService::scheduleTask(const ScheduleInfo& scheduleInfo) {
331 ClientContext context;
332 ScheduleTaskRequest request = {};
333 ScheduleTaskResponse response = {};
Yu Shan4f5ede62023-12-21 17:25:57 -0800334
335 if (scheduleInfo.count < 0) {
336 return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
337 "count must be >= 0");
338 }
339 if (scheduleInfo.startTimeInEpochSeconds < 0) {
340 return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
341 "startTimeInEpochSeconds must be >= 0");
342 }
343 if (scheduleInfo.periodicInSeconds < 0) {
344 return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
345 "periodicInSeconds must be >= 0");
346 }
347 if (scheduleInfo.taskData.size() > scheduleInfo.MAX_TASK_DATA_SIZE_IN_BYTES) {
348 return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
349 "task data too big");
350 }
351
Yu Shan72d6f892023-08-30 11:44:13 -0700352 request.mutable_scheduleinfo()->set_clientid(scheduleInfo.clientId);
353 request.mutable_scheduleinfo()->set_scheduleid(scheduleInfo.scheduleId);
354 request.mutable_scheduleinfo()->set_data(scheduleInfo.taskData.data(),
355 scheduleInfo.taskData.size());
356 request.mutable_scheduleinfo()->set_count(scheduleInfo.count);
357 request.mutable_scheduleinfo()->set_starttimeinepochseconds(
358 scheduleInfo.startTimeInEpochSeconds);
359 request.mutable_scheduleinfo()->set_periodicinseconds(scheduleInfo.periodicInSeconds);
360 Status status = mGrpcStub->ScheduleTask(&context, request, &response);
361 if (!status.ok()) {
362 return rpcStatusToScopedAStatus(status, "Failed to call ScheduleTask");
363 }
364 int errorCode = response.errorcode();
365 switch (errorCode) {
366 case ErrorCode::OK:
367 return ScopedAStatus::ok();
368 case ErrorCode::INVALID_ARG:
Yu Shan4f5ede62023-12-21 17:25:57 -0800369 return ScopedAStatus::fromExceptionCodeWithMessage(
370 EX_ILLEGAL_ARGUMENT, "received invalid_arg from grpc server");
Yu Shan72d6f892023-08-30 11:44:13 -0700371 default:
372 // Should not happen.
373 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
374 -1, ("Got unknown error code: " + ErrorCode_Name(errorCode) +
375 " from remote access HAL")
376 .c_str());
377 }
378}
379
380ScopedAStatus RemoteAccessService::unscheduleTask(const std::string& clientId,
381 const std::string& scheduleId) {
382 ClientContext context;
383 UnscheduleTaskRequest request = {};
384 UnscheduleTaskResponse response = {};
385 request.set_clientid(clientId);
386 request.set_scheduleid(scheduleId);
387 Status status = mGrpcStub->UnscheduleTask(&context, request, &response);
388 if (!status.ok()) {
389 return rpcStatusToScopedAStatus(status, "Failed to call UnscheduleTask");
390 }
Yu Shan06ddbc62023-08-23 18:05:26 -0700391 return ScopedAStatus::ok();
392}
393
Yu Shan72d6f892023-08-30 11:44:13 -0700394ScopedAStatus RemoteAccessService::unscheduleAllTasks(const std::string& clientId) {
395 ClientContext context;
396 UnscheduleAllTasksRequest request = {};
397 UnscheduleAllTasksResponse response = {};
398 request.set_clientid(clientId);
399 Status status = mGrpcStub->UnscheduleAllTasks(&context, request, &response);
400 if (!status.ok()) {
401 return rpcStatusToScopedAStatus(status, "Failed to call UnscheduleAllTasks");
402 }
Yu Shan06ddbc62023-08-23 18:05:26 -0700403 return ScopedAStatus::ok();
404}
405
Yu Shan72d6f892023-08-30 11:44:13 -0700406ScopedAStatus RemoteAccessService::isTaskScheduled(const std::string& clientId,
407 const std::string& scheduleId, bool* out) {
408 ClientContext context;
409 IsTaskScheduledRequest request = {};
410 IsTaskScheduledResponse response = {};
411 request.set_clientid(clientId);
412 request.set_scheduleid(scheduleId);
413 Status status = mGrpcStub->IsTaskScheduled(&context, request, &response);
414 if (!status.ok()) {
415 return rpcStatusToScopedAStatus(status, "Failed to call isTaskScheduled");
416 }
417 *out = response.istaskscheduled();
Yu Shan06ddbc62023-08-23 18:05:26 -0700418 return ScopedAStatus::ok();
419}
420
Yu Shan59f33e42023-12-18 16:10:41 -0800421ScopedAStatus RemoteAccessService::getAllPendingScheduledTasks(const std::string& clientId,
422 std::vector<ScheduleInfo>* out) {
Yu Shan72d6f892023-08-30 11:44:13 -0700423 ClientContext context;
Yu Shan59f33e42023-12-18 16:10:41 -0800424 GetAllPendingScheduledTasksRequest request = {};
425 GetAllPendingScheduledTasksResponse response = {};
Yu Shan72d6f892023-08-30 11:44:13 -0700426 request.set_clientid(clientId);
Yu Shan59f33e42023-12-18 16:10:41 -0800427 Status status = mGrpcStub->GetAllPendingScheduledTasks(&context, request, &response);
Yu Shan72d6f892023-08-30 11:44:13 -0700428 if (!status.ok()) {
429 return rpcStatusToScopedAStatus(status, "Failed to call isTaskScheduled");
430 }
431 out->clear();
432 for (int i = 0; i < response.allscheduledtasks_size(); i++) {
433 const GrpcScheduleInfo& rpcScheduleInfo = response.allscheduledtasks(i);
434 ScheduleInfo scheduleInfo = {
435 .clientId = rpcScheduleInfo.clientid(),
436 .scheduleId = rpcScheduleInfo.scheduleid(),
437 .taskData = stringToBytes(rpcScheduleInfo.data()),
438 .count = rpcScheduleInfo.count(),
439 .startTimeInEpochSeconds = rpcScheduleInfo.starttimeinepochseconds(),
440 .periodicInSeconds = rpcScheduleInfo.periodicinseconds(),
441 };
442 out->push_back(std::move(scheduleInfo));
443 }
Yu Shan06ddbc62023-08-23 18:05:26 -0700444 return ScopedAStatus::ok();
445}
446
Yu Shan7a5283f2022-10-25 18:01:05 -0700447bool RemoteAccessService::checkDumpPermission() {
448 uid_t uid = AIBinder_getCallingUid();
449 return uid == AID_ROOT || uid == AID_SHELL || uid == AID_SYSTEM;
450}
451
452void RemoteAccessService::dumpHelp(int fd) {
Yu Shan95493682023-03-21 18:00:17 -0700453 dprintf(fd,
454 "RemoteAccess HAL debug interface, Usage: \n"
455 "%s [0/1](isReadyForRemoteTask) [0/1](isWakeupRequired): Set the new AP state\n"
456 "%s: Start a debug callback that will record the received tasks\n"
457 "%s: Stop the debug callback\n"
458 "%s: Show tasks received by debug callback\n"
459 "%s: Get vehicle id\n"
460 "%s [client_id] [task_data]: Inject a task\n"
Yu Shan194757d2023-04-19 11:44:35 -0700461 "%s [client_id] [task_data] [latencyInSec]: "
462 "Inject a task on next reboot after latencyInSec seconds\n"
Yu Shan95493682023-03-21 18:00:17 -0700463 "%s: Show status\n",
464 COMMAND_SET_AP_STATE, COMMAND_START_DEBUG_CALLBACK, COMMAND_STOP_DEBUG_CALLBACK,
Yu Shan194757d2023-04-19 11:44:35 -0700465 COMMAND_SHOW_TASK, COMMAND_GET_VEHICLE_ID, COMMAND_INJECT_TASK,
466 COMMAND_INJECT_TASK_NEXT_REBOOT, COMMAND_STATUS);
Yu Shan7a5283f2022-10-25 18:01:05 -0700467}
468
469binder_status_t RemoteAccessService::dump(int fd, const char** args, uint32_t numArgs) {
470 if (!checkDumpPermission()) {
471 dprintf(fd, "Caller must be root, system or shell\n");
472 return STATUS_PERMISSION_DENIED;
473 }
474
475 if (numArgs == 0) {
476 dumpHelp(fd);
Yu Shan95493682023-03-21 18:00:17 -0700477 printCurrentStatus(fd);
Yu Shan7a5283f2022-10-25 18:01:05 -0700478 return STATUS_OK;
479 }
480
481 if (!strcmp(args[0], COMMAND_SET_AP_STATE)) {
482 if (numArgs < 3) {
483 dumpHelp(fd);
484 return STATUS_OK;
485 }
486 ApState apState = {};
487 const char* remoteTaskFlag = args[1];
488 if (!strcmp(remoteTaskFlag, "1") && !strcmp(remoteTaskFlag, "0")) {
489 dumpHelp(fd);
490 return STATUS_OK;
491 }
492 if (!checkBoolFlag(args[1])) {
493 dumpHelp(fd);
494 return STATUS_OK;
495 }
496 if (!strcmp(args[1], "1")) {
497 apState.isReadyForRemoteTask = true;
498 }
499 if (!checkBoolFlag(args[2])) {
500 dumpHelp(fd);
501 return STATUS_OK;
502 }
503 if (!strcmp(args[2], "1")) {
504 apState.isWakeupRequired = true;
505 }
506 auto status = notifyApStateChange(apState);
507 if (!status.isOk()) {
508 dprintErrorStatus(fd, "Failed to set AP state", status);
509 } else {
510 dprintf(fd, "successfully set the new AP state\n");
511 }
512 } else if (!strcmp(args[0], COMMAND_START_DEBUG_CALLBACK)) {
513 mDebugCallback = ndk::SharedRefBase::make<DebugRemoteTaskCallback>();
514 setRemoteTaskCallback(mDebugCallback);
515 dprintf(fd, "Debug callback registered\n");
516 } else if (!strcmp(args[0], COMMAND_STOP_DEBUG_CALLBACK)) {
517 if (mDebugCallback) {
518 mDebugCallback.reset();
519 }
520 clearRemoteTaskCallback();
521 dprintf(fd, "Debug callback unregistered\n");
522 } else if (!strcmp(args[0], COMMAND_SHOW_TASK)) {
523 if (mDebugCallback) {
524 dprintf(fd, "%s", mDebugCallback->printTasks().c_str());
525 } else {
526 dprintf(fd, "Debug callback is not currently used, use \"%s\" first.\n",
527 COMMAND_START_DEBUG_CALLBACK);
528 }
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700529 } else if (!strcmp(args[0], COMMAND_GET_VEHICLE_ID)) {
530 std::string vehicleId;
531 auto status = getVehicleId(&vehicleId);
Yu Shan7a5283f2022-10-25 18:01:05 -0700532 if (!status.isOk()) {
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700533 dprintErrorStatus(fd, "Failed to get vehicle ID", status);
Yu Shan7a5283f2022-10-25 18:01:05 -0700534 } else {
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700535 dprintf(fd, "Vehicle Id: %s\n", vehicleId.c_str());
Yu Shan7a5283f2022-10-25 18:01:05 -0700536 }
Yu Shan95493682023-03-21 18:00:17 -0700537 } else if (!strcmp(args[0], COMMAND_INJECT_TASK)) {
538 if (numArgs < 3) {
539 dumpHelp(fd);
540 return STATUS_OK;
541 }
542 debugInjectTask(fd, args[1], args[2]);
Yu Shan194757d2023-04-19 11:44:35 -0700543 } else if (!strcmp(args[0], COMMAND_INJECT_TASK_NEXT_REBOOT)) {
544 if (numArgs < 4) {
545 dumpHelp(fd);
546 return STATUS_OK;
547 }
548 debugInjectTaskNextReboot(fd, args[1], args[2], args[3]);
Yu Shan95493682023-03-21 18:00:17 -0700549 } else if (!strcmp(args[0], COMMAND_STATUS)) {
550 printCurrentStatus(fd);
Yu Shan7a5283f2022-10-25 18:01:05 -0700551 } else {
552 dumpHelp(fd);
553 }
554
555 return STATUS_OK;
556}
557
Yu Shan95493682023-03-21 18:00:17 -0700558void RemoteAccessService::printCurrentStatus(int fd) {
559 std::lock_guard<std::mutex> lockGuard(mLock);
560 dprintf(fd,
561 "\nRemoteAccess HAL status \n"
562 "Remote task callback registered: %s\n"
563 "Task receiving GRPC connection established: %s\n"
564 "Received task count by clientId: \n%s\n",
565 boolToString(mRemoteTaskCallback.get()).c_str(), boolToString(mGrpcConnected).c_str(),
566 clientIdToTaskCountToStringLocked().c_str());
567}
568
569void RemoteAccessService::debugInjectTask(int fd, std::string_view clientId,
570 std::string_view taskData) {
571 std::string clientIdCopy = std::string(clientId);
572 if (auto result = deliverRemoteTaskThroughCallback(clientIdCopy, taskData); !result.ok()) {
Yu Shan194757d2023-04-19 11:44:35 -0700573 dprintf(fd, "Failed to inject task: %s\n", result.error().message().c_str());
Yu Shan95493682023-03-21 18:00:17 -0700574 return;
575 }
576 dprintf(fd, "Task for client: %s, data: [%s] successfully injected\n", clientId.data(),
577 taskData.data());
578}
579
Yu Shan194757d2023-04-19 11:44:35 -0700580void RemoteAccessService::debugInjectTaskNextReboot(int fd, std::string_view clientId,
581 std::string_view taskData,
582 const char* latencyInSecStr) {
583 int latencyInSec;
584 if (!ParseInt(latencyInSecStr, &latencyInSec)) {
585 dprintf(fd, "The input latency in second is not a valid integer");
586 return;
587 }
588 std::ofstream debugTaskFile;
589 debugTaskFile.open(DEBUG_TASK_FILE, std::ios::out);
590 if (!debugTaskFile.is_open()) {
591 dprintf(fd,
592 "Failed to open debug task file, please run the command: "
593 "'adb shell touch %s' first\n",
594 DEBUG_TASK_FILE);
595 return;
596 }
597 if (taskData.find("\n") != std::string::npos) {
598 dprintf(fd, "Task data must not contain newline\n");
599 return;
600 }
601 debugTaskFile << clientId << "\n" << taskData << "\n" << latencyInSec;
602 debugTaskFile.close();
603 dprintf(fd,
604 "Task with clientId: %s, task data: %s, latency: %d sec scheduled for next reboot\n",
605 clientId.data(), taskData.data(), latencyInSec);
606}
607
Yu Shan95493682023-03-21 18:00:17 -0700608std::string RemoteAccessService::clientIdToTaskCountToStringLocked() {
609 // Print the table header
610 std::string output = "| ClientId | Count |\n";
611 for (const auto& [clientId, taskCount] : mClientIdToTaskCount) {
612 output += StringPrintf(" %-9s %-6zu\n", clientId.c_str(), taskCount);
613 }
614 return output;
615}
616
Yu Shan7a5283f2022-10-25 18:01:05 -0700617ScopedAStatus DebugRemoteTaskCallback::onRemoteTaskRequested(const std::string& clientId,
618 const std::vector<uint8_t>& data) {
619 std::lock_guard<std::mutex> lockGuard(mLock);
620 mTasks.push_back({
621 .clientId = clientId,
622 .data = data,
623 });
624 return ScopedAStatus::ok();
625}
626
627std::string DebugRemoteTaskCallback::printTasks() {
628 std::lock_guard<std::mutex> lockGuard(mLock);
629 std::string s = StringPrintf("Received %zu tasks in %f seconds", mTasks.size(),
630 (android::uptimeMillis() - mStartTimeMillis) / 1000.);
631 for (size_t i = 0; i < mTasks.size(); i++) {
632 StringAppendF(&s, "Client Id: %s, Data: %s\n", mTasks[i].clientId.c_str(),
633 printBytes(mTasks[i].data).c_str());
634 }
635 return s;
636}
637
638} // namespace remoteaccess
639} // namespace automotive
640} // namespace hardware
641} // namespace android