blob: 83e12aed3a24b81f58f8cf971dcc31864fe59811 [file] [log] [blame]
Brian Duddiecd3a43f2016-12-07 16:53:11 -08001/*
2 * Copyright (C) 2017 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#define LOG_TAG "contexthub_hidl_hal_test"
18
19#include <android-base/logging.h>
20#include <android/hardware/contexthub/1.0/IContexthub.h>
21#include <android/hardware/contexthub/1.0/IContexthubCallback.h>
22#include <android/hardware/contexthub/1.0/types.h>
23#include <android/log.h>
Dan Shie10b1d62019-12-12 10:12:52 -080024#include <gtest/gtest.h>
25#include <hidl/GtestPrinter.h>
26#include <hidl/ServiceManagement.h>
Steven Moreland3eb7df72017-04-06 12:15:23 -070027#include <log/log.h>
Brian Duddiecd3a43f2016-12-07 16:53:11 -080028
29#include <cinttypes>
30#include <future>
31#include <utility>
32
Brian Duddieaf8a2f92020-02-14 15:39:19 -080033using ::android::sp;
Brian Duddiecd3a43f2016-12-07 16:53:11 -080034using ::android::hardware::hidl_string;
35using ::android::hardware::hidl_vec;
Brian Duddieaf8a2f92020-02-14 15:39:19 -080036using ::android::hardware::Return;
37using ::android::hardware::Void;
Brian Duddiecd3a43f2016-12-07 16:53:11 -080038using ::android::hardware::contexthub::V1_0::AsyncEventType;
39using ::android::hardware::contexthub::V1_0::ContextHub;
40using ::android::hardware::contexthub::V1_0::ContextHubMsg;
41using ::android::hardware::contexthub::V1_0::HubAppInfo;
42using ::android::hardware::contexthub::V1_0::IContexthub;
43using ::android::hardware::contexthub::V1_0::IContexthubCallback;
44using ::android::hardware::contexthub::V1_0::NanoAppBinary;
45using ::android::hardware::contexthub::V1_0::Result;
46using ::android::hardware::contexthub::V1_0::TransactionResult;
Brian Duddiecd3a43f2016-12-07 16:53:11 -080047
Brian Duddiecd3a43f2016-12-07 16:53:11 -080048#define ASSERT_OK(result) ASSERT_EQ(result, Result::OK)
49#define EXPECT_OK(result) EXPECT_EQ(result, Result::OK)
50
51namespace {
52
53// App ID with vendor "GoogT" (Google Testing), app identifier 0x555555. This
54// app ID is reserved and must never appear in the list of loaded apps.
55constexpr uint64_t kNonExistentAppId = 0x476f6f6754555555;
56
57// Helper that does explicit conversion of an enum class to its underlying/base
58// type. Useful for stream output of enum values.
Brian Duddieaf8a2f92020-02-14 15:39:19 -080059template <typename EnumType>
60constexpr typename std::underlying_type<EnumType>::type asBaseType(EnumType value) {
61 return static_cast<typename std::underlying_type<EnumType>::type>(value);
Brian Duddiecd3a43f2016-12-07 16:53:11 -080062}
63
64// Synchronously queries IContexthub::getHubs() and returns the result
65hidl_vec<ContextHub> getHubsSync(sp<IContexthub> hubApi) {
Brian Duddieaf8a2f92020-02-14 15:39:19 -080066 hidl_vec<ContextHub> hubList;
67 std::promise<void> barrier;
Brian Duddiecd3a43f2016-12-07 16:53:11 -080068
Brian Duddieaf8a2f92020-02-14 15:39:19 -080069 hubApi->getHubs([&hubList, &barrier](const hidl_vec<ContextHub>& hubs) {
70 hubList = hubs;
71 barrier.set_value();
72 });
73 barrier.get_future().wait_for(std::chrono::seconds(1));
Brian Duddiecd3a43f2016-12-07 16:53:11 -080074
Brian Duddieaf8a2f92020-02-14 15:39:19 -080075 return hubList;
Brian Duddiecd3a43f2016-12-07 16:53:11 -080076}
77
78// Gets a list of valid hub IDs in the system
Dan Shie10b1d62019-12-12 10:12:52 -080079std::vector<std::string> getHubIds(const std::string& service_name) {
80 std::vector<std::string> hubIds;
Brian Duddiecd3a43f2016-12-07 16:53:11 -080081
Dan Shie10b1d62019-12-12 10:12:52 -080082 sp<IContexthub> hubApi = IContexthub::getService(service_name);
Brian Duddiecd3a43f2016-12-07 16:53:11 -080083
84 if (hubApi != nullptr) {
Dan Shie10b1d62019-12-12 10:12:52 -080085 for (const ContextHub& hub : getHubsSync(hubApi)) {
86 hubIds.push_back(std::to_string(hub.hubId));
87 }
Brian Duddiecd3a43f2016-12-07 16:53:11 -080088 }
Brian Duddiecd3a43f2016-12-07 16:53:11 -080089
Dan Shie10b1d62019-12-12 10:12:52 -080090 ALOGD("Running tests against all %zu reported hubs for service %s", hubIds.size(),
91 service_name.c_str());
92 return hubIds;
Brian Duddiecd3a43f2016-12-07 16:53:11 -080093}
94
Dan Shie10b1d62019-12-12 10:12:52 -080095// Test fixture parameterized by hub ID, initializes the HAL and makes the context hub API handle
96// available.
97class ContexthubHidlTest : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
98 public:
99 virtual void SetUp() override {
100 hubApi = IContexthub::getService(std::get<0>(GetParam()));
101 ASSERT_NE(hubApi, nullptr);
Zhuoyao Zhangebae6472018-02-08 20:48:38 -0800102
Dan Shie10b1d62019-12-12 10:12:52 -0800103 // getHubs() must be called at least once for proper initialization of the
104 // HAL implementation
105 getHubsSync(hubApi);
106 }
Zhuoyao Zhangebae6472018-02-08 20:48:38 -0800107
Dan Shie10b1d62019-12-12 10:12:52 -0800108 uint32_t getHubId() { return std::stoi(std::get<1>(GetParam())); }
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800109
Dan Shie10b1d62019-12-12 10:12:52 -0800110 Result registerCallback(sp<IContexthubCallback> cb) {
111 Result result = hubApi->registerCallback(getHubId(), cb);
112 ALOGD("Registered callback, result %" PRIu32, result);
113 return result;
114 }
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800115
Dan Shie10b1d62019-12-12 10:12:52 -0800116 sp<IContexthub> hubApi;
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800117};
118
119// Base callback implementation that just logs all callbacks by default
120class ContexthubCallbackBase : public IContexthubCallback {
Brian Duddieaf8a2f92020-02-14 15:39:19 -0800121 public:
122 virtual Return<void> handleClientMsg(const ContextHubMsg& /*msg*/) override {
123 ALOGD("Got client message callback");
124 return Void();
125 }
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800126
Brian Duddieaf8a2f92020-02-14 15:39:19 -0800127 virtual Return<void> handleTxnResult(uint32_t txnId, TransactionResult result) override {
128 ALOGD("Got transaction result callback for txnId %" PRIu32 " with result %" PRId32, txnId,
129 result);
130 return Void();
131 }
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800132
Brian Duddieaf8a2f92020-02-14 15:39:19 -0800133 virtual Return<void> handleHubEvent(AsyncEventType evt) override {
134 ALOGD("Got hub event callback for event type %" PRIu32, evt);
135 return Void();
136 }
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800137
Brian Duddieaf8a2f92020-02-14 15:39:19 -0800138 virtual Return<void> handleAppAbort(uint64_t appId, uint32_t abortCode) override {
139 ALOGD("Got app abort notification for appId 0x%" PRIx64
140 " with abort code "
141 "0x%" PRIx32,
142 appId, abortCode);
143 return Void();
144 }
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800145
Brian Duddieaf8a2f92020-02-14 15:39:19 -0800146 virtual Return<void> handleAppsInfo(const hidl_vec<HubAppInfo>& /*appInfo*/) override {
147 ALOGD("Got app info callback");
148 return Void();
149 }
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800150};
151
152// Wait for a callback to occur (signaled by the given future) up to the
153// provided timeout. If the future is invalid or the callback does not come
154// within the given time, returns false.
Brian Duddieaf8a2f92020-02-14 15:39:19 -0800155template <class ReturnType>
156bool waitForCallback(std::future<ReturnType> future, ReturnType* result,
157 std::chrono::milliseconds timeout = std::chrono::seconds(5)) {
158 auto expiration = std::chrono::system_clock::now() + timeout;
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800159
Brian Duddieaf8a2f92020-02-14 15:39:19 -0800160 EXPECT_NE(result, nullptr);
161 EXPECT_TRUE(future.valid());
162 if (result != nullptr && future.valid()) {
163 std::future_status status = future.wait_until(expiration);
164 EXPECT_NE(status, std::future_status::timeout) << "Timed out waiting for callback";
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800165
Brian Duddieaf8a2f92020-02-14 15:39:19 -0800166 if (status == std::future_status::ready) {
167 *result = future.get();
168 return true;
169 }
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800170 }
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800171
Brian Duddieaf8a2f92020-02-14 15:39:19 -0800172 return false;
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800173}
174
175// Ensures that the metadata reported in getHubs() is sane
Dan Shie10b1d62019-12-12 10:12:52 -0800176TEST_P(ContexthubHidlTest, TestGetHubs) {
177 hidl_vec<ContextHub> hubs = getHubsSync(hubApi);
178 ALOGD("System reports %zu hubs", hubs.size());
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800179
Dan Shie10b1d62019-12-12 10:12:52 -0800180 for (const ContextHub& hub : hubs) {
181 ALOGD("Checking hub ID %" PRIu32, hub.hubId);
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800182
Dan Shie10b1d62019-12-12 10:12:52 -0800183 EXPECT_FALSE(hub.name.empty());
184 EXPECT_FALSE(hub.vendor.empty());
185 EXPECT_FALSE(hub.toolchain.empty());
186 EXPECT_GT(hub.peakMips, 0);
187 EXPECT_GE(hub.stoppedPowerDrawMw, 0);
188 EXPECT_GE(hub.sleepPowerDrawMw, 0);
189 EXPECT_GT(hub.peakPowerDrawMw, 0);
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800190
Dan Shie10b1d62019-12-12 10:12:52 -0800191 // Minimum 128 byte MTU as required by CHRE API v1.0
192 EXPECT_GE(hub.maxSupportedMsgLen, UINT32_C(128));
193 }
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800194}
195
196TEST_P(ContexthubHidlTest, TestRegisterCallback) {
Brian Duddieaf8a2f92020-02-14 15:39:19 -0800197 ALOGD("TestRegisterCallback called, hubId %" PRIu32, getHubId());
198 ASSERT_OK(registerCallback(new ContexthubCallbackBase()));
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800199}
200
201TEST_P(ContexthubHidlTest, TestRegisterNullCallback) {
Brian Duddieaf8a2f92020-02-14 15:39:19 -0800202 ALOGD("TestRegisterNullCallback called, hubId %" PRIu32, getHubId());
203 ASSERT_OK(registerCallback(nullptr));
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800204}
205
206// Helper callback that puts the async appInfo callback data into a promise
207class QueryAppsCallback : public ContexthubCallbackBase {
Brian Duddieaf8a2f92020-02-14 15:39:19 -0800208 public:
209 virtual Return<void> handleAppsInfo(const hidl_vec<HubAppInfo>& appInfo) override {
210 ALOGD("Got app info callback with %zu apps", appInfo.size());
211 promise.set_value(appInfo);
212 return Void();
213 }
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800214
Brian Duddieaf8a2f92020-02-14 15:39:19 -0800215 std::promise<hidl_vec<HubAppInfo>> promise;
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800216};
217
218// Calls queryApps() and checks the returned metadata
219TEST_P(ContexthubHidlTest, TestQueryApps) {
Brian Duddieaf8a2f92020-02-14 15:39:19 -0800220 ALOGD("TestQueryApps called, hubId %u", getHubId());
221 sp<QueryAppsCallback> cb = new QueryAppsCallback();
222 ASSERT_OK(registerCallback(cb));
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800223
Brian Duddieaf8a2f92020-02-14 15:39:19 -0800224 Result result = hubApi->queryApps(getHubId());
225 ASSERT_OK(result);
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800226
Brian Duddieaf8a2f92020-02-14 15:39:19 -0800227 ALOGD("Waiting for app info callback");
228 hidl_vec<HubAppInfo> appList;
229 ASSERT_TRUE(waitForCallback(cb->promise.get_future(), &appList));
230 for (const HubAppInfo& appInfo : appList) {
231 EXPECT_NE(appInfo.appId, UINT64_C(0));
232 EXPECT_NE(appInfo.appId, kNonExistentAppId);
233 }
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800234}
235
236// Helper callback that puts the TransactionResult for the expectedTxnId into a
237// promise
238class TxnResultCallback : public ContexthubCallbackBase {
Brian Duddieaf8a2f92020-02-14 15:39:19 -0800239 public:
240 virtual Return<void> handleTxnResult(uint32_t txnId, TransactionResult result) override {
241 ALOGD("Got transaction result callback for txnId %" PRIu32 " (expecting %" PRIu32
242 ") with result %" PRId32,
243 txnId, expectedTxnId, result);
244 if (txnId == expectedTxnId) {
245 promise.set_value(result);
246 }
247 return Void();
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800248 }
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800249
Brian Duddieaf8a2f92020-02-14 15:39:19 -0800250 uint32_t expectedTxnId = 0;
251 std::promise<TransactionResult> promise;
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800252};
253
254// Parameterized fixture that sets the callback to TxnResultCallback
255class ContexthubTxnTest : public ContexthubHidlTest {
Brian Duddieaf8a2f92020-02-14 15:39:19 -0800256 public:
257 virtual void SetUp() override {
258 ContexthubHidlTest::SetUp();
259 ASSERT_OK(registerCallback(cb));
260 }
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800261
Brian Duddieaf8a2f92020-02-14 15:39:19 -0800262 sp<TxnResultCallback> cb = new TxnResultCallback();
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800263};
264
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800265// Checks cases where the hub implementation is expected to return an error, but
266// that error can be returned either synchronously or in the asynchronous
267// transaction callback. Returns an AssertionResult that can be used in
268// ASSERT/EXPECT_TRUE. Allows checking the sync result against 1 additional
269// allowed error code apart from OK and TRANSACTION_FAILED, which are always
270// allowed.
Brian Duddieaf8a2f92020-02-14 15:39:19 -0800271::testing::AssertionResult checkFailureSyncOrAsync(Result result, Result allowedSyncResult,
272 std::future<TransactionResult>&& future) {
273 if (result == Result::OK) {
274 // No error reported synchronously - this is OK, but then we should get an
275 // async callback with a failure status
276 TransactionResult asyncResult;
277 if (!waitForCallback(std::forward<std::future<TransactionResult>>(future), &asyncResult)) {
278 return ::testing::AssertionFailure()
279 << "Got successful sync result, then failed to receive async cb";
280 } else if (asyncResult == TransactionResult::SUCCESS) {
281 return ::testing::AssertionFailure()
282 << "Got successful sync result, then unexpected successful async "
283 "result";
284 }
285 } else if (result != allowedSyncResult && result != Result::TRANSACTION_FAILED) {
286 return ::testing::AssertionFailure()
287 << "Got sync result " << asBaseType(result) << ", expected TRANSACTION_FAILED or "
288 << asBaseType(allowedSyncResult);
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800289 }
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800290
Brian Duddieaf8a2f92020-02-14 15:39:19 -0800291 return ::testing::AssertionSuccess();
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800292}
293
294TEST_P(ContexthubTxnTest, TestSendMessageToNonExistentNanoApp) {
Brian Duddieaf8a2f92020-02-14 15:39:19 -0800295 ContextHubMsg msg;
296 msg.appName = kNonExistentAppId;
297 msg.msgType = 1;
298 msg.msg.resize(4);
299 std::fill(msg.msg.begin(), msg.msg.end(), 0);
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800300
Brian Duddieaf8a2f92020-02-14 15:39:19 -0800301 ALOGD("Sending message to non-existent nanoapp");
302 Result result = hubApi->sendMessageToHub(getHubId(), msg);
303 if (result != Result::OK && result != Result::BAD_PARAMS &&
304 result != Result::TRANSACTION_FAILED) {
305 FAIL() << "Got result " << asBaseType(result) << ", expected OK, BAD_PARAMS"
306 << ", or TRANSACTION_FAILED";
307 }
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800308}
309
310TEST_P(ContexthubTxnTest, TestLoadEmptyNanoApp) {
Brian Duddieaf8a2f92020-02-14 15:39:19 -0800311 cb->expectedTxnId = 0123;
312 NanoAppBinary emptyApp;
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800313
Brian Duddieaf8a2f92020-02-14 15:39:19 -0800314 emptyApp.appId = kNonExistentAppId;
315 emptyApp.appVersion = 1;
316 emptyApp.flags = 0;
317 emptyApp.targetChreApiMajorVersion = 1;
318 emptyApp.targetChreApiMinorVersion = 0;
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800319
Brian Duddieaf8a2f92020-02-14 15:39:19 -0800320 ALOGD("Loading empty nanoapp");
321 Result result = hubApi->loadNanoApp(getHubId(), emptyApp, cb->expectedTxnId);
322 EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS, cb->promise.get_future()));
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800323}
324
325TEST_P(ContexthubTxnTest, TestUnloadNonexistentNanoApp) {
Brian Duddieaf8a2f92020-02-14 15:39:19 -0800326 cb->expectedTxnId = 1234;
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800327
Brian Duddieaf8a2f92020-02-14 15:39:19 -0800328 ALOGD("Unloading nonexistent nanoapp");
329 Result result = hubApi->unloadNanoApp(getHubId(), kNonExistentAppId, cb->expectedTxnId);
330 EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS, cb->promise.get_future()));
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800331}
332
333TEST_P(ContexthubTxnTest, TestEnableNonexistentNanoApp) {
Brian Duddieaf8a2f92020-02-14 15:39:19 -0800334 cb->expectedTxnId = 2345;
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800335
Brian Duddieaf8a2f92020-02-14 15:39:19 -0800336 ALOGD("Enabling nonexistent nanoapp");
337 Result result = hubApi->enableNanoApp(getHubId(), kNonExistentAppId, cb->expectedTxnId);
338 EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS, cb->promise.get_future()));
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800339}
340
341TEST_P(ContexthubTxnTest, TestDisableNonexistentNanoApp) {
Brian Duddieaf8a2f92020-02-14 15:39:19 -0800342 cb->expectedTxnId = 3456;
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800343
Brian Duddieaf8a2f92020-02-14 15:39:19 -0800344 ALOGD("Disabling nonexistent nanoapp");
345 Result result = hubApi->disableNanoApp(getHubId(), kNonExistentAppId, cb->expectedTxnId);
346 EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS, cb->promise.get_future()));
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800347}
348
Dan Shie10b1d62019-12-12 10:12:52 -0800349// Return the test parameters of a vecter of tuples for all IContexthub services and each of its hub
350// id: <service name of IContexthub, hub id of the IContexthub service>
351static std::vector<std::tuple<std::string, std::string>> get_parameters() {
352 std::vector<std::tuple<std::string, std::string>> parameters;
353 std::vector<std::string> service_names =
354 android::hardware::getAllHalInstanceNames(IContexthub::descriptor);
355 for (const std::string& service_name : service_names) {
356 std::vector<std::string> ids = getHubIds(service_name);
357 for (const std::string& id : ids) {
358 parameters.push_back(std::make_tuple(service_name, id));
359 }
360 }
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800361
Dan Shie10b1d62019-12-12 10:12:52 -0800362 return parameters;
Brian Duddiecd3a43f2016-12-07 16:53:11 -0800363}
364
Dan Shie10b1d62019-12-12 10:12:52 -0800365static std::vector<std::tuple<std::string, std::string>> kTestParameters = get_parameters();
366
367INSTANTIATE_TEST_SUITE_P(HubIdSpecificTests, ContexthubHidlTest, testing::ValuesIn(kTestParameters),
368 android::hardware::PrintInstanceTupleNameToString<>);
369
370INSTANTIATE_TEST_SUITE_P(HubIdSpecificTests, ContexthubTxnTest, testing::ValuesIn(kTestParameters),
371 android::hardware::PrintInstanceTupleNameToString<>);
372
373} // anonymous namespace