blob: dbd5bed7df313c152c19cdb9bf5926cf8ddff7f7 [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) {
Yu Shan0fbc17f2023-12-26 15:57:47 -0800106 if (mGrpcStub != nullptr) {
107 mGrpcServerExist = true;
108 }
109
Yu Shan194757d2023-04-19 11:44:35 -0700110 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}
Yu Shan7a5283f2022-10-25 18:01:05 -0700140
141RemoteAccessService::~RemoteAccessService() {
142 maybeStopTaskLoop();
Yu Shan194757d2023-04-19 11:44:35 -0700143 if (mInjectDebugTaskThread.joinable()) {
144 mInjectDebugTaskThread.join();
145 }
Yu Shan7a5283f2022-10-25 18:01:05 -0700146}
147
148void 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
159void 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();
Yu Shandf39d6e2022-12-02 17:01:57 -0800170 // 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.
Yu Shan7a5283f2022-10-25 18:01:05 -0700173 }
174 mTaskWaitStopped = true;
175 mCv.notify_all();
176 }
177 if (mThread.joinable()) {
178 mThread.join();
179 }
180
181 mTaskLoopRunning = false;
182}
183
Yu Shan0fbc17f2023-12-26 15:57:47 -0800184void RemoteAccessService::updateGrpcReadChannelOpen(bool grpcReadChannelOpen) {
Yu Shan95493682023-03-21 18:00:17 -0700185 std::lock_guard<std::mutex> lockGuard(mLock);
Yu Shan0fbc17f2023-12-26 15:57:47 -0800186 mGrpcReadChannelOpen = grpcReadChannelOpen;
Yu Shan95493682023-03-21 18:00:17 -0700187}
188
189Result<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
Yu Shan7a5283f2022-10-25 18:01:05 -0700211void 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 }
Yu Shan0fbc17f2023-12-26 15:57:47 -0800220 updateGrpcReadChannelOpen(true);
Yu Shan7a5283f2022-10-25 18:01:05 -0700221 GetRemoteTasksResponse response;
222 while (reader->Read(&response)) {
223 ALOGI("Receiving one task from remote task client");
224
Yu Shan95493682023-03-21 18:00:17 -0700225 if (auto result =
226 deliverRemoteTaskThroughCallback(response.clientid(), response.data());
227 !result.ok()) {
228 ALOGE("%s", result.error().message().c_str());
Yu Shan7a5283f2022-10-25 18:01:05 -0700229 continue;
230 }
Yu Shan7a5283f2022-10-25 18:01:05 -0700231 }
Yu Shan0fbc17f2023-12-26 15:57:47 -0800232 updateGrpcReadChannelOpen(false);
Yu Shan7a5283f2022-10-25 18:01:05 -0700233 Status status = reader->Finish();
Yu Shandf39d6e2022-12-02 17:01:57 -0800234 mGetRemoteTasksContext.reset();
Yu Shan7a5283f2022-10-25 18:01:05 -0700235
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
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700253ScopedAStatus RemoteAccessService::getVehicleId(std::string* vehicleId) {
Yu Shan7a5283f2022-10-25 18:01:05 -0700254#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(
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700259 /*errorCode=*/0, "Failed to connect to VHAL to get vehicle ID");
Yu Shan7a5283f2022-10-25 18:01:05 -0700260 }
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700261 return getVehicleIdWithClient(*vhalClient.get(), vehicleId);
Yu Shan7a5283f2022-10-25 18:01:05 -0700262#else
263 // Don't use VHAL client in fuzzing since IPC is not allowed.
264 return ScopedAStatus::ok();
265#endif
266}
267
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700268ScopedAStatus RemoteAccessService::getVehicleIdWithClient(IVhalClient& vhalClient,
269 std::string* vehicleId) {
Yu Shan7a5283f2022-10-25 18:01:05 -0700270 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 }
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700277 *vehicleId = (*result)->getStringValue();
278 return ScopedAStatus::ok();
279}
280
281ScopedAStatus RemoteAccessService::getProcessorId(std::string* processorId) {
282 *processorId = PROCESSOR_ID;
Yu Shan7a5283f2022-10-25 18:01:05 -0700283 return ScopedAStatus::ok();
284}
285
286ScopedAStatus RemoteAccessService::getWakeupServiceName(std::string* wakeupServiceName) {
287 *wakeupServiceName = WAKEUP_SERVICE_NAME;
288 return ScopedAStatus::ok();
289}
290
291ScopedAStatus 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
298ScopedAStatus RemoteAccessService::clearRemoteTaskCallback() {
299 std::lock_guard<std::mutex> lockGuard(mLock);
300 mRemoteTaskCallback.reset();
301 return ScopedAStatus::ok();
302}
303
304ScopedAStatus RemoteAccessService::notifyApStateChange(const ApState& newState) {
Yu Shan0fbc17f2023-12-26 15:57:47 -0800305 if (!mGrpcServerExist) {
306 ALOGW("GRPC server does not exist, do nothing");
307 return ScopedAStatus::ok();
308 }
309
Yu Shan7a5283f2022-10-25 18:01:05 -0700310 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
Yu Shan0fbc17f2023-12-26 15:57:47 -0800327bool 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
Yu Shan72d6f892023-08-30 11:44:13 -0700336ScopedAStatus RemoteAccessService::isTaskScheduleSupported(bool* out) {
Yu Shan0fbc17f2023-12-26 15:57:47 -0800337 *out = isTaskScheduleSupported();
Yu Shan06ddbc62023-08-23 18:05:26 -0700338 return ScopedAStatus::ok();
339}
340
Yu Shan8459a062023-12-13 17:49:37 -0800341ndk::ScopedAStatus RemoteAccessService::getSupportedTaskTypesForScheduling(
342 std::vector<TaskType>* out) {
Yu Shan0fbc17f2023-12-26 15:57:47 -0800343 out->clear();
344 if (!isTaskScheduleSupported()) {
345 ALOGW("Task scheduleing is not supported, return empty task types");
346 return ScopedAStatus::ok();
347 }
348
Yu Shan8459a062023-12-13 17:49:37 -0800349 // TODO(b/316233421): support ENTER_GARAGE_MODE type.
350 out->push_back(TaskType::CUSTOM);
351 return ScopedAStatus::ok();
352}
353
Yu Shan72d6f892023-08-30 11:44:13 -0700354ScopedAStatus RemoteAccessService::scheduleTask(const ScheduleInfo& scheduleInfo) {
Yu Shan0fbc17f2023-12-26 15:57:47 -0800355 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
Yu Shan72d6f892023-08-30 11:44:13 -0700361 ClientContext context;
362 ScheduleTaskRequest request = {};
363 ScheduleTaskResponse response = {};
Yu Shan4f5ede62023-12-21 17:25:57 -0800364
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
Yu Shan72d6f892023-08-30 11:44:13 -0700382 request.mutable_scheduleinfo()->set_clientid(scheduleInfo.clientId);
383 request.mutable_scheduleinfo()->set_scheduleid(scheduleInfo.scheduleId);
384 request.mutable_scheduleinfo()->set_data(scheduleInfo.taskData.data(),
385 scheduleInfo.taskData.size());
386 request.mutable_scheduleinfo()->set_count(scheduleInfo.count);
387 request.mutable_scheduleinfo()->set_starttimeinepochseconds(
388 scheduleInfo.startTimeInEpochSeconds);
389 request.mutable_scheduleinfo()->set_periodicinseconds(scheduleInfo.periodicInSeconds);
390 Status status = mGrpcStub->ScheduleTask(&context, request, &response);
391 if (!status.ok()) {
392 return rpcStatusToScopedAStatus(status, "Failed to call ScheduleTask");
393 }
394 int errorCode = response.errorcode();
395 switch (errorCode) {
396 case ErrorCode::OK:
397 return ScopedAStatus::ok();
398 case ErrorCode::INVALID_ARG:
Yu Shan4f5ede62023-12-21 17:25:57 -0800399 return ScopedAStatus::fromExceptionCodeWithMessage(
400 EX_ILLEGAL_ARGUMENT, "received invalid_arg from grpc server");
Yu Shan72d6f892023-08-30 11:44:13 -0700401 default:
402 // Should not happen.
403 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
404 -1, ("Got unknown error code: " + ErrorCode_Name(errorCode) +
405 " from remote access HAL")
406 .c_str());
407 }
408}
409
410ScopedAStatus RemoteAccessService::unscheduleTask(const std::string& clientId,
411 const std::string& scheduleId) {
Yu Shan0fbc17f2023-12-26 15:57:47 -0800412 if (!isTaskScheduleSupported()) {
413 ALOGW("Task scheduleing is not supported, do nothing");
414 return ScopedAStatus::ok();
415 }
416
Yu Shan72d6f892023-08-30 11:44:13 -0700417 ClientContext context;
418 UnscheduleTaskRequest request = {};
419 UnscheduleTaskResponse response = {};
420 request.set_clientid(clientId);
421 request.set_scheduleid(scheduleId);
422 Status status = mGrpcStub->UnscheduleTask(&context, request, &response);
423 if (!status.ok()) {
424 return rpcStatusToScopedAStatus(status, "Failed to call UnscheduleTask");
425 }
Yu Shan06ddbc62023-08-23 18:05:26 -0700426 return ScopedAStatus::ok();
427}
428
Yu Shan72d6f892023-08-30 11:44:13 -0700429ScopedAStatus RemoteAccessService::unscheduleAllTasks(const std::string& clientId) {
Yu Shan0fbc17f2023-12-26 15:57:47 -0800430 if (!isTaskScheduleSupported()) {
431 ALOGW("Task scheduleing is not supported, do nothing");
432 return ScopedAStatus::ok();
433 }
434
Yu Shan72d6f892023-08-30 11:44:13 -0700435 ClientContext context;
436 UnscheduleAllTasksRequest request = {};
437 UnscheduleAllTasksResponse response = {};
438 request.set_clientid(clientId);
439 Status status = mGrpcStub->UnscheduleAllTasks(&context, request, &response);
440 if (!status.ok()) {
441 return rpcStatusToScopedAStatus(status, "Failed to call UnscheduleAllTasks");
442 }
Yu Shan06ddbc62023-08-23 18:05:26 -0700443 return ScopedAStatus::ok();
444}
445
Yu Shan72d6f892023-08-30 11:44:13 -0700446ScopedAStatus RemoteAccessService::isTaskScheduled(const std::string& clientId,
447 const std::string& scheduleId, bool* out) {
Yu Shan0fbc17f2023-12-26 15:57:47 -0800448 if (!isTaskScheduleSupported()) {
449 ALOGW("Task scheduleing is not supported, return false");
450 *out = false;
451 return ScopedAStatus::ok();
452 }
453
Yu Shan72d6f892023-08-30 11:44:13 -0700454 ClientContext context;
455 IsTaskScheduledRequest request = {};
456 IsTaskScheduledResponse response = {};
457 request.set_clientid(clientId);
458 request.set_scheduleid(scheduleId);
459 Status status = mGrpcStub->IsTaskScheduled(&context, request, &response);
460 if (!status.ok()) {
461 return rpcStatusToScopedAStatus(status, "Failed to call isTaskScheduled");
462 }
463 *out = response.istaskscheduled();
Yu Shan06ddbc62023-08-23 18:05:26 -0700464 return ScopedAStatus::ok();
465}
466
Yu Shan59f33e42023-12-18 16:10:41 -0800467ScopedAStatus RemoteAccessService::getAllPendingScheduledTasks(const std::string& clientId,
468 std::vector<ScheduleInfo>* out) {
Yu Shan0fbc17f2023-12-26 15:57:47 -0800469 if (!isTaskScheduleSupported()) {
470 ALOGW("Task scheduleing is not supported, return empty array");
471 out->clear();
472 return ScopedAStatus::ok();
473 }
474
Yu Shan72d6f892023-08-30 11:44:13 -0700475 ClientContext context;
Yu Shan59f33e42023-12-18 16:10:41 -0800476 GetAllPendingScheduledTasksRequest request = {};
477 GetAllPendingScheduledTasksResponse response = {};
Yu Shan72d6f892023-08-30 11:44:13 -0700478 request.set_clientid(clientId);
Yu Shan59f33e42023-12-18 16:10:41 -0800479 Status status = mGrpcStub->GetAllPendingScheduledTasks(&context, request, &response);
Yu Shan72d6f892023-08-30 11:44:13 -0700480 if (!status.ok()) {
481 return rpcStatusToScopedAStatus(status, "Failed to call isTaskScheduled");
482 }
483 out->clear();
484 for (int i = 0; i < response.allscheduledtasks_size(); i++) {
485 const GrpcScheduleInfo& rpcScheduleInfo = response.allscheduledtasks(i);
486 ScheduleInfo scheduleInfo = {
487 .clientId = rpcScheduleInfo.clientid(),
488 .scheduleId = rpcScheduleInfo.scheduleid(),
489 .taskData = stringToBytes(rpcScheduleInfo.data()),
490 .count = rpcScheduleInfo.count(),
491 .startTimeInEpochSeconds = rpcScheduleInfo.starttimeinepochseconds(),
492 .periodicInSeconds = rpcScheduleInfo.periodicinseconds(),
493 };
494 out->push_back(std::move(scheduleInfo));
495 }
Yu Shan06ddbc62023-08-23 18:05:26 -0700496 return ScopedAStatus::ok();
497}
498
Yu Shan7a5283f2022-10-25 18:01:05 -0700499bool RemoteAccessService::checkDumpPermission() {
500 uid_t uid = AIBinder_getCallingUid();
501 return uid == AID_ROOT || uid == AID_SHELL || uid == AID_SYSTEM;
502}
503
504void RemoteAccessService::dumpHelp(int fd) {
Yu Shan95493682023-03-21 18:00:17 -0700505 dprintf(fd,
506 "RemoteAccess HAL debug interface, Usage: \n"
507 "%s [0/1](isReadyForRemoteTask) [0/1](isWakeupRequired): Set the new AP state\n"
508 "%s: Start a debug callback that will record the received tasks\n"
509 "%s: Stop the debug callback\n"
510 "%s: Show tasks received by debug callback\n"
511 "%s: Get vehicle id\n"
512 "%s [client_id] [task_data]: Inject a task\n"
Yu Shan194757d2023-04-19 11:44:35 -0700513 "%s [client_id] [task_data] [latencyInSec]: "
514 "Inject a task on next reboot after latencyInSec seconds\n"
Yu Shan95493682023-03-21 18:00:17 -0700515 "%s: Show status\n",
516 COMMAND_SET_AP_STATE, COMMAND_START_DEBUG_CALLBACK, COMMAND_STOP_DEBUG_CALLBACK,
Yu Shan194757d2023-04-19 11:44:35 -0700517 COMMAND_SHOW_TASK, COMMAND_GET_VEHICLE_ID, COMMAND_INJECT_TASK,
518 COMMAND_INJECT_TASK_NEXT_REBOOT, COMMAND_STATUS);
Yu Shan7a5283f2022-10-25 18:01:05 -0700519}
520
521binder_status_t RemoteAccessService::dump(int fd, const char** args, uint32_t numArgs) {
522 if (!checkDumpPermission()) {
523 dprintf(fd, "Caller must be root, system or shell\n");
524 return STATUS_PERMISSION_DENIED;
525 }
526
527 if (numArgs == 0) {
528 dumpHelp(fd);
Yu Shan95493682023-03-21 18:00:17 -0700529 printCurrentStatus(fd);
Yu Shan7a5283f2022-10-25 18:01:05 -0700530 return STATUS_OK;
531 }
532
533 if (!strcmp(args[0], COMMAND_SET_AP_STATE)) {
534 if (numArgs < 3) {
535 dumpHelp(fd);
536 return STATUS_OK;
537 }
538 ApState apState = {};
539 const char* remoteTaskFlag = args[1];
540 if (!strcmp(remoteTaskFlag, "1") && !strcmp(remoteTaskFlag, "0")) {
541 dumpHelp(fd);
542 return STATUS_OK;
543 }
544 if (!checkBoolFlag(args[1])) {
545 dumpHelp(fd);
546 return STATUS_OK;
547 }
548 if (!strcmp(args[1], "1")) {
549 apState.isReadyForRemoteTask = true;
550 }
551 if (!checkBoolFlag(args[2])) {
552 dumpHelp(fd);
553 return STATUS_OK;
554 }
555 if (!strcmp(args[2], "1")) {
556 apState.isWakeupRequired = true;
557 }
558 auto status = notifyApStateChange(apState);
559 if (!status.isOk()) {
560 dprintErrorStatus(fd, "Failed to set AP state", status);
561 } else {
562 dprintf(fd, "successfully set the new AP state\n");
563 }
564 } else if (!strcmp(args[0], COMMAND_START_DEBUG_CALLBACK)) {
565 mDebugCallback = ndk::SharedRefBase::make<DebugRemoteTaskCallback>();
566 setRemoteTaskCallback(mDebugCallback);
567 dprintf(fd, "Debug callback registered\n");
568 } else if (!strcmp(args[0], COMMAND_STOP_DEBUG_CALLBACK)) {
569 if (mDebugCallback) {
570 mDebugCallback.reset();
571 }
572 clearRemoteTaskCallback();
573 dprintf(fd, "Debug callback unregistered\n");
574 } else if (!strcmp(args[0], COMMAND_SHOW_TASK)) {
575 if (mDebugCallback) {
576 dprintf(fd, "%s", mDebugCallback->printTasks().c_str());
577 } else {
578 dprintf(fd, "Debug callback is not currently used, use \"%s\" first.\n",
579 COMMAND_START_DEBUG_CALLBACK);
580 }
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700581 } else if (!strcmp(args[0], COMMAND_GET_VEHICLE_ID)) {
582 std::string vehicleId;
583 auto status = getVehicleId(&vehicleId);
Yu Shan7a5283f2022-10-25 18:01:05 -0700584 if (!status.isOk()) {
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700585 dprintErrorStatus(fd, "Failed to get vehicle ID", status);
Yu Shan7a5283f2022-10-25 18:01:05 -0700586 } else {
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700587 dprintf(fd, "Vehicle Id: %s\n", vehicleId.c_str());
Yu Shan7a5283f2022-10-25 18:01:05 -0700588 }
Yu Shan95493682023-03-21 18:00:17 -0700589 } else if (!strcmp(args[0], COMMAND_INJECT_TASK)) {
590 if (numArgs < 3) {
591 dumpHelp(fd);
592 return STATUS_OK;
593 }
594 debugInjectTask(fd, args[1], args[2]);
Yu Shan194757d2023-04-19 11:44:35 -0700595 } else if (!strcmp(args[0], COMMAND_INJECT_TASK_NEXT_REBOOT)) {
596 if (numArgs < 4) {
597 dumpHelp(fd);
598 return STATUS_OK;
599 }
600 debugInjectTaskNextReboot(fd, args[1], args[2], args[3]);
Yu Shan95493682023-03-21 18:00:17 -0700601 } else if (!strcmp(args[0], COMMAND_STATUS)) {
602 printCurrentStatus(fd);
Yu Shan7a5283f2022-10-25 18:01:05 -0700603 } else {
604 dumpHelp(fd);
605 }
606
607 return STATUS_OK;
608}
609
Yu Shan95493682023-03-21 18:00:17 -0700610void RemoteAccessService::printCurrentStatus(int fd) {
611 std::lock_guard<std::mutex> lockGuard(mLock);
612 dprintf(fd,
613 "\nRemoteAccess HAL status \n"
614 "Remote task callback registered: %s\n"
Yu Shan0fbc17f2023-12-26 15:57:47 -0800615 "GRPC server exist: %s\n"
616 "GRPC read channel for receiving tasks open: %s\n"
Yu Shan95493682023-03-21 18:00:17 -0700617 "Received task count by clientId: \n%s\n",
Yu Shan0fbc17f2023-12-26 15:57:47 -0800618 boolToString(mRemoteTaskCallback.get()).c_str(), boolToString(mGrpcServerExist).c_str(),
619 boolToString(mGrpcReadChannelOpen).c_str(),
Yu Shan95493682023-03-21 18:00:17 -0700620 clientIdToTaskCountToStringLocked().c_str());
621}
622
623void RemoteAccessService::debugInjectTask(int fd, std::string_view clientId,
624 std::string_view taskData) {
625 std::string clientIdCopy = std::string(clientId);
626 if (auto result = deliverRemoteTaskThroughCallback(clientIdCopy, taskData); !result.ok()) {
Yu Shan194757d2023-04-19 11:44:35 -0700627 dprintf(fd, "Failed to inject task: %s\n", result.error().message().c_str());
Yu Shan95493682023-03-21 18:00:17 -0700628 return;
629 }
630 dprintf(fd, "Task for client: %s, data: [%s] successfully injected\n", clientId.data(),
631 taskData.data());
632}
633
Yu Shan194757d2023-04-19 11:44:35 -0700634void RemoteAccessService::debugInjectTaskNextReboot(int fd, std::string_view clientId,
635 std::string_view taskData,
636 const char* latencyInSecStr) {
637 int latencyInSec;
638 if (!ParseInt(latencyInSecStr, &latencyInSec)) {
639 dprintf(fd, "The input latency in second is not a valid integer");
640 return;
641 }
642 std::ofstream debugTaskFile;
643 debugTaskFile.open(DEBUG_TASK_FILE, std::ios::out);
644 if (!debugTaskFile.is_open()) {
645 dprintf(fd,
646 "Failed to open debug task file, please run the command: "
647 "'adb shell touch %s' first\n",
648 DEBUG_TASK_FILE);
649 return;
650 }
651 if (taskData.find("\n") != std::string::npos) {
652 dprintf(fd, "Task data must not contain newline\n");
653 return;
654 }
655 debugTaskFile << clientId << "\n" << taskData << "\n" << latencyInSec;
656 debugTaskFile.close();
657 dprintf(fd,
658 "Task with clientId: %s, task data: %s, latency: %d sec scheduled for next reboot\n",
659 clientId.data(), taskData.data(), latencyInSec);
660}
661
Yu Shan95493682023-03-21 18:00:17 -0700662std::string RemoteAccessService::clientIdToTaskCountToStringLocked() {
663 // Print the table header
664 std::string output = "| ClientId | Count |\n";
665 for (const auto& [clientId, taskCount] : mClientIdToTaskCount) {
666 output += StringPrintf(" %-9s %-6zu\n", clientId.c_str(), taskCount);
667 }
668 return output;
669}
670
Yu Shan7a5283f2022-10-25 18:01:05 -0700671ScopedAStatus DebugRemoteTaskCallback::onRemoteTaskRequested(const std::string& clientId,
672 const std::vector<uint8_t>& data) {
673 std::lock_guard<std::mutex> lockGuard(mLock);
674 mTasks.push_back({
675 .clientId = clientId,
676 .data = data,
677 });
678 return ScopedAStatus::ok();
679}
680
681std::string DebugRemoteTaskCallback::printTasks() {
682 std::lock_guard<std::mutex> lockGuard(mLock);
683 std::string s = StringPrintf("Received %zu tasks in %f seconds", mTasks.size(),
684 (android::uptimeMillis() - mStartTimeMillis) / 1000.);
685 for (size_t i = 0; i < mTasks.size(); i++) {
686 StringAppendF(&s, "Client Id: %s, Data: %s\n", mTasks[i].clientId.c_str(),
687 printBytes(mTasks[i].data).c_str());
688 }
689 return s;
690}
691
692} // namespace remoteaccess
693} // namespace automotive
694} // namespace hardware
695} // namespace android