blob: d9445933aecf7f866a7277f227fb9d4a7b5db67c [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;
39using ::android::base::ScopedLockAssertion;
40using ::android::base::StringAppendF;
41using ::android::base::StringPrintf;
42using ::android::frameworks::automotive::vhal::IVhalClient;
43using ::android::hardware::automotive::vehicle::toInt;
44using ::grpc::ClientContext;
45using ::grpc::ClientReaderInterface;
46using ::grpc::Status;
47using ::grpc::StatusCode;
48using ::ndk::ScopedAStatus;
49
50const std::string WAKEUP_SERVICE_NAME = "com.google.vehicle.wakeup";
Eric Jeong6c3a1d82023-03-16 00:45:40 -070051const std::string PROCESSOR_ID = "application_processor";
Yu Shan7a5283f2022-10-25 18:01:05 -070052constexpr char COMMAND_SET_AP_STATE[] = "--set-ap-state";
53constexpr char COMMAND_START_DEBUG_CALLBACK[] = "--start-debug-callback";
54constexpr char COMMAND_STOP_DEBUG_CALLBACK[] = "--stop-debug-callback";
55constexpr char COMMAND_SHOW_TASK[] = "--show-task";
Eric Jeong6c3a1d82023-03-16 00:45:40 -070056constexpr char COMMAND_GET_VEHICLE_ID[] = "--get-vehicle-id";
Yu Shan7a5283f2022-10-25 18:01:05 -070057
58std::vector<uint8_t> stringToBytes(const std::string& s) {
59 const char* data = s.data();
60 return std::vector<uint8_t>(data, data + s.size());
61}
62
63ScopedAStatus rpcStatusToScopedAStatus(const Status& status, const std::string& errorMsg) {
64 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
65 status.error_code(), (errorMsg + ", error: " + status.error_message()).c_str());
66}
67
68std::string printBytes(const std::vector<uint8_t>& bytes) {
69 std::string s;
70 for (size_t i = 0; i < bytes.size(); i++) {
71 StringAppendF(&s, "%02x", bytes[i]);
72 }
73 return s;
74}
75
76bool checkBoolFlag(const char* flag) {
77 return !strcmp(flag, "1") || !strcmp(flag, "0");
78}
79
80void dprintErrorStatus(int fd, const char* detail, const ScopedAStatus& status) {
81 dprintf(fd, "%s, code: %d, error: %s\n", detail, status.getStatus(), status.getMessage());
82}
83
84} // namespace
85
86RemoteAccessService::RemoteAccessService(WakeupClient::StubInterface* grpcStub)
87 : mGrpcStub(grpcStub){};
88
89RemoteAccessService::~RemoteAccessService() {
90 maybeStopTaskLoop();
91}
92
93void RemoteAccessService::maybeStartTaskLoop() {
94 std::lock_guard<std::mutex> lockGuard(mStartStopTaskLoopLock);
95 if (mTaskLoopRunning) {
96 return;
97 }
98
99 mThread = std::thread([this]() { runTaskLoop(); });
100
101 mTaskLoopRunning = true;
102}
103
104void RemoteAccessService::maybeStopTaskLoop() {
105 std::lock_guard<std::mutex> lockGuard(mStartStopTaskLoopLock);
106 if (!mTaskLoopRunning) {
107 return;
108 }
109
110 {
111 std::lock_guard<std::mutex> lockGuard(mLock);
112 // Try to stop the reading stream.
113 if (mGetRemoteTasksContext) {
114 mGetRemoteTasksContext->TryCancel();
Yu Shandf39d6e2022-12-02 17:01:57 -0800115 // Don't reset mGetRemoteTaskContext here since the read stream might still be affective
116 // and might still be using it. This will cause reader->Read to return false and
117 // mGetRemoteTasksContext will be cleared after reader->Finish() is called.
Yu Shan7a5283f2022-10-25 18:01:05 -0700118 }
119 mTaskWaitStopped = true;
120 mCv.notify_all();
121 }
122 if (mThread.joinable()) {
123 mThread.join();
124 }
125
126 mTaskLoopRunning = false;
127}
128
129void RemoteAccessService::runTaskLoop() {
130 GetRemoteTasksRequest request = {};
131 std::unique_ptr<ClientReaderInterface<GetRemoteTasksResponse>> reader;
132 while (true) {
133 {
134 std::lock_guard<std::mutex> lockGuard(mLock);
135 mGetRemoteTasksContext.reset(new ClientContext());
136 reader = mGrpcStub->GetRemoteTasks(mGetRemoteTasksContext.get(), request);
137 }
138 GetRemoteTasksResponse response;
139 while (reader->Read(&response)) {
140 ALOGI("Receiving one task from remote task client");
141
142 std::shared_ptr<IRemoteTaskCallback> callback;
143 {
144 std::lock_guard<std::mutex> lockGuard(mLock);
145 callback = mRemoteTaskCallback;
146 }
147 if (callback == nullptr) {
148 ALOGD("No callback registered, task ignored");
149 continue;
150 }
151 ALOGD("Calling onRemoteTaskRequested callback for client ID: %s",
152 response.clientid().c_str());
153 ScopedAStatus callbackStatus = callback->onRemoteTaskRequested(
154 response.clientid(), stringToBytes(response.data()));
155 if (!callbackStatus.isOk()) {
156 ALOGE("Failed to call onRemoteTaskRequested callback, status: %d, message: %s",
157 callbackStatus.getStatus(), callbackStatus.getMessage());
158 }
159 }
160 Status status = reader->Finish();
Yu Shandf39d6e2022-12-02 17:01:57 -0800161 mGetRemoteTasksContext.reset();
Yu Shan7a5283f2022-10-25 18:01:05 -0700162
163 ALOGE("GetRemoteTasks stream breaks, code: %d, message: %s, sleeping for 10s and retry",
164 status.error_code(), status.error_message().c_str());
165 // The long lasting connection should not return. But if the server returns, retry after
166 // 10s.
167 {
168 std::unique_lock lk(mLock);
169 if (mCv.wait_for(lk, std::chrono::milliseconds(mRetryWaitInMs), [this] {
170 ScopedLockAssertion lockAssertion(mLock);
171 return mTaskWaitStopped;
172 })) {
173 // If the stopped flag is set, we are quitting, exit the loop.
174 break;
175 }
176 }
177 }
178}
179
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700180ScopedAStatus RemoteAccessService::getVehicleId(std::string* vehicleId) {
Yu Shan7a5283f2022-10-25 18:01:05 -0700181#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
182 auto vhalClient = IVhalClient::tryCreate();
183 if (vhalClient == nullptr) {
184 ALOGE("Failed to connect to VHAL");
185 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700186 /*errorCode=*/0, "Failed to connect to VHAL to get vehicle ID");
Yu Shan7a5283f2022-10-25 18:01:05 -0700187 }
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700188 return getVehicleIdWithClient(*vhalClient.get(), vehicleId);
Yu Shan7a5283f2022-10-25 18:01:05 -0700189#else
190 // Don't use VHAL client in fuzzing since IPC is not allowed.
191 return ScopedAStatus::ok();
192#endif
193}
194
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700195ScopedAStatus RemoteAccessService::getVehicleIdWithClient(IVhalClient& vhalClient,
196 std::string* vehicleId) {
Yu Shan7a5283f2022-10-25 18:01:05 -0700197 auto result = vhalClient.getValueSync(
198 *vhalClient.createHalPropValue(toInt(VehicleProperty::INFO_VIN)));
199 if (!result.ok()) {
200 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
201 /*errorCode=*/0,
202 ("failed to get INFO_VIN from VHAL: " + result.error().message()).c_str());
203 }
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700204 *vehicleId = (*result)->getStringValue();
205 return ScopedAStatus::ok();
206}
207
208ScopedAStatus RemoteAccessService::getProcessorId(std::string* processorId) {
209 *processorId = PROCESSOR_ID;
Yu Shan7a5283f2022-10-25 18:01:05 -0700210 return ScopedAStatus::ok();
211}
212
213ScopedAStatus RemoteAccessService::getWakeupServiceName(std::string* wakeupServiceName) {
214 *wakeupServiceName = WAKEUP_SERVICE_NAME;
215 return ScopedAStatus::ok();
216}
217
218ScopedAStatus RemoteAccessService::setRemoteTaskCallback(
219 const std::shared_ptr<IRemoteTaskCallback>& callback) {
220 std::lock_guard<std::mutex> lockGuard(mLock);
221 mRemoteTaskCallback = callback;
222 return ScopedAStatus::ok();
223}
224
225ScopedAStatus RemoteAccessService::clearRemoteTaskCallback() {
226 std::lock_guard<std::mutex> lockGuard(mLock);
227 mRemoteTaskCallback.reset();
228 return ScopedAStatus::ok();
229}
230
231ScopedAStatus RemoteAccessService::notifyApStateChange(const ApState& newState) {
232 ClientContext context;
233 NotifyWakeupRequiredRequest request = {};
234 request.set_iswakeuprequired(newState.isWakeupRequired);
235 NotifyWakeupRequiredResponse response = {};
236 Status status = mGrpcStub->NotifyWakeupRequired(&context, request, &response);
237 if (!status.ok()) {
238 return rpcStatusToScopedAStatus(status, "Failed to notify isWakeupRequired");
239 }
240
241 if (newState.isReadyForRemoteTask) {
242 maybeStartTaskLoop();
243 } else {
244 maybeStopTaskLoop();
245 }
246 return ScopedAStatus::ok();
247}
248
249bool RemoteAccessService::checkDumpPermission() {
250 uid_t uid = AIBinder_getCallingUid();
251 return uid == AID_ROOT || uid == AID_SHELL || uid == AID_SYSTEM;
252}
253
254void RemoteAccessService::dumpHelp(int fd) {
255 dprintf(fd, "%s",
256 (std::string("RemoteAccess HAL debug interface, Usage: \n") + COMMAND_SET_AP_STATE +
257 " [0/1](isReadyForRemoteTask) [0/1](isWakeupRequired) Set the new AP state\n" +
258 COMMAND_START_DEBUG_CALLBACK +
259 " Start a debug callback that will record the received tasks\n" +
260 COMMAND_STOP_DEBUG_CALLBACK + " Stop the debug callback\n" + COMMAND_SHOW_TASK +
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700261 " Show tasks received by debug callback\n" + COMMAND_GET_VEHICLE_ID +
262 " Get vehicle id\n")
Yu Shan7a5283f2022-10-25 18:01:05 -0700263 .c_str());
264}
265
266binder_status_t RemoteAccessService::dump(int fd, const char** args, uint32_t numArgs) {
267 if (!checkDumpPermission()) {
268 dprintf(fd, "Caller must be root, system or shell\n");
269 return STATUS_PERMISSION_DENIED;
270 }
271
272 if (numArgs == 0) {
273 dumpHelp(fd);
274 return STATUS_OK;
275 }
276
277 if (!strcmp(args[0], COMMAND_SET_AP_STATE)) {
278 if (numArgs < 3) {
279 dumpHelp(fd);
280 return STATUS_OK;
281 }
282 ApState apState = {};
283 const char* remoteTaskFlag = args[1];
284 if (!strcmp(remoteTaskFlag, "1") && !strcmp(remoteTaskFlag, "0")) {
285 dumpHelp(fd);
286 return STATUS_OK;
287 }
288 if (!checkBoolFlag(args[1])) {
289 dumpHelp(fd);
290 return STATUS_OK;
291 }
292 if (!strcmp(args[1], "1")) {
293 apState.isReadyForRemoteTask = true;
294 }
295 if (!checkBoolFlag(args[2])) {
296 dumpHelp(fd);
297 return STATUS_OK;
298 }
299 if (!strcmp(args[2], "1")) {
300 apState.isWakeupRequired = true;
301 }
302 auto status = notifyApStateChange(apState);
303 if (!status.isOk()) {
304 dprintErrorStatus(fd, "Failed to set AP state", status);
305 } else {
306 dprintf(fd, "successfully set the new AP state\n");
307 }
308 } else if (!strcmp(args[0], COMMAND_START_DEBUG_CALLBACK)) {
309 mDebugCallback = ndk::SharedRefBase::make<DebugRemoteTaskCallback>();
310 setRemoteTaskCallback(mDebugCallback);
311 dprintf(fd, "Debug callback registered\n");
312 } else if (!strcmp(args[0], COMMAND_STOP_DEBUG_CALLBACK)) {
313 if (mDebugCallback) {
314 mDebugCallback.reset();
315 }
316 clearRemoteTaskCallback();
317 dprintf(fd, "Debug callback unregistered\n");
318 } else if (!strcmp(args[0], COMMAND_SHOW_TASK)) {
319 if (mDebugCallback) {
320 dprintf(fd, "%s", mDebugCallback->printTasks().c_str());
321 } else {
322 dprintf(fd, "Debug callback is not currently used, use \"%s\" first.\n",
323 COMMAND_START_DEBUG_CALLBACK);
324 }
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700325 } else if (!strcmp(args[0], COMMAND_GET_VEHICLE_ID)) {
326 std::string vehicleId;
327 auto status = getVehicleId(&vehicleId);
Yu Shan7a5283f2022-10-25 18:01:05 -0700328 if (!status.isOk()) {
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700329 dprintErrorStatus(fd, "Failed to get vehicle ID", status);
Yu Shan7a5283f2022-10-25 18:01:05 -0700330 } else {
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700331 dprintf(fd, "Vehicle Id: %s\n", vehicleId.c_str());
Yu Shan7a5283f2022-10-25 18:01:05 -0700332 }
333 } else {
334 dumpHelp(fd);
335 }
336
337 return STATUS_OK;
338}
339
340ScopedAStatus DebugRemoteTaskCallback::onRemoteTaskRequested(const std::string& clientId,
341 const std::vector<uint8_t>& data) {
342 std::lock_guard<std::mutex> lockGuard(mLock);
343 mTasks.push_back({
344 .clientId = clientId,
345 .data = data,
346 });
347 return ScopedAStatus::ok();
348}
349
350std::string DebugRemoteTaskCallback::printTasks() {
351 std::lock_guard<std::mutex> lockGuard(mLock);
352 std::string s = StringPrintf("Received %zu tasks in %f seconds", mTasks.size(),
353 (android::uptimeMillis() - mStartTimeMillis) / 1000.);
354 for (size_t i = 0; i < mTasks.size(); i++) {
355 StringAppendF(&s, "Client Id: %s, Data: %s\n", mTasks[i].clientId.c_str(),
356 printBytes(mTasks[i].data).c_str());
357 }
358 return s;
359}
360
361} // namespace remoteaccess
362} // namespace automotive
363} // namespace hardware
364} // namespace android