1     /*
2  * Copyright (C) 2012 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 package android.hardware;
18 
19 import android.Manifest;
20 import android.content.Context;
21 import android.content.pm.PackageManager;
22 import android.os.Handler;
23 import android.os.Looper;
24 import android.os.MessageQueue;
25 import android.util.Log;
26 import android.util.SparseArray;
27 import android.util.SparseBooleanArray;
28 import android.util.SparseIntArray;
29 import dalvik.system.CloseGuard;
30 
31 import java.lang.ref.WeakReference;
32 import java.util.ArrayList;
33 import java.util.HashMap;
34 import java.util.List;
35 
36 /**
37  * Sensor manager implementation that communicates with the built-in
38  * system sensors.
39  *
40  * @hide
41  */
42 public class SystemSensorManager extends SensorManager {
nativeClassInit()43     private static native void nativeClassInit();
nativeCreate(String opPackageName)44     private static native long nativeCreate(String opPackageName);
nativeGetSensorAtIndex(long nativeInstance, Sensor sensor, int index)45     private static native boolean nativeGetSensorAtIndex(long nativeInstance,
46             Sensor sensor, int index);
nativeIsDataInjectionEnabled(long nativeInstance)47     private static native boolean nativeIsDataInjectionEnabled(long nativeInstance);
48 
49     private static boolean sSensorModuleInitialized = false;
50     private static InjectEventQueue mInjectEventQueue = null;
51 
52     private final Object mLock = new Object();
53 
54     private final ArrayList<Sensor> mFullSensorsList = new ArrayList<>();
55     private final SparseArray<Sensor> mHandleToSensor = new SparseArray<>();
56 
57     // Listener list
58     private final HashMap<SensorEventListener, SensorEventQueue> mSensorListeners =
59             new HashMap<SensorEventListener, SensorEventQueue>();
60     private final HashMap<TriggerEventListener, TriggerEventQueue> mTriggerListeners =
61             new HashMap<TriggerEventListener, TriggerEventQueue>();
62 
63     // Looper associated with the context in which this instance was created.
64     private final Looper mMainLooper;
65     private final int mTargetSdkLevel;
66     private final Context mContext;
67     private final long mNativeInstance;
68 
69     /** {@hide} */
SystemSensorManager(Context context, Looper mainLooper)70     public SystemSensorManager(Context context, Looper mainLooper) {
71         mMainLooper = mainLooper;
72         mTargetSdkLevel = context.getApplicationInfo().targetSdkVersion;
73         mContext = context;
74         mNativeInstance = nativeCreate(context.getOpPackageName());
75 
76         synchronized(mLock) {
77             if (!sSensorModuleInitialized) {
78                 sSensorModuleInitialized = true;
79                 nativeClassInit();
80             }
81         }
82 
83         // initialize the sensor list
84         for (int index = 0;;++index) {
85             Sensor sensor = new Sensor();
86             if (!nativeGetSensorAtIndex(mNativeInstance, sensor, index)) break;
87             mFullSensorsList.add(sensor);
88             mHandleToSensor.append(sensor.getHandle(), sensor);
89         }
90     }
91 
92 
93     /** @hide */
94     @Override
getFullSensorList()95     protected List<Sensor> getFullSensorList() {
96         return mFullSensorsList;
97     }
98 
99 
100     /** @hide */
101     @Override
registerListenerImpl(SensorEventListener listener, Sensor sensor, int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags)102     protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
103             int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags) {
104         if (listener == null || sensor == null) {
105             Log.e(TAG, "sensor or listener is null");
106             return false;
107         }
108         // Trigger Sensors should use the requestTriggerSensor call.
109         if (sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
110             Log.e(TAG, "Trigger Sensors should use the requestTriggerSensor.");
111             return false;
112         }
113         if (maxBatchReportLatencyUs < 0 || delayUs < 0) {
114             Log.e(TAG, "maxBatchReportLatencyUs and delayUs should be non-negative");
115             return false;
116         }
117 
118         // Invariants to preserve:
119         // - one Looper per SensorEventListener
120         // - one Looper per SensorEventQueue
121         // We map SensorEventListener to a SensorEventQueue, which holds the looper
122         synchronized (mSensorListeners) {
123             SensorEventQueue queue = mSensorListeners.get(listener);
124             if (queue == null) {
125                 Looper looper = (handler != null) ? handler.getLooper() : mMainLooper;
126                 final String fullClassName = listener.getClass().getEnclosingClass() != null ?
127                     listener.getClass().getEnclosingClass().getName() :
128                     listener.getClass().getName();
129                 queue = new SensorEventQueue(listener, looper, this, fullClassName);
130                 if (!queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs)) {
131                     queue.dispose();
132                     return false;
133                 }
134                 mSensorListeners.put(listener, queue);
135                 return true;
136             } else {
137                 return queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs);
138             }
139         }
140     }
141 
142     /** @hide */
143     @Override
unregisterListenerImpl(SensorEventListener listener, Sensor sensor)144     protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) {
145         // Trigger Sensors should use the cancelTriggerSensor call.
146         if (sensor != null && sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
147             return;
148         }
149 
150         synchronized (mSensorListeners) {
151             SensorEventQueue queue = mSensorListeners.get(listener);
152             if (queue != null) {
153                 boolean result;
154                 if (sensor == null) {
155                     result = queue.removeAllSensors();
156                 } else {
157                     result = queue.removeSensor(sensor, true);
158                 }
159                 if (result && !queue.hasSensors()) {
160                     mSensorListeners.remove(listener);
161                     queue.dispose();
162                 }
163             }
164         }
165     }
166 
167     /** @hide */
168     @Override
requestTriggerSensorImpl(TriggerEventListener listener, Sensor sensor)169     protected boolean requestTriggerSensorImpl(TriggerEventListener listener, Sensor sensor) {
170         if (sensor == null) throw new IllegalArgumentException("sensor cannot be null");
171 
172         if (listener == null) throw new IllegalArgumentException("listener cannot be null");
173 
174         if (sensor.getReportingMode() != Sensor.REPORTING_MODE_ONE_SHOT) return false;
175 
176         synchronized (mTriggerListeners) {
177             TriggerEventQueue queue = mTriggerListeners.get(listener);
178             if (queue == null) {
179                 final String fullClassName = listener.getClass().getEnclosingClass() != null ?
180                     listener.getClass().getEnclosingClass().getName() :
181                     listener.getClass().getName();
182                 queue = new TriggerEventQueue(listener, mMainLooper, this, fullClassName);
183                 if (!queue.addSensor(sensor, 0, 0)) {
184                     queue.dispose();
185                     return false;
186                 }
187                 mTriggerListeners.put(listener, queue);
188                 return true;
189             } else {
190                 return queue.addSensor(sensor, 0, 0);
191             }
192         }
193     }
194 
195     /** @hide */
196     @Override
cancelTriggerSensorImpl(TriggerEventListener listener, Sensor sensor, boolean disable)197     protected boolean cancelTriggerSensorImpl(TriggerEventListener listener, Sensor sensor,
198             boolean disable) {
199         if (sensor != null && sensor.getReportingMode() != Sensor.REPORTING_MODE_ONE_SHOT) {
200             return false;
201         }
202         synchronized (mTriggerListeners) {
203             TriggerEventQueue queue = mTriggerListeners.get(listener);
204             if (queue != null) {
205                 boolean result;
206                 if (sensor == null) {
207                     result = queue.removeAllSensors();
208                 } else {
209                     result = queue.removeSensor(sensor, disable);
210                 }
211                 if (result && !queue.hasSensors()) {
212                     mTriggerListeners.remove(listener);
213                     queue.dispose();
214                 }
215                 return result;
216             }
217             return false;
218         }
219     }
220 
flushImpl(SensorEventListener listener)221     protected boolean flushImpl(SensorEventListener listener) {
222         if (listener == null) throw new IllegalArgumentException("listener cannot be null");
223 
224         synchronized (mSensorListeners) {
225             SensorEventQueue queue = mSensorListeners.get(listener);
226             if (queue == null) {
227                 return false;
228             } else {
229                 return (queue.flush() == 0);
230             }
231         }
232     }
233 
initDataInjectionImpl(boolean enable)234     protected boolean initDataInjectionImpl(boolean enable) {
235         synchronized (mLock) {
236             if (enable) {
237                 boolean isDataInjectionModeEnabled = nativeIsDataInjectionEnabled(mNativeInstance);
238                 // The HAL does not support injection OR SensorService hasn't been set in DI mode.
239                 if (!isDataInjectionModeEnabled) {
240                     Log.e(TAG, "Data Injection mode not enabled");
241                     return false;
242                 }
243                 // Initialize a client for data_injection.
244                 if (mInjectEventQueue == null) {
245                     mInjectEventQueue = new InjectEventQueue(mMainLooper, this,
246                             mContext.getPackageName());
247                 }
248             } else {
249                 // If data injection is being disabled clean up the native resources.
250                 if (mInjectEventQueue != null) {
251                     mInjectEventQueue.dispose();
252                     mInjectEventQueue = null;
253                 }
254             }
255             return true;
256         }
257     }
258 
injectSensorDataImpl(Sensor sensor, float[] values, int accuracy, long timestamp)259     protected boolean injectSensorDataImpl(Sensor sensor, float[] values, int accuracy,
260             long timestamp) {
261         synchronized (mLock) {
262             if (mInjectEventQueue == null) {
263                 Log.e(TAG, "Data injection mode not activated before calling injectSensorData");
264                 return false;
265             }
266             int ret = mInjectEventQueue.injectSensorData(sensor.getHandle(), values, accuracy,
267                                                          timestamp);
268             // If there are any errors in data injection clean up the native resources.
269             if (ret != 0) {
270                 mInjectEventQueue.dispose();
271                 mInjectEventQueue = null;
272             }
273             return ret == 0;
274         }
275     }
276 
277     /*
278      * BaseEventQueue is the communication channel with the sensor service,
279      * SensorEventQueue, TriggerEventQueue are subclases and there is one-to-one mapping between
280      * the queues and the listeners. InjectEventQueue is also a sub-class which is a special case
281      * where data is being injected into the sensor HAL through the sensor service. It is not
282      * associated with any listener and there is one InjectEventQueue associated with a
283      * SensorManager instance.
284      */
285     private static abstract class BaseEventQueue {
nativeInitBaseEventQueue(long nativeManager, WeakReference<BaseEventQueue> eventQWeak, MessageQueue msgQ, float[] scratch, String packageName, int mode, String opPackageName)286         private static native long nativeInitBaseEventQueue(long nativeManager,
287                 WeakReference<BaseEventQueue> eventQWeak, MessageQueue msgQ, float[] scratch,
288                 String packageName, int mode, String opPackageName);
nativeEnableSensor(long eventQ, int handle, int rateUs, int maxBatchReportLatencyUs)289         private static native int nativeEnableSensor(long eventQ, int handle, int rateUs,
290                 int maxBatchReportLatencyUs);
nativeDisableSensor(long eventQ, int handle)291         private static native int nativeDisableSensor(long eventQ, int handle);
nativeDestroySensorEventQueue(long eventQ)292         private static native void nativeDestroySensorEventQueue(long eventQ);
nativeFlushSensor(long eventQ)293         private static native int nativeFlushSensor(long eventQ);
nativeInjectSensorData(long eventQ, int handle, float[] values,int accuracy, long timestamp)294         private static native int nativeInjectSensorData(long eventQ, int handle,
295                 float[] values,int accuracy, long timestamp);
296 
297         private long nSensorEventQueue;
298         private final SparseBooleanArray mActiveSensors = new SparseBooleanArray();
299         protected final SparseIntArray mSensorAccuracies = new SparseIntArray();
300         protected final SparseBooleanArray mFirstEvent = new SparseBooleanArray();
301         private final CloseGuard mCloseGuard = CloseGuard.get();
302         private final float[] mScratch = new float[16];
303         protected final SystemSensorManager mManager;
304 
305         protected static final int OPERATING_MODE_NORMAL = 0;
306         protected static final int OPERATING_MODE_DATA_INJECTION = 1;
307 
BaseEventQueue(Looper looper, SystemSensorManager manager, int mode, String packageName)308         BaseEventQueue(Looper looper, SystemSensorManager manager, int mode, String packageName) {
309             if (packageName == null) packageName = "";
310             nSensorEventQueue = nativeInitBaseEventQueue(manager.mNativeInstance,
311                     new WeakReference<>(this), looper.getQueue(), mScratch,
312                     packageName, mode, manager.mContext.getOpPackageName());
313             mCloseGuard.open("dispose");
314             mManager = manager;
315         }
316 
dispose()317         public void dispose() {
318             dispose(false);
319         }
320 
addSensor( Sensor sensor, int delayUs, int maxBatchReportLatencyUs)321         public boolean addSensor(
322                 Sensor sensor, int delayUs, int maxBatchReportLatencyUs) {
323             // Check if already present.
324             int handle = sensor.getHandle();
325             if (mActiveSensors.get(handle)) return false;
326 
327             // Get ready to receive events before calling enable.
328             mActiveSensors.put(handle, true);
329             addSensorEvent(sensor);
330             if (enableSensor(sensor, delayUs, maxBatchReportLatencyUs) != 0) {
331                 // Try continuous mode if batching fails.
332                 if (maxBatchReportLatencyUs == 0 ||
333                     maxBatchReportLatencyUs > 0 && enableSensor(sensor, delayUs, 0) != 0) {
334                   removeSensor(sensor, false);
335                   return false;
336                 }
337             }
338             return true;
339         }
340 
removeAllSensors()341         public boolean removeAllSensors() {
342             for (int i=0 ; i<mActiveSensors.size(); i++) {
343                 if (mActiveSensors.valueAt(i) == true) {
344                     int handle = mActiveSensors.keyAt(i);
345                     Sensor sensor = mManager.mHandleToSensor.get(handle);
346                     if (sensor != null) {
347                         disableSensor(sensor);
348                         mActiveSensors.put(handle, false);
349                         removeSensorEvent(sensor);
350                     } else {
351                         // it should never happen -- just ignore.
352                     }
353                 }
354             }
355             return true;
356         }
357 
removeSensor(Sensor sensor, boolean disable)358         public boolean removeSensor(Sensor sensor, boolean disable) {
359             final int handle = sensor.getHandle();
360             if (mActiveSensors.get(handle)) {
361                 if (disable) disableSensor(sensor);
362                 mActiveSensors.put(sensor.getHandle(), false);
363                 removeSensorEvent(sensor);
364                 return true;
365             }
366             return false;
367         }
368 
flush()369         public int flush() {
370             if (nSensorEventQueue == 0) throw new NullPointerException();
371             return nativeFlushSensor(nSensorEventQueue);
372         }
373 
hasSensors()374         public boolean hasSensors() {
375             // no more sensors are set
376             return mActiveSensors.indexOfValue(true) >= 0;
377         }
378 
379         @Override
finalize()380         protected void finalize() throws Throwable {
381             try {
382                 dispose(true);
383             } finally {
384                 super.finalize();
385             }
386         }
387 
dispose(boolean finalized)388         private void dispose(boolean finalized) {
389             if (mCloseGuard != null) {
390                 if (finalized) {
391                     mCloseGuard.warnIfOpen();
392                 }
393                 mCloseGuard.close();
394             }
395             if (nSensorEventQueue != 0) {
396                 nativeDestroySensorEventQueue(nSensorEventQueue);
397                 nSensorEventQueue = 0;
398             }
399         }
400 
enableSensor( Sensor sensor, int rateUs, int maxBatchReportLatencyUs)401         private int enableSensor(
402                 Sensor sensor, int rateUs, int maxBatchReportLatencyUs) {
403             if (nSensorEventQueue == 0) throw new NullPointerException();
404             if (sensor == null) throw new NullPointerException();
405             return nativeEnableSensor(nSensorEventQueue, sensor.getHandle(), rateUs,
406                     maxBatchReportLatencyUs);
407         }
408 
injectSensorDataBase(int handle, float[] values, int accuracy, long timestamp)409         protected int injectSensorDataBase(int handle, float[] values, int accuracy,
410                                            long timestamp) {
411             return nativeInjectSensorData(nSensorEventQueue, handle, values, accuracy, timestamp);
412         }
413 
disableSensor(Sensor sensor)414         private int disableSensor(Sensor sensor) {
415             if (nSensorEventQueue == 0) throw new NullPointerException();
416             if (sensor == null) throw new NullPointerException();
417             return nativeDisableSensor(nSensorEventQueue, sensor.getHandle());
418         }
dispatchSensorEvent(int handle, float[] values, int accuracy, long timestamp)419         protected abstract void dispatchSensorEvent(int handle, float[] values, int accuracy,
420                 long timestamp);
dispatchFlushCompleteEvent(int handle)421         protected abstract void dispatchFlushCompleteEvent(int handle);
422 
addSensorEvent(Sensor sensor)423         protected abstract void addSensorEvent(Sensor sensor);
removeSensorEvent(Sensor sensor)424         protected abstract void removeSensorEvent(Sensor sensor);
425     }
426 
427     static final class SensorEventQueue extends BaseEventQueue {
428         private final SensorEventListener mListener;
429         private final SparseArray<SensorEvent> mSensorsEvents = new SparseArray<SensorEvent>();
430 
SensorEventQueue(SensorEventListener listener, Looper looper, SystemSensorManager manager, String packageName)431         public SensorEventQueue(SensorEventListener listener, Looper looper,
432                 SystemSensorManager manager, String packageName) {
433             super(looper, manager, OPERATING_MODE_NORMAL, packageName);
434             mListener = listener;
435         }
436 
437         @Override
addSensorEvent(Sensor sensor)438         public void addSensorEvent(Sensor sensor) {
439             SensorEvent t = new SensorEvent(Sensor.getMaxLengthValuesArray(sensor,
440                     mManager.mTargetSdkLevel));
441             synchronized (mSensorsEvents) {
442                 mSensorsEvents.put(sensor.getHandle(), t);
443             }
444         }
445 
446         @Override
removeSensorEvent(Sensor sensor)447         public void removeSensorEvent(Sensor sensor) {
448             synchronized (mSensorsEvents) {
449                 mSensorsEvents.delete(sensor.getHandle());
450             }
451         }
452 
453         // Called from native code.
454         @SuppressWarnings("unused")
455         @Override
dispatchSensorEvent(int handle, float[] values, int inAccuracy, long timestamp)456         protected void dispatchSensorEvent(int handle, float[] values, int inAccuracy,
457                 long timestamp) {
458             final Sensor sensor = mManager.mHandleToSensor.get(handle);
459             SensorEvent t = null;
460             synchronized (mSensorsEvents) {
461                 t = mSensorsEvents.get(handle);
462             }
463 
464             if (t == null) {
465                 // This may happen if the client has unregistered and there are pending events in
466                 // the queue waiting to be delivered. Ignore.
467                 return;
468             }
469             // Copy from the values array.
470             System.arraycopy(values, 0, t.values, 0, t.values.length);
471             t.timestamp = timestamp;
472             t.accuracy = inAccuracy;
473             t.sensor = sensor;
474 
475             // call onAccuracyChanged() only if the value changes
476             final int accuracy = mSensorAccuracies.get(handle);
477             if ((t.accuracy >= 0) && (accuracy != t.accuracy)) {
478                 mSensorAccuracies.put(handle, t.accuracy);
479                 mListener.onAccuracyChanged(t.sensor, t.accuracy);
480             }
481             mListener.onSensorChanged(t);
482         }
483 
484         @SuppressWarnings("unused")
dispatchFlushCompleteEvent(int handle)485         protected void dispatchFlushCompleteEvent(int handle) {
486             if (mListener instanceof SensorEventListener2) {
487                 final Sensor sensor = mManager.mHandleToSensor.get(handle);
488                 ((SensorEventListener2)mListener).onFlushCompleted(sensor);
489             }
490             return;
491         }
492     }
493 
494     static final class TriggerEventQueue extends BaseEventQueue {
495         private final TriggerEventListener mListener;
496         private final SparseArray<TriggerEvent> mTriggerEvents = new SparseArray<TriggerEvent>();
497 
TriggerEventQueue(TriggerEventListener listener, Looper looper, SystemSensorManager manager, String packageName)498         public TriggerEventQueue(TriggerEventListener listener, Looper looper,
499                 SystemSensorManager manager, String packageName) {
500             super(looper, manager, OPERATING_MODE_NORMAL, packageName);
501             mListener = listener;
502         }
503 
504         @Override
addSensorEvent(Sensor sensor)505         public void addSensorEvent(Sensor sensor) {
506             TriggerEvent t = new TriggerEvent(Sensor.getMaxLengthValuesArray(sensor,
507                     mManager.mTargetSdkLevel));
508             synchronized (mTriggerEvents) {
509                 mTriggerEvents.put(sensor.getHandle(), t);
510             }
511         }
512 
513         @Override
removeSensorEvent(Sensor sensor)514         public void removeSensorEvent(Sensor sensor) {
515             synchronized (mTriggerEvents) {
516                 mTriggerEvents.delete(sensor.getHandle());
517             }
518         }
519 
520         // Called from native code.
521         @SuppressWarnings("unused")
522         @Override
dispatchSensorEvent(int handle, float[] values, int accuracy, long timestamp)523         protected void dispatchSensorEvent(int handle, float[] values, int accuracy,
524                 long timestamp) {
525             final Sensor sensor = mManager.mHandleToSensor.get(handle);
526             TriggerEvent t = null;
527             synchronized (mTriggerEvents) {
528                 t = mTriggerEvents.get(handle);
529             }
530             if (t == null) {
531                 Log.e(TAG, "Error: Trigger Event is null for Sensor: " + sensor);
532                 return;
533             }
534 
535             // Copy from the values array.
536             System.arraycopy(values, 0, t.values, 0, t.values.length);
537             t.timestamp = timestamp;
538             t.sensor = sensor;
539 
540             // A trigger sensor is auto disabled. So just clean up and don't call native
541             // disable.
542             mManager.cancelTriggerSensorImpl(mListener, sensor, false);
543 
544             mListener.onTrigger(t);
545         }
546 
547         @SuppressWarnings("unused")
dispatchFlushCompleteEvent(int handle)548         protected void dispatchFlushCompleteEvent(int handle) {
549         }
550     }
551 
552     final class InjectEventQueue extends BaseEventQueue {
InjectEventQueue(Looper looper, SystemSensorManager manager, String packageName)553         public InjectEventQueue(Looper looper, SystemSensorManager manager, String packageName) {
554             super(looper, manager, OPERATING_MODE_DATA_INJECTION, packageName);
555         }
556 
injectSensorData(int handle, float[] values,int accuracy, long timestamp)557         int injectSensorData(int handle, float[] values,int accuracy, long timestamp) {
558              return injectSensorDataBase(handle, values, accuracy, timestamp);
559         }
560 
561         @SuppressWarnings("unused")
dispatchSensorEvent(int handle, float[] values, int accuracy, long timestamp)562         protected void dispatchSensorEvent(int handle, float[] values, int accuracy,
563                 long timestamp) {
564         }
565 
566         @SuppressWarnings("unused")
dispatchFlushCompleteEvent(int handle)567         protected void dispatchFlushCompleteEvent(int handle) {
568 
569         }
570 
571         @SuppressWarnings("unused")
addSensorEvent(Sensor sensor)572         protected void addSensorEvent(Sensor sensor) {
573 
574         }
575 
576         @SuppressWarnings("unused")
removeSensorEvent(Sensor sensor)577         protected void removeSensorEvent(Sensor sensor) {
578 
579         }
580     }
581 }
582