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