• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #define LOG_TAG "sensor_manager_aidl_hal_test"
18 #include <aidl/Gtest.h>
19 #include <aidl/Vintf.h>
20 #include <aidl/android/frameworks/sensorservice/ISensorManager.h>
21 #include <aidl/sensors/convert.h>
22 #include <android-base/logging.h>
23 #include <android-base/result.h>
24 #include <android/binder_manager.h>
25 #include <android/sensor.h>
26 #include <binder/IServiceManager.h>
27 #include <cutils/ashmem.h>
28 #include <gmock/gmock.h>
29 #include <gtest/gtest.h>
30 #include <sys/mman.h>
31 
32 #include <chrono>
33 #include <thread>
34 
35 using aidl::android::frameworks::sensorservice::IDirectReportChannel;
36 using aidl::android::frameworks::sensorservice::ISensorManager;
37 using aidl::android::hardware::common::Ashmem;
38 using aidl::android::hardware::sensors::Event;
39 using aidl::android::hardware::sensors::ISensors;
40 using aidl::android::hardware::sensors::SensorInfo;
41 using aidl::android::hardware::sensors::SensorType;
42 using ::android::sp;
43 using ndk::ScopedAStatus;
44 using ndk::ScopedFileDescriptor;
45 using ::testing::Contains;
46 
isOk(const ScopedAStatus & status)47 static inline ::testing::AssertionResult isOk(const ScopedAStatus& status) {
48     return status.isOk() ? ::testing::AssertionSuccess()
49                          : ::testing::AssertionFailure() << status.getDescription();
50 }
51 
52 template <typename I, typename F>
isIncreasing(I begin,I end,F getField)53 static ::testing::AssertionResult isIncreasing(I begin, I end, F getField) {
54     typename std::iterator_traits<I>::pointer lastValue = nullptr;
55     I iter;
56     size_t pos;
57     for (iter = begin, pos = 0; iter != end; ++iter, ++pos) {
58         if (iter == begin) {
59             lastValue = &(*iter);
60             continue;
61         }
62         if (getField(*iter) < getField(*lastValue)) {
63             return ::testing::AssertionFailure()
64                    << "Not an increasing sequence, pos = " << pos << ", " << getField(*iter)
65                    << " < " << getField(*lastValue);
66         }
67     }
68     return ::testing::AssertionSuccess();
69 }
70 
71 #define EXPECT_OK(__ret__) EXPECT_TRUE(isOk(__ret__))
72 #define ASSERT_OK(__ret__) ASSERT_TRUE(isOk(__ret__))
73 
74 class SensorManagerTest : public ::testing::TestWithParam<std::string> {
75    public:
SetUp()76     virtual void SetUp() override {
77         manager_ = ISensorManager::fromBinder(
78             ndk::SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
79         ASSERT_NE(manager_, nullptr);
80     }
81 
82     // Call getSensorList. Filter result based on |pred| if it is provided.
GetSensorList(std::vector<SensorInfo> * out_info,const std::function<bool (SensorInfo)> & pred=nullptr)83     ndk::ScopedAStatus GetSensorList(std::vector<SensorInfo>* out_info,
84                                      const std::function<bool(SensorInfo)>& pred = nullptr) {
85         ndk::ScopedAStatus ret = manager_->getSensorList(out_info);
86         if (ret.isOk() && pred) {
87             out_info->erase(std::remove_if(out_info->begin(), out_info->end(), std::not1(pred)),
88                             out_info->end());
89         }
90         return ret;
91     }
92 
93     std::shared_ptr<ISensorManager> manager_;
94 };
95 
96 using map_region = std::unique_ptr<void, std::function<void(void*)>>;
97 
map(const Ashmem & mem)98 map_region map(const Ashmem& mem) {
99     if (mem.fd.get() == -1) {
100         return nullptr;
101     }
102     size_t size = mem.size;
103     void* buf = mmap(nullptr, size, PROT_READ, MAP_SHARED, mem.fd.get(), 0);
104     return map_region{buf, [size](void* localBuf) { munmap(localBuf, size); }};
105 }
106 
TEST_P(SensorManagerTest,List)107 TEST_P(SensorManagerTest, List) {
108     std::vector<SensorInfo> sensorList;
109     auto res = GetSensorList(&sensorList);
110     ASSERT_OK(res) << res.getDescription();
111 }
112 
TEST_P(SensorManagerTest,Ashmem)113 TEST_P(SensorManagerTest, Ashmem) {
114     std::vector<SensorInfo> sensorList;
115     auto res = GetSensorList(&sensorList, [](const auto& info) {
116         return info.flags & SensorInfo::SENSOR_FLAG_BITS_DIRECT_CHANNEL_ASHMEM;
117     });
118     ASSERT_OK(res);
119     if (sensorList.empty()) {
120         GTEST_SKIP() << "DIRECT_CHANNEL_ASHMEM not supported by HAL, skipping";
121     }
122     auto testOne = [this](int64_t memSize, int64_t intendedSize,
123                           void (*callback)(const std::shared_ptr<IDirectReportChannel>&,
124                                            const ScopedAStatus&)) {
125         auto fd = ashmem_create_region("sensorservice_vts", memSize);
126         ASSERT_TRUE(fd != -1);
127         Ashmem ashmem = {ScopedFileDescriptor(fd), memSize};
128         std::shared_ptr<IDirectReportChannel> chan;
129         ScopedAStatus res = manager_->createAshmemDirectChannel(ashmem, intendedSize, &chan);
130         callback(chan, res);
131     };
132 
133     testOne(16, 16, [](const auto& chan, const ScopedAStatus& result) {
134         EXPECT_EQ(result.getServiceSpecificError(), ISensorManager::RESULT_BAD_VALUE)
135             << "unexpected result when memory size is too small";
136         EXPECT_EQ(chan, nullptr);
137     });
138 
139     testOne(1024, 1024, [](const auto& chan, const ScopedAStatus& result) {
140         EXPECT_OK(result);
141         EXPECT_NE(chan, nullptr);
142     });
143 
144     testOne(1024, 2048, [](const auto& chan, const ScopedAStatus& result) {
145         EXPECT_EQ(result.getServiceSpecificError(), ISensorManager::RESULT_BAD_VALUE)
146             << "unexpected result when intended size is too big";
147         EXPECT_EQ(chan, nullptr);
148     });
149 
150     testOne(1024, 16, [](const auto& chan, const ScopedAStatus& result) {
151         EXPECT_EQ(result.getServiceSpecificError(), ISensorManager::RESULT_BAD_VALUE)
152             << "unexpected result when intended size is too small";
153         EXPECT_EQ(chan, nullptr);
154     });
155 }
156 
parseEvents(uint8_t * buf,size_t memSize)157 static std::vector<Event> parseEvents(uint8_t* buf, size_t memSize) {
158     using android::hardware::sensors::implementation::convertFromSensorEvent;
159     size_t offset = 0;
160     int64_t lastCounter = -1;
161     std::vector<Event> events;
162     Event event;
163 
164     while (offset + (size_t)ISensors::DIRECT_REPORT_SENSOR_EVENT_TOTAL_LENGTH <= memSize) {
165         uint8_t* start = buf + offset;
166         int64_t atomicCounter = *reinterpret_cast<uint32_t*>(
167             start + (size_t)ISensors::DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_ATOMIC_COUNTER);
168         if (atomicCounter <= lastCounter) {
169             break;
170         }
171         int32_t size = *reinterpret_cast<int32_t*>(
172             start + (size_t)ISensors::DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_FIELD);
173         if (size != (size_t)ISensors::DIRECT_REPORT_SENSOR_EVENT_TOTAL_LENGTH) {
174             // unknown error, events parsed may be wrong, remove all
175             events.clear();
176             break;
177         }
178 
179         convertFromSensorEvent(*reinterpret_cast<const sensors_event_t*>(start), &event);
180         events.push_back(event);
181         lastCounter = atomicCounter;
182         offset += (size_t)ISensors::DIRECT_REPORT_SENSOR_EVENT_TOTAL_LENGTH;
183     }
184     return events;
185 }
186 
TEST_P(SensorManagerTest,GetDefaultAccelerometer)187 TEST_P(SensorManagerTest, GetDefaultAccelerometer) {
188     std::vector<SensorInfo> sensorList;
189     auto res = GetSensorList(
190         &sensorList, [](const auto& info) { return info.type == SensorType::ACCELEROMETER; });
191     ASSERT_OK(res);
192 
193     SensorInfo info;
194     res = manager_->getDefaultSensor(SensorType::ACCELEROMETER, &info);
195     if (sensorList.empty()) {
196         ASSERT_EQ(ISensorManager::RESULT_NOT_EXIST, res.getServiceSpecificError());
197     } else {
198         ASSERT_OK(res);
199         ASSERT_THAT(sensorList, Contains(info));
200     }
201 }
202 
TEST_P(SensorManagerTest,Accelerometer)203 TEST_P(SensorManagerTest, Accelerometer) {
204     using std::literals::chrono_literals::operator""ms;
205 
206     std::vector<SensorInfo> sensorList;
207     auto res = GetSensorList(&sensorList, [](const auto& info) {
208         if (info.type != SensorType::ACCELEROMETER) return false;
209         if (!(info.flags & SensorInfo::SENSOR_FLAG_BITS_DIRECT_CHANNEL_ASHMEM)) return false;
210         int maxLevel = (info.flags & SensorInfo::SENSOR_FLAG_BITS_MASK_DIRECT_REPORT) >>
211                        SensorInfo::SENSOR_FLAG_SHIFT_DIRECT_REPORT;
212         return maxLevel >= static_cast<int>(ISensors::RateLevel::FAST);
213     });
214     ASSERT_OK(res);
215 
216     if (sensorList.empty()) {
217         GTEST_SKIP()
218             << "No accelerometer sensor that supports DIRECT_CHANNEL_ASHMEM and fast report "
219             << "rate, skipping";
220     }
221 
222     for (const auto& info : sensorList) {
223         int32_t handle = info.sensorHandle;
224         const size_t memSize = (size_t)ISensors::DIRECT_REPORT_SENSOR_EVENT_TOTAL_LENGTH * 300;
225         auto fd = ashmem_create_region("sensorservice_vts", memSize);
226         ASSERT_TRUE(fd != -1);
227         Ashmem mem = {ScopedFileDescriptor(fd), memSize};
228         map_region buf = map(mem);
229         ASSERT_NE(buf, nullptr);
230         std::shared_ptr<IDirectReportChannel> chan;
231         auto res = manager_->createAshmemDirectChannel(mem, memSize, &chan);
232         ASSERT_OK(res);
233         ASSERT_NE(chan, nullptr);
234 
235         int32_t token = 0;
236         ASSERT_OK(chan->configure(handle, ISensors::RateLevel::FAST, &token));
237         ASSERT_GT(token, 0);
238         std::this_thread::sleep_for(500ms);
239         int32_t zeroToken = 0;
240         ASSERT_OK(chan->configure(handle, ISensors::RateLevel::STOP, &zeroToken));
241         ASSERT_OK(res);
242         ASSERT_EQ(zeroToken, 0);
243 
244         auto events = parseEvents(static_cast<uint8_t*>(buf.get()), memSize);
245 
246         EXPECT_TRUE(isIncreasing(events.begin(), events.end(), [](const auto& event) {
247             return event.timestamp;
248         })) << "timestamp is not monotonically increasing";
249         for (const auto& event : events) {
250             EXPECT_EQ(token, event.sensorHandle)
251                 << "configure token and sensor handle don't match.";
252         }
253     }
254 }
255 
256 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SensorManagerTest);
257 INSTANTIATE_TEST_SUITE_P(
258     PerInstance, SensorManagerTest,
259     testing::ValuesIn(android::getAidlHalInstanceNames(ISensorManager::descriptor)),
260     android::PrintInstanceNameToString);
261