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
38 static struct {
39 jclass clazz;
40 jmethodID dispatchSensorEvent;
41 jmethodID dispatchFlushCompleteEvent;
42 } gBaseEventQueueClassInfo;
43
44 namespace android {
45
46 struct 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
70 static void
nativeClassInit(JNIEnv * _env,jclass _this)71 nativeClassInit (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 */
99 class InternedStringCompare {
100 public:
operator ()(const String8 * string1,const String8 * string2) const101 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 */
118 static jstring
getInternedString(JNIEnv * env,const String8 * string)119 getInternedString(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 return internedString;
134 }
135
136 static jlong
nativeCreate(JNIEnv * env,jclass clazz,jstring opPackageName)137 nativeCreate
138 (JNIEnv *env, jclass clazz, jstring opPackageName)
139 {
140 ScopedUtfChars opPackageNameUtf(env, opPackageName);
141 return (jlong) new SensorManager(String16(opPackageNameUtf.c_str()));
142 }
143
144 static jboolean
nativeGetSensorAtIndex(JNIEnv * env,jclass clazz,jlong sensorManager,jobject sensor,jint index)145 nativeGetSensorAtIndex(JNIEnv *env, jclass clazz, jlong sensorManager, jobject sensor, jint index)
146 {
147 SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
148
149 Sensor const* const* sensorList;
150 size_t count = mgr->getSensorList(&sensorList);
151 if (size_t(index) >= count) {
152 return false;
153 }
154
155 Sensor const* const list = sensorList[index];
156 const SensorOffsets& sensorOffsets(gSensorOffsets);
157 jstring name = getInternedString(env, &list->getName());
158 jstring vendor = getInternedString(env, &list->getVendor());
159 jstring requiredPermission = getInternedString(env, &list->getRequiredPermission());
160 env->SetObjectField(sensor, sensorOffsets.name, name);
161 env->SetObjectField(sensor, sensorOffsets.vendor, vendor);
162 env->SetIntField(sensor, sensorOffsets.version, list->getVersion());
163 env->SetIntField(sensor, sensorOffsets.handle, list->getHandle());
164 env->SetFloatField(sensor, sensorOffsets.range, list->getMaxValue());
165 env->SetFloatField(sensor, sensorOffsets.resolution, list->getResolution());
166 env->SetFloatField(sensor, sensorOffsets.power, list->getPowerUsage());
167 env->SetIntField(sensor, sensorOffsets.minDelay, list->getMinDelay());
168 env->SetIntField(sensor, sensorOffsets.fifoReservedEventCount,
169 list->getFifoReservedEventCount());
170 env->SetIntField(sensor, sensorOffsets.fifoMaxEventCount,
171 list->getFifoMaxEventCount());
172 env->SetObjectField(sensor, sensorOffsets.requiredPermission,
173 requiredPermission);
174 env->SetIntField(sensor, sensorOffsets.maxDelay, list->getMaxDelay());
175 env->SetIntField(sensor, sensorOffsets.flags, list->getFlags());
176 if (env->CallBooleanMethod(sensor, sensorOffsets.setType, list->getType()) == JNI_FALSE) {
177 jstring stringType = getInternedString(env, &list->getStringType());
178 env->SetObjectField(sensor, sensorOffsets.stringType, stringType);
179 }
180 return true;
181 }
182
nativeIsDataInjectionEnabled(JNIEnv * _env,jclass _this,jlong sensorManager)183 static jboolean nativeIsDataInjectionEnabled(JNIEnv *_env, jclass _this, jlong sensorManager) {
184 SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
185 return mgr->isDataInjectionEnabled();
186 }
187
188 //----------------------------------------------------------------------------
189
190 class Receiver : public LooperCallback {
191 sp<SensorEventQueue> mSensorQueue;
192 sp<MessageQueue> mMessageQueue;
193 jobject mReceiverWeakGlobal;
194 jfloatArray mScratch;
195 public:
Receiver(const sp<SensorEventQueue> & sensorQueue,const sp<MessageQueue> & messageQueue,jobject receiverWeak,jfloatArray scratch)196 Receiver(const sp<SensorEventQueue>& sensorQueue,
197 const sp<MessageQueue>& messageQueue,
198 jobject receiverWeak, jfloatArray scratch) {
199 JNIEnv* env = AndroidRuntime::getJNIEnv();
200 mSensorQueue = sensorQueue;
201 mMessageQueue = messageQueue;
202 mReceiverWeakGlobal = env->NewGlobalRef(receiverWeak);
203 mScratch = (jfloatArray)env->NewGlobalRef(scratch);
204 }
~Receiver()205 ~Receiver() {
206 JNIEnv* env = AndroidRuntime::getJNIEnv();
207 env->DeleteGlobalRef(mReceiverWeakGlobal);
208 env->DeleteGlobalRef(mScratch);
209 }
getSensorEventQueue() const210 sp<SensorEventQueue> getSensorEventQueue() const {
211 return mSensorQueue;
212 }
213
destroy()214 void destroy() {
215 mMessageQueue->getLooper()->removeFd( mSensorQueue->getFd() );
216 }
217
218 private:
onFirstRef()219 virtual void onFirstRef() {
220 LooperCallback::onFirstRef();
221 mMessageQueue->getLooper()->addFd(mSensorQueue->getFd(), 0,
222 ALOOPER_EVENT_INPUT, this, mSensorQueue.get());
223 }
224
handleEvent(int fd,int events,void * data)225 virtual int handleEvent(int fd, int events, void* data) {
226 JNIEnv* env = AndroidRuntime::getJNIEnv();
227 sp<SensorEventQueue> q = reinterpret_cast<SensorEventQueue *>(data);
228 ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
229
230 ssize_t n;
231 ASensorEvent buffer[16];
232 while ((n = q->read(buffer, 16)) > 0) {
233 for (int i=0 ; i<n ; i++) {
234 if (buffer[i].type == SENSOR_TYPE_STEP_COUNTER) {
235 // step-counter returns a uint64, but the java API only deals with floats
236 float value = float(buffer[i].u64.step_counter);
237 env->SetFloatArrayRegion(mScratch, 0, 1, &value);
238 } else {
239 env->SetFloatArrayRegion(mScratch, 0, 16, buffer[i].data);
240 }
241
242 if (buffer[i].type == SENSOR_TYPE_META_DATA) {
243 // This is a flush complete sensor event. Call dispatchFlushCompleteEvent
244 // method.
245 if (receiverObj.get()) {
246 env->CallVoidMethod(receiverObj.get(),
247 gBaseEventQueueClassInfo.dispatchFlushCompleteEvent,
248 buffer[i].meta_data.sensor);
249 }
250 } else {
251 int8_t status;
252 switch (buffer[i].type) {
253 case SENSOR_TYPE_ORIENTATION:
254 case SENSOR_TYPE_MAGNETIC_FIELD:
255 case SENSOR_TYPE_ACCELEROMETER:
256 case SENSOR_TYPE_GYROSCOPE:
257 case SENSOR_TYPE_GRAVITY:
258 case SENSOR_TYPE_LINEAR_ACCELERATION:
259 status = buffer[i].vector.status;
260 break;
261 case SENSOR_TYPE_HEART_RATE:
262 status = buffer[i].heart_rate.status;
263 break;
264 default:
265 status = SENSOR_STATUS_ACCURACY_HIGH;
266 break;
267 }
268 if (receiverObj.get()) {
269 env->CallVoidMethod(receiverObj.get(),
270 gBaseEventQueueClassInfo.dispatchSensorEvent,
271 buffer[i].sensor,
272 mScratch,
273 status,
274 buffer[i].timestamp);
275 }
276 }
277 if (env->ExceptionCheck()) {
278 mSensorQueue->sendAck(buffer, n);
279 ALOGE("Exception dispatching input event.");
280 return 1;
281 }
282 }
283 mSensorQueue->sendAck(buffer, n);
284 }
285 if (n<0 && n != -EAGAIN) {
286 // FIXME: error receiving events, what to do in this case?
287 }
288 return 1;
289 }
290 };
291
nativeInitSensorEventQueue(JNIEnv * env,jclass clazz,jlong sensorManager,jobject eventQWeak,jobject msgQ,jfloatArray scratch,jstring packageName,jint mode)292 static jlong nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jlong sensorManager,
293 jobject eventQWeak, jobject msgQ, jfloatArray scratch, jstring packageName, jint mode) {
294 SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
295 ScopedUtfChars packageUtf(env, packageName);
296 String8 clientName(packageUtf.c_str());
297 sp<SensorEventQueue> queue(mgr->createEventQueue(clientName, mode));
298
299 sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, msgQ);
300 if (messageQueue == NULL) {
301 jniThrowRuntimeException(env, "MessageQueue is not initialized.");
302 return 0;
303 }
304
305 sp<Receiver> receiver = new Receiver(queue, messageQueue, eventQWeak, scratch);
306 receiver->incStrong((void*)nativeInitSensorEventQueue);
307 return jlong(receiver.get());
308 }
309
nativeEnableSensor(JNIEnv * env,jclass clazz,jlong eventQ,jint handle,jint rate_us,jint maxBatchReportLatency)310 static jint nativeEnableSensor(JNIEnv *env, jclass clazz, jlong eventQ, jint handle, jint rate_us,
311 jint maxBatchReportLatency) {
312 sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
313 return receiver->getSensorEventQueue()->enableSensor(handle, rate_us, maxBatchReportLatency,
314 0);
315 }
316
nativeDisableSensor(JNIEnv * env,jclass clazz,jlong eventQ,jint handle)317 static jint nativeDisableSensor(JNIEnv *env, jclass clazz, jlong eventQ, jint handle) {
318 sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
319 return receiver->getSensorEventQueue()->disableSensor(handle);
320 }
321
nativeDestroySensorEventQueue(JNIEnv * env,jclass clazz,jlong eventQ)322 static void nativeDestroySensorEventQueue(JNIEnv *env, jclass clazz, jlong eventQ) {
323 sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
324 receiver->destroy();
325 receiver->decStrong((void*)nativeInitSensorEventQueue);
326 }
327
nativeFlushSensor(JNIEnv * env,jclass clazz,jlong eventQ)328 static jint nativeFlushSensor(JNIEnv *env, jclass clazz, jlong eventQ) {
329 sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
330 return receiver->getSensorEventQueue()->flush();
331 }
332
nativeInjectSensorData(JNIEnv * env,jclass clazz,jlong eventQ,jint handle,jfloatArray values,jint accuracy,jlong timestamp)333 static jint nativeInjectSensorData(JNIEnv *env, jclass clazz, jlong eventQ, jint handle,
334 jfloatArray values, jint accuracy, jlong timestamp) {
335 sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
336 // Create a sensor_event from the above data which can be injected into the HAL.
337 ASensorEvent sensor_event;
338 memset(&sensor_event, 0, sizeof(sensor_event));
339 sensor_event.sensor = handle;
340 sensor_event.timestamp = timestamp;
341 env->GetFloatArrayRegion(values, 0, env->GetArrayLength(values), sensor_event.data);
342 return receiver->getSensorEventQueue()->injectSensorEvent(sensor_event);
343 }
344 //----------------------------------------------------------------------------
345
346 static JNINativeMethod gSystemSensorManagerMethods[] = {
347 {"nativeClassInit",
348 "()V",
349 (void*)nativeClassInit },
350 {"nativeCreate",
351 "(Ljava/lang/String;)J",
352 (void*)nativeCreate },
353
354 {"nativeGetSensorAtIndex",
355 "(JLandroid/hardware/Sensor;I)Z",
356 (void*)nativeGetSensorAtIndex },
357
358 {"nativeIsDataInjectionEnabled",
359 "(J)Z",
360 (void*)nativeIsDataInjectionEnabled},
361 };
362
363 static JNINativeMethod gBaseEventQueueMethods[] = {
364 {"nativeInitBaseEventQueue",
365 "(JLjava/lang/ref/WeakReference;Landroid/os/MessageQueue;[FLjava/lang/String;ILjava/lang/String;)J",
366 (void*)nativeInitSensorEventQueue },
367
368 {"nativeEnableSensor",
369 "(JIII)I",
370 (void*)nativeEnableSensor },
371
372 {"nativeDisableSensor",
373 "(JI)I",
374 (void*)nativeDisableSensor },
375
376 {"nativeDestroySensorEventQueue",
377 "(J)V",
378 (void*)nativeDestroySensorEventQueue },
379
380 {"nativeFlushSensor",
381 "(J)I",
382 (void*)nativeFlushSensor },
383
384 {"nativeInjectSensorData",
385 "(JI[FIJ)I",
386 (void*)nativeInjectSensorData },
387 };
388
389 }; // namespace android
390
391 using namespace android;
392
register_android_hardware_SensorManager(JNIEnv * env)393 int register_android_hardware_SensorManager(JNIEnv *env)
394 {
395 RegisterMethodsOrDie(env, "android/hardware/SystemSensorManager",
396 gSystemSensorManagerMethods, NELEM(gSystemSensorManagerMethods));
397
398 RegisterMethodsOrDie(env, "android/hardware/SystemSensorManager$BaseEventQueue",
399 gBaseEventQueueMethods, NELEM(gBaseEventQueueMethods));
400
401 gBaseEventQueueClassInfo.clazz = FindClassOrDie(env,
402 "android/hardware/SystemSensorManager$BaseEventQueue");
403
404 gBaseEventQueueClassInfo.dispatchSensorEvent = GetMethodIDOrDie(env,
405 gBaseEventQueueClassInfo.clazz, "dispatchSensorEvent", "(I[FIJ)V");
406
407 gBaseEventQueueClassInfo.dispatchFlushCompleteEvent = GetMethodIDOrDie(env,
408 gBaseEventQueueClassInfo.clazz, "dispatchFlushCompleteEvent", "(I)V");
409
410 return 0;
411 }
412