blob: 5081ac0a9b773caea2d58f9e79e178606710b2b9 [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;
42using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
Yu Shan95493682023-03-21 18:00:17 -070043using ::android::base::Error;
Yu Shan194757d2023-04-19 11:44:35 -070044using ::android::base::ParseInt;
Yu Shan95493682023-03-21 18:00:17 -070045using ::android::base::Result;
Yu Shan7a5283f2022-10-25 18:01:05 -070046using ::android::base::ScopedLockAssertion;
47using ::android::base::StringAppendF;
48using ::android::base::StringPrintf;
49using ::android::frameworks::automotive::vhal::IVhalClient;
50using ::android::hardware::automotive::vehicle::toInt;
51using ::grpc::ClientContext;
52using ::grpc::ClientReaderInterface;
53using ::grpc::Status;
54using ::grpc::StatusCode;
55using ::ndk::ScopedAStatus;
56
57const std::string WAKEUP_SERVICE_NAME = "com.google.vehicle.wakeup";
Eric Jeong6c3a1d82023-03-16 00:45:40 -070058const std::string PROCESSOR_ID = "application_processor";
Yu Shan7a5283f2022-10-25 18:01:05 -070059constexpr char COMMAND_SET_AP_STATE[] = "--set-ap-state";
60constexpr char COMMAND_START_DEBUG_CALLBACK[] = "--start-debug-callback";
61constexpr char COMMAND_STOP_DEBUG_CALLBACK[] = "--stop-debug-callback";
62constexpr char COMMAND_SHOW_TASK[] = "--show-task";
Eric Jeong6c3a1d82023-03-16 00:45:40 -070063constexpr char COMMAND_GET_VEHICLE_ID[] = "--get-vehicle-id";
Yu Shan95493682023-03-21 18:00:17 -070064constexpr char COMMAND_INJECT_TASK[] = "--inject-task";
Yu Shan194757d2023-04-19 11:44:35 -070065constexpr char COMMAND_INJECT_TASK_NEXT_REBOOT[] = "--inject-task-next-reboot";
Yu Shan95493682023-03-21 18:00:17 -070066constexpr char COMMAND_STATUS[] = "--status";
Yu Shan7a5283f2022-10-25 18:01:05 -070067
Yu Shan58ff0912023-05-12 18:00:59 -070068constexpr char DEBUG_TASK_FILE[] = "/data/vendor/remoteaccess/debugTask";
Yu Shan194757d2023-04-19 11:44:35 -070069
Yu Shan95493682023-03-21 18:00:17 -070070std::vector<uint8_t> stringToBytes(std::string_view s) {
Yu Shan7a5283f2022-10-25 18:01:05 -070071 const char* data = s.data();
72 return std::vector<uint8_t>(data, data + s.size());
73}
74
75ScopedAStatus 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
80std::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
88bool checkBoolFlag(const char* flag) {
89 return !strcmp(flag, "1") || !strcmp(flag, "0");
90}
91
92void 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
Yu Shan95493682023-03-21 18:00:17 -070096std::string boolToString(bool x) {
97 return x ? "true" : "false";
98}
99
Yu Shan7a5283f2022-10-25 18:01:05 -0700100} // namespace
101
102RemoteAccessService::RemoteAccessService(WakeupClient::StubInterface* grpcStub)
Yu Shan194757d2023-04-19 11:44:35 -0700103 : 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}
Yu Shan7a5283f2022-10-25 18:01:05 -0700134
135RemoteAccessService::~RemoteAccessService() {
136 maybeStopTaskLoop();
Yu Shan194757d2023-04-19 11:44:35 -0700137 if (mInjectDebugTaskThread.joinable()) {
138 mInjectDebugTaskThread.join();
139 }
Yu Shan7a5283f2022-10-25 18:01:05 -0700140}
141
142void 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
153void 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();
Yu Shandf39d6e2022-12-02 17:01:57 -0800164 // 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.
Yu Shan7a5283f2022-10-25 18:01:05 -0700167 }
168 mTaskWaitStopped = true;
169 mCv.notify_all();
170 }
171 if (mThread.joinable()) {
172 mThread.join();
173 }
174
175 mTaskLoopRunning = false;
176}
177
Yu Shan95493682023-03-21 18:00:17 -0700178void RemoteAccessService::updateGrpcConnected(bool connected) {
179 std::lock_guard<std::mutex> lockGuard(mLock);
180 mGrpcConnected = connected;
181}
182
183Result<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
Yu Shan7a5283f2022-10-25 18:01:05 -0700205void 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 }
Yu Shan95493682023-03-21 18:00:17 -0700214 updateGrpcConnected(true);
Yu Shan7a5283f2022-10-25 18:01:05 -0700215 GetRemoteTasksResponse response;
216 while (reader->Read(&response)) {
217 ALOGI("Receiving one task from remote task client");
218
Yu Shan95493682023-03-21 18:00:17 -0700219 if (auto result =
220 deliverRemoteTaskThroughCallback(response.clientid(), response.data());
221 !result.ok()) {
222 ALOGE("%s", result.error().message().c_str());
Yu Shan7a5283f2022-10-25 18:01:05 -0700223 continue;
224 }
Yu Shan7a5283f2022-10-25 18:01:05 -0700225 }
Yu Shan95493682023-03-21 18:00:17 -0700226 updateGrpcConnected(false);
Yu Shan7a5283f2022-10-25 18:01:05 -0700227 Status status = reader->Finish();
Yu Shandf39d6e2022-12-02 17:01:57 -0800228 mGetRemoteTasksContext.reset();
Yu Shan7a5283f2022-10-25 18:01:05 -0700229
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
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700247ScopedAStatus RemoteAccessService::getVehicleId(std::string* vehicleId) {
Yu Shan7a5283f2022-10-25 18:01:05 -0700248#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(
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700253 /*errorCode=*/0, "Failed to connect to VHAL to get vehicle ID");
Yu Shan7a5283f2022-10-25 18:01:05 -0700254 }
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700255 return getVehicleIdWithClient(*vhalClient.get(), vehicleId);
Yu Shan7a5283f2022-10-25 18:01:05 -0700256#else
257 // Don't use VHAL client in fuzzing since IPC is not allowed.
258 return ScopedAStatus::ok();
259#endif
260}
261
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700262ScopedAStatus RemoteAccessService::getVehicleIdWithClient(IVhalClient& vhalClient,
263 std::string* vehicleId) {
Yu Shan7a5283f2022-10-25 18:01:05 -0700264 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 }
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700271 *vehicleId = (*result)->getStringValue();
272 return ScopedAStatus::ok();
273}
274
275ScopedAStatus RemoteAccessService::getProcessorId(std::string* processorId) {
276 *processorId = PROCESSOR_ID;
Yu Shan7a5283f2022-10-25 18:01:05 -0700277 return ScopedAStatus::ok();
278}
279
280ScopedAStatus RemoteAccessService::getWakeupServiceName(std::string* wakeupServiceName) {
281 *wakeupServiceName = WAKEUP_SERVICE_NAME;
282 return ScopedAStatus::ok();
283}
284
285ScopedAStatus 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
292ScopedAStatus RemoteAccessService::clearRemoteTaskCallback() {
293 std::lock_guard<std::mutex> lockGuard(mLock);
294 mRemoteTaskCallback.reset();
295 return ScopedAStatus::ok();
296}
297
298ScopedAStatus 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
316bool RemoteAccessService::checkDumpPermission() {
317 uid_t uid = AIBinder_getCallingUid();
318 return uid == AID_ROOT || uid == AID_SHELL || uid == AID_SYSTEM;
319}
320
321void RemoteAccessService::dumpHelp(int fd) {
Yu Shan95493682023-03-21 18:00:17 -0700322 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"
Yu Shan194757d2023-04-19 11:44:35 -0700330 "%s [client_id] [task_data] [latencyInSec]: "
331 "Inject a task on next reboot after latencyInSec seconds\n"
Yu Shan95493682023-03-21 18:00:17 -0700332 "%s: Show status\n",
333 COMMAND_SET_AP_STATE, COMMAND_START_DEBUG_CALLBACK, COMMAND_STOP_DEBUG_CALLBACK,
Yu Shan194757d2023-04-19 11:44:35 -0700334 COMMAND_SHOW_TASK, COMMAND_GET_VEHICLE_ID, COMMAND_INJECT_TASK,
335 COMMAND_INJECT_TASK_NEXT_REBOOT, COMMAND_STATUS);
Yu Shan7a5283f2022-10-25 18:01:05 -0700336}
337
338binder_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);
Yu Shan95493682023-03-21 18:00:17 -0700346 printCurrentStatus(fd);
Yu Shan7a5283f2022-10-25 18:01:05 -0700347 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 }
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700398 } else if (!strcmp(args[0], COMMAND_GET_VEHICLE_ID)) {
399 std::string vehicleId;
400 auto status = getVehicleId(&vehicleId);
Yu Shan7a5283f2022-10-25 18:01:05 -0700401 if (!status.isOk()) {
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700402 dprintErrorStatus(fd, "Failed to get vehicle ID", status);
Yu Shan7a5283f2022-10-25 18:01:05 -0700403 } else {
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700404 dprintf(fd, "Vehicle Id: %s\n", vehicleId.c_str());
Yu Shan7a5283f2022-10-25 18:01:05 -0700405 }
Yu Shan95493682023-03-21 18:00:17 -0700406 } 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]);
Yu Shan194757d2023-04-19 11:44:35 -0700412 } 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]);
Yu Shan95493682023-03-21 18:00:17 -0700418 } else if (!strcmp(args[0], COMMAND_STATUS)) {
419 printCurrentStatus(fd);
Yu Shan7a5283f2022-10-25 18:01:05 -0700420 } else {
421 dumpHelp(fd);
422 }
423
424 return STATUS_OK;
425}
426
Yu Shan95493682023-03-21 18:00:17 -0700427void 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
438void 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()) {
Yu Shan194757d2023-04-19 11:44:35 -0700442 dprintf(fd, "Failed to inject task: %s\n", result.error().message().c_str());
Yu Shan95493682023-03-21 18:00:17 -0700443 return;
444 }
445 dprintf(fd, "Task for client: %s, data: [%s] successfully injected\n", clientId.data(),
446 taskData.data());
447}
448
Yu Shan194757d2023-04-19 11:44:35 -0700449void 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
Yu Shan95493682023-03-21 18:00:17 -0700477std::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
Yu Shan7a5283f2022-10-25 18:01:05 -0700486ScopedAStatus 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
496std::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