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