android_hardware_SensorManager.cpp revision a29583553957a19755bfba26f48b6ebe977879cb
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#include <ScopedLocalRef.h>
23
24#include <utils/Log.h>
25#include <utils/Looper.h>
26#include <utils/Vector.h>
27
28#include <gui/Sensor.h>
29#include <gui/SensorManager.h>
30#include <gui/SensorEventQueue.h>
31
32#include "jni.h"
33#include "JNIHelp.h"
34#include "android_os_MessageQueue.h"
35#include <android_runtime/AndroidRuntime.h>
36
37#include "core_jni_helpers.h"
38
39static struct {
40    jclass clazz;
41    jmethodID dispatchSensorEvent;
42    jmethodID dispatchFlushCompleteEvent;
43    jmethodID dispatchAdditionalInfoEvent;
44} gBaseEventQueueClassInfo;
45
46namespace android {
47
48struct SensorOffsets
49{
50    jclass      clazz;
51    jfieldID    name;
52    jfieldID    vendor;
53    jfieldID    version;
54    jfieldID    handle;
55    jfieldID    range;
56    jfieldID    resolution;
57    jfieldID    power;
58    jfieldID    minDelay;
59    jfieldID    fifoReservedEventCount;
60    jfieldID    fifoMaxEventCount;
61    jfieldID    stringType;
62    jfieldID    requiredPermission;
63    jfieldID    maxDelay;
64    jfieldID    flags;
65    jmethodID   setType;
66    jmethodID   init;
67} gSensorOffsets;
68
69struct ListOffsets {
70    jclass      clazz;
71    jmethodID   add;
72} gListOffsets;
73
74/*
75 * The method below are not thread-safe and not intended to be
76 */
77
78static void
79nativeClassInit (JNIEnv *_env, jclass _this)
80{
81    //android.hardware.Sensor
82    SensorOffsets& sensorOffsets = gSensorOffsets;
83    jclass sensorClass = (jclass) _env->NewGlobalRef(_env->FindClass("android/hardware/Sensor"));
84    sensorOffsets.clazz       = sensorClass;
85    sensorOffsets.name        = _env->GetFieldID(sensorClass, "mName",      "Ljava/lang/String;");
86    sensorOffsets.vendor      = _env->GetFieldID(sensorClass, "mVendor",    "Ljava/lang/String;");
87    sensorOffsets.version     = _env->GetFieldID(sensorClass, "mVersion",   "I");
88    sensorOffsets.handle      = _env->GetFieldID(sensorClass, "mHandle",    "I");
89    sensorOffsets.range       = _env->GetFieldID(sensorClass, "mMaxRange",  "F");
90    sensorOffsets.resolution  = _env->GetFieldID(sensorClass, "mResolution","F");
91    sensorOffsets.power       = _env->GetFieldID(sensorClass, "mPower",     "F");
92    sensorOffsets.minDelay    = _env->GetFieldID(sensorClass, "mMinDelay",  "I");
93    sensorOffsets.fifoReservedEventCount =
94            _env->GetFieldID(sensorClass, "mFifoReservedEventCount",  "I");
95    sensorOffsets.fifoMaxEventCount = _env->GetFieldID(sensorClass, "mFifoMaxEventCount",  "I");
96    sensorOffsets.stringType = _env->GetFieldID(sensorClass, "mStringType", "Ljava/lang/String;");
97    sensorOffsets.requiredPermission = _env->GetFieldID(sensorClass, "mRequiredPermission",
98                                                        "Ljava/lang/String;");
99    sensorOffsets.maxDelay    = _env->GetFieldID(sensorClass, "mMaxDelay",  "I");
100    sensorOffsets.flags = _env->GetFieldID(sensorClass, "mFlags",  "I");
101
102    sensorOffsets.setType = _env->GetMethodID(sensorClass, "setType", "(I)Z");
103    sensorOffsets.init = _env->GetMethodID(sensorClass, "<init>", "()V");
104
105    // java.util.List;
106    ListOffsets& listOffsets = gListOffsets;
107    jclass listClass = (jclass) _env->NewGlobalRef(_env->FindClass("java/util/List"));
108    listOffsets.clazz = listClass;
109    listOffsets.add = _env->GetMethodID(listClass, "add", "(Ljava/lang/Object;)Z");
110}
111
112/**
113 * A key comparator predicate.
114 * It is used to intern strings associated with Sensor data.
115 * It defines a 'Strict weak ordering' for the interned strings.
116 */
117class InternedStringCompare {
118public:
119    bool operator()(const String8* string1, const String8* string2) const {
120        if (string1 == NULL) {
121            return string2 != NULL;
122        }
123        if (string2 == NULL) {
124            return false;
125        }
126        return string1->compare(*string2) < 0;
127    }
128};
129
130/**
131 * A localized interning mechanism for Sensor strings.
132 * We implement our own interning to avoid the overhead of using java.lang.String#intern().
133 * It is common that Vendor, StringType, and RequirePermission data is common between many of the
134 * Sensors, by interning the memory usage to represent Sensors is optimized.
135 */
136static jstring
137getInternedString(JNIEnv *env, const String8* string) {
138    static std::map<const String8*, jstring, InternedStringCompare> internedStrings;
139
140    jstring internedString;
141    std::map<const String8*, jstring>::iterator iterator = internedStrings.find(string);
142    if (iterator != internedStrings.end()) {
143        internedString = iterator->second;
144    } else {
145        jstring localString = env->NewStringUTF(string->string());
146        // we are implementing our own interning so expect these strings to be backed by global refs
147        internedString = (jstring) env->NewGlobalRef(localString);
148        internedStrings.insert(std::make_pair(string, internedString));
149        env->DeleteLocalRef(localString);
150    }
151    return internedString;
152}
153
154static jlong
155nativeCreate
156(JNIEnv *env, jclass clazz, jstring opPackageName)
157{
158    ScopedUtfChars opPackageNameUtf(env, opPackageName);
159    return (jlong) &SensorManager::getInstanceForPackage(String16(opPackageNameUtf.c_str()));
160}
161
162static jobject
163translateNativeSensorToJavaSensor(JNIEnv *env, jobject sensor, const Sensor& nativeSensor) {
164    const SensorOffsets& sensorOffsets(gSensorOffsets);
165
166    if (sensor == NULL) {
167        // Sensor sensor = new Sensor();
168        sensor = env->NewObject(sensorOffsets.clazz, sensorOffsets.init, "");
169    }
170
171    if (sensor != NULL) {
172        jstring name = env->NewStringUTF(nativeSensor.getName().string());
173        jstring vendor = env->NewStringUTF(nativeSensor.getVendor().string());
174        jstring requiredPermission =
175                env->NewStringUTF(nativeSensor.getRequiredPermission().string());
176
177        env->SetObjectField(sensor, sensorOffsets.name,      name);
178        env->SetObjectField(sensor, sensorOffsets.vendor,    vendor);
179        env->SetIntField(sensor, sensorOffsets.version,      nativeSensor.getVersion());
180        env->SetIntField(sensor, sensorOffsets.handle,       nativeSensor.getHandle());
181        env->SetFloatField(sensor, sensorOffsets.range,      nativeSensor.getMaxValue());
182        env->SetFloatField(sensor, sensorOffsets.resolution, nativeSensor.getResolution());
183        env->SetFloatField(sensor, sensorOffsets.power,      nativeSensor.getPowerUsage());
184        env->SetIntField(sensor, sensorOffsets.minDelay,     nativeSensor.getMinDelay());
185        env->SetIntField(sensor, sensorOffsets.fifoReservedEventCount,
186                         nativeSensor.getFifoReservedEventCount());
187        env->SetIntField(sensor, sensorOffsets.fifoMaxEventCount,
188                         nativeSensor.getFifoMaxEventCount());
189        env->SetObjectField(sensor, sensorOffsets.requiredPermission,
190                            requiredPermission);
191        env->SetIntField(sensor, sensorOffsets.maxDelay, nativeSensor.getMaxDelay());
192        env->SetIntField(sensor, sensorOffsets.flags, nativeSensor.getFlags());
193        if (env->CallBooleanMethod(sensor, sensorOffsets.setType, nativeSensor.getType())
194                == JNI_FALSE) {
195            jstring stringType = getInternedString(env, &nativeSensor.getStringType());
196            env->SetObjectField(sensor, sensorOffsets.stringType, stringType);
197        }
198    }
199    return sensor;
200}
201
202static jboolean
203nativeGetSensorAtIndex(JNIEnv *env, jclass clazz, jlong sensorManager, jobject sensor, jint index)
204{
205    SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
206
207    Sensor const* const* sensorList;
208    size_t count = mgr->getSensorList(&sensorList);
209    if (size_t(index) >= count) {
210        return false;
211    }
212
213    Sensor const* const list = sensorList[index];
214    const SensorOffsets& sensorOffsets(gSensorOffsets);
215    jstring name = getInternedString(env, &list->getName());
216    jstring vendor = getInternedString(env, &list->getVendor());
217    jstring requiredPermission = getInternedString(env, &list->getRequiredPermission());
218    env->SetObjectField(sensor, sensorOffsets.name,      name);
219    env->SetObjectField(sensor, sensorOffsets.vendor,    vendor);
220    env->SetIntField(sensor, sensorOffsets.version,      list->getVersion());
221    env->SetIntField(sensor, sensorOffsets.handle,       list->getHandle());
222    env->SetFloatField(sensor, sensorOffsets.range,      list->getMaxValue());
223    env->SetFloatField(sensor, sensorOffsets.resolution, list->getResolution());
224    env->SetFloatField(sensor, sensorOffsets.power,      list->getPowerUsage());
225    env->SetIntField(sensor, sensorOffsets.minDelay,     list->getMinDelay());
226    env->SetIntField(sensor, sensorOffsets.fifoReservedEventCount,
227                     list->getFifoReservedEventCount());
228    env->SetIntField(sensor, sensorOffsets.fifoMaxEventCount,
229                     list->getFifoMaxEventCount());
230    env->SetObjectField(sensor, sensorOffsets.requiredPermission,
231                        requiredPermission);
232    env->SetIntField(sensor, sensorOffsets.maxDelay, list->getMaxDelay());
233    env->SetIntField(sensor, sensorOffsets.flags, list->getFlags());
234    if (env->CallBooleanMethod(sensor, sensorOffsets.setType, list->getType()) == JNI_FALSE) {
235        jstring stringType = getInternedString(env, &list->getStringType());
236        env->SetObjectField(sensor, sensorOffsets.stringType, stringType);
237    }
238    return true;
239}
240
241static void
242nativeGetDynamicSensors(JNIEnv *env, jclass clazz, jlong sensorManager, jobject sensorList) {
243
244    SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
245    const ListOffsets& listOffsets(gListOffsets);
246
247    Vector<Sensor> nativeList;
248
249    mgr->getDynamicSensorList(nativeList);
250
251    ALOGI("DYNS native SensorManager.getDynamicSensorList return %d sensors", nativeList.size());
252    for (size_t i = 0; i < nativeList.size(); ++i) {
253        jobject sensor = translateNativeSensorToJavaSensor(env, NULL, nativeList[i]);
254        // add to list
255        env->CallBooleanMethod(sensorList, listOffsets.add, sensor);
256    }
257}
258
259static jboolean nativeIsDataInjectionEnabled(JNIEnv *_env, jclass _this, jlong sensorManager) {
260    SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
261    return mgr->isDataInjectionEnabled();
262}
263
264//----------------------------------------------------------------------------
265
266class Receiver : public LooperCallback {
267    sp<SensorEventQueue> mSensorQueue;
268    sp<MessageQueue> mMessageQueue;
269    jobject mReceiverWeakGlobal;
270    jfloatArray mFloatScratch;
271    jintArray   mIntScratch;
272public:
273    Receiver(const sp<SensorEventQueue>& sensorQueue,
274            const sp<MessageQueue>& messageQueue,
275            jobject receiverWeak) {
276        JNIEnv* env = AndroidRuntime::getJNIEnv();
277        mSensorQueue = sensorQueue;
278        mMessageQueue = messageQueue;
279        mReceiverWeakGlobal = env->NewGlobalRef(receiverWeak);
280
281        mIntScratch = (jintArray) env->NewGlobalRef(env->NewIntArray(16));
282        mFloatScratch = (jfloatArray) env->NewGlobalRef(env->NewFloatArray(16));
283    }
284    ~Receiver() {
285        JNIEnv* env = AndroidRuntime::getJNIEnv();
286        env->DeleteGlobalRef(mReceiverWeakGlobal);
287        env->DeleteGlobalRef(mFloatScratch);
288        env->DeleteGlobalRef(mIntScratch);
289    }
290    sp<SensorEventQueue> getSensorEventQueue() const {
291        return mSensorQueue;
292    }
293
294    void destroy() {
295        mMessageQueue->getLooper()->removeFd( mSensorQueue->getFd() );
296    }
297
298private:
299    virtual void onFirstRef() {
300        LooperCallback::onFirstRef();
301        mMessageQueue->getLooper()->addFd(mSensorQueue->getFd(), 0,
302                ALOOPER_EVENT_INPUT, this, mSensorQueue.get());
303    }
304
305    virtual int handleEvent(int fd, int events, void* data) {
306        JNIEnv* env = AndroidRuntime::getJNIEnv();
307        sp<SensorEventQueue> q = reinterpret_cast<SensorEventQueue *>(data);
308        ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
309
310        ssize_t n;
311        ASensorEvent buffer[16];
312        while ((n = q->read(buffer, 16)) > 0) {
313            for (int i=0 ; i<n ; i++) {
314                if (buffer[i].type == SENSOR_TYPE_STEP_COUNTER) {
315                    // step-counter returns a uint64, but the java API only deals with floats
316                    float value = float(buffer[i].u64.step_counter);
317                    env->SetFloatArrayRegion(mFloatScratch, 0, 1, &value);
318                } else if (buffer[i].type == SENSOR_TYPE_DYNAMIC_SENSOR_META) {
319                    float value[2];
320                    value[0] = buffer[i].dynamic_sensor_meta.connected ? 1.f: 0.f;
321                    value[1] = float(buffer[i].dynamic_sensor_meta.handle);
322                    env->SetFloatArrayRegion(mFloatScratch, 0, 2, value);
323                } else if (buffer[i].type == SENSOR_TYPE_ADDITIONAL_INFO) {
324                    env->SetIntArrayRegion(mIntScratch, 0, 14,
325                                           buffer[i].additional_info.data_int32);
326                    env->SetFloatArrayRegion(mFloatScratch, 0, 14,
327                                             buffer[i].additional_info.data_float);
328                } else {
329                    env->SetFloatArrayRegion(mFloatScratch, 0, 16, buffer[i].data);
330                }
331
332                if (buffer[i].type == SENSOR_TYPE_META_DATA) {
333                    // This is a flush complete sensor event. Call dispatchFlushCompleteEvent
334                    // method.
335                    if (receiverObj.get()) {
336                        env->CallVoidMethod(receiverObj.get(),
337                                            gBaseEventQueueClassInfo.dispatchFlushCompleteEvent,
338                                            buffer[i].meta_data.sensor);
339                    }
340                } else if (buffer[i].type == SENSOR_TYPE_ADDITIONAL_INFO) {
341                    // This is a flush complete sensor event. Call dispatchAdditionalInfoEvent
342                    // method.
343                    if (receiverObj.get()) {
344                        int type = buffer[i].additional_info.type;
345                        int serial = buffer[i].additional_info.serial;
346                        env->CallVoidMethod(receiverObj.get(),
347                                            gBaseEventQueueClassInfo.dispatchAdditionalInfoEvent,
348                                            buffer[i].sensor,
349                                            type, serial,
350                                            mFloatScratch,
351                                            mIntScratch,
352                                            buffer[i].timestamp);
353                    }
354                }else {
355                    int8_t status;
356                    switch (buffer[i].type) {
357                    case SENSOR_TYPE_ORIENTATION:
358                    case SENSOR_TYPE_MAGNETIC_FIELD:
359                    case SENSOR_TYPE_ACCELEROMETER:
360                    case SENSOR_TYPE_GYROSCOPE:
361                    case SENSOR_TYPE_GRAVITY:
362                    case SENSOR_TYPE_LINEAR_ACCELERATION:
363                        status = buffer[i].vector.status;
364                        break;
365                    case SENSOR_TYPE_HEART_RATE:
366                        status = buffer[i].heart_rate.status;
367                        break;
368                    default:
369                        status = SENSOR_STATUS_ACCURACY_HIGH;
370                        break;
371                    }
372                    if (receiverObj.get()) {
373                        env->CallVoidMethod(receiverObj.get(),
374                                            gBaseEventQueueClassInfo.dispatchSensorEvent,
375                                            buffer[i].sensor,
376                                            mFloatScratch,
377                                            status,
378                                            buffer[i].timestamp);
379                    }
380                }
381                if (env->ExceptionCheck()) {
382                    mSensorQueue->sendAck(buffer, n);
383                    ALOGE("Exception dispatching input event.");
384                    return 1;
385                }
386            }
387            mSensorQueue->sendAck(buffer, n);
388        }
389        if (n<0 && n != -EAGAIN) {
390            // FIXME: error receiving events, what to do in this case?
391        }
392        return 1;
393    }
394};
395
396static jlong nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jlong sensorManager,
397        jobject eventQWeak, jobject msgQ, jstring packageName, jint mode) {
398    SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
399    ScopedUtfChars packageUtf(env, packageName);
400    String8 clientName(packageUtf.c_str());
401    sp<SensorEventQueue> queue(mgr->createEventQueue(clientName, mode));
402
403    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, msgQ);
404    if (messageQueue == NULL) {
405        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
406        return 0;
407    }
408
409    sp<Receiver> receiver = new Receiver(queue, messageQueue, eventQWeak);
410    receiver->incStrong((void*)nativeInitSensorEventQueue);
411    return jlong(receiver.get());
412}
413
414static jint nativeEnableSensor(JNIEnv *env, jclass clazz, jlong eventQ, jint handle, jint rate_us,
415                               jint maxBatchReportLatency) {
416    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
417    return receiver->getSensorEventQueue()->enableSensor(handle, rate_us, maxBatchReportLatency,
418                                                         0);
419}
420
421static jint nativeDisableSensor(JNIEnv *env, jclass clazz, jlong eventQ, jint handle) {
422    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
423    return receiver->getSensorEventQueue()->disableSensor(handle);
424}
425
426static void nativeDestroySensorEventQueue(JNIEnv *env, jclass clazz, jlong eventQ) {
427    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
428    receiver->destroy();
429    receiver->decStrong((void*)nativeInitSensorEventQueue);
430}
431
432static jint nativeFlushSensor(JNIEnv *env, jclass clazz, jlong eventQ) {
433    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
434    return receiver->getSensorEventQueue()->flush();
435}
436
437static jint nativeInjectSensorData(JNIEnv *env, jclass clazz, jlong eventQ, jint handle,
438        jfloatArray values, jint accuracy, jlong timestamp) {
439    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
440    // Create a sensor_event from the above data which can be injected into the HAL.
441    ASensorEvent sensor_event;
442    memset(&sensor_event, 0, sizeof(sensor_event));
443    sensor_event.sensor = handle;
444    sensor_event.timestamp = timestamp;
445    env->GetFloatArrayRegion(values, 0, env->GetArrayLength(values), sensor_event.data);
446    return receiver->getSensorEventQueue()->injectSensorEvent(sensor_event);
447}
448//----------------------------------------------------------------------------
449
450static const JNINativeMethod gSystemSensorManagerMethods[] = {
451    {"nativeClassInit",
452            "()V",
453            (void*)nativeClassInit },
454    {"nativeCreate",
455             "(Ljava/lang/String;)J",
456             (void*)nativeCreate },
457
458    {"nativeGetSensorAtIndex",
459            "(JLandroid/hardware/Sensor;I)Z",
460            (void*)nativeGetSensorAtIndex },
461
462    {"nativeGetDynamicSensors",
463            "(JLjava/util/List;)V",
464            (void*)nativeGetDynamicSensors },
465
466    {"nativeIsDataInjectionEnabled",
467            "(J)Z",
468            (void*)nativeIsDataInjectionEnabled},
469};
470
471static const JNINativeMethod gBaseEventQueueMethods[] = {
472    {"nativeInitBaseEventQueue",
473             "(JLjava/lang/ref/WeakReference;Landroid/os/MessageQueue;Ljava/lang/String;ILjava/lang/String;)J",
474             (void*)nativeInitSensorEventQueue },
475
476    {"nativeEnableSensor",
477            "(JIII)I",
478            (void*)nativeEnableSensor },
479
480    {"nativeDisableSensor",
481            "(JI)I",
482            (void*)nativeDisableSensor },
483
484    {"nativeDestroySensorEventQueue",
485            "(J)V",
486            (void*)nativeDestroySensorEventQueue },
487
488    {"nativeFlushSensor",
489            "(J)I",
490            (void*)nativeFlushSensor },
491
492    {"nativeInjectSensorData",
493            "(JI[FIJ)I",
494            (void*)nativeInjectSensorData },
495};
496
497}; // namespace android
498
499using namespace android;
500
501int register_android_hardware_SensorManager(JNIEnv *env)
502{
503    RegisterMethodsOrDie(env, "android/hardware/SystemSensorManager",
504            gSystemSensorManagerMethods, NELEM(gSystemSensorManagerMethods));
505
506    RegisterMethodsOrDie(env, "android/hardware/SystemSensorManager$BaseEventQueue",
507            gBaseEventQueueMethods, NELEM(gBaseEventQueueMethods));
508
509    gBaseEventQueueClassInfo.clazz = FindClassOrDie(env,
510            "android/hardware/SystemSensorManager$BaseEventQueue");
511
512    gBaseEventQueueClassInfo.dispatchSensorEvent = GetMethodIDOrDie(env,
513            gBaseEventQueueClassInfo.clazz, "dispatchSensorEvent", "(I[FIJ)V");
514
515    gBaseEventQueueClassInfo.dispatchFlushCompleteEvent = GetMethodIDOrDie(env,
516            gBaseEventQueueClassInfo.clazz, "dispatchFlushCompleteEvent", "(I)V");
517
518    gBaseEventQueueClassInfo.dispatchAdditionalInfoEvent = GetMethodIDOrDie(env,
519            gBaseEventQueueClassInfo.clazz, "dispatchAdditionalInfoEvent", "(III[F[I)V");
520
521    return 0;
522}
523