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