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 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: 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 */ 138 static jstring 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 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 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 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 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 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: 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 280 private: 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 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 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 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 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 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 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 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