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