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