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.content.BroadcastReceiver;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.IntentFilter;
23 import android.os.Handler;
24 import android.os.Looper;
25 import android.os.MemoryFile;
26 import android.os.MessageQueue;
27 import android.util.Log;
28 import android.util.SparseArray;
29 import android.util.SparseBooleanArray;
30 import android.util.SparseIntArray;
31 
32 import com.android.internal.annotations.GuardedBy;
33 
34 import dalvik.system.CloseGuard;
35 
36 import java.io.IOException;
37 import java.io.UncheckedIOException;
38 import java.lang.ref.WeakReference;
39 import java.util.ArrayList;
40 import java.util.HashMap;
41 import java.util.List;
42 import java.util.Map;
43 
44 /**
45  * Sensor manager implementation that communicates with the built-in
46  * system sensors.
47  *
48  * @hide
49  */
50 public class SystemSensorManager extends SensorManager {
51     //TODO: disable extra logging before release
52     private static final boolean DEBUG_DYNAMIC_SENSOR = true;
53     private static final int MIN_DIRECT_CHANNEL_BUFFER_SIZE = 104;
54     private static final int MAX_LISTENER_COUNT = 128;
55 
nativeClassInit()56     private static native void nativeClassInit();
nativeCreate(String opPackageName)57     private static native long nativeCreate(String opPackageName);
nativeGetSensorAtIndex(long nativeInstance, Sensor sensor, int index)58     private static native boolean nativeGetSensorAtIndex(long nativeInstance,
59             Sensor sensor, int index);
nativeGetDynamicSensors(long nativeInstance, List<Sensor> list)60     private static native void nativeGetDynamicSensors(long nativeInstance, List<Sensor> list);
nativeIsDataInjectionEnabled(long nativeInstance)61     private static native boolean nativeIsDataInjectionEnabled(long nativeInstance);
62 
nativeCreateDirectChannel( long nativeInstance, long size, int channelType, int fd, HardwareBuffer buffer)63     private static native int nativeCreateDirectChannel(
64             long nativeInstance, long size, int channelType, int fd, HardwareBuffer buffer);
nativeDestroyDirectChannel( long nativeInstance, int channelHandle)65     private static native void nativeDestroyDirectChannel(
66             long nativeInstance, int channelHandle);
nativeConfigDirectChannel( long nativeInstance, int channelHandle, int sensorHandle, int rate)67     private static native int nativeConfigDirectChannel(
68             long nativeInstance, int channelHandle, int sensorHandle, int rate);
69 
nativeSetOperationParameter( long nativeInstance, int handle, int type, float[] floatValues, int[] intValues)70     private static native int nativeSetOperationParameter(
71             long nativeInstance, int handle, int type, float[] floatValues, int[] intValues);
72 
73     private static final Object sLock = new Object();
74     @GuardedBy("sLock")
75     private static boolean sNativeClassInited = false;
76     @GuardedBy("sLock")
77     private static InjectEventQueue sInjectEventQueue = null;
78 
79     private final ArrayList<Sensor> mFullSensorsList = new ArrayList<>();
80     private List<Sensor> mFullDynamicSensorsList = new ArrayList<>();
81     private boolean mDynamicSensorListDirty = true;
82 
83     private final HashMap<Integer, Sensor> mHandleToSensor = new HashMap<>();
84 
85     // Listener list
86     private final HashMap<SensorEventListener, SensorEventQueue> mSensorListeners =
87             new HashMap<SensorEventListener, SensorEventQueue>();
88     private final HashMap<TriggerEventListener, TriggerEventQueue> mTriggerListeners =
89             new HashMap<TriggerEventListener, TriggerEventQueue>();
90 
91     // Dynamic Sensor callbacks
92     private HashMap<DynamicSensorCallback, Handler>
93             mDynamicSensorCallbacks = new HashMap<>();
94     private BroadcastReceiver mDynamicSensorBroadcastReceiver;
95 
96     // Looper associated with the context in which this instance was created.
97     private final Looper mMainLooper;
98     private final int mTargetSdkLevel;
99     private final Context mContext;
100     private final long mNativeInstance;
101 
102     /** {@hide} */
SystemSensorManager(Context context, Looper mainLooper)103     public SystemSensorManager(Context context, Looper mainLooper) {
104         synchronized (sLock) {
105             if (!sNativeClassInited) {
106                 sNativeClassInited = true;
107                 nativeClassInit();
108             }
109         }
110 
111         mMainLooper = mainLooper;
112         mTargetSdkLevel = context.getApplicationInfo().targetSdkVersion;
113         mContext = context;
114         mNativeInstance = nativeCreate(context.getOpPackageName());
115 
116         // initialize the sensor list
117         for (int index = 0;; ++index) {
118             Sensor sensor = new Sensor();
119             if (!nativeGetSensorAtIndex(mNativeInstance, sensor, index)) break;
120             mFullSensorsList.add(sensor);
121             mHandleToSensor.put(sensor.getHandle(), sensor);
122         }
123     }
124 
125 
126     /** @hide */
127     @Override
getFullSensorList()128     protected List<Sensor> getFullSensorList() {
129         return mFullSensorsList;
130     }
131 
132     /** @hide */
133     @Override
getFullDynamicSensorList()134     protected List<Sensor> getFullDynamicSensorList() {
135         // only set up broadcast receiver if the application tries to find dynamic sensors or
136         // explicitly register a DynamicSensorCallback
137         setupDynamicSensorBroadcastReceiver();
138         updateDynamicSensorList();
139         return mFullDynamicSensorsList;
140     }
141 
142     /** @hide */
143     @Override
registerListenerImpl(SensorEventListener listener, Sensor sensor, int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags)144     protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
145             int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags) {
146         if (listener == null || sensor == null) {
147             Log.e(TAG, "sensor or listener is null");
148             return false;
149         }
150         // Trigger Sensors should use the requestTriggerSensor call.
151         if (sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
152             Log.e(TAG, "Trigger Sensors should use the requestTriggerSensor.");
153             return false;
154         }
155         if (maxBatchReportLatencyUs < 0 || delayUs < 0) {
156             Log.e(TAG, "maxBatchReportLatencyUs and delayUs should be non-negative");
157             return false;
158         }
159         if (mSensorListeners.size() >= MAX_LISTENER_COUNT) {
160             throw new IllegalStateException("register failed, "
161                 + "the sensor listeners size has exceeded the maximum limit "
162                 + MAX_LISTENER_COUNT);
163         }
164 
165         // Invariants to preserve:
166         // - one Looper per SensorEventListener
167         // - one Looper per SensorEventQueue
168         // We map SensorEventListener to a SensorEventQueue, which holds the looper
169         synchronized (mSensorListeners) {
170             SensorEventQueue queue = mSensorListeners.get(listener);
171             if (queue == null) {
172                 Looper looper = (handler != null) ? handler.getLooper() : mMainLooper;
173                 final String fullClassName =
174                         listener.getClass().getEnclosingClass() != null
175                             ? listener.getClass().getEnclosingClass().getName()
176                             : listener.getClass().getName();
177                 queue = new SensorEventQueue(listener, looper, this, fullClassName);
178                 if (!queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs)) {
179                     queue.dispose();
180                     return false;
181                 }
182                 mSensorListeners.put(listener, queue);
183                 return true;
184             } else {
185                 return queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs);
186             }
187         }
188     }
189 
190     /** @hide */
191     @Override
unregisterListenerImpl(SensorEventListener listener, Sensor sensor)192     protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) {
193         // Trigger Sensors should use the cancelTriggerSensor call.
194         if (sensor != null && sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
195             return;
196         }
197 
198         synchronized (mSensorListeners) {
199             SensorEventQueue queue = mSensorListeners.get(listener);
200             if (queue != null) {
201                 boolean result;
202                 if (sensor == null) {
203                     result = queue.removeAllSensors();
204                 } else {
205                     result = queue.removeSensor(sensor, true);
206                 }
207                 if (result && !queue.hasSensors()) {
208                     mSensorListeners.remove(listener);
209                     queue.dispose();
210                 }
211             }
212         }
213     }
214 
215     /** @hide */
216     @Override
requestTriggerSensorImpl(TriggerEventListener listener, Sensor sensor)217     protected boolean requestTriggerSensorImpl(TriggerEventListener listener, Sensor sensor) {
218         if (sensor == null) throw new IllegalArgumentException("sensor cannot be null");
219 
220         if (listener == null) throw new IllegalArgumentException("listener cannot be null");
221 
222         if (sensor.getReportingMode() != Sensor.REPORTING_MODE_ONE_SHOT) return false;
223 
224         if (mTriggerListeners.size() >= MAX_LISTENER_COUNT) {
225             throw new IllegalStateException("request failed, "
226                     + "the trigger listeners size has exceeded the maximum limit "
227                     + MAX_LISTENER_COUNT);
228         }
229 
230         synchronized (mTriggerListeners) {
231             TriggerEventQueue queue = mTriggerListeners.get(listener);
232             if (queue == null) {
233                 final String fullClassName =
234                         listener.getClass().getEnclosingClass() != null
235                             ? listener.getClass().getEnclosingClass().getName()
236                             : listener.getClass().getName();
237                 queue = new TriggerEventQueue(listener, mMainLooper, this, fullClassName);
238                 if (!queue.addSensor(sensor, 0, 0)) {
239                     queue.dispose();
240                     return false;
241                 }
242                 mTriggerListeners.put(listener, queue);
243                 return true;
244             } else {
245                 return queue.addSensor(sensor, 0, 0);
246             }
247         }
248     }
249 
250     /** @hide */
251     @Override
cancelTriggerSensorImpl(TriggerEventListener listener, Sensor sensor, boolean disable)252     protected boolean cancelTriggerSensorImpl(TriggerEventListener listener, Sensor sensor,
253             boolean disable) {
254         if (sensor != null && sensor.getReportingMode() != Sensor.REPORTING_MODE_ONE_SHOT) {
255             return false;
256         }
257         synchronized (mTriggerListeners) {
258             TriggerEventQueue queue = mTriggerListeners.get(listener);
259             if (queue != null) {
260                 boolean result;
261                 if (sensor == null) {
262                     result = queue.removeAllSensors();
263                 } else {
264                     result = queue.removeSensor(sensor, disable);
265                 }
266                 if (result && !queue.hasSensors()) {
267                     mTriggerListeners.remove(listener);
268                     queue.dispose();
269                 }
270                 return result;
271             }
272             return false;
273         }
274     }
275 
flushImpl(SensorEventListener listener)276     protected boolean flushImpl(SensorEventListener listener) {
277         if (listener == null) throw new IllegalArgumentException("listener cannot be null");
278 
279         synchronized (mSensorListeners) {
280             SensorEventQueue queue = mSensorListeners.get(listener);
281             if (queue == null) {
282                 return false;
283             } else {
284                 return (queue.flush() == 0);
285             }
286         }
287     }
288 
initDataInjectionImpl(boolean enable)289     protected boolean initDataInjectionImpl(boolean enable) {
290         synchronized (sLock) {
291             if (enable) {
292                 boolean isDataInjectionModeEnabled = nativeIsDataInjectionEnabled(mNativeInstance);
293                 // The HAL does not support injection OR SensorService hasn't been set in DI mode.
294                 if (!isDataInjectionModeEnabled) {
295                     Log.e(TAG, "Data Injection mode not enabled");
296                     return false;
297                 }
298                 // Initialize a client for data_injection.
299                 if (sInjectEventQueue == null) {
300                     try {
301                         sInjectEventQueue = new InjectEventQueue(
302                                 mMainLooper, this, mContext.getPackageName());
303                     } catch (RuntimeException e) {
304                         Log.e(TAG, "Cannot create InjectEventQueue: " + e);
305                     }
306                 }
307                 return sInjectEventQueue != null;
308             } else {
309                 // If data injection is being disabled clean up the native resources.
310                 if (sInjectEventQueue != null) {
311                     sInjectEventQueue.dispose();
312                     sInjectEventQueue = null;
313                 }
314                 return true;
315             }
316         }
317     }
318 
injectSensorDataImpl(Sensor sensor, float[] values, int accuracy, long timestamp)319     protected boolean injectSensorDataImpl(Sensor sensor, float[] values, int accuracy,
320             long timestamp) {
321         synchronized (sLock) {
322             if (sInjectEventQueue == null) {
323                 Log.e(TAG, "Data injection mode not activated before calling injectSensorData");
324                 return false;
325             }
326             int ret = sInjectEventQueue.injectSensorData(sensor.getHandle(), values, accuracy,
327                                                          timestamp);
328             // If there are any errors in data injection clean up the native resources.
329             if (ret != 0) {
330                 sInjectEventQueue.dispose();
331                 sInjectEventQueue = null;
332             }
333             return ret == 0;
334         }
335     }
336 
cleanupSensorConnection(Sensor sensor)337     private void cleanupSensorConnection(Sensor sensor) {
338         mHandleToSensor.remove(sensor.getHandle());
339 
340         if (sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
341             synchronized (mTriggerListeners) {
342                 HashMap<TriggerEventListener, TriggerEventQueue> triggerListeners =
343                         new HashMap<TriggerEventListener, TriggerEventQueue>(mTriggerListeners);
344 
345                 for (TriggerEventListener l : triggerListeners.keySet()) {
346                     if (DEBUG_DYNAMIC_SENSOR) {
347                         Log.i(TAG, "removed trigger listener" + l.toString()
348                                 + " due to sensor disconnection");
349                     }
350                     cancelTriggerSensorImpl(l, sensor, true);
351                 }
352             }
353         } else {
354             synchronized (mSensorListeners) {
355                 HashMap<SensorEventListener, SensorEventQueue> sensorListeners =
356                         new HashMap<SensorEventListener, SensorEventQueue>(mSensorListeners);
357 
358                 for (SensorEventListener l: sensorListeners.keySet()) {
359                     if (DEBUG_DYNAMIC_SENSOR) {
360                         Log.i(TAG, "removed event listener" + l.toString()
361                                 + " due to sensor disconnection");
362                     }
363                     unregisterListenerImpl(l, sensor);
364                 }
365             }
366         }
367     }
368 
updateDynamicSensorList()369     private void updateDynamicSensorList() {
370         synchronized (mFullDynamicSensorsList) {
371             if (mDynamicSensorListDirty) {
372                 List<Sensor> list = new ArrayList<>();
373                 nativeGetDynamicSensors(mNativeInstance, list);
374 
375                 final List<Sensor> updatedList = new ArrayList<>();
376                 final List<Sensor> addedList = new ArrayList<>();
377                 final List<Sensor> removedList = new ArrayList<>();
378 
379                 boolean changed = diffSortedSensorList(
380                         mFullDynamicSensorsList, list, updatedList, addedList, removedList);
381 
382                 if (changed) {
383                     if (DEBUG_DYNAMIC_SENSOR) {
384                         Log.i(TAG, "DYNS dynamic sensor list cached should be updated");
385                     }
386                     mFullDynamicSensorsList = updatedList;
387 
388                     for (Sensor s: addedList) {
389                         mHandleToSensor.put(s.getHandle(), s);
390                     }
391 
392                     Handler mainHandler = new Handler(mContext.getMainLooper());
393 
394                     for (Map.Entry<DynamicSensorCallback, Handler> entry :
395                             mDynamicSensorCallbacks.entrySet()) {
396                         final DynamicSensorCallback callback = entry.getKey();
397                         Handler handler =
398                                 entry.getValue() == null ? mainHandler : entry.getValue();
399 
400                         handler.post(new Runnable() {
401                             @Override
402                             public void run() {
403                                 for (Sensor s: addedList) {
404                                     callback.onDynamicSensorConnected(s);
405                                 }
406                                 for (Sensor s: removedList) {
407                                     callback.onDynamicSensorDisconnected(s);
408                                 }
409                             }
410                         });
411                     }
412 
413                     for (Sensor s: removedList) {
414                         cleanupSensorConnection(s);
415                     }
416                 }
417 
418                 mDynamicSensorListDirty = false;
419             }
420         }
421     }
422 
setupDynamicSensorBroadcastReceiver()423     private void setupDynamicSensorBroadcastReceiver() {
424         if (mDynamicSensorBroadcastReceiver == null) {
425             mDynamicSensorBroadcastReceiver = new BroadcastReceiver() {
426                 @Override
427                 public void onReceive(Context context, Intent intent) {
428                     if (intent.getAction() == Intent.ACTION_DYNAMIC_SENSOR_CHANGED) {
429                         if (DEBUG_DYNAMIC_SENSOR) {
430                             Log.i(TAG, "DYNS received DYNAMIC_SENSOR_CHANED broadcast");
431                         }
432                         // Dynamic sensors probably changed
433                         mDynamicSensorListDirty = true;
434                         updateDynamicSensorList();
435                     }
436                 }
437             };
438 
439             IntentFilter filter = new IntentFilter("dynamic_sensor_change");
440             filter.addAction(Intent.ACTION_DYNAMIC_SENSOR_CHANGED);
441             mContext.registerReceiver(mDynamicSensorBroadcastReceiver, filter);
442         }
443     }
444 
teardownDynamicSensorBroadcastReceiver()445     private void teardownDynamicSensorBroadcastReceiver() {
446         mDynamicSensorCallbacks.clear();
447         mContext.unregisterReceiver(mDynamicSensorBroadcastReceiver);
448         mDynamicSensorBroadcastReceiver = null;
449     }
450 
451     /** @hide */
registerDynamicSensorCallbackImpl( DynamicSensorCallback callback, Handler handler)452     protected void registerDynamicSensorCallbackImpl(
453             DynamicSensorCallback callback, Handler handler) {
454         if (DEBUG_DYNAMIC_SENSOR) {
455             Log.i(TAG, "DYNS Register dynamic sensor callback");
456         }
457 
458         if (callback == null) {
459             throw new IllegalArgumentException("callback cannot be null");
460         }
461         if (mDynamicSensorCallbacks.containsKey(callback)) {
462             // has been already registered, ignore
463             return;
464         }
465 
466         setupDynamicSensorBroadcastReceiver();
467         mDynamicSensorCallbacks.put(callback, handler);
468     }
469 
470     /** @hide */
unregisterDynamicSensorCallbackImpl( DynamicSensorCallback callback)471     protected void unregisterDynamicSensorCallbackImpl(
472             DynamicSensorCallback callback) {
473         if (DEBUG_DYNAMIC_SENSOR) {
474             Log.i(TAG, "Removing dynamic sensor listerner");
475         }
476         mDynamicSensorCallbacks.remove(callback);
477     }
478 
479     /*
480      * Find the difference of two List<Sensor> assuming List are sorted by handle of sensor,
481      * assuming the input list is already sorted by handle. Inputs are ol and nl; outputs are
482      * updated, added and removed. Any of the output lists can be null in case the result is not
483      * interested.
484      */
diffSortedSensorList( List<Sensor> oldList, List<Sensor> newList, List<Sensor> updated, List<Sensor> added, List<Sensor> removed)485     private static boolean diffSortedSensorList(
486             List<Sensor> oldList, List<Sensor> newList, List<Sensor> updated,
487             List<Sensor> added, List<Sensor> removed) {
488 
489         boolean changed = false;
490 
491         int i = 0, j = 0;
492         while (true) {
493             if (j < oldList.size() && (i >= newList.size()
494                     || newList.get(i).getHandle() > oldList.get(j).getHandle())) {
495                 changed = true;
496                 if (removed != null) {
497                     removed.add(oldList.get(j));
498                 }
499                 ++j;
500             } else if (i < newList.size() && (j >= oldList.size()
501                     || newList.get(i).getHandle() < oldList.get(j).getHandle())) {
502                 changed = true;
503                 if (added != null) {
504                     added.add(newList.get(i));
505                 }
506                 if (updated != null) {
507                     updated.add(newList.get(i));
508                 }
509                 ++i;
510             } else if (i < newList.size() && j < oldList.size()
511                     && newList.get(i).getHandle() == oldList.get(j).getHandle()) {
512                 if (updated != null) {
513                     updated.add(oldList.get(j));
514                 }
515                 ++i;
516                 ++j;
517             } else {
518                 break;
519             }
520         }
521         return changed;
522     }
523 
524     /** @hide */
configureDirectChannelImpl( SensorDirectChannel channel, Sensor sensor, int rate)525     protected int configureDirectChannelImpl(
526             SensorDirectChannel channel, Sensor sensor, int rate) {
527         if (!channel.isOpen()) {
528             throw new IllegalStateException("channel is closed");
529         }
530 
531         if (rate < SensorDirectChannel.RATE_STOP
532                 || rate > SensorDirectChannel.RATE_VERY_FAST) {
533             throw new IllegalArgumentException("rate parameter invalid");
534         }
535 
536         if (sensor == null && rate != SensorDirectChannel.RATE_STOP) {
537             // the stop all sensors case
538             throw new IllegalArgumentException(
539                     "when sensor is null, rate can only be DIRECT_RATE_STOP");
540         }
541 
542         int sensorHandle = (sensor == null) ? -1 : sensor.getHandle();
543 
544         int ret = nativeConfigDirectChannel(
545                 mNativeInstance, channel.getNativeHandle(), sensorHandle, rate);
546 
547         if (rate == SensorDirectChannel.RATE_STOP) {
548             return (ret == 0) ? 1 : 0;
549         } else {
550             return (ret > 0) ? ret : 0;
551         }
552     }
553 
554     /** @hide */
createDirectChannelImpl( MemoryFile memoryFile, HardwareBuffer hardwareBuffer)555     protected SensorDirectChannel createDirectChannelImpl(
556             MemoryFile memoryFile, HardwareBuffer hardwareBuffer) {
557         int id;
558         int type;
559         long size;
560         if (memoryFile != null) {
561             int fd;
562             try {
563                 fd = memoryFile.getFileDescriptor().getInt$();
564             } catch (IOException e) {
565                 throw new IllegalArgumentException("MemoryFile object is not valid");
566             }
567 
568             if (memoryFile.length() < MIN_DIRECT_CHANNEL_BUFFER_SIZE) {
569                 throw new IllegalArgumentException(
570                         "Size of MemoryFile has to be greater than "
571                         + MIN_DIRECT_CHANNEL_BUFFER_SIZE);
572             }
573 
574             size = memoryFile.length();
575             id = nativeCreateDirectChannel(
576                     mNativeInstance, size, SensorDirectChannel.TYPE_MEMORY_FILE, fd, null);
577             if (id <= 0) {
578                 throw new UncheckedIOException(
579                         new IOException("create MemoryFile direct channel failed " + id));
580             }
581             type = SensorDirectChannel.TYPE_MEMORY_FILE;
582         } else if (hardwareBuffer != null) {
583             if (hardwareBuffer.getFormat() != HardwareBuffer.BLOB) {
584                 throw new IllegalArgumentException("Format of HardwareBuffer must be BLOB");
585             }
586             if (hardwareBuffer.getHeight() != 1) {
587                 throw new IllegalArgumentException("Height of HardwareBuffer must be 1");
588             }
589             if (hardwareBuffer.getWidth() < MIN_DIRECT_CHANNEL_BUFFER_SIZE) {
590                 throw new IllegalArgumentException(
591                         "Width if HaradwareBuffer must be greater than "
592                         + MIN_DIRECT_CHANNEL_BUFFER_SIZE);
593             }
594             if ((hardwareBuffer.getUsage() & HardwareBuffer.USAGE_SENSOR_DIRECT_DATA) == 0) {
595                 throw new IllegalArgumentException(
596                         "HardwareBuffer must set usage flag USAGE_SENSOR_DIRECT_DATA");
597             }
598             size = hardwareBuffer.getWidth();
599             id = nativeCreateDirectChannel(
600                     mNativeInstance, size, SensorDirectChannel.TYPE_HARDWARE_BUFFER,
601                     -1, hardwareBuffer);
602             if (id <= 0) {
603                 throw new UncheckedIOException(
604                         new IOException("create HardwareBuffer direct channel failed " + id));
605             }
606             type = SensorDirectChannel.TYPE_HARDWARE_BUFFER;
607         } else {
608             throw new NullPointerException("shared memory object cannot be null");
609         }
610         return new SensorDirectChannel(this, id, type, size);
611     }
612 
613     /** @hide */
destroyDirectChannelImpl(SensorDirectChannel channel)614     protected void destroyDirectChannelImpl(SensorDirectChannel channel) {
615         if (channel != null) {
616             nativeDestroyDirectChannel(mNativeInstance, channel.getNativeHandle());
617         }
618     }
619 
620     /*
621      * BaseEventQueue is the communication channel with the sensor service,
622      * SensorEventQueue, TriggerEventQueue are subclases and there is one-to-one mapping between
623      * the queues and the listeners. InjectEventQueue is also a sub-class which is a special case
624      * where data is being injected into the sensor HAL through the sensor service. It is not
625      * associated with any listener and there is one InjectEventQueue associated with a
626      * SensorManager instance.
627      */
628     private abstract static class BaseEventQueue {
nativeInitBaseEventQueue(long nativeManager, WeakReference<BaseEventQueue> eventQWeak, MessageQueue msgQ, String packageName, int mode, String opPackageName)629         private static native long nativeInitBaseEventQueue(long nativeManager,
630                 WeakReference<BaseEventQueue> eventQWeak, MessageQueue msgQ,
631                 String packageName, int mode, String opPackageName);
nativeEnableSensor(long eventQ, int handle, int rateUs, int maxBatchReportLatencyUs)632         private static native int nativeEnableSensor(long eventQ, int handle, int rateUs,
633                 int maxBatchReportLatencyUs);
nativeDisableSensor(long eventQ, int handle)634         private static native int nativeDisableSensor(long eventQ, int handle);
nativeDestroySensorEventQueue(long eventQ)635         private static native void nativeDestroySensorEventQueue(long eventQ);
nativeFlushSensor(long eventQ)636         private static native int nativeFlushSensor(long eventQ);
nativeInjectSensorData(long eventQ, int handle, float[] values, int accuracy, long timestamp)637         private static native int nativeInjectSensorData(long eventQ, int handle,
638                 float[] values, int accuracy, long timestamp);
639 
640         private long mNativeSensorEventQueue;
641         private final SparseBooleanArray mActiveSensors = new SparseBooleanArray();
642         protected final SparseIntArray mSensorAccuracies = new SparseIntArray();
643         private final CloseGuard mCloseGuard = CloseGuard.get();
644         protected final SystemSensorManager mManager;
645 
646         protected static final int OPERATING_MODE_NORMAL = 0;
647         protected static final int OPERATING_MODE_DATA_INJECTION = 1;
648 
BaseEventQueue(Looper looper, SystemSensorManager manager, int mode, String packageName)649         BaseEventQueue(Looper looper, SystemSensorManager manager, int mode, String packageName) {
650             if (packageName == null) packageName = "";
651             mNativeSensorEventQueue = nativeInitBaseEventQueue(manager.mNativeInstance,
652                     new WeakReference<>(this), looper.getQueue(),
653                     packageName, mode, manager.mContext.getOpPackageName());
654             mCloseGuard.open("dispose");
655             mManager = manager;
656         }
657 
dispose()658         public void dispose() {
659             dispose(false);
660         }
661 
addSensor( Sensor sensor, int delayUs, int maxBatchReportLatencyUs)662         public boolean addSensor(
663                 Sensor sensor, int delayUs, int maxBatchReportLatencyUs) {
664             // Check if already present.
665             int handle = sensor.getHandle();
666             if (mActiveSensors.get(handle)) return false;
667 
668             // Get ready to receive events before calling enable.
669             mActiveSensors.put(handle, true);
670             addSensorEvent(sensor);
671             if (enableSensor(sensor, delayUs, maxBatchReportLatencyUs) != 0) {
672                 // Try continuous mode if batching fails.
673                 if (maxBatchReportLatencyUs == 0
674                         || maxBatchReportLatencyUs > 0 && enableSensor(sensor, delayUs, 0) != 0) {
675                     removeSensor(sensor, false);
676                     return false;
677                 }
678             }
679             return true;
680         }
681 
removeAllSensors()682         public boolean removeAllSensors() {
683             for (int i = 0; i < mActiveSensors.size(); i++) {
684                 if (mActiveSensors.valueAt(i) == true) {
685                     int handle = mActiveSensors.keyAt(i);
686                     Sensor sensor = mManager.mHandleToSensor.get(handle);
687                     if (sensor != null) {
688                         disableSensor(sensor);
689                         mActiveSensors.put(handle, false);
690                         removeSensorEvent(sensor);
691                     } else {
692                         // sensor just disconnected -- just ignore.
693                     }
694                 }
695             }
696             return true;
697         }
698 
removeSensor(Sensor sensor, boolean disable)699         public boolean removeSensor(Sensor sensor, boolean disable) {
700             final int handle = sensor.getHandle();
701             if (mActiveSensors.get(handle)) {
702                 if (disable) disableSensor(sensor);
703                 mActiveSensors.put(sensor.getHandle(), false);
704                 removeSensorEvent(sensor);
705                 return true;
706             }
707             return false;
708         }
709 
flush()710         public int flush() {
711             if (mNativeSensorEventQueue == 0) throw new NullPointerException();
712             return nativeFlushSensor(mNativeSensorEventQueue);
713         }
714 
hasSensors()715         public boolean hasSensors() {
716             // no more sensors are set
717             return mActiveSensors.indexOfValue(true) >= 0;
718         }
719 
720         @Override
finalize()721         protected void finalize() throws Throwable {
722             try {
723                 dispose(true);
724             } finally {
725                 super.finalize();
726             }
727         }
728 
dispose(boolean finalized)729         private void dispose(boolean finalized) {
730             if (mCloseGuard != null) {
731                 if (finalized) {
732                     mCloseGuard.warnIfOpen();
733                 }
734                 mCloseGuard.close();
735             }
736             if (mNativeSensorEventQueue != 0) {
737                 nativeDestroySensorEventQueue(mNativeSensorEventQueue);
738                 mNativeSensorEventQueue = 0;
739             }
740         }
741 
enableSensor( Sensor sensor, int rateUs, int maxBatchReportLatencyUs)742         private int enableSensor(
743                 Sensor sensor, int rateUs, int maxBatchReportLatencyUs) {
744             if (mNativeSensorEventQueue == 0) throw new NullPointerException();
745             if (sensor == null) throw new NullPointerException();
746             return nativeEnableSensor(mNativeSensorEventQueue, sensor.getHandle(), rateUs,
747                     maxBatchReportLatencyUs);
748         }
749 
injectSensorDataBase(int handle, float[] values, int accuracy, long timestamp)750         protected int injectSensorDataBase(int handle, float[] values, int accuracy,
751                                            long timestamp) {
752             return nativeInjectSensorData(
753                     mNativeSensorEventQueue, handle, values, accuracy, timestamp);
754         }
755 
disableSensor(Sensor sensor)756         private int disableSensor(Sensor sensor) {
757             if (mNativeSensorEventQueue == 0) throw new NullPointerException();
758             if (sensor == null) throw new NullPointerException();
759             return nativeDisableSensor(mNativeSensorEventQueue, sensor.getHandle());
760         }
dispatchSensorEvent(int handle, float[] values, int accuracy, long timestamp)761         protected abstract void dispatchSensorEvent(int handle, float[] values, int accuracy,
762                 long timestamp);
dispatchFlushCompleteEvent(int handle)763         protected abstract void dispatchFlushCompleteEvent(int handle);
764 
dispatchAdditionalInfoEvent( int handle, int type, int serial, float[] floatValues, int[] intValues)765         protected void dispatchAdditionalInfoEvent(
766                 int handle, int type, int serial, float[] floatValues, int[] intValues) {
767             // default implementation is do nothing
768         }
769 
addSensorEvent(Sensor sensor)770         protected abstract void addSensorEvent(Sensor sensor);
removeSensorEvent(Sensor sensor)771         protected abstract void removeSensorEvent(Sensor sensor);
772     }
773 
774     static final class SensorEventQueue extends BaseEventQueue {
775         private final SensorEventListener mListener;
776         private final SparseArray<SensorEvent> mSensorsEvents = new SparseArray<SensorEvent>();
777 
SensorEventQueue(SensorEventListener listener, Looper looper, SystemSensorManager manager, String packageName)778         public SensorEventQueue(SensorEventListener listener, Looper looper,
779                 SystemSensorManager manager, String packageName) {
780             super(looper, manager, OPERATING_MODE_NORMAL, packageName);
781             mListener = listener;
782         }
783 
784         @Override
addSensorEvent(Sensor sensor)785         public void addSensorEvent(Sensor sensor) {
786             SensorEvent t = new SensorEvent(Sensor.getMaxLengthValuesArray(sensor,
787                     mManager.mTargetSdkLevel));
788             synchronized (mSensorsEvents) {
789                 mSensorsEvents.put(sensor.getHandle(), t);
790             }
791         }
792 
793         @Override
removeSensorEvent(Sensor sensor)794         public void removeSensorEvent(Sensor sensor) {
795             synchronized (mSensorsEvents) {
796                 mSensorsEvents.delete(sensor.getHandle());
797             }
798         }
799 
800         // Called from native code.
801         @SuppressWarnings("unused")
802         @Override
dispatchSensorEvent(int handle, float[] values, int inAccuracy, long timestamp)803         protected void dispatchSensorEvent(int handle, float[] values, int inAccuracy,
804                 long timestamp) {
805             final Sensor sensor = mManager.mHandleToSensor.get(handle);
806             if (sensor == null) {
807                 // sensor disconnected
808                 return;
809             }
810 
811             SensorEvent t = null;
812             synchronized (mSensorsEvents) {
813                 t = mSensorsEvents.get(handle);
814             }
815 
816             if (t == null) {
817                 // This may happen if the client has unregistered and there are pending events in
818                 // the queue waiting to be delivered. Ignore.
819                 return;
820             }
821             // Copy from the values array.
822             System.arraycopy(values, 0, t.values, 0, t.values.length);
823             t.timestamp = timestamp;
824             t.accuracy = inAccuracy;
825             t.sensor = sensor;
826 
827             // call onAccuracyChanged() only if the value changes
828             final int accuracy = mSensorAccuracies.get(handle);
829             if ((t.accuracy >= 0) && (accuracy != t.accuracy)) {
830                 mSensorAccuracies.put(handle, t.accuracy);
831                 mListener.onAccuracyChanged(t.sensor, t.accuracy);
832             }
833             mListener.onSensorChanged(t);
834         }
835 
836         // Called from native code.
837         @SuppressWarnings("unused")
838         @Override
dispatchFlushCompleteEvent(int handle)839         protected void dispatchFlushCompleteEvent(int handle) {
840             if (mListener instanceof SensorEventListener2) {
841                 final Sensor sensor = mManager.mHandleToSensor.get(handle);
842                 if (sensor == null) {
843                     // sensor disconnected
844                     return;
845                 }
846                 ((SensorEventListener2) mListener).onFlushCompleted(sensor);
847             }
848             return;
849         }
850 
851         // Called from native code.
852         @SuppressWarnings("unused")
853         @Override
dispatchAdditionalInfoEvent( int handle, int type, int serial, float[] floatValues, int[] intValues)854         protected void dispatchAdditionalInfoEvent(
855                 int handle, int type, int serial, float[] floatValues, int[] intValues) {
856             if (mListener instanceof SensorEventCallback) {
857                 final Sensor sensor = mManager.mHandleToSensor.get(handle);
858                 if (sensor == null) {
859                     // sensor disconnected
860                     return;
861                 }
862                 SensorAdditionalInfo info =
863                         new SensorAdditionalInfo(sensor, type, serial, intValues, floatValues);
864                 ((SensorEventCallback) mListener).onSensorAdditionalInfo(info);
865             }
866         }
867     }
868 
869     static final class TriggerEventQueue extends BaseEventQueue {
870         private final TriggerEventListener mListener;
871         private final SparseArray<TriggerEvent> mTriggerEvents = new SparseArray<TriggerEvent>();
872 
TriggerEventQueue(TriggerEventListener listener, Looper looper, SystemSensorManager manager, String packageName)873         public TriggerEventQueue(TriggerEventListener listener, Looper looper,
874                 SystemSensorManager manager, String packageName) {
875             super(looper, manager, OPERATING_MODE_NORMAL, packageName);
876             mListener = listener;
877         }
878 
879         @Override
addSensorEvent(Sensor sensor)880         public void addSensorEvent(Sensor sensor) {
881             TriggerEvent t = new TriggerEvent(Sensor.getMaxLengthValuesArray(sensor,
882                     mManager.mTargetSdkLevel));
883             synchronized (mTriggerEvents) {
884                 mTriggerEvents.put(sensor.getHandle(), t);
885             }
886         }
887 
888         @Override
removeSensorEvent(Sensor sensor)889         public void removeSensorEvent(Sensor sensor) {
890             synchronized (mTriggerEvents) {
891                 mTriggerEvents.delete(sensor.getHandle());
892             }
893         }
894 
895         // Called from native code.
896         @SuppressWarnings("unused")
897         @Override
dispatchSensorEvent(int handle, float[] values, int accuracy, long timestamp)898         protected void dispatchSensorEvent(int handle, float[] values, int accuracy,
899                 long timestamp) {
900             final Sensor sensor = mManager.mHandleToSensor.get(handle);
901             if (sensor == null) {
902                 // sensor disconnected
903                 return;
904             }
905             TriggerEvent t = null;
906             synchronized (mTriggerEvents) {
907                 t = mTriggerEvents.get(handle);
908             }
909             if (t == null) {
910                 Log.e(TAG, "Error: Trigger Event is null for Sensor: " + sensor);
911                 return;
912             }
913 
914             // Copy from the values array.
915             System.arraycopy(values, 0, t.values, 0, t.values.length);
916             t.timestamp = timestamp;
917             t.sensor = sensor;
918 
919             // A trigger sensor is auto disabled. So just clean up and don't call native
920             // disable.
921             mManager.cancelTriggerSensorImpl(mListener, sensor, false);
922 
923             mListener.onTrigger(t);
924         }
925 
926         @SuppressWarnings("unused")
dispatchFlushCompleteEvent(int handle)927         protected void dispatchFlushCompleteEvent(int handle) {
928         }
929     }
930 
931     final class InjectEventQueue extends BaseEventQueue {
InjectEventQueue(Looper looper, SystemSensorManager manager, String packageName)932         public InjectEventQueue(Looper looper, SystemSensorManager manager, String packageName) {
933             super(looper, manager, OPERATING_MODE_DATA_INJECTION, packageName);
934         }
935 
injectSensorData(int handle, float[] values, int accuracy, long timestamp)936         int injectSensorData(int handle, float[] values, int accuracy, long timestamp) {
937             return injectSensorDataBase(handle, values, accuracy, timestamp);
938         }
939 
940         @SuppressWarnings("unused")
dispatchSensorEvent(int handle, float[] values, int accuracy, long timestamp)941         protected void dispatchSensorEvent(int handle, float[] values, int accuracy,
942                 long timestamp) {
943         }
944 
945         @SuppressWarnings("unused")
dispatchFlushCompleteEvent(int handle)946         protected void dispatchFlushCompleteEvent(int handle) {
947 
948         }
949 
950         @SuppressWarnings("unused")
addSensorEvent(Sensor sensor)951         protected void addSensorEvent(Sensor sensor) {
952 
953         }
954 
955         @SuppressWarnings("unused")
removeSensorEvent(Sensor sensor)956         protected void removeSensorEvent(Sensor sensor) {
957 
958         }
959     }
960 
setOperationParameterImpl(SensorAdditionalInfo parameter)961     protected boolean setOperationParameterImpl(SensorAdditionalInfo parameter) {
962         int handle = -1;
963         if (parameter.sensor != null) handle = parameter.sensor.getHandle();
964         return nativeSetOperationParameter(
965                 mNativeInstance, handle,
966                 parameter.type, parameter.floatValues, parameter.intValues) == 0;
967     }
968 }
969