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 <cstdint>
18
19 #include "chre/pal/sensor.h"
20 #include "chre/platform/condition_variable.h"
21 #include "chre/platform/linux/task_util/task_manager.h"
22 #include "chre/platform/mutex.h"
23 #include "chre/platform/shared/pal_system_api.h"
24 #include "chre/util/fixed_size_vector.h"
25 #include "chre/util/lock_guard.h"
26 #include "chre/util/macros.h"
27 #include "chre/util/optional.h"
28 #include "chre/util/time.h"
29 #include "chre/util/unique_ptr.h"
30 #include "gmock/gmock.h"
31 #include "gtest/gtest.h"
32
33 namespace {
34
35 using ::chre::ConditionVariable;
36 using ::chre::FixedSizeVector;
37 using ::chre::gChrePalSystemApi;
38 using ::chre::kOneMillisecondInNanoseconds;
39 using ::chre::LockGuard;
40 using ::chre::MakeUnique;
41 using ::chre::Mutex;
42 using ::chre::Nanoseconds;
43 using ::chre::Optional;
44 using ::chre::UniquePtr;
45 using ::testing::ElementsAre;
46
47 const struct chrePalSensorApi *gApi = nullptr;
48
49 constexpr uint32_t kTimeoutMultiplier = 10;
50
51 class Callbacks {
52 public:
samplingStatusUpdateCallback(uint32_t sensorInfoIndex,struct chreSensorSamplingStatus * status)53 void samplingStatusUpdateCallback(uint32_t sensorInfoIndex,
54 struct chreSensorSamplingStatus *status) {
55 LockGuard<Mutex> lock(mMutex);
56 if (!mStatusSensorIndex.has_value()) {
57 mStatusSensorIndex = sensorInfoIndex;
58 mStatus = status;
59 mCondVarStatus.notify_one();
60 }
61 }
62
dataEventCallback(uint32_t sensorInfoIndex,void * data)63 void dataEventCallback(uint32_t sensorInfoIndex, void *data) {
64 LockGuard<Mutex> lock(mMutex);
65 if (gApi == nullptr) {
66 return;
67 }
68
69 if (!mEventSensorIndices.full()) {
70 mEventSensorIndices.push_back(sensorInfoIndex);
71 mEventData.push_back(data);
72 if (mEventSensorIndices.full()) {
73 mCondVarEvents.notify_one();
74 }
75 } else {
76 gApi->releaseSensorDataEvent(data);
77 }
78 }
79
biasEventCallback(uint32_t sensorInfoIndex,void * biasData)80 void biasEventCallback(uint32_t sensorInfoIndex, void *biasData) {
81 UNUSED_VAR(sensorInfoIndex);
82 UNUSED_VAR(biasData);
83 }
84
flushCompleteCallback(uint32_t sensorInfoIndex,uint32_t flushRequestId,uint8_t errorCode)85 void flushCompleteCallback(uint32_t sensorInfoIndex, uint32_t flushRequestId,
86 uint8_t errorCode) {
87 UNUSED_VAR(sensorInfoIndex);
88 UNUSED_VAR(flushRequestId);
89 UNUSED_VAR(errorCode);
90 }
91
92 static constexpr uint32_t kNumEvents = 3;
93
94 Optional<uint32_t> mStatusSensorIndex;
95 Optional<struct chreSensorSamplingStatus *> mStatus;
96
97 FixedSizeVector<uint32_t, kNumEvents> mEventSensorIndices;
98 FixedSizeVector<void *, kNumEvents> mEventData;
99
100 //! Synchronize access to class members.
101 Mutex mMutex;
102 ConditionVariable mCondVarEvents;
103 ConditionVariable mCondVarStatus;
104 };
105
106 UniquePtr<Callbacks> gCallbacks = nullptr;
107
samplingStatusUpdateCallback(uint32_t sensorInfoIndex,struct chreSensorSamplingStatus * status)108 void samplingStatusUpdateCallback(uint32_t sensorInfoIndex,
109 struct chreSensorSamplingStatus *status) {
110 if (gCallbacks != nullptr) {
111 gCallbacks->samplingStatusUpdateCallback(sensorInfoIndex, status);
112 }
113 }
114
dataEventCallback(uint32_t sensorInfoIndex,void * data)115 void dataEventCallback(uint32_t sensorInfoIndex, void *data) {
116 if (gCallbacks != nullptr) {
117 gCallbacks->dataEventCallback(sensorInfoIndex, data);
118 }
119 }
120
biasEventCallback(uint32_t sensorInfoIndex,void * biasData)121 void biasEventCallback(uint32_t sensorInfoIndex, void *biasData) {
122 if (gCallbacks != nullptr) {
123 gCallbacks->biasEventCallback(sensorInfoIndex, biasData);
124 }
125 }
126
flushCompleteCallback(uint32_t sensorInfoIndex,uint32_t flushRequestId,uint8_t errorCode)127 void flushCompleteCallback(uint32_t sensorInfoIndex, uint32_t flushRequestId,
128 uint8_t errorCode) {
129 if (gCallbacks != nullptr) {
130 gCallbacks->flushCompleteCallback(sensorInfoIndex, flushRequestId,
131 errorCode);
132 }
133 }
134
135 class PalSensorTest : public testing::Test {
136 protected:
SetUp()137 void SetUp() override {
138 gCallbacks = MakeUnique<Callbacks>();
139 chre::TaskManagerSingleton::deinit();
140 chre::TaskManagerSingleton::init();
141 gApi = chrePalSensorGetApi(CHRE_PAL_SENSOR_API_CURRENT_VERSION);
142 ASSERT_NE(gApi, nullptr);
143 EXPECT_EQ(gApi->moduleVersion, CHRE_PAL_SENSOR_API_CURRENT_VERSION);
144 ASSERT_TRUE(gApi->open(&gChrePalSystemApi, &mPalCallbacks));
145 }
146
TearDown()147 void TearDown() override {
148 if (gApi != nullptr) {
149 gApi->close();
150 }
151 chre::TaskManagerSingleton::deinit();
152 gCallbacks = nullptr;
153 }
154
155 const struct chrePalSensorCallbacks mPalCallbacks = {
156 .samplingStatusUpdateCallback = samplingStatusUpdateCallback,
157 .dataEventCallback = dataEventCallback,
158 .biasEventCallback = biasEventCallback,
159 .flushCompleteCallback = flushCompleteCallback,
160 };
161 };
162
TEST_F(PalSensorTest,GetTheListOfSensors)163 TEST_F(PalSensorTest, GetTheListOfSensors) {
164 const struct chreSensorInfo *sensors;
165 uint32_t arraySize;
166
167 EXPECT_TRUE(gApi->getSensors(&sensors, &arraySize));
168 EXPECT_EQ(arraySize, 1);
169 EXPECT_STREQ(sensors[0].sensorName, "Test Accelerometer");
170 }
171
TEST_F(PalSensorTest,EnableAContinuousSensor)172 TEST_F(PalSensorTest, EnableAContinuousSensor) {
173 EXPECT_TRUE(gApi->configureSensor(
174 0 /* sensorInfoIndex */, CHRE_SENSOR_CONFIGURE_MODE_CONTINUOUS,
175 kOneMillisecondInNanoseconds /* intervalNs */, 0 /* latencyNs */));
176
177 LockGuard<Mutex> lock(gCallbacks->mMutex);
178 gCallbacks->mCondVarStatus.wait_for(
179 gCallbacks->mMutex,
180 Nanoseconds(kTimeoutMultiplier * kOneMillisecondInNanoseconds));
181 ASSERT_TRUE(gCallbacks->mStatusSensorIndex.has_value());
182 EXPECT_EQ(gCallbacks->mStatusSensorIndex.value(), 0);
183 ASSERT_TRUE(gCallbacks->mStatus.has_value());
184 EXPECT_TRUE(gCallbacks->mStatus.value()->enabled);
185 gApi->releaseSamplingStatusEvent(gCallbacks->mStatus.value());
186 gCallbacks->mStatus.reset();
187 gCallbacks->mStatusSensorIndex.reset();
188
189 gCallbacks->mCondVarEvents.wait_for(
190 gCallbacks->mMutex,
191 Nanoseconds((2 + gCallbacks->kNumEvents) * kTimeoutMultiplier *
192 kOneMillisecondInNanoseconds));
193 EXPECT_TRUE(gCallbacks->mEventSensorIndices.full());
194 EXPECT_THAT(gCallbacks->mEventSensorIndices, ElementsAre(0, 0, 0));
195 EXPECT_TRUE(gCallbacks->mEventData.full());
196 for (void *data : gCallbacks->mEventData) {
197 auto threeAxisData =
198 static_cast<const struct chreSensorThreeAxisData *>(data);
199 EXPECT_EQ(threeAxisData->header.readingCount, 1);
200 gApi->releaseSensorDataEvent(data);
201 }
202 // Need to unlock this mutex because the following disable sensor request
203 // needs it.
204 gCallbacks->mMutex.unlock();
205
206 EXPECT_TRUE(gApi->configureSensor(
207 0 /* sensorInfoIndex */, CHRE_SENSOR_CONFIGURE_MODE_DONE,
208 kOneMillisecondInNanoseconds /* intervalNs */, 0 /* latencyNs */));
209 gCallbacks->mMutex.lock();
210 gCallbacks->mCondVarStatus.wait_for(
211 gCallbacks->mMutex,
212 Nanoseconds(kTimeoutMultiplier * kOneMillisecondInNanoseconds));
213 ASSERT_TRUE(gCallbacks->mStatusSensorIndex.has_value());
214 ASSERT_TRUE(gCallbacks->mStatus.has_value());
215 gApi->releaseSamplingStatusEvent(gCallbacks->mStatus.value());
216 gCallbacks->mStatus.reset();
217 gCallbacks->mStatusSensorIndex.reset();
218 }
219
TEST_F(PalSensorTest,DisableAContinuousSensor)220 TEST_F(PalSensorTest, DisableAContinuousSensor) {
221 EXPECT_TRUE(gApi->configureSensor(
222 0 /* sensorInfoIndex */, CHRE_SENSOR_CONFIGURE_MODE_DONE,
223 kOneMillisecondInNanoseconds /* intervalNs */, 0 /* latencyNs */));
224
225 LockGuard<Mutex> lock(gCallbacks->mMutex);
226 gCallbacks->mCondVarStatus.wait_for(
227 gCallbacks->mMutex,
228 Nanoseconds(kTimeoutMultiplier * kOneMillisecondInNanoseconds));
229 ASSERT_TRUE(gCallbacks->mStatusSensorIndex.has_value());
230 EXPECT_EQ(gCallbacks->mStatusSensorIndex.value(), 0);
231 ASSERT_TRUE(gCallbacks->mStatus.has_value());
232 EXPECT_FALSE(gCallbacks->mStatus.value()->enabled);
233 gApi->releaseSamplingStatusEvent(gCallbacks->mStatus.value());
234 gCallbacks->mStatus.reset();
235 gCallbacks->mStatusSensorIndex.reset();
236 }
237
238 } // namespace
239