1 /*
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 <AidlHalPropValue.h>
20 #include <IVhalClient.h>
21 #include <aidl/android/hardware/automotive/remoteaccess/ApState.h>
22 #include <aidl/android/hardware/automotive/remoteaccess/BnRemoteTaskCallback.h>
23 #include <aidl/android/hardware/automotive/vehicle/VehiclePropValue.h>
24 #include <gmock/gmock.h>
25 #include <grpcpp/test/mock_stream.h>
26 #include <gtest/gtest.h>
27 #include <wakeup_client.grpc.pb.h>
28 #include <chrono>
29 #include <thread>
30
31 namespace android {
32 namespace hardware {
33 namespace automotive {
34 namespace remoteaccess {
35
36 namespace {
37
38 using ::android::base::ScopedLockAssertion;
39 using ::android::frameworks::automotive::vhal::AidlHalPropValue;
40 using ::android::frameworks::automotive::vhal::IHalPropConfig;
41 using ::android::frameworks::automotive::vhal::IHalPropValue;
42 using ::android::frameworks::automotive::vhal::ISubscriptionCallback;
43 using ::android::frameworks::automotive::vhal::ISubscriptionClient;
44 using ::android::frameworks::automotive::vhal::IVhalClient;
45 using ::android::frameworks::automotive::vhal::VhalClientResult;
46
47 using ::aidl::android::hardware::automotive::remoteaccess::ApState;
48 using ::aidl::android::hardware::automotive::remoteaccess::BnRemoteTaskCallback;
49 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
50
51 using ::grpc::ClientAsyncReaderInterface;
52 using ::grpc::ClientAsyncResponseReaderInterface;
53 using ::grpc::ClientContext;
54 using ::grpc::ClientReader;
55 using ::grpc::ClientReaderInterface;
56 using ::grpc::CompletionQueue;
57 using ::grpc::Status;
58 using ::grpc::testing::MockClientReader;
59 using ::ndk::ScopedAStatus;
60 using ::testing::_;
61 using ::testing::DoAll;
62 using ::testing::Return;
63 using ::testing::SetArgPointee;
64
65 constexpr char kTestVin[] = "test_VIN";
66
67 } // namespace
68
69 class MockGrpcClientStub : public WakeupClient::StubInterface {
70 public:
71 MOCK_METHOD(ClientReaderInterface<GetRemoteTasksResponse>*, GetRemoteTasksRaw,
72 (ClientContext * context, const GetRemoteTasksRequest& request));
73 MOCK_METHOD(Status, NotifyWakeupRequired,
74 (ClientContext * context, const NotifyWakeupRequiredRequest& request,
75 NotifyWakeupRequiredResponse* response));
76 // Async methods which we do not care.
77 MOCK_METHOD(ClientAsyncReaderInterface<GetRemoteTasksResponse>*, AsyncGetRemoteTasksRaw,
78 (ClientContext * context, const GetRemoteTasksRequest& request, CompletionQueue* cq,
79 void* tag));
80 MOCK_METHOD(ClientAsyncReaderInterface<GetRemoteTasksResponse>*, PrepareAsyncGetRemoteTasksRaw,
81 (ClientContext * context, const GetRemoteTasksRequest& request,
82 CompletionQueue* cq));
83 MOCK_METHOD(ClientAsyncResponseReaderInterface<NotifyWakeupRequiredResponse>*,
84 AsyncNotifyWakeupRequiredRaw,
85 (ClientContext * context, const NotifyWakeupRequiredRequest& request,
86 CompletionQueue* cq));
87 MOCK_METHOD(ClientAsyncResponseReaderInterface<NotifyWakeupRequiredResponse>*,
88 PrepareAsyncNotifyWakeupRequiredRaw,
89 (ClientContext * context, const NotifyWakeupRequiredRequest& request,
90 CompletionQueue* cq));
91 };
92
93 class FakeVhalClient final : public android::frameworks::automotive::vhal::IVhalClient {
94 public:
isAidlVhal()95 inline bool isAidlVhal() { return true; }
96
getValueSync(const IHalPropValue & requestValue)97 VhalClientResult<std::unique_ptr<IHalPropValue>> getValueSync(
98 const IHalPropValue& requestValue) override {
99 auto propValue = std::make_unique<AidlHalPropValue>(requestValue.getPropId());
100 propValue->setStringValue(kTestVin);
101 return propValue;
102 }
103
createHalPropValue(int32_t propId)104 std::unique_ptr<IHalPropValue> createHalPropValue(int32_t propId) override {
105 return std::make_unique<AidlHalPropValue>(propId);
106 }
107
108 // Functions we do not care.
createHalPropValue(int32_t propId,int32_t areaId)109 std::unique_ptr<IHalPropValue> createHalPropValue([[maybe_unused]] int32_t propId,
110 [[maybe_unused]] int32_t areaId) override {
111 return nullptr;
112 }
113
getValue(const IHalPropValue & requestValue,std::shared_ptr<GetValueCallbackFunc> callback)114 void getValue([[maybe_unused]] const IHalPropValue& requestValue,
115 [[maybe_unused]] std::shared_ptr<GetValueCallbackFunc> callback) override {}
116
setValue(const IHalPropValue & requestValue,std::shared_ptr<SetValueCallbackFunc> callback)117 void setValue([[maybe_unused]] const IHalPropValue& requestValue,
118 [[maybe_unused]] std::shared_ptr<SetValueCallbackFunc> callback) override {}
119
setValueSync(const IHalPropValue & requestValue)120 VhalClientResult<void> setValueSync([[maybe_unused]] const IHalPropValue& requestValue) {
121 return {};
122 }
123
addOnBinderDiedCallback(std::shared_ptr<OnBinderDiedCallbackFunc> callback)124 VhalClientResult<void> addOnBinderDiedCallback(
125 [[maybe_unused]] std::shared_ptr<OnBinderDiedCallbackFunc> callback) override {
126 return {};
127 }
128
removeOnBinderDiedCallback(std::shared_ptr<OnBinderDiedCallbackFunc> callback)129 VhalClientResult<void> removeOnBinderDiedCallback(
130 [[maybe_unused]] std::shared_ptr<OnBinderDiedCallbackFunc> callback) override {
131 return {};
132 }
133
getAllPropConfigs()134 VhalClientResult<std::vector<std::unique_ptr<IHalPropConfig>>> getAllPropConfigs() override {
135 return std::vector<std::unique_ptr<IHalPropConfig>>();
136 }
137
getPropConfigs(std::vector<int32_t> propIds)138 VhalClientResult<std::vector<std::unique_ptr<IHalPropConfig>>> getPropConfigs(
139 [[maybe_unused]] std::vector<int32_t> propIds) override {
140 return std::vector<std::unique_ptr<IHalPropConfig>>();
141 }
142
getSubscriptionClient(std::shared_ptr<ISubscriptionCallback> callback)143 std::unique_ptr<ISubscriptionClient> getSubscriptionClient(
144 [[maybe_unused]] std::shared_ptr<ISubscriptionCallback> callback) override {
145 return nullptr;
146 }
147 };
148
149 class FakeRemoteTaskCallback : public BnRemoteTaskCallback {
150 public:
onRemoteTaskRequested(const std::string & clientId,const std::vector<uint8_t> & data)151 ScopedAStatus onRemoteTaskRequested(const std::string& clientId,
152 const std::vector<uint8_t>& data) override {
153 std::lock_guard<std::mutex> lockGuard(mLock);
154 mDataByClientId[clientId] = data;
155 mTaskCount++;
156 mCv.notify_all();
157 return ScopedAStatus::ok();
158 }
159
getData(const std::string & clientId)160 std::vector<uint8_t> getData(const std::string& clientId) { return mDataByClientId[clientId]; }
161
wait(size_t taskCount,size_t timeoutInSec)162 bool wait(size_t taskCount, size_t timeoutInSec) {
163 std::unique_lock<std::mutex> lock(mLock);
164 return mCv.wait_for(lock, std::chrono::seconds(timeoutInSec), [taskCount, this] {
165 ScopedLockAssertion lockAssertion(mLock);
166 return mTaskCount >= taskCount;
167 });
168 }
169
170 private:
171 std::mutex mLock;
172 std::unordered_map<std::string, std::vector<uint8_t>> mDataByClientId GUARDED_BY(mLock);
173 size_t mTaskCount GUARDED_BY(mLock) = 0;
174 std::condition_variable mCv;
175 };
176
177 class RemoteAccessServiceUnitTest : public ::testing::Test {
178 public:
SetUp()179 virtual void SetUp() override {
180 mGrpcWakeupClientStub = std::make_unique<MockGrpcClientStub>();
181 mService = ndk::SharedRefBase::make<RemoteAccessService>(mGrpcWakeupClientStub.get());
182 }
183
getGrpcWakeupClientStub()184 MockGrpcClientStub* getGrpcWakeupClientStub() { return mGrpcWakeupClientStub.get(); }
185
getService()186 RemoteAccessService* getService() { return mService.get(); }
187
setRetryWaitInMs(size_t retryWaitInMs)188 void setRetryWaitInMs(size_t retryWaitInMs) { mService->setRetryWaitInMs(retryWaitInMs); }
189
getVehicleIdWithClient(IVhalClient & vhalClient,std::string * vehicleId)190 ScopedAStatus getVehicleIdWithClient(IVhalClient& vhalClient, std::string* vehicleId) {
191 return mService->getVehicleIdWithClient(vhalClient, vehicleId);
192 }
193
194 private:
195 std::unique_ptr<MockGrpcClientStub> mGrpcWakeupClientStub;
196 std::shared_ptr<RemoteAccessService> mService;
197 };
198
TEST_F(RemoteAccessServiceUnitTest,TestGetWakeupServiceName)199 TEST_F(RemoteAccessServiceUnitTest, TestGetWakeupServiceName) {
200 std::string serviceName;
201
202 ScopedAStatus status = getService()->getWakeupServiceName(&serviceName);
203
204 EXPECT_TRUE(status.isOk());
205 EXPECT_EQ(serviceName, "com.google.vehicle.wakeup");
206 }
207
TEST_F(RemoteAccessServiceUnitTest,TestNotifyApStateChangeWakeupRequired)208 TEST_F(RemoteAccessServiceUnitTest, TestNotifyApStateChangeWakeupRequired) {
209 bool isWakeupRequired = false;
210 EXPECT_CALL(*getGrpcWakeupClientStub(), NotifyWakeupRequired)
211 .WillOnce([&isWakeupRequired]([[maybe_unused]] ClientContext* context,
212 const NotifyWakeupRequiredRequest& request,
213 [[maybe_unused]] NotifyWakeupRequiredResponse* response) {
214 isWakeupRequired = request.iswakeuprequired();
215 return Status();
216 });
217
218 ApState newState = {
219 .isWakeupRequired = true,
220 };
221 ScopedAStatus status = getService()->notifyApStateChange(newState);
222
223 EXPECT_TRUE(status.isOk());
224 EXPECT_TRUE(isWakeupRequired);
225 }
226
TEST_F(RemoteAccessServiceUnitTest,TestGetRemoteTasks)227 TEST_F(RemoteAccessServiceUnitTest, TestGetRemoteTasks) {
228 GetRemoteTasksResponse response1;
229 std::vector<uint8_t> testData = {0xde, 0xad, 0xbe, 0xef};
230 response1.set_clientid("1");
231 response1.set_data(testData.data(), testData.size());
232 GetRemoteTasksResponse response2;
233 response2.set_clientid("2");
234 std::shared_ptr<FakeRemoteTaskCallback> callback =
235 ndk::SharedRefBase::make<FakeRemoteTaskCallback>();
236
237 ON_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw)
238 .WillByDefault(
239 [response1, response2]([[maybe_unused]] ClientContext* context,
240 [[maybe_unused]] const GetRemoteTasksRequest& request) {
241 // mockReader ownership will be transferred to the client so we don't own it
242 // here.
243 MockClientReader<GetRemoteTasksResponse>* mockClientReader =
244 new MockClientReader<GetRemoteTasksResponse>();
245 EXPECT_CALL(*mockClientReader, Finish()).WillOnce(Return(Status::OK));
246 EXPECT_CALL(*mockClientReader, Read(_))
247 .WillOnce(DoAll(SetArgPointee<0>(response1), Return(true)))
248 .WillOnce(DoAll(SetArgPointee<0>(response2), Return(true)))
249 .WillRepeatedly(Return(false));
250 return mockClientReader;
251 });
252
253 getService()->setRemoteTaskCallback(callback);
254 // Start the long live connection to receive tasks.
255 ApState newState = {
256 .isReadyForRemoteTask = true,
257 };
258 ASSERT_TRUE(getService()->notifyApStateChange(newState).isOk());
259
260 ASSERT_TRUE(callback->wait(/*taskCount=*/2, /*timeoutInSec=*/10))
261 << "Did not receive enough tasks";
262 EXPECT_EQ(callback->getData("1"), testData);
263 EXPECT_EQ(callback->getData("2"), std::vector<uint8_t>());
264 }
265
TEST_F(RemoteAccessServiceUnitTest,TestGetRemoteTasksRetryConnection)266 TEST_F(RemoteAccessServiceUnitTest, TestGetRemoteTasksRetryConnection) {
267 GetRemoteTasksResponse response;
268 std::shared_ptr<FakeRemoteTaskCallback> callback =
269 ndk::SharedRefBase::make<FakeRemoteTaskCallback>();
270
271 ON_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw)
272 .WillByDefault([response]([[maybe_unused]] ClientContext* context,
273 [[maybe_unused]] const GetRemoteTasksRequest& request) {
274 // mockReader ownership will be transferred to the client so we don't own it here.
275 MockClientReader<GetRemoteTasksResponse>* mockClientReader =
276 new MockClientReader<GetRemoteTasksResponse>();
277 EXPECT_CALL(*mockClientReader, Finish()).WillOnce(Return(Status::OK));
278 // Connection fails after receiving one task. Should retry after some time.
279 EXPECT_CALL(*mockClientReader, Read(_))
280 .WillOnce(DoAll(SetArgPointee<0>(response), Return(true)))
281 .WillRepeatedly(Return(false));
282 return mockClientReader;
283 });
284
285 getService()->setRemoteTaskCallback(callback);
286 setRetryWaitInMs(100);
287 // Start the long live connection to receive tasks.
288 ApState newState = {
289 .isReadyForRemoteTask = true,
290 };
291 ASSERT_TRUE(getService()->notifyApStateChange(newState).isOk());
292
293 ASSERT_TRUE(callback->wait(/*taskCount=*/2, /*timeoutInSec=*/10))
294 << "Did not receive enough tasks";
295 }
296
TEST_F(RemoteAccessServiceUnitTest,TestGetRemoteTasksDefaultNotReady)297 TEST_F(RemoteAccessServiceUnitTest, TestGetRemoteTasksDefaultNotReady) {
298 GetRemoteTasksResponse response1;
299 std::vector<uint8_t> testData = {0xde, 0xad, 0xbe, 0xef};
300 response1.set_clientid("1");
301 response1.set_data(testData.data(), testData.size());
302 GetRemoteTasksResponse response2;
303 response2.set_clientid("2");
304 std::shared_ptr<FakeRemoteTaskCallback> callback =
305 ndk::SharedRefBase::make<FakeRemoteTaskCallback>();
306
307 EXPECT_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw).Times(0);
308
309 // Default state is not ready for remote tasks, so no callback will be called.
310 getService()->setRemoteTaskCallback(callback);
311
312 std::this_thread::sleep_for(std::chrono::milliseconds(100));
313 }
314
TEST_F(RemoteAccessServiceUnitTest,TestGetRemoteTasksNotReadyAfterReady)315 TEST_F(RemoteAccessServiceUnitTest, TestGetRemoteTasksNotReadyAfterReady) {
316 GetRemoteTasksResponse response1;
317 std::vector<uint8_t> testData = {0xde, 0xad, 0xbe, 0xef};
318 response1.set_clientid("1");
319 response1.set_data(testData.data(), testData.size());
320 GetRemoteTasksResponse response2;
321 response2.set_clientid("2");
322 std::shared_ptr<FakeRemoteTaskCallback> callback =
323 ndk::SharedRefBase::make<FakeRemoteTaskCallback>();
324
325 ON_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw)
326 .WillByDefault(
327 [response1, response2]([[maybe_unused]] ClientContext* context,
328 [[maybe_unused]] const GetRemoteTasksRequest& request) {
329 // mockReader ownership will be transferred to the client so we don't own it
330 // here.
331 MockClientReader<GetRemoteTasksResponse>* mockClientReader =
332 new MockClientReader<GetRemoteTasksResponse>();
333 EXPECT_CALL(*mockClientReader, Finish()).WillOnce(Return(Status::OK));
334 EXPECT_CALL(*mockClientReader, Read(_))
335 .WillOnce(DoAll(SetArgPointee<0>(response1), Return(true)))
336 .WillOnce(DoAll(SetArgPointee<0>(response2), Return(true)))
337 .WillRepeatedly(Return(false));
338 return mockClientReader;
339 });
340 // Should only be called once when is is ready for remote task.
341 EXPECT_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw).Times(1);
342
343 getService()->setRemoteTaskCallback(callback);
344 setRetryWaitInMs(100);
345 // Start the long live connection to receive tasks.
346 ApState newState = {
347 .isReadyForRemoteTask = true,
348 };
349 ASSERT_TRUE(getService()->notifyApStateChange(newState).isOk());
350 ASSERT_TRUE(callback->wait(/*taskCount=*/2, /*timeoutInSec=*/10))
351 << "Did not receive enough tasks";
352
353 // Stop the long live connection.
354 newState.isReadyForRemoteTask = false;
355 ASSERT_TRUE(getService()->notifyApStateChange(newState).isOk());
356
357 // Wait for the retry delay, but the loop should already exit.
358 std::this_thread::sleep_for(std::chrono::milliseconds(150));
359 }
360
TEST_F(RemoteAccessServiceUnitTest,testGetVehicleId)361 TEST_F(RemoteAccessServiceUnitTest, testGetVehicleId) {
362 std::string vehicleId;
363
364 FakeVhalClient vhalClient;
365
366 ASSERT_TRUE(getVehicleIdWithClient(vhalClient, &vehicleId).isOk());
367 ASSERT_EQ(vehicleId, kTestVin);
368 }
369
370 } // namespace remoteaccess
371 } // namespace automotive
372 } // namespace hardware
373 } // namespace android
374