1 /*
2  * Copyright (C) 2021 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 #include <aidl/Gtest.h>
17 #include <aidl/Vintf.h>
18 
19 #include "VtsHalContexthubUtilsCommon.h"
20 
21 #include <android/hardware/contexthub/BnContextHub.h>
22 #include <android/hardware/contexthub/BnContextHubCallback.h>
23 #include <android/hardware/contexthub/IContextHub.h>
24 #include <android/hardware/contexthub/IContextHubCallback.h>
25 #include <binder/IServiceManager.h>
26 #include <binder/ProcessState.h>
27 #include <log/log.h>
28 
29 #include <cinttypes>
30 #include <future>
31 
32 using ::android::ProcessState;
33 using ::android::sp;
34 using ::android::String16;
35 using ::android::binder::Status;
36 using ::android::hardware::contexthub::AsyncEventType;
37 using ::android::hardware::contexthub::ContextHubInfo;
38 using ::android::hardware::contexthub::ContextHubMessage;
39 using ::android::hardware::contexthub::ErrorCode;
40 using ::android::hardware::contexthub::HostEndpointInfo;
41 using ::android::hardware::contexthub::IContextHub;
42 using ::android::hardware::contexthub::IContextHubCallbackDefault;
43 using ::android::hardware::contexthub::MessageDeliveryStatus;
44 using ::android::hardware::contexthub::NanoappBinary;
45 using ::android::hardware::contexthub::NanoappInfo;
46 using ::android::hardware::contexthub::NanoappRpcService;
47 using ::android::hardware::contexthub::NanSessionRequest;
48 using ::android::hardware::contexthub::NanSessionStateUpdate;
49 using ::android::hardware::contexthub::Setting;
50 using ::android::hardware::contexthub::vts_utils::kNonExistentAppId;
51 using ::android::hardware::contexthub::vts_utils::waitForCallback;
52 
53 // 6612b522-b717-41c8-b48d-c0b1cc64e142
54 constexpr std::array<uint8_t, 16> kUuid = {0x66, 0x12, 0xb5, 0x22, 0xb7, 0x17, 0x41, 0xc8,
55                                            0xb4, 0x8d, 0xc0, 0xb1, 0xcc, 0x64, 0xe1, 0x42};
56 const String16 kName{"VtsAidlHalContextHubTargetTest"};
57 
58 class ContextHubAidl : public testing::TestWithParam<std::tuple<std::string, int32_t>> {
59   public:
SetUp()60     virtual void SetUp() override {
61         contextHub = android::waitForDeclaredService<IContextHub>(
62                 String16(std::get<0>(GetParam()).c_str()));
63         ASSERT_NE(contextHub, nullptr);
64     }
65 
getHubId()66     uint32_t getHubId() { return std::get<1>(GetParam()); }
67 
68     void testSettingChanged(Setting setting);
69 
70     sp<IContextHub> contextHub;
71 };
72 
TEST_P(ContextHubAidl,TestGetHubs)73 TEST_P(ContextHubAidl, TestGetHubs) {
74     std::vector<ContextHubInfo> hubs;
75     ASSERT_TRUE(contextHub->getContextHubs(&hubs).isOk());
76 
77     ALOGD("System reports %zu hubs", hubs.size());
78 
79     for (const ContextHubInfo& hub : hubs) {
80         ALOGD("Checking hub ID %" PRIu32, hub.id);
81 
82         EXPECT_GT(hub.name.size(), 0);
83         EXPECT_GT(hub.vendor.size(), 0);
84         EXPECT_GT(hub.toolchain.size(), 0);
85         EXPECT_GT(hub.peakMips, 0);
86         EXPECT_GT(hub.chrePlatformId, 0);
87         EXPECT_GT(hub.chreApiMajorVersion, 0);
88         EXPECT_GE(hub.chreApiMinorVersion, 0);
89         EXPECT_GE(hub.chrePatchVersion, 0);
90 
91         // Minimum 128 byte MTU as required by CHRE API v1.0
92         EXPECT_GE(hub.maxSupportedMessageLengthBytes, UINT32_C(128));
93     }
94 }
95 
TEST_P(ContextHubAidl,TestEnableTestMode)96 TEST_P(ContextHubAidl, TestEnableTestMode) {
97     Status status = contextHub->setTestMode(true);
98     if (status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION ||
99         status.transactionError() == android::UNKNOWN_TRANSACTION) {
100         GTEST_SKIP() << "Not supported -> old API; or not implemented";
101     } else {
102         ASSERT_TRUE(status.isOk());
103     }
104 }
105 
TEST_P(ContextHubAidl,TestDisableTestMode)106 TEST_P(ContextHubAidl, TestDisableTestMode) {
107     Status status = contextHub->setTestMode(false);
108     if (status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION ||
109         status.transactionError() == android::UNKNOWN_TRANSACTION) {
110         GTEST_SKIP() << "Not supported -> old API; or not implemented";
111     } else {
112         ASSERT_TRUE(status.isOk());
113     }
114 }
115 
116 class EmptyContextHubCallback : public android::hardware::contexthub::BnContextHubCallback {
117   public:
handleNanoappInfo(const std::vector<NanoappInfo> &)118     Status handleNanoappInfo(const std::vector<NanoappInfo>& /* appInfo */) override {
119         return Status::ok();
120     }
121 
handleContextHubMessage(const ContextHubMessage &,const std::vector<String16> &)122     Status handleContextHubMessage(const ContextHubMessage& /* msg */,
123                                    const std::vector<String16>& /* msgContentPerms */) override {
124         return Status::ok();
125     }
126 
handleContextHubAsyncEvent(AsyncEventType)127     Status handleContextHubAsyncEvent(AsyncEventType /* evt */) override { return Status::ok(); }
128 
handleTransactionResult(int32_t,bool)129     Status handleTransactionResult(int32_t /* transactionId */, bool /* success */) override {
130         return Status::ok();
131     }
132 
handleNanSessionRequest(const NanSessionRequest &)133     Status handleNanSessionRequest(const NanSessionRequest& /* request */) override {
134         return Status::ok();
135     }
136 
handleMessageDeliveryStatus(char16_t,const MessageDeliveryStatus &)137     Status handleMessageDeliveryStatus(
138             char16_t /* hostEndPointId */,
139             const MessageDeliveryStatus& /* messageDeliveryStatus */) override {
140         return Status::ok();
141     }
142 
getUuid(std::array<uint8_t,16> * out_uuid)143     Status getUuid(std::array<uint8_t, 16>* out_uuid) override {
144         *out_uuid = kUuid;
145         return Status::ok();
146     }
147 
getName(::android::String16 * out_name)148     Status getName(::android::String16* out_name) override {
149         *out_name = kName;
150         return Status::ok();
151     }
152 };
153 
TEST_P(ContextHubAidl,TestRegisterCallback)154 TEST_P(ContextHubAidl, TestRegisterCallback) {
155     sp<EmptyContextHubCallback> cb = sp<EmptyContextHubCallback>::make();
156     ASSERT_TRUE(contextHub->registerCallback(getHubId(), cb).isOk());
157 }
158 
159 // Helper callback that puts the async appInfo callback data into a promise
160 class QueryAppsCallback : public android::hardware::contexthub::BnContextHubCallback {
161   public:
handleNanoappInfo(const std::vector<NanoappInfo> & appInfo)162     Status handleNanoappInfo(const std::vector<NanoappInfo>& appInfo) override {
163         ALOGD("Got app info callback with %zu apps", appInfo.size());
164         promise.set_value(appInfo);
165         return Status::ok();
166     }
167 
handleContextHubMessage(const ContextHubMessage &,const std::vector<String16> &)168     Status handleContextHubMessage(const ContextHubMessage& /* msg */,
169                                    const std::vector<String16>& /* msgContentPerms */) override {
170         return Status::ok();
171     }
172 
handleContextHubAsyncEvent(AsyncEventType)173     Status handleContextHubAsyncEvent(AsyncEventType /* evt */) override { return Status::ok(); }
174 
handleTransactionResult(int32_t,bool)175     Status handleTransactionResult(int32_t /* transactionId */, bool /* success */) override {
176         return Status::ok();
177     }
178 
handleNanSessionRequest(const NanSessionRequest &)179     Status handleNanSessionRequest(const NanSessionRequest& /* request */) override {
180         return Status::ok();
181     }
182 
handleMessageDeliveryStatus(char16_t,const MessageDeliveryStatus &)183     Status handleMessageDeliveryStatus(
184             char16_t /* hostEndPointId */,
185             const MessageDeliveryStatus& /* messageDeliveryStatus */) override {
186         return Status::ok();
187     }
188 
getUuid(std::array<uint8_t,16> * out_uuid)189     Status getUuid(std::array<uint8_t, 16>* out_uuid) override {
190         *out_uuid = kUuid;
191         return Status::ok();
192     }
193 
getName(::android::String16 * out_name)194     Status getName(::android::String16* out_name) override {
195         *out_name = kName;
196         return Status::ok();
197     }
198 
199     std::promise<std::vector<NanoappInfo>> promise;
200 };
201 
202 // Calls queryApps() and checks the returned metadata
TEST_P(ContextHubAidl,TestQueryApps)203 TEST_P(ContextHubAidl, TestQueryApps) {
204     sp<QueryAppsCallback> cb = sp<QueryAppsCallback>::make();
205     ASSERT_TRUE(contextHub->registerCallback(getHubId(), cb).isOk());
206     ASSERT_TRUE(contextHub->queryNanoapps(getHubId()).isOk());
207 
208     std::vector<NanoappInfo> appInfoList;
209     ASSERT_TRUE(waitForCallback(cb->promise.get_future(), &appInfoList));
210     for (const NanoappInfo& appInfo : appInfoList) {
211         EXPECT_NE(appInfo.nanoappId, UINT64_C(0));
212         EXPECT_NE(appInfo.nanoappId, kNonExistentAppId);
213 
214         // Verify services are unique.
215         std::set<uint64_t> existingServiceIds;
216         for (const NanoappRpcService& rpcService : appInfo.rpcServices) {
217             EXPECT_NE(rpcService.id, UINT64_C(0));
218             EXPECT_EQ(existingServiceIds.count(rpcService.id), 0);
219             existingServiceIds.insert(rpcService.id);
220         }
221     }
222 }
223 
224 // Calls getPreloadedNanoappsIds() and verifies there are preloaded nanoapps
TEST_P(ContextHubAidl,TestGetPreloadedNanoappIds)225 TEST_P(ContextHubAidl, TestGetPreloadedNanoappIds) {
226     std::vector<int64_t> preloadedNanoappIds;
227     Status status = contextHub->getPreloadedNanoappIds(getHubId(), &preloadedNanoappIds);
228     if (status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION ||
229         status.transactionError() == android::UNKNOWN_TRANSACTION) {
230         GTEST_SKIP() << "Not supported -> old API; or not implemented";
231     } else {
232         ASSERT_TRUE(status.isOk());
233     }
234 }
235 
236 // Helper callback that puts the TransactionResult for the expectedTransactionId into a
237 // promise
238 class TransactionResultCallback : public android::hardware::contexthub::BnContextHubCallback {
239   public:
handleNanoappInfo(const std::vector<NanoappInfo> &)240     Status handleNanoappInfo(const std::vector<NanoappInfo>& /* appInfo */) override {
241         return Status::ok();
242     }
243 
handleContextHubMessage(const ContextHubMessage &,const std::vector<String16> &)244     Status handleContextHubMessage(const ContextHubMessage& /* msg */,
245                                    const std::vector<String16>& /* msgContentPerms */) override {
246         return Status::ok();
247     }
248 
handleContextHubAsyncEvent(AsyncEventType)249     Status handleContextHubAsyncEvent(AsyncEventType /* evt */) override { return Status::ok(); }
250 
handleTransactionResult(int32_t transactionId,bool success)251     Status handleTransactionResult(int32_t transactionId, bool success) override {
252         ALOGD("Got transaction result callback for transactionId %" PRIu32 " (expecting %" PRIu32
253               ") with success %d",
254               transactionId, expectedTransactionId, success);
255         if (transactionId == expectedTransactionId) {
256             promise.set_value(success);
257         }
258         return Status::ok();
259     }
260 
handleNanSessionRequest(const NanSessionRequest &)261     Status handleNanSessionRequest(const NanSessionRequest& /* request */) override {
262         return Status::ok();
263     }
264 
handleMessageDeliveryStatus(char16_t,const MessageDeliveryStatus &)265     Status handleMessageDeliveryStatus(
266             char16_t /* hostEndPointId */,
267             const MessageDeliveryStatus& /* messageDeliveryStatus */) override {
268         return Status::ok();
269     }
270 
getUuid(std::array<uint8_t,16> * out_uuid)271     Status getUuid(std::array<uint8_t, 16>* out_uuid) override {
272         *out_uuid = kUuid;
273         return Status::ok();
274     }
275 
getName(::android::String16 * out_name)276     Status getName(::android::String16* out_name) override {
277         *out_name = kName;
278         return Status::ok();
279     }
280 
281     uint32_t expectedTransactionId = 0;
282     std::promise<bool> promise;
283 };
284 
285 // Parameterized fixture that sets the callback to TransactionResultCallback
286 class ContextHubTransactionTest : public ContextHubAidl {
287   public:
SetUp()288     virtual void SetUp() override {
289         ContextHubAidl::SetUp();
290         ASSERT_TRUE(contextHub->registerCallback(getHubId(), cb).isOk());
291     }
292 
293     sp<TransactionResultCallback> cb = sp<TransactionResultCallback>::make();
294 };
295 
TEST_P(ContextHubTransactionTest,TestSendMessageToNonExistentNanoapp)296 TEST_P(ContextHubTransactionTest, TestSendMessageToNonExistentNanoapp) {
297     ContextHubMessage message;
298     message.nanoappId = kNonExistentAppId;
299     message.messageType = 1;
300     message.messageBody.resize(4);
301     std::fill(message.messageBody.begin(), message.messageBody.end(), 0);
302 
303     ALOGD("Sending message to non-existent nanoapp");
304     ASSERT_TRUE(contextHub->sendMessageToHub(getHubId(), message).isOk());
305 }
306 
TEST_P(ContextHubTransactionTest,TestLoadEmptyNanoapp)307 TEST_P(ContextHubTransactionTest, TestLoadEmptyNanoapp) {
308     cb->expectedTransactionId = 0123;
309     NanoappBinary emptyApp;
310 
311     emptyApp.nanoappId = kNonExistentAppId;
312     emptyApp.nanoappVersion = 1;
313     emptyApp.flags = 0;
314     emptyApp.targetChreApiMajorVersion = 1;
315     emptyApp.targetChreApiMinorVersion = 0;
316 
317     ALOGD("Loading empty nanoapp");
318     bool success = contextHub->loadNanoapp(getHubId(), emptyApp, cb->expectedTransactionId).isOk();
319     if (success) {
320         bool transactionSuccess;
321         ASSERT_TRUE(waitForCallback(cb->promise.get_future(), &transactionSuccess));
322         ASSERT_FALSE(transactionSuccess);
323     }
324 }
325 
TEST_P(ContextHubTransactionTest,TestUnloadNonexistentNanoapp)326 TEST_P(ContextHubTransactionTest, TestUnloadNonexistentNanoapp) {
327     cb->expectedTransactionId = 1234;
328 
329     ALOGD("Unloading nonexistent nanoapp");
330     bool success =
331             contextHub->unloadNanoapp(getHubId(), kNonExistentAppId, cb->expectedTransactionId)
332                     .isOk();
333     if (success) {
334         bool transactionSuccess;
335         ASSERT_TRUE(waitForCallback(cb->promise.get_future(), &transactionSuccess));
336         ASSERT_FALSE(transactionSuccess);
337     }
338 }
339 
TEST_P(ContextHubTransactionTest,TestEnableNonexistentNanoapp)340 TEST_P(ContextHubTransactionTest, TestEnableNonexistentNanoapp) {
341     cb->expectedTransactionId = 2345;
342 
343     ALOGD("Enabling nonexistent nanoapp");
344     bool success =
345             contextHub->enableNanoapp(getHubId(), kNonExistentAppId, cb->expectedTransactionId)
346                     .isOk();
347     if (success) {
348         bool transactionSuccess;
349         ASSERT_TRUE(waitForCallback(cb->promise.get_future(), &transactionSuccess));
350         ASSERT_FALSE(transactionSuccess);
351     }
352 }
353 
TEST_P(ContextHubTransactionTest,TestDisableNonexistentNanoapp)354 TEST_P(ContextHubTransactionTest, TestDisableNonexistentNanoapp) {
355     cb->expectedTransactionId = 3456;
356 
357     ALOGD("Disabling nonexistent nanoapp");
358     bool success =
359             contextHub->disableNanoapp(getHubId(), kNonExistentAppId, cb->expectedTransactionId)
360                     .isOk();
361     if (success) {
362         bool transactionSuccess;
363         ASSERT_TRUE(waitForCallback(cb->promise.get_future(), &transactionSuccess));
364         ASSERT_FALSE(transactionSuccess);
365     }
366 }
367 
testSettingChanged(Setting setting)368 void ContextHubAidl::testSettingChanged(Setting setting) {
369     // In VTS, we only test that sending the values doesn't cause things to blow up - GTS tests
370     // verify the expected E2E behavior in CHRE
371     sp<EmptyContextHubCallback> cb = sp<EmptyContextHubCallback>::make();
372     ASSERT_TRUE(contextHub->registerCallback(getHubId(), cb).isOk());
373 
374     ASSERT_TRUE(contextHub->onSettingChanged(setting, true /* enabled */).isOk());
375     ASSERT_TRUE(contextHub->onSettingChanged(setting, false /* enabled */).isOk());
376 }
377 
TEST_P(ContextHubAidl,TestOnLocationSettingChanged)378 TEST_P(ContextHubAidl, TestOnLocationSettingChanged) {
379     testSettingChanged(Setting::LOCATION);
380 }
381 
TEST_P(ContextHubAidl,TestOnWifiMainSettingChanged)382 TEST_P(ContextHubAidl, TestOnWifiMainSettingChanged) {
383     testSettingChanged(Setting::WIFI_MAIN);
384 }
385 
TEST_P(ContextHubAidl,TestOnWifiScanningSettingChanged)386 TEST_P(ContextHubAidl, TestOnWifiScanningSettingChanged) {
387     testSettingChanged(Setting::WIFI_SCANNING);
388 }
389 
TEST_P(ContextHubAidl,TestOnAirplaneModeSettingChanged)390 TEST_P(ContextHubAidl, TestOnAirplaneModeSettingChanged) {
391     testSettingChanged(Setting::AIRPLANE_MODE);
392 }
393 
TEST_P(ContextHubAidl,TestOnMicrophoneSettingChanged)394 TEST_P(ContextHubAidl, TestOnMicrophoneSettingChanged) {
395     testSettingChanged(Setting::MICROPHONE);
396 }
397 
TEST_P(ContextHubAidl,TestOnBtMainSettingChanged)398 TEST_P(ContextHubAidl, TestOnBtMainSettingChanged) {
399     testSettingChanged(Setting::BT_MAIN);
400 }
401 
TEST_P(ContextHubAidl,TestOnBtScanningSettingChanged)402 TEST_P(ContextHubAidl, TestOnBtScanningSettingChanged) {
403     testSettingChanged(Setting::BT_SCANNING);
404 }
405 
generateContextHubMapping()406 std::vector<std::tuple<std::string, int32_t>> generateContextHubMapping() {
407     std::vector<std::tuple<std::string, int32_t>> tuples;
408     auto contextHubAidlNames = android::getAidlHalInstanceNames(IContextHub::descriptor);
409     std::vector<ContextHubInfo> contextHubInfos;
410 
411     for (int i = 0; i < contextHubAidlNames.size(); i++) {
412         auto contextHubName = contextHubAidlNames[i].c_str();
413         auto contextHub = android::waitForDeclaredService<IContextHub>(String16(contextHubName));
414         if (contextHub->getContextHubs(&contextHubInfos).isOk()) {
415             for (auto& info : contextHubInfos) {
416                 tuples.push_back(std::make_tuple(contextHubName, info.id));
417             }
418         }
419     }
420 
421     return tuples;
422 }
423 
TEST_P(ContextHubTransactionTest,TestHostConnection)424 TEST_P(ContextHubTransactionTest, TestHostConnection) {
425     constexpr char16_t kHostEndpointId = 1;
426     HostEndpointInfo hostEndpointInfo;
427     hostEndpointInfo.type = HostEndpointInfo::Type::NATIVE;
428     hostEndpointInfo.hostEndpointId = kHostEndpointId;
429 
430     ASSERT_TRUE(contextHub->onHostEndpointConnected(hostEndpointInfo).isOk());
431     ASSERT_TRUE(contextHub->onHostEndpointDisconnected(kHostEndpointId).isOk());
432 }
433 
TEST_P(ContextHubTransactionTest,TestInvalidHostConnection)434 TEST_P(ContextHubTransactionTest, TestInvalidHostConnection) {
435     constexpr char16_t kHostEndpointId = 1;
436 
437     ASSERT_TRUE(contextHub->onHostEndpointDisconnected(kHostEndpointId).isOk());
438 }
439 
TEST_P(ContextHubTransactionTest,TestNanSessionStateChange)440 TEST_P(ContextHubTransactionTest, TestNanSessionStateChange) {
441     NanSessionStateUpdate update;
442     update.state = true;
443     Status status = contextHub->onNanSessionStateChanged(update);
444     if (status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION ||
445         status.transactionError() == android::UNKNOWN_TRANSACTION) {
446         GTEST_SKIP() << "Not supported -> old API; or not implemented";
447     } else {
448         ASSERT_TRUE(status.isOk());
449         update.state = false;
450         ASSERT_TRUE(contextHub->onNanSessionStateChanged(update).isOk());
451     }
452 }
453 
TEST_P(ContextHubAidl,TestSendMessageDeliveryStatusToHub)454 TEST_P(ContextHubAidl, TestSendMessageDeliveryStatusToHub) {
455     MessageDeliveryStatus messageDeliveryStatus;
456     messageDeliveryStatus.messageSequenceNumber = 123;
457     messageDeliveryStatus.errorCode = ErrorCode::OK;
458 
459     Status status = contextHub->sendMessageDeliveryStatusToHub(getHubId(), messageDeliveryStatus);
460     if (status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION ||
461         status.transactionError() == android::UNKNOWN_TRANSACTION) {
462         GTEST_SKIP() << "Not supported -> old API; or not implemented";
463     } else {
464         EXPECT_TRUE(status.isOk());
465     }
466 }
467 
PrintGeneratedTest(const testing::TestParamInfo<ContextHubAidl::ParamType> & info)468 std::string PrintGeneratedTest(const testing::TestParamInfo<ContextHubAidl::ParamType>& info) {
469     return std::string("CONTEXT_HUB_ID_") + std::to_string(std::get<1>(info.param));
470 }
471 
472 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ContextHubAidl);
473 INSTANTIATE_TEST_SUITE_P(ContextHub, ContextHubAidl, testing::ValuesIn(generateContextHubMapping()),
474                          PrintGeneratedTest);
475 
476 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ContextHubTransactionTest);
477 INSTANTIATE_TEST_SUITE_P(ContextHub, ContextHubTransactionTest,
478                          testing::ValuesIn(generateContextHubMapping()), PrintGeneratedTest);
479 
main(int argc,char ** argv)480 int main(int argc, char** argv) {
481     ::testing::InitGoogleTest(&argc, argv);
482     ProcessState::self()->setThreadPoolMaxThreadCount(1);
483     ProcessState::self()->startThreadPool();
484     return RUN_ALL_TESTS();
485 }
486