blob: c5afd6300f9a5cff635cd86256abccdae2224066 [file] [log] [blame]
Yu Shane2974562022-08-10 18:37:03 -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
Yu Shanbc2ed2a2022-09-15 19:01:52 -070019#include <AidlHalPropValue.h>
20#include <IVhalClient.h>
Yu Shanb138c422022-09-06 19:11:23 -070021#include <aidl/android/hardware/automotive/remoteaccess/ApState.h>
22#include <aidl/android/hardware/automotive/remoteaccess/BnRemoteTaskCallback.h>
Yu Shanbc2ed2a2022-09-15 19:01:52 -070023#include <aidl/android/hardware/automotive/vehicle/VehiclePropValue.h>
Yu Shane2974562022-08-10 18:37:03 -070024#include <gmock/gmock.h>
Yu Shanb138c422022-09-06 19:11:23 -070025#include <grpcpp/test/mock_stream.h>
Yu Shane2974562022-08-10 18:37:03 -070026#include <gtest/gtest.h>
27#include <wakeup_client.grpc.pb.h>
Yu Shanb138c422022-09-06 19:11:23 -070028#include <chrono>
29#include <thread>
Yu Shane2974562022-08-10 18:37:03 -070030
31namespace android {
32namespace hardware {
33namespace automotive {
34namespace remoteaccess {
35
Yu Shanbc2ed2a2022-09-15 19:01:52 -070036namespace {
37
Yu Shanb138c422022-09-06 19:11:23 -070038using ::android::base::ScopedLockAssertion;
Yu Shanbc2ed2a2022-09-15 19:01:52 -070039using ::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;
45using ::android::frameworks::automotive::vhal::VhalClientResult;
Yu Shanb138c422022-09-06 19:11:23 -070046
47using ::aidl::android::hardware::automotive::remoteaccess::ApState;
48using ::aidl::android::hardware::automotive::remoteaccess::BnRemoteTaskCallback;
Yu Shanbc2ed2a2022-09-15 19:01:52 -070049using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
Yu Shanb138c422022-09-06 19:11:23 -070050
Yu Shane2974562022-08-10 18:37:03 -070051using ::grpc::ClientAsyncReaderInterface;
52using ::grpc::ClientAsyncResponseReaderInterface;
53using ::grpc::ClientContext;
54using ::grpc::ClientReader;
55using ::grpc::ClientReaderInterface;
56using ::grpc::CompletionQueue;
57using ::grpc::Status;
Yu Shanb138c422022-09-06 19:11:23 -070058using ::grpc::testing::MockClientReader;
Yu Shane2974562022-08-10 18:37:03 -070059using ::ndk::ScopedAStatus;
Yu Shanb138c422022-09-06 19:11:23 -070060using ::testing::_;
61using ::testing::DoAll;
62using ::testing::Return;
63using ::testing::SetArgPointee;
Yu Shane2974562022-08-10 18:37:03 -070064
Yu Shanbc2ed2a2022-09-15 19:01:52 -070065constexpr char kTestVin[] = "test_VIN";
66
67} // namespace
68
Yu Shane2974562022-08-10 18:37:03 -070069class 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
Yu Shanbc2ed2a2022-09-15 19:01:52 -070093class FakeVhalClient final : public android::frameworks::automotive::vhal::IVhalClient {
94 public:
95 inline bool isAidlVhal() { return true; }
96
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
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.
109 std::unique_ptr<IHalPropValue> createHalPropValue([[maybe_unused]] int32_t propId,
110 [[maybe_unused]] int32_t areaId) override {
111 return nullptr;
112 }
113
114 void getValue([[maybe_unused]] const IHalPropValue& requestValue,
115 [[maybe_unused]] std::shared_ptr<GetValueCallbackFunc> callback) override {}
116
117 void setValue([[maybe_unused]] const IHalPropValue& requestValue,
118 [[maybe_unused]] std::shared_ptr<SetValueCallbackFunc> callback) override {}
119
120 VhalClientResult<void> setValueSync([[maybe_unused]] const IHalPropValue& requestValue) {
121 return {};
122 }
123
124 VhalClientResult<void> addOnBinderDiedCallback(
125 [[maybe_unused]] std::shared_ptr<OnBinderDiedCallbackFunc> callback) override {
126 return {};
127 }
128
129 VhalClientResult<void> removeOnBinderDiedCallback(
130 [[maybe_unused]] std::shared_ptr<OnBinderDiedCallbackFunc> callback) override {
131 return {};
132 }
133
134 VhalClientResult<std::vector<std::unique_ptr<IHalPropConfig>>> getAllPropConfigs() override {
135 return std::vector<std::unique_ptr<IHalPropConfig>>();
136 }
137
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
143 std::unique_ptr<ISubscriptionClient> getSubscriptionClient(
144 [[maybe_unused]] std::shared_ptr<ISubscriptionCallback> callback) override {
145 return nullptr;
146 }
147};
148
Yu Shanb138c422022-09-06 19:11:23 -0700149class FakeRemoteTaskCallback : public BnRemoteTaskCallback {
150 public:
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
160 std::vector<uint8_t> getData(const std::string& clientId) { return mDataByClientId[clientId]; }
161
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
Yu Shane2974562022-08-10 18:37:03 -0700177class RemoteAccessServiceUnitTest : public ::testing::Test {
178 public:
Yu Shanb138c422022-09-06 19:11:23 -0700179 virtual void SetUp() override {
Yu Shane2974562022-08-10 18:37:03 -0700180 mGrpcWakeupClientStub = std::make_unique<MockGrpcClientStub>();
181 mService = ndk::SharedRefBase::make<RemoteAccessService>(mGrpcWakeupClientStub.get());
182 }
183
184 MockGrpcClientStub* getGrpcWakeupClientStub() { return mGrpcWakeupClientStub.get(); }
185
186 RemoteAccessService* getService() { return mService.get(); }
187
Yu Shanb138c422022-09-06 19:11:23 -0700188 void setRetryWaitInMs(size_t retryWaitInMs) { mService->setRetryWaitInMs(retryWaitInMs); }
189
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700190 ScopedAStatus getVehicleIdWithClient(IVhalClient& vhalClient, std::string* vehicleId) {
191 return mService->getVehicleIdWithClient(vhalClient, vehicleId);
Yu Shanbc2ed2a2022-09-15 19:01:52 -0700192 }
193
Yu Shane2974562022-08-10 18:37:03 -0700194 private:
195 std::unique_ptr<MockGrpcClientStub> mGrpcWakeupClientStub;
196 std::shared_ptr<RemoteAccessService> mService;
197};
198
199TEST_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
Yu Shanb138c422022-09-06 19:11:23 -0700208TEST_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
227TEST_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
266TEST_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
297TEST_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
315TEST_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
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700361TEST_F(RemoteAccessServiceUnitTest, testGetVehicleId) {
362 std::string vehicleId;
Yu Shanbc2ed2a2022-09-15 19:01:52 -0700363
364 FakeVhalClient vhalClient;
365
Eric Jeong6c3a1d82023-03-16 00:45:40 -0700366 ASSERT_TRUE(getVehicleIdWithClient(vhalClient, &vehicleId).isOk());
367 ASSERT_EQ(vehicleId, kTestVin);
Yu Shanbc2ed2a2022-09-15 19:01:52 -0700368}
369
Yu Shane2974562022-08-10 18:37:03 -0700370} // namespace remoteaccess
371} // namespace automotive
372} // namespace hardware
373} // namespace android