summaryrefslogtreecommitdiff
path: root/sensors/common/default/2.X/Sensors.h
blob: 1124425f99f52aec9bb6fed0ab12832fb8cc92bf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ANDROID_HARDWARE_SENSORS_V2_X_SENSORS_H
#define ANDROID_HARDWARE_SENSORS_V2_X_SENSORS_H

#include "EventMessageQueueWrapper.h"
#include "Sensor.h"

#include <android/hardware/sensors/2.0/ISensors.h>
#include <android/hardware/sensors/2.0/types.h>
#include <fmq/MessageQueue.h>
#include <hardware_legacy/power.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
#include <log/log.h>

#include <atomic>
#include <memory>
#include <thread>

namespace android {
namespace hardware {
namespace sensors {
namespace V2_X {
namespace implementation {

template <class ISensorsInterface>
struct Sensors : public ISensorsInterface, public ISensorsEventCallback {
    using Event = ::android::hardware::sensors::V1_0::Event;
    using OperationMode = ::android::hardware::sensors::V1_0::OperationMode;
    using RateLevel = ::android::hardware::sensors::V1_0::RateLevel;
    using Result = ::android::hardware::sensors::V1_0::Result;
    using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo;
    using EventQueueFlagBits = ::android::hardware::sensors::V2_0::EventQueueFlagBits;
    using SensorTimeout = ::android::hardware::sensors::V2_0::SensorTimeout;
    using WakeLockQueueFlagBits = ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
    using ISensorsCallback = ::android::hardware::sensors::V2_0::ISensorsCallback;
    using EventMessageQueue = MessageQueue<Event, kSynchronizedReadWrite>;
    using WakeLockMessageQueue = MessageQueue<uint32_t, kSynchronizedReadWrite>;

    static constexpr const char* kWakeLockName = "SensorsHAL_WAKEUP";

    Sensors()
        : mEventQueueFlag(nullptr),
          mNextHandle(1),
          mOutstandingWakeUpEvents(0),
          mReadWakeLockQueueRun(false),
          mAutoReleaseWakeLockTime(0),
          mHasWakeLock(false) {
        AddSensor<AccelSensor>();
        AddSensor<GyroSensor>();
        AddSensor<AmbientTempSensor>();
        AddSensor<PressureSensor>();
        AddSensor<MagnetometerSensor>();
        AddSensor<LightSensor>();
        AddSensor<ProximitySensor>();
        AddSensor<RelativeHumiditySensor>();
    }

    virtual ~Sensors() {
        deleteEventFlag();
        mReadWakeLockQueueRun = false;
        mWakeLockThread.join();
    }

    // Methods from ::android::hardware::sensors::V2_0::ISensors follow.
    Return<Result> setOperationMode(OperationMode mode) override {
        for (auto sensor : mSensors) {
            sensor.second->setOperationMode(mode);
        }
        return Result::OK;
    }

    Return<Result> activate(int32_t sensorHandle, bool enabled) override {
        auto sensor = mSensors.find(sensorHandle);
        if (sensor != mSensors.end()) {
            sensor->second->activate(enabled);
            return Result::OK;
        }
        return Result::BAD_VALUE;
    }

    Return<Result> initialize(
            const ::android::hardware::MQDescriptorSync<Event>& eventQueueDescriptor,
            const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
            const sp<ISensorsCallback>& sensorsCallback) override {
        auto eventQueue =
                std::make_unique<EventMessageQueue>(eventQueueDescriptor, true /* resetPointers */);
        std::unique_ptr<V2_1::implementation::EventMessageQueueWrapperBase> wrapper =
                std::make_unique<V2_1::implementation::EventMessageQueueWrapperV1_0>(eventQueue);
        return initializeBase(wrapper, wakeLockDescriptor, sensorsCallback);
    }

    Return<Result> initializeBase(
            std::unique_ptr<V2_1::implementation::EventMessageQueueWrapperBase>& eventQueue,
            const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
            const sp<ISensorsCallback>& sensorsCallback) {
        Result result = Result::OK;

        // Ensure that all sensors are disabled
        for (auto sensor : mSensors) {
            sensor.second->activate(false /* enable */);
        }

        // Stop the Wake Lock thread if it is currently running
        if (mReadWakeLockQueueRun.load()) {
            mReadWakeLockQueueRun = false;
            mWakeLockThread.join();
        }

        // Save a reference to the callback
        mCallback = sensorsCallback;

        // Save the event queue.
        mEventQueue = std::move(eventQueue);

        // Ensure that any existing EventFlag is properly deleted
        deleteEventFlag();

        // Create the EventFlag that is used to signal to the framework that sensor events have been
        // written to the Event FMQ
        if (EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag) != OK) {
            result = Result::BAD_VALUE;
        }

        // Create the Wake Lock FMQ that is used by the framework to communicate whenever WAKE_UP
        // events have been successfully read and handled by the framework.
        mWakeLockQueue = std::make_unique<WakeLockMessageQueue>(wakeLockDescriptor,
                                                                true /* resetPointers */);

        if (!mCallback || !mEventQueue || !mWakeLockQueue || mEventQueueFlag == nullptr) {
            result = Result::BAD_VALUE;
        }

        // Start the thread to read events from the Wake Lock FMQ
        mReadWakeLockQueueRun = true;
        mWakeLockThread = std::thread(startReadWakeLockThread, this);

        return result;
    }

    Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
                         int64_t /* maxReportLatencyNs */) override {
        auto sensor = mSensors.find(sensorHandle);
        if (sensor != mSensors.end()) {
            sensor->second->batch(samplingPeriodNs);
            return Result::OK;
        }
        return Result::BAD_VALUE;
    }

    Return<Result> flush(int32_t sensorHandle) override {
        auto sensor = mSensors.find(sensorHandle);
        if (sensor != mSensors.end()) {
            return sensor->second->flush();
        }
        return Result::BAD_VALUE;
    }

    Return<Result> injectSensorData(const Event& event) override {
        auto sensor = mSensors.find(event.sensorHandle);
        if (sensor != mSensors.end()) {
            return sensor->second->injectEvent(V2_1::implementation::convertToNewEvent(event));
        }

        return Result::BAD_VALUE;
    }

    Return<void> registerDirectChannel(const SharedMemInfo& /* mem */,
                                       V2_0::ISensors::registerDirectChannel_cb _hidl_cb) override {
        _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */);
        return Return<void>();
    }

    Return<Result> unregisterDirectChannel(int32_t /* channelHandle */) override {
        return Result::INVALID_OPERATION;
    }

    Return<void> configDirectReport(int32_t /* sensorHandle */, int32_t /* channelHandle */,
                                    RateLevel /* rate */,
                                    V2_0::ISensors::configDirectReport_cb _hidl_cb) override {
        _hidl_cb(Result::INVALID_OPERATION, 0 /* reportToken */);
        return Return<void>();
    }

    void postEvents(const std::vector<V2_1::Event>& events, bool wakeup) override {
        std::lock_guard<std::mutex> lock(mWriteLock);
        if (mEventQueue->write(events)) {
            mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS));

            if (wakeup) {
                // Keep track of the number of outstanding WAKE_UP events in order to properly hold
                // a wake lock until the framework has secured a wake lock
                updateWakeLock(events.size(), 0 /* eventsHandled */);
            }
        }
    }

  protected:
    /**
     * Add a new sensor
     */
    template <class SensorType>
    void AddSensor() {
        std::shared_ptr<SensorType> sensor =
                std::make_shared<SensorType>(mNextHandle++ /* sensorHandle */, this /* callback */);
        mSensors[sensor->getSensorInfo().sensorHandle] = sensor;
    }

    /**
     * Utility function to delete the Event Flag
     */
    void deleteEventFlag() {
        status_t status = EventFlag::deleteEventFlag(&mEventQueueFlag);
        if (status != OK) {
            ALOGI("Failed to delete event flag: %d", status);
        }
    }

    static void startReadWakeLockThread(Sensors* sensors) { sensors->readWakeLockFMQ(); }

    /**
     * Function to read the Wake Lock FMQ and release the wake lock when appropriate
     */
    void readWakeLockFMQ() {
        while (mReadWakeLockQueueRun.load()) {
            constexpr int64_t kReadTimeoutNs = 500 * 1000 * 1000;  // 500 ms
            uint32_t eventsHandled = 0;

            // Read events from the Wake Lock FMQ. Timeout after a reasonable amount of time to
            // ensure that any held wake lock is able to be released if it is held for too long.
            mWakeLockQueue->readBlocking(&eventsHandled, 1 /* count */, 0 /* readNotification */,
                                         static_cast<uint32_t>(WakeLockQueueFlagBits::DATA_WRITTEN),
                                         kReadTimeoutNs);
            updateWakeLock(0 /* eventsWritten */, eventsHandled);
        }
    }

    /**
     * Responsible for acquiring and releasing a wake lock when there are unhandled WAKE_UP events
     */
    void updateWakeLock(int32_t eventsWritten, int32_t eventsHandled) {
        std::lock_guard<std::mutex> lock(mWakeLockLock);
        int32_t newVal = mOutstandingWakeUpEvents + eventsWritten - eventsHandled;
        if (newVal < 0) {
            mOutstandingWakeUpEvents = 0;
        } else {
            mOutstandingWakeUpEvents = newVal;
        }

        if (eventsWritten > 0) {
            // Update the time at which the last WAKE_UP event was sent
            mAutoReleaseWakeLockTime =
                    ::android::uptimeMillis() +
                    static_cast<uint32_t>(SensorTimeout::WAKE_LOCK_SECONDS) * 1000;
        }

        if (!mHasWakeLock && mOutstandingWakeUpEvents > 0 &&
            acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLockName) == 0) {
            mHasWakeLock = true;
        } else if (mHasWakeLock) {
            // Check if the wake lock should be released automatically if
            // SensorTimeout::WAKE_LOCK_SECONDS has elapsed since the last WAKE_UP event was written
            // to the Wake Lock FMQ.
            if (::android::uptimeMillis() > mAutoReleaseWakeLockTime) {
                ALOGD("No events read from wake lock FMQ for %d seconds, auto releasing wake lock",
                      SensorTimeout::WAKE_LOCK_SECONDS);
                mOutstandingWakeUpEvents = 0;
            }

            if (mOutstandingWakeUpEvents == 0 && release_wake_lock(kWakeLockName) == 0) {
                mHasWakeLock = false;
            }
        }
    }

    /**
     * The Event FMQ where sensor events are written
     */
    std::unique_ptr<V2_1::implementation::EventMessageQueueWrapperBase> mEventQueue;

    /**
     * The Wake Lock FMQ that is read to determine when the framework has handled WAKE_UP events
     */
    std::unique_ptr<WakeLockMessageQueue> mWakeLockQueue;

    /**
     * Event Flag to signal to the framework when sensor events are available to be read
     */
    EventFlag* mEventQueueFlag;

    /**
     * Callback for asynchronous events, such as dynamic sensor connections.
     */
    sp<ISensorsCallback> mCallback;

    /**
     * A map of the available sensors
     */
    std::map<int32_t, std::shared_ptr<Sensor>> mSensors;

    /**
     * The next available sensor handle
     */
    int32_t mNextHandle;

    /**
     * Lock to protect writes to the FMQs
     */
    std::mutex mWriteLock;

    /**
     * Lock to protect acquiring and releasing the wake lock
     */
    std::mutex mWakeLockLock;

    /**
     * Track the number of WAKE_UP events that have not been handled by the framework
     */
    uint32_t mOutstandingWakeUpEvents;

    /**
     * A thread to read the Wake Lock FMQ
     */
    std::thread mWakeLockThread;

    /**
     * Flag to indicate that the Wake Lock Thread should continue to run
     */
    std::atomic_bool mReadWakeLockQueueRun;

    /**
     * Track the time when the wake lock should automatically be released
     */
    int64_t mAutoReleaseWakeLockTime;

    /**
     * Flag to indicate if a wake lock has been acquired
     */
    bool mHasWakeLock;
};

}  // namespace implementation
}  // namespace V2_X
}  // namespace sensors
}  // namespace hardware
}  // namespace android

#endif  // ANDROID_HARDWARE_SENSORS_V2_X_SENSORS_H