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