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