blob: bbda9df759a9aa6c8dd97d3fd4fa21da170150f5 [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>
21#include <android-base/stringprintf.h>
22#include <android/binder_status.h>
23#include <grpc++/grpc++.h>
24#include <private/android_filesystem_config.h>
25#include <utils/Log.h>
26#include <chrono>
27#include <thread>
28
29namespace android {
30namespace hardware {
31namespace automotive {
32namespace remoteaccess {
33
34namespace {
35
36using ::aidl::android::hardware::automotive::remoteaccess::ApState;
37using ::aidl::android::hardware::automotive::remoteaccess::IRemoteTaskCallback;
38using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
Yu Shan95493682023-03-21 18:00:17 -070039using ::android::base::Error;
40using ::android::base::Result;
Yu Shan7a5283f2022-10-25 18:01:05 -070041using ::android::base::ScopedLockAssertion;
42using ::android::base::StringAppendF;
43using ::android::base::StringPrintf;
44using ::android::frameworks::automotive::vhal::IVhalClient;
45using ::android::hardware::automotive::vehicle::toInt;
46using ::grpc::ClientContext;
47using ::grpc::ClientReaderInterface;
48using ::grpc::Status;
49using ::grpc::StatusCode;
50using ::ndk::ScopedAStatus;
51
52const std::string WAKEUP_SERVICE_NAME = "com.google.vehicle.wakeup";
Eric Jeong6c3a1d82023-03-16 00:45:40 -070053const std::string PROCESSOR_ID = "application_processor";
Yu Shan7a5283f2022-10-25 18:01:05 -070054constexpr char COMMAND_SET_AP_STATE[] = "--set-ap-state";
55constexpr char COMMAND_START_DEBUG_CALLBACK[] = "--start-debug-callback";
56constexpr char COMMAND_STOP_DEBUG_CALLBACK[] = "--stop-debug-callback";
57constexpr char COMMAND_SHOW_TASK[] = "--show-task";
Eric Jeong6c3a1d82023-03-16 00:45:40 -070058constexpr char COMMAND_GET_VEHICLE_ID[] = "--get-vehicle-id";
Yu Shan95493682023-03-21 18:00:17 -070059constexpr char COMMAND_INJECT_TASK[] = "--inject-task";
60constexpr char COMMAND_STATUS[] = "--status";
Yu Shan7a5283f2022-10-25 18:01:05 -070061
Yu Shan95493682023-03-21 18:00:17 -070062std::vector<uint8_t> stringToBytes(std::string_view s) {
Yu Shan7a5283f2022-10-25 18:01:05 -070063 const char* data = s.data();
64 return std::vector<uint8_t>(data, data + s.size());
65}
66
67ScopedAStatus rpcStatusToScopedAStatus(const Status& status, const std::string& errorMsg) {
68 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
69 status.error_code(), (errorMsg + ", error: " + status.error_message()).c_str());
70}
71
72std::string printBytes(const std::vector<uint8_t>& bytes) {
73 std::string s;
74 for (size_t i = 0; i < bytes.size(); i++) {
75 StringAppendF(&s, "%02x", bytes[i]);
76 }
77 return s;
78}
79
80bool checkBoolFlag(const char* flag) {
81 return !strcmp(flag, "1") || !strcmp(flag, "0");
82}
83
84void dprintErrorStatus(int fd, const char* detail, const ScopedAStatus& status) {
85 dprintf(fd, "%s, code: %d, error: %s\n", detail, status.getStatus(), status.getMessage());
86}
87
Yu Shan95493682023-03-21 18:00:17 -070088std::string boolToString(bool x) {
89 return x ? "true" : "false";
90}
91
Yu Shan7a5283f2022-10-25 18:01:05 -070092} // namespace
93
94RemoteAccessService::RemoteAccessService(WakeupClient::StubInterface* grpcStub)
95 : mGrpcStub(grpcStub){};
96
97RemoteAccessService::~RemoteAccessService() {
98 maybeStopTaskLoop();
99}
100
101void RemoteAccessService::maybeStartTaskLoop() {
102 std::lock_guard<std::mutex> lockGuard(mStartStopTaskLoopLock);
103 if (mTaskLoopRunning) {
104 return;
105 }
106
107 mThread = std::thread([this]() { runTaskLoop(); });
108
109 mTaskLoopRunning = true;
110}
111
112void RemoteAccessService::maybeStopTaskLoop() {
113 std::lock_guard<std::mutex> lockGuard(mStartStopTaskLoopLock);
114 if (!mTaskLoopRunning) {
115 return;
116 }
117
118 {
119 std::lock_guard<std::mutex> lockGuard(mLock);
120 // Try to stop the reading stream.
121 if (mGetRemoteTasksContext) {
122 mGetRemoteTasksContext->TryCancel();
Yu Shandf39d6e2022-12-02 17:01:57 -0800123 // Don't reset mGetRemoteTaskContext here since the read stream might still be affective
124 // and might still be using it. This will cause reader->Read to return false and
125 // mGetRemoteTasksContext will be cleared after reader->Finish() is called.
Yu Shan7a5283f2022-10-25 18:01:05 -0700126 }
127 mTaskWaitStopped = true;
128 mCv.notify_all();
129 }
130 if (mThread.joinable()) {
131 mThread.join();
132 }
133
134 mTaskLoopRunning = false;
135}
136
Yu Shan95493682023-03-21 18:00:17 -0700137void RemoteAccessService::updateGrpcConnected(bool connected) {
138 std::lock_guard<std::mutex> lockGuard(mLock);
139 mGrpcConnected = connected;
140}
141
142Result<void> RemoteAccessService::deliverRemoteTaskThroughCallback(const std::string& clientId,
143 std::string_view taskData) {
144 std::shared_ptr<IRemoteTaskCallback> callback;
145 {
146 std::lock_guard<std::mutex> lockGuard(mLock);
147 callback = mRemoteTaskCallback;
148 mClientIdToTaskCount[clientId] += 1;
149 }
150 if (callback == nullptr) {
151 return Error() << "No callback registered, task ignored";
152 }
153 ALOGD("Calling onRemoteTaskRequested callback for client ID: %s", clientId.c_str());
154 ScopedAStatus callbackStatus =
155 callback->onRemoteTaskRequested(clientId, stringToBytes(taskData));
156 if (!callbackStatus.isOk()) {
157 return Error() << "Failed to call onRemoteTaskRequested callback, status: "
158 << callbackStatus.getStatus()
159 << ", message: " << callbackStatus.getMessage();
160 }
161 return {};
162}
163
Yu Shan7a5283f2022-10-25 18:01:05 -0700164void RemoteAccessService::runTaskLoop() {
165 GetRemoteTasksRequest request = {};
166 std::unique_ptr<ClientReaderInterface<GetRemoteTasksResponse>> reader;
167 while (true) {
168 {
169 std::lock_guard<std::mutex> lockGuard(mLock);
170 mGetRemoteTasksContext.reset(new ClientContext());
171 reader = mGrpcStub->GetRemoteTasks(mGetRemoteTasksContext.get(), request);
172 }
Yu Shan95493682023-03-21 18:00:17 -0700173 updateGrpcConnected(true);
Yu Shan7a5283f2022-10-25 18:01:05 -0700174 GetRemoteTasksResponse response;
175 while (reader->Read(&response)) {
176 ALOGI("Receiving one task from remote task client");
177
Yu Shan95493682023-03-21 18:00:17 -0700178 if (auto result =
179 deliverRemoteTaskThroughCallback(response.clientid(), response.data());
180 !result.ok()) {
181 ALOGE("%s", result.error().message().c_str());
Yu Shan7a5283f2022-10-25 18:01:05 -0700182 continue;
183 }
Yu Shan7a5283f2022-10-25 18:01:05 -0700184 }
Yu Shan95493682023-03-21 18:00:17 -0700185 updateGrpcConnected(false);
Yu Shan7a5283f2022-10-25 18:01:05 -0700186 Status status = reader->Finish();
Yu Shandf39d6e2022-12-02 17:01:57 -0800187 mGetRemoteTasksContext.reset();
Yu Shan7a5283f2022-10-25 18:01:05 -0700188
189 ALOGE("GetRemoteTasks stream breaks, code: %d, message: %s, sleeping for 10s and retry",
190 status.error_code(), status.error_message().c_str());
191 // The long lasting connection should not return. But if the server returns, retry after
192 // 10s.
193 {
194 std::unique_lock lk(mLock);
195 if (mCv.wait_for(lk, std::chrono::milliseconds(mRetryWaitInMs), [this] {
196 ScopedLockAssertion lockAssertion(mLock);
197 return mTaskWaitStopped;
198 })) {
199 // If the stopped flag is set, we are quitting, exit the loop.
200 break;
201 }
202 }
203 }
204}
205
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700206ScopedAStatus RemoteAccessService::getVehicleId(std::string* vehicleId) {
Yu Shan7a5283f2022-10-25 18:01:05 -0700207#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
208 auto vhalClient = IVhalClient::tryCreate();
209 if (vhalClient == nullptr) {
210 ALOGE("Failed to connect to VHAL");
211 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700212 /*errorCode=*/0, "Failed to connect to VHAL to get vehicle ID");
Yu Shan7a5283f2022-10-25 18:01:05 -0700213 }
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700214 return getVehicleIdWithClient(*vhalClient.get(), vehicleId);
Yu Shan7a5283f2022-10-25 18:01:05 -0700215#else
216 // Don't use VHAL client in fuzzing since IPC is not allowed.
217 return ScopedAStatus::ok();
218#endif
219}
220
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700221ScopedAStatus RemoteAccessService::getVehicleIdWithClient(IVhalClient& vhalClient,
222 std::string* vehicleId) {
Yu Shan7a5283f2022-10-25 18:01:05 -0700223 auto result = vhalClient.getValueSync(
224 *vhalClient.createHalPropValue(toInt(VehicleProperty::INFO_VIN)));
225 if (!result.ok()) {
226 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
227 /*errorCode=*/0,
228 ("failed to get INFO_VIN from VHAL: " + result.error().message()).c_str());
229 }
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700230 *vehicleId = (*result)->getStringValue();
231 return ScopedAStatus::ok();
232}
233
234ScopedAStatus RemoteAccessService::getProcessorId(std::string* processorId) {
235 *processorId = PROCESSOR_ID;
Yu Shan7a5283f2022-10-25 18:01:05 -0700236 return ScopedAStatus::ok();
237}
238
239ScopedAStatus RemoteAccessService::getWakeupServiceName(std::string* wakeupServiceName) {
240 *wakeupServiceName = WAKEUP_SERVICE_NAME;
241 return ScopedAStatus::ok();
242}
243
244ScopedAStatus RemoteAccessService::setRemoteTaskCallback(
245 const std::shared_ptr<IRemoteTaskCallback>& callback) {
246 std::lock_guard<std::mutex> lockGuard(mLock);
247 mRemoteTaskCallback = callback;
248 return ScopedAStatus::ok();
249}
250
251ScopedAStatus RemoteAccessService::clearRemoteTaskCallback() {
252 std::lock_guard<std::mutex> lockGuard(mLock);
253 mRemoteTaskCallback.reset();
254 return ScopedAStatus::ok();
255}
256
257ScopedAStatus RemoteAccessService::notifyApStateChange(const ApState& newState) {
258 ClientContext context;
259 NotifyWakeupRequiredRequest request = {};
260 request.set_iswakeuprequired(newState.isWakeupRequired);
261 NotifyWakeupRequiredResponse response = {};
262 Status status = mGrpcStub->NotifyWakeupRequired(&context, request, &response);
263 if (!status.ok()) {
264 return rpcStatusToScopedAStatus(status, "Failed to notify isWakeupRequired");
265 }
266
267 if (newState.isReadyForRemoteTask) {
268 maybeStartTaskLoop();
269 } else {
270 maybeStopTaskLoop();
271 }
272 return ScopedAStatus::ok();
273}
274
275bool RemoteAccessService::checkDumpPermission() {
276 uid_t uid = AIBinder_getCallingUid();
277 return uid == AID_ROOT || uid == AID_SHELL || uid == AID_SYSTEM;
278}
279
280void RemoteAccessService::dumpHelp(int fd) {
Yu Shan95493682023-03-21 18:00:17 -0700281 dprintf(fd,
282 "RemoteAccess HAL debug interface, Usage: \n"
283 "%s [0/1](isReadyForRemoteTask) [0/1](isWakeupRequired): Set the new AP state\n"
284 "%s: Start a debug callback that will record the received tasks\n"
285 "%s: Stop the debug callback\n"
286 "%s: Show tasks received by debug callback\n"
287 "%s: Get vehicle id\n"
288 "%s [client_id] [task_data]: Inject a task\n"
289 "%s: Show status\n",
290 COMMAND_SET_AP_STATE, COMMAND_START_DEBUG_CALLBACK, COMMAND_STOP_DEBUG_CALLBACK,
291 COMMAND_SHOW_TASK, COMMAND_GET_VEHICLE_ID, COMMAND_INJECT_TASK, COMMAND_STATUS);
Yu Shan7a5283f2022-10-25 18:01:05 -0700292}
293
294binder_status_t RemoteAccessService::dump(int fd, const char** args, uint32_t numArgs) {
295 if (!checkDumpPermission()) {
296 dprintf(fd, "Caller must be root, system or shell\n");
297 return STATUS_PERMISSION_DENIED;
298 }
299
300 if (numArgs == 0) {
301 dumpHelp(fd);
Yu Shan95493682023-03-21 18:00:17 -0700302 printCurrentStatus(fd);
Yu Shan7a5283f2022-10-25 18:01:05 -0700303 return STATUS_OK;
304 }
305
306 if (!strcmp(args[0], COMMAND_SET_AP_STATE)) {
307 if (numArgs < 3) {
308 dumpHelp(fd);
309 return STATUS_OK;
310 }
311 ApState apState = {};
312 const char* remoteTaskFlag = args[1];
313 if (!strcmp(remoteTaskFlag, "1") && !strcmp(remoteTaskFlag, "0")) {
314 dumpHelp(fd);
315 return STATUS_OK;
316 }
317 if (!checkBoolFlag(args[1])) {
318 dumpHelp(fd);
319 return STATUS_OK;
320 }
321 if (!strcmp(args[1], "1")) {
322 apState.isReadyForRemoteTask = true;
323 }
324 if (!checkBoolFlag(args[2])) {
325 dumpHelp(fd);
326 return STATUS_OK;
327 }
328 if (!strcmp(args[2], "1")) {
329 apState.isWakeupRequired = true;
330 }
331 auto status = notifyApStateChange(apState);
332 if (!status.isOk()) {
333 dprintErrorStatus(fd, "Failed to set AP state", status);
334 } else {
335 dprintf(fd, "successfully set the new AP state\n");
336 }
337 } else if (!strcmp(args[0], COMMAND_START_DEBUG_CALLBACK)) {
338 mDebugCallback = ndk::SharedRefBase::make<DebugRemoteTaskCallback>();
339 setRemoteTaskCallback(mDebugCallback);
340 dprintf(fd, "Debug callback registered\n");
341 } else if (!strcmp(args[0], COMMAND_STOP_DEBUG_CALLBACK)) {
342 if (mDebugCallback) {
343 mDebugCallback.reset();
344 }
345 clearRemoteTaskCallback();
346 dprintf(fd, "Debug callback unregistered\n");
347 } else if (!strcmp(args[0], COMMAND_SHOW_TASK)) {
348 if (mDebugCallback) {
349 dprintf(fd, "%s", mDebugCallback->printTasks().c_str());
350 } else {
351 dprintf(fd, "Debug callback is not currently used, use \"%s\" first.\n",
352 COMMAND_START_DEBUG_CALLBACK);
353 }
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700354 } else if (!strcmp(args[0], COMMAND_GET_VEHICLE_ID)) {
355 std::string vehicleId;
356 auto status = getVehicleId(&vehicleId);
Yu Shan7a5283f2022-10-25 18:01:05 -0700357 if (!status.isOk()) {
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700358 dprintErrorStatus(fd, "Failed to get vehicle ID", status);
Yu Shan7a5283f2022-10-25 18:01:05 -0700359 } else {
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700360 dprintf(fd, "Vehicle Id: %s\n", vehicleId.c_str());
Yu Shan7a5283f2022-10-25 18:01:05 -0700361 }
Yu Shan95493682023-03-21 18:00:17 -0700362 } else if (!strcmp(args[0], COMMAND_INJECT_TASK)) {
363 if (numArgs < 3) {
364 dumpHelp(fd);
365 return STATUS_OK;
366 }
367 debugInjectTask(fd, args[1], args[2]);
368 } else if (!strcmp(args[0], COMMAND_STATUS)) {
369 printCurrentStatus(fd);
Yu Shan7a5283f2022-10-25 18:01:05 -0700370 } else {
371 dumpHelp(fd);
372 }
373
374 return STATUS_OK;
375}
376
Yu Shan95493682023-03-21 18:00:17 -0700377void RemoteAccessService::printCurrentStatus(int fd) {
378 std::lock_guard<std::mutex> lockGuard(mLock);
379 dprintf(fd,
380 "\nRemoteAccess HAL status \n"
381 "Remote task callback registered: %s\n"
382 "Task receiving GRPC connection established: %s\n"
383 "Received task count by clientId: \n%s\n",
384 boolToString(mRemoteTaskCallback.get()).c_str(), boolToString(mGrpcConnected).c_str(),
385 clientIdToTaskCountToStringLocked().c_str());
386}
387
388void RemoteAccessService::debugInjectTask(int fd, std::string_view clientId,
389 std::string_view taskData) {
390 std::string clientIdCopy = std::string(clientId);
391 if (auto result = deliverRemoteTaskThroughCallback(clientIdCopy, taskData); !result.ok()) {
392 dprintf(fd, "Failed to inject task: %s", result.error().message().c_str());
393 return;
394 }
395 dprintf(fd, "Task for client: %s, data: [%s] successfully injected\n", clientId.data(),
396 taskData.data());
397}
398
399std::string RemoteAccessService::clientIdToTaskCountToStringLocked() {
400 // Print the table header
401 std::string output = "| ClientId | Count |\n";
402 for (const auto& [clientId, taskCount] : mClientIdToTaskCount) {
403 output += StringPrintf(" %-9s %-6zu\n", clientId.c_str(), taskCount);
404 }
405 return output;
406}
407
Yu Shan7a5283f2022-10-25 18:01:05 -0700408ScopedAStatus DebugRemoteTaskCallback::onRemoteTaskRequested(const std::string& clientId,
409 const std::vector<uint8_t>& data) {
410 std::lock_guard<std::mutex> lockGuard(mLock);
411 mTasks.push_back({
412 .clientId = clientId,
413 .data = data,
414 });
415 return ScopedAStatus::ok();
416}
417
418std::string DebugRemoteTaskCallback::printTasks() {
419 std::lock_guard<std::mutex> lockGuard(mLock);
420 std::string s = StringPrintf("Received %zu tasks in %f seconds", mTasks.size(),
421 (android::uptimeMillis() - mStartTimeMillis) / 1000.);
422 for (size_t i = 0; i < mTasks.size(); i++) {
423 StringAppendF(&s, "Client Id: %s, Data: %s\n", mTasks[i].clientId.c_str(),
424 printBytes(mTasks[i].data).c_str());
425 }
426 return s;
427}
428
429} // namespace remoteaccess
430} // namespace automotive
431} // namespace hardware
432} // namespace android