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