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