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