android_hardware_SensorManager.cpp revision 9ba7c1c17567c19f0187d73cdca55ca99590674e
1/*
2 * Copyright 2008, 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 "SensorManager"
18
19#include <map>
20
21#include <utils/Log.h>
22#include <utils/Looper.h>
23
24#include <gui/Sensor.h>
25#include <gui/SensorManager.h>
26#include <gui/SensorEventQueue.h>
27
28#include "jni.h"
29#include "JNIHelp.h"
30#include "android_os_MessageQueue.h"
31#include <android_runtime/AndroidRuntime.h>
32
33#include "core_jni_helpers.h"
34
35static struct {
36    jclass clazz;
37    jmethodID dispatchSensorEvent;
38    jmethodID dispatchFlushCompleteEvent;
39} gBaseEventQueueClassInfo;
40
41namespace android {
42
43struct SensorOffsets
44{
45    jfieldID    name;
46    jfieldID    vendor;
47    jfieldID    version;
48    jfieldID    handle;
49    jfieldID    range;
50    jfieldID    resolution;
51    jfieldID    power;
52    jfieldID    minDelay;
53    jfieldID    fifoReservedEventCount;
54    jfieldID    fifoMaxEventCount;
55    jfieldID    stringType;
56    jfieldID    requiredPermission;
57    jfieldID    maxDelay;
58    jfieldID    flags;
59    jmethodID   setType;
60} gSensorOffsets;
61
62
63/*
64 * The method below are not thread-safe and not intended to be
65 */
66
67static void
68nativeClassInit (JNIEnv *_env, jclass _this)
69{
70    jclass sensorClass = _env->FindClass("android/hardware/Sensor");
71    SensorOffsets& sensorOffsets = gSensorOffsets;
72    sensorOffsets.name        = _env->GetFieldID(sensorClass, "mName",      "Ljava/lang/String;");
73    sensorOffsets.vendor      = _env->GetFieldID(sensorClass, "mVendor",    "Ljava/lang/String;");
74    sensorOffsets.version     = _env->GetFieldID(sensorClass, "mVersion",   "I");
75    sensorOffsets.handle      = _env->GetFieldID(sensorClass, "mHandle",    "I");
76    sensorOffsets.range       = _env->GetFieldID(sensorClass, "mMaxRange",  "F");
77    sensorOffsets.resolution  = _env->GetFieldID(sensorClass, "mResolution","F");
78    sensorOffsets.power       = _env->GetFieldID(sensorClass, "mPower",     "F");
79    sensorOffsets.minDelay    = _env->GetFieldID(sensorClass, "mMinDelay",  "I");
80    sensorOffsets.fifoReservedEventCount =
81            _env->GetFieldID(sensorClass, "mFifoReservedEventCount",  "I");
82    sensorOffsets.fifoMaxEventCount = _env->GetFieldID(sensorClass, "mFifoMaxEventCount",  "I");
83    sensorOffsets.stringType = _env->GetFieldID(sensorClass, "mStringType", "Ljava/lang/String;");
84    sensorOffsets.requiredPermission = _env->GetFieldID(sensorClass, "mRequiredPermission",
85                                                        "Ljava/lang/String;");
86    sensorOffsets.maxDelay    = _env->GetFieldID(sensorClass, "mMaxDelay",  "I");
87    sensorOffsets.flags = _env->GetFieldID(sensorClass, "mFlags",  "I");
88    sensorOffsets.setType = _env->GetMethodID(sensorClass, "setType", "(I)Z");
89}
90
91/**
92 * A key comparator predicate.
93 * It is used to intern strings associated with Sensor data.
94 * It defines a 'Strict weak ordering' for the interned strings.
95 */
96class InternedStringCompare {
97public:
98    bool operator()(const String8* string1, const String8* string2) const {
99        if (string1 == NULL) {
100            return string2 != NULL;
101        }
102        return string1->compare(*string2) < 0;
103    }
104};
105
106/**
107 * A localized interning mechanism for Sensor strings.
108 * We implement our own interning to avoid the overhead of using java.lang.String#intern().
109 * It is common that Vendor, StringType, and RequirePermission data is common between many of the
110 * Sensors, by interning the memory usage to represent Sensors is optimized.
111 */
112static jstring
113getInternedString(JNIEnv *env, const String8* string) {
114    static std::map<const String8*, jstring, InternedStringCompare> internedStrings;
115
116    jstring internedString;
117    std::map<const String8*, jstring>::iterator iterator = internedStrings.find(string);
118    if (iterator != internedStrings.end()) {
119        internedString = iterator->second;
120    } else {
121        jstring localString = env->NewStringUTF(string->string());
122        // we are implementing our own interning so expect these strings to be backed by global refs
123        internedString = (jstring) env->NewGlobalRef(localString);
124        internedStrings.insert(std::make_pair(string, internedString));
125        env->DeleteLocalRef(localString);
126    }
127
128    return internedString;
129}
130
131static jint
132nativeGetNextSensor(JNIEnv *env, jclass clazz, jobject sensor, jint next)
133{
134    SensorManager& mgr(SensorManager::getInstance());
135
136    Sensor const* const* sensorList;
137    size_t count = mgr.getSensorList(&sensorList);
138    if (size_t(next) >= count) {
139        return -1;
140    }
141
142    Sensor const* const list = sensorList[next];
143    const SensorOffsets& sensorOffsets(gSensorOffsets);
144    jstring name = getInternedString(env, &list->getName());
145    jstring vendor = getInternedString(env, &list->getVendor());
146    jstring requiredPermission = getInternedString(env, &list->getRequiredPermission());
147    env->SetObjectField(sensor, sensorOffsets.name,      name);
148    env->SetObjectField(sensor, sensorOffsets.vendor,    vendor);
149    env->SetIntField(sensor, sensorOffsets.version,      list->getVersion());
150    env->SetIntField(sensor, sensorOffsets.handle,       list->getHandle());
151    env->SetFloatField(sensor, sensorOffsets.range,      list->getMaxValue());
152    env->SetFloatField(sensor, sensorOffsets.resolution, list->getResolution());
153    env->SetFloatField(sensor, sensorOffsets.power,      list->getPowerUsage());
154    env->SetIntField(sensor, sensorOffsets.minDelay,     list->getMinDelay());
155    env->SetIntField(sensor, sensorOffsets.fifoReservedEventCount,
156                     list->getFifoReservedEventCount());
157    env->SetIntField(sensor, sensorOffsets.fifoMaxEventCount,
158                     list->getFifoMaxEventCount());
159    env->SetObjectField(sensor, sensorOffsets.requiredPermission,
160                        requiredPermission);
161    env->SetIntField(sensor, sensorOffsets.maxDelay, list->getMaxDelay());
162    env->SetIntField(sensor, sensorOffsets.flags, list->getFlags());
163    if (env->CallBooleanMethod(sensor, sensorOffsets.setType, list->getType()) == JNI_FALSE) {
164        jstring stringType = getInternedString(env, &list->getStringType());
165        env->SetObjectField(sensor, sensorOffsets.stringType, stringType);
166    }
167    next++;
168    return size_t(next) < count ? next : 0;
169}
170
171//----------------------------------------------------------------------------
172
173class Receiver : public LooperCallback {
174    sp<SensorEventQueue> mSensorQueue;
175    sp<MessageQueue> mMessageQueue;
176    jobject mReceiverObject;
177    jfloatArray mScratch;
178public:
179    Receiver(const sp<SensorEventQueue>& sensorQueue,
180            const sp<MessageQueue>& messageQueue,
181            jobject receiverObject, jfloatArray scratch) {
182        JNIEnv* env = AndroidRuntime::getJNIEnv();
183        mSensorQueue = sensorQueue;
184        mMessageQueue = messageQueue;
185        mReceiverObject = env->NewGlobalRef(receiverObject);
186        mScratch = (jfloatArray)env->NewGlobalRef(scratch);
187    }
188    ~Receiver() {
189        JNIEnv* env = AndroidRuntime::getJNIEnv();
190        env->DeleteGlobalRef(mReceiverObject);
191        env->DeleteGlobalRef(mScratch);
192    }
193    sp<SensorEventQueue> getSensorEventQueue() const {
194        return mSensorQueue;
195    }
196
197    void destroy() {
198        mMessageQueue->getLooper()->removeFd( mSensorQueue->getFd() );
199    }
200
201private:
202    virtual void onFirstRef() {
203        LooperCallback::onFirstRef();
204        mMessageQueue->getLooper()->addFd(mSensorQueue->getFd(), 0,
205                ALOOPER_EVENT_INPUT, this, mSensorQueue.get());
206    }
207
208    virtual int handleEvent(int fd, int events, void* data) {
209        JNIEnv* env = AndroidRuntime::getJNIEnv();
210        sp<SensorEventQueue> q = reinterpret_cast<SensorEventQueue *>(data);
211        ssize_t n;
212        ASensorEvent buffer[16];
213        while ((n = q->read(buffer, 16)) > 0) {
214            for (int i=0 ; i<n ; i++) {
215                if (buffer[i].type == SENSOR_TYPE_STEP_COUNTER) {
216                    // step-counter returns a uint64, but the java API only deals with floats
217                    float value = float(buffer[i].u64.step_counter);
218                    env->SetFloatArrayRegion(mScratch, 0, 1, &value);
219                } else {
220                    env->SetFloatArrayRegion(mScratch, 0, 16, buffer[i].data);
221                }
222
223                if (buffer[i].type == SENSOR_TYPE_META_DATA) {
224                    // This is a flush complete sensor event. Call dispatchFlushCompleteEvent
225                    // method.
226                    env->CallVoidMethod(mReceiverObject,
227                                        gBaseEventQueueClassInfo.dispatchFlushCompleteEvent,
228                                        buffer[i].meta_data.sensor);
229                } else {
230                    int8_t status;
231                    switch (buffer[i].type) {
232                    case SENSOR_TYPE_ORIENTATION:
233                    case SENSOR_TYPE_MAGNETIC_FIELD:
234                    case SENSOR_TYPE_ACCELEROMETER:
235                    case SENSOR_TYPE_GYROSCOPE:
236                        status = buffer[i].vector.status;
237                        break;
238                    case SENSOR_TYPE_HEART_RATE:
239                        status = buffer[i].heart_rate.status;
240                        break;
241                    default:
242                        status = SENSOR_STATUS_ACCURACY_HIGH;
243                        break;
244                    }
245                    env->CallVoidMethod(mReceiverObject,
246                                        gBaseEventQueueClassInfo.dispatchSensorEvent,
247                                        buffer[i].sensor,
248                                        mScratch,
249                                        status,
250                                        buffer[i].timestamp);
251                }
252                if (env->ExceptionCheck()) {
253                    mSensorQueue->sendAck(buffer, n);
254                    ALOGE("Exception dispatching input event.");
255                    return 1;
256                }
257            }
258            mSensorQueue->sendAck(buffer, n);
259        }
260        if (n<0 && n != -EAGAIN) {
261            // FIXME: error receiving events, what to do in this case?
262        }
263        return 1;
264    }
265};
266
267static jlong nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jobject eventQ, jobject msgQ, jfloatArray scratch) {
268    SensorManager& mgr(SensorManager::getInstance());
269    sp<SensorEventQueue> queue(mgr.createEventQueue());
270
271    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, msgQ);
272    if (messageQueue == NULL) {
273        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
274        return 0;
275    }
276
277    sp<Receiver> receiver = new Receiver(queue, messageQueue, eventQ, scratch);
278    receiver->incStrong((void*)nativeInitSensorEventQueue);
279    return jlong(receiver.get());
280}
281
282static jint nativeEnableSensor(JNIEnv *env, jclass clazz, jlong eventQ, jint handle, jint rate_us,
283                               jint maxBatchReportLatency, jint reservedFlags) {
284    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
285    return receiver->getSensorEventQueue()->enableSensor(handle, rate_us, maxBatchReportLatency,
286                                                         reservedFlags);
287}
288
289static jint nativeDisableSensor(JNIEnv *env, jclass clazz, jlong eventQ, jint handle) {
290    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
291    return receiver->getSensorEventQueue()->disableSensor(handle);
292}
293
294static void nativeDestroySensorEventQueue(JNIEnv *env, jclass clazz, jlong eventQ, jint handle) {
295    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
296    receiver->destroy();
297    receiver->decStrong((void*)nativeInitSensorEventQueue);
298}
299
300static jint nativeFlushSensor(JNIEnv *env, jclass clazz, jlong eventQ) {
301    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
302    return receiver->getSensorEventQueue()->flush();
303}
304
305//----------------------------------------------------------------------------
306
307static JNINativeMethod gSystemSensorManagerMethods[] = {
308    {"nativeClassInit",
309            "()V",
310            (void*)nativeClassInit },
311
312    {"nativeGetNextSensor",
313            "(Landroid/hardware/Sensor;I)I",
314            (void*)nativeGetNextSensor },
315};
316
317static JNINativeMethod gBaseEventQueueMethods[] = {
318    {"nativeInitBaseEventQueue",
319            "(Landroid/hardware/SystemSensorManager$BaseEventQueue;Landroid/os/MessageQueue;[F)J",
320            (void*)nativeInitSensorEventQueue },
321
322    {"nativeEnableSensor",
323            "(JIIII)I",
324            (void*)nativeEnableSensor },
325
326    {"nativeDisableSensor",
327            "(JI)I",
328            (void*)nativeDisableSensor },
329
330    {"nativeDestroySensorEventQueue",
331            "(J)V",
332            (void*)nativeDestroySensorEventQueue },
333
334    {"nativeFlushSensor",
335            "(J)I",
336            (void*)nativeFlushSensor },
337};
338
339}; // namespace android
340
341using namespace android;
342
343int register_android_hardware_SensorManager(JNIEnv *env)
344{
345    RegisterMethodsOrDie(env, "android/hardware/SystemSensorManager",
346            gSystemSensorManagerMethods, NELEM(gSystemSensorManagerMethods));
347
348    RegisterMethodsOrDie(env, "android/hardware/SystemSensorManager$BaseEventQueue",
349            gBaseEventQueueMethods, NELEM(gBaseEventQueueMethods));
350
351    gBaseEventQueueClassInfo.clazz = FindClassOrDie(env,
352            "android/hardware/SystemSensorManager$BaseEventQueue");
353
354    gBaseEventQueueClassInfo.dispatchSensorEvent = GetMethodIDOrDie(env,
355            gBaseEventQueueClassInfo.clazz, "dispatchSensorEvent", "(I[FIJ)V");
356
357    gBaseEventQueueClassInfo.dispatchFlushCompleteEvent = GetMethodIDOrDie(env,
358            gBaseEventQueueClassInfo.clazz, "dispatchFlushCompleteEvent", "(I)V");
359
360    return 0;
361}
362