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