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 
35 namespace {
36 
37 using namespace android;
38 
39 struct {
40     jclass clazz;
41     jmethodID dispatchSensorEvent;
42     jmethodID dispatchFlushCompleteEvent;
43     jmethodID dispatchAdditionalInfoEvent;
44 } gBaseEventQueueClassInfo;
45 
46 struct 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 
70 struct 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  */
79 static void
nativeClassInit(JNIEnv * _env,jclass _this)80 nativeClassInit (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  */
119 class InternedStringCompare {
120 public:
operator ()(const String8 * string1,const String8 * string2) const121     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  */
138 static jstring
getInternedString(JNIEnv * env,const String8 * string)139 getInternedString(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 
156 static jlong
nativeCreate(JNIEnv * env,jclass clazz,jstring opPackageName)157 nativeCreate
158 (JNIEnv *env, jclass clazz, jstring opPackageName)
159 {
160     ScopedUtfChars opPackageNameUtf(env, opPackageName);
161     return (jlong) &SensorManager::getInstanceForPackage(String16(opPackageNameUtf.c_str()));
162 }
163 
164 static jobject
translateNativeSensorToJavaSensor(JNIEnv * env,jobject sensor,const Sensor & nativeSensor)165 translateNativeSensorToJavaSensor(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 
209 static jboolean
nativeGetSensorAtIndex(JNIEnv * env,jclass clazz,jlong sensorManager,jobject sensor,jint index)210 nativeGetSensorAtIndex(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 
223 static void
nativeGetDynamicSensors(JNIEnv * env,jclass clazz,jlong sensorManager,jobject sensorList)224 nativeGetDynamicSensors(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 %d 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 
nativeIsDataInjectionEnabled(JNIEnv * _env,jclass _this,jlong sensorManager)241 static jboolean nativeIsDataInjectionEnabled(JNIEnv *_env, jclass _this, jlong sensorManager) {
242     SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
243     return mgr->isDataInjectionEnabled();
244 }
245 
246 //----------------------------------------------------------------------------
247 
248 class Receiver : public LooperCallback {
249     sp<SensorEventQueue> mSensorQueue;
250     sp<MessageQueue> mMessageQueue;
251     jobject mReceiverWeakGlobal;
252     jfloatArray mFloatScratch;
253     jintArray   mIntScratch;
254 public:
Receiver(const sp<SensorEventQueue> & sensorQueue,const sp<MessageQueue> & messageQueue,jobject receiverWeak)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     }
~Receiver()266     ~Receiver() {
267         JNIEnv* env = AndroidRuntime::getJNIEnv();
268         env->DeleteGlobalRef(mReceiverWeakGlobal);
269         env->DeleteGlobalRef(mFloatScratch);
270         env->DeleteGlobalRef(mIntScratch);
271     }
getSensorEventQueue() const272     sp<SensorEventQueue> getSensorEventQueue() const {
273         return mSensorQueue;
274     }
275 
destroy()276     void destroy() {
277         mMessageQueue->getLooper()->removeFd( mSensorQueue->getFd() );
278     }
279 
280 private:
onFirstRef()281     virtual void onFirstRef() {
282         LooperCallback::onFirstRef();
283         mMessageQueue->getLooper()->addFd(mSensorQueue->getFd(), 0,
284                 ALOOPER_EVENT_INPUT, this, mSensorQueue.get());
285     }
286 
handleEvent(int fd,int events,void * data)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 
nativeInitSensorEventQueue(JNIEnv * env,jclass clazz,jlong sensorManager,jobject eventQWeak,jobject msgQ,jstring packageName,jint mode)378 static 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 
nativeEnableSensor(JNIEnv * env,jclass clazz,jlong eventQ,jint handle,jint rate_us,jint maxBatchReportLatency)396 static 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 
nativeDisableSensor(JNIEnv * env,jclass clazz,jlong eventQ,jint handle)403 static 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 
nativeDestroySensorEventQueue(JNIEnv * env,jclass clazz,jlong eventQ)408 static 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 
nativeFlushSensor(JNIEnv * env,jclass clazz,jlong eventQ)414 static jint nativeFlushSensor(JNIEnv *env, jclass clazz, jlong eventQ) {
415     sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
416     return receiver->getSensorEventQueue()->flush();
417 }
418 
nativeInjectSensorData(JNIEnv * env,jclass clazz,jlong eventQ,jint handle,jfloatArray values,jint accuracy,jlong timestamp)419 static 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 
432 static 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 
453 static 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 
register_android_hardware_SensorManager(JNIEnv * env)481 int 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