summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Prabir Pradhan <prabirmsp@google.com> 2023-11-21 01:53:34 +0000
committer Prabir Pradhan <prabirmsp@google.com> 2023-11-30 02:08:07 +0000
commitff45ea84b7560390c3648086f0798d21ee23d64c (patch)
tree9871124269c94804e61dd5a12635e84872b3e1e5
parent0e51c4b2ef84013342dc19f4b898e5d6a48ac5a6 (diff)
Sync InputDeviceSensorManager device state with InputManagerGlobal
Previously, InputDeviceSensorManager created its own thread for two purposes: 1. To receive input devices changed callbacks, and 2. To notify events for listeners that were registered without a handler on which they should be notified. The fact that the sensor manager was getting devices changed callbacks on a separate thread meant that the callbacks would race with app callbaks, so it was possible for apps to be notified of devices changing before the manager was. In that case, an app that queries a newly added device's sensors will not get the sensor even if it exists, because the sensor manager doesn't know about the device yet. To fix this, we no longer receive device changes on the sensor thread. Instead, we notify the sensor manager of device changes directly from the binder thread to keep it in sync with InputManagerGlobal. The sensor thread will now be lazy-initialized only for case 2., where a listener is added with a null handler. Bug: 290254916 Test: atest InputDeviceSensorManagerTest Change-Id: I6877a353e8cddd85f0aed5f4aa51e0e16fc364e7
-rw-r--r--core/java/android/hardware/input/InputDeviceSensorManager.java39
-rw-r--r--core/java/android/hardware/input/InputManagerGlobal.java20
2 files changed, 40 insertions, 19 deletions
diff --git a/core/java/android/hardware/input/InputDeviceSensorManager.java b/core/java/android/hardware/input/InputDeviceSensorManager.java
index 05024ea95eda..85e1ac014396 100644
--- a/core/java/android/hardware/input/InputDeviceSensorManager.java
+++ b/core/java/android/hardware/input/InputDeviceSensorManager.java
@@ -17,6 +17,7 @@
package android.hardware.input;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.hardware.HardwareBuffer;
import android.hardware.Sensor;
import android.hardware.SensorAdditionalInfo;
@@ -49,7 +50,7 @@ import java.util.Map;
* sensors.
* @hide
*/
-public class InputDeviceSensorManager implements InputManager.InputDeviceListener {
+public class InputDeviceSensorManager {
private static final String TAG = "InputDeviceSensorManager";
private static final boolean DEBUG = false;
@@ -67,18 +68,15 @@ public class InputDeviceSensorManager implements InputManager.InputDeviceListene
@GuardedBy("mInputSensorLock")
private final ArrayList<InputSensorEventListenerDelegate> mInputSensorEventListeners =
new ArrayList<InputSensorEventListenerDelegate>();
- private final HandlerThread mSensorThread;
- private final Handler mSensorHandler;
+
+ // The sensor thread is only initialized if there is a listener added without a handler.
+ @GuardedBy("mInputSensorLock")
+ @Nullable
+ private HandlerThread mSensorThread;
public InputDeviceSensorManager(InputManagerGlobal inputManagerGlobal) {
mGlobal = inputManagerGlobal;
- mSensorThread = new HandlerThread("SensorThread");
- mSensorThread.start();
- mSensorHandler = new Handler(mSensorThread.getLooper());
-
- // Register the input device listener
- mGlobal.registerInputDeviceListener(this, mSensorHandler);
// Initialize the sensor list
initializeSensors();
}
@@ -105,7 +103,6 @@ public class InputDeviceSensorManager implements InputManager.InputDeviceListene
}
}
- @Override
public void onInputDeviceAdded(int deviceId) {
synchronized (mInputSensorLock) {
if (!mSensors.containsKey(deviceId)) {
@@ -117,14 +114,12 @@ public class InputDeviceSensorManager implements InputManager.InputDeviceListene
}
}
- @Override
public void onInputDeviceRemoved(int deviceId) {
synchronized (mInputSensorLock) {
mSensors.remove(deviceId);
}
}
- @Override
public void onInputDeviceChanged(int deviceId) {
synchronized (mInputSensorLock) {
mSensors.remove(deviceId);
@@ -261,8 +256,8 @@ public class InputDeviceSensorManager implements InputManager.InputDeviceListene
private final SparseArray<SensorEvent> mSensorEvents = new SparseArray<SensorEvent>();
InputSensorEventListenerDelegate(SensorEventListener listener, Sensor sensor,
- int delayUs, int maxBatchReportLatencyUs, Handler handler) {
- super(handler != null ? handler.getLooper() : Looper.myLooper());
+ int delayUs, int maxBatchReportLatencyUs, Looper looper) {
+ super(looper);
mListener = listener;
mDelayUs = delayUs;
mMaxBatchReportLatencyUs = maxBatchReportLatencyUs;
@@ -477,8 +472,7 @@ public class InputDeviceSensorManager implements InputManager.InputDeviceListene
if (idx < 0) {
InputSensorEventListenerDelegate d =
new InputSensorEventListenerDelegate(listener, sensor, delayUs,
- maxBatchReportLatencyUs,
- handler == null ? mSensorHandler : handler);
+ maxBatchReportLatencyUs, getLooperForListenerLocked(handler));
mInputSensorEventListeners.add(d);
} else {
// The listener is already registered, see if it wants to listen to more sensors.
@@ -489,6 +483,19 @@ public class InputDeviceSensorManager implements InputManager.InputDeviceListene
return true;
}
+ @GuardedBy("mInputSensorLock")
+ @NonNull
+ private Looper getLooperForListenerLocked(@Nullable Handler requestedHandler) {
+ if (requestedHandler != null) {
+ return requestedHandler.getLooper();
+ }
+ if (mSensorThread == null) {
+ mSensorThread = new HandlerThread("SensorThread");
+ mSensorThread.start();
+ }
+ return mSensorThread.getLooper();
+ }
+
private void unregisterListenerInternal(SensorEventListener listener, Sensor sensor) {
if (DEBUG) {
Slog.d(TAG, "unregisterListenerImpl listener=" + listener + " sensor=" + sensor);
diff --git a/core/java/android/hardware/input/InputManagerGlobal.java b/core/java/android/hardware/input/InputManagerGlobal.java
index 8c598aeae67c..fb174b8cd689 100644
--- a/core/java/android/hardware/input/InputManagerGlobal.java
+++ b/core/java/android/hardware/input/InputManagerGlobal.java
@@ -100,6 +100,9 @@ public final class InputManagerGlobal {
@GuardedBy("mKeyboardBacklightListenerLock")
@Nullable private IKeyboardBacklightListener mKeyboardBacklightListener;
+ // InputDeviceSensorManager gets notified synchronously from the binder thread when input
+ // devices change, so it must be synchronized with the input device listeners.
+ @GuardedBy("mInputDeviceListeners")
@Nullable private InputDeviceSensorManager mInputDeviceSensorManager;
private static InputManagerGlobal sInstance;
@@ -250,6 +253,9 @@ public final class InputManagerGlobal {
Log.d(TAG, "Device removed: " + deviceId);
}
mInputDevices.removeAt(i);
+ if (mInputDeviceSensorManager != null) {
+ mInputDeviceSensorManager.onInputDeviceRemoved(deviceId);
+ }
sendMessageToInputDeviceListenersLocked(
InputDeviceListenerDelegate.MSG_DEVICE_REMOVED, deviceId);
}
@@ -267,6 +273,9 @@ public final class InputManagerGlobal {
Log.d(TAG, "Device changed: " + deviceId);
}
mInputDevices.setValueAt(index, null);
+ if (mInputDeviceSensorManager != null) {
+ mInputDeviceSensorManager.onInputDeviceChanged(deviceId);
+ }
sendMessageToInputDeviceListenersLocked(
InputDeviceListenerDelegate.MSG_DEVICE_CHANGED, deviceId);
}
@@ -276,6 +285,9 @@ public final class InputManagerGlobal {
Log.d(TAG, "Device added: " + deviceId);
}
mInputDevices.put(deviceId, null);
+ if (mInputDeviceSensorManager != null) {
+ mInputDeviceSensorManager.onInputDeviceAdded(deviceId);
+ }
sendMessageToInputDeviceListenersLocked(
InputDeviceListenerDelegate.MSG_DEVICE_ADDED, deviceId);
}
@@ -930,10 +942,12 @@ public final class InputManagerGlobal {
*/
@NonNull
public SensorManager getInputDeviceSensorManager(int deviceId) {
- if (mInputDeviceSensorManager == null) {
- mInputDeviceSensorManager = new InputDeviceSensorManager(this);
+ synchronized (mInputDeviceListeners) {
+ if (mInputDeviceSensorManager == null) {
+ mInputDeviceSensorManager = new InputDeviceSensorManager(this);
+ }
+ return mInputDeviceSensorManager.getSensorManager(deviceId);
}
- return mInputDeviceSensorManager.getSensorManager(deviceId);
}
/**