diff --git a/services/core/java/com/android/server/input/BatteryController.java b/services/core/java/com/android/server/input/BatteryController.java index 2f369ccc51b1b..696b6047137a6 100644 --- a/services/core/java/com/android/server/input/BatteryController.java +++ b/services/core/java/com/android/server/input/BatteryController.java @@ -48,8 +48,13 @@ import java.util.Set; /** * A thread-safe component of {@link InputManagerService} responsible for managing the battery state * of input devices. + * + * Interactions with BatteryController can happen on several threads, including Binder threads, the + * {@link UEventObserver}'s thread, or its own Handler thread, among others. All public methods, and + * private methods prefixed with "handle-" (e.g. {@link #handleListeningProcessDied(int)}), + * serve as entry points for these threads. */ -final class BatteryController implements InputManager.InputDeviceListener { +final class BatteryController { private static final String TAG = BatteryController.class.getSimpleName(); // To enable these logs, run: @@ -70,10 +75,9 @@ final class BatteryController implements InputManager.InputDeviceListener { @GuardedBy("mLock") private final ArrayMap mListenerRecords = new ArrayMap<>(); - // Maps a deviceId that is being monitored to the battery state for the device. - // This must be kept in sync with {@link #mListenerRecords}. + // Maps a deviceId that is being monitored to the monitor for the battery state of the device. @GuardedBy("mLock") - private final ArrayMap mMonitoredDeviceStates = new ArrayMap<>(); + private final ArrayMap mDeviceMonitors = new ArrayMap<>(); @GuardedBy("mLock") private boolean mIsPolling = false; @@ -93,9 +97,9 @@ final class BatteryController implements InputManager.InputDeviceListener { mUEventManager = uEventManager; } - void systemRunning() { + public void systemRunning() { Objects.requireNonNull(mContext.getSystemService(InputManager.class)) - .registerInputDeviceListener(this, mHandler); + .registerInputDeviceListener(mInputDeviceListener, mHandler); } /** @@ -103,7 +107,7 @@ final class BatteryController implements InputManager.InputDeviceListener { * state. */ @BinderThread - void registerBatteryListener(int deviceId, @NonNull IInputDeviceBatteryListener listener, + public void registerBatteryListener(int deviceId, @NonNull IInputDeviceBatteryListener listener, int pid) { synchronized (mLock) { ListenerRecord listenerRecord = mListenerRecords.get(pid); @@ -132,11 +136,11 @@ final class BatteryController implements InputManager.InputDeviceListener { + " is already monitoring deviceId " + deviceId); } - MonitoredDeviceState deviceState = mMonitoredDeviceStates.get(deviceId); - if (deviceState == null) { + DeviceMonitor monitor = mDeviceMonitors.get(deviceId); + if (monitor == null) { // This is the first listener that is monitoring this device. - deviceState = new MonitoredDeviceState(deviceId); - mMonitoredDeviceStates.put(deviceId, deviceState); + monitor = new DeviceMonitor(deviceId); + mDeviceMonitors.put(deviceId, monitor); } if (DEBUG) { @@ -145,37 +149,35 @@ final class BatteryController implements InputManager.InputDeviceListener { } updatePollingLocked(true /*delayStart*/); - notifyBatteryListener(listenerRecord, deviceState); + notifyBatteryListener(listenerRecord, monitor.getBatteryStateForReporting()); } } - private static void notifyBatteryListener(ListenerRecord listenerRecord, - MonitoredDeviceState deviceState) { + private static void notifyBatteryListener(ListenerRecord listenerRecord, State state) { try { - listenerRecord.mListener.onBatteryStateChanged( - new State(deviceState.mState)); + listenerRecord.mListener.onBatteryStateChanged(state); } catch (RemoteException e) { Slog.e(TAG, "Failed to notify listener", e); } if (DEBUG) { Slog.d(TAG, "Notified battery listener from pid " + listenerRecord.mPid - + " of state of deviceId " + deviceState.mState.deviceId); + + " of state of deviceId " + state.deviceId); } } @GuardedBy("mLock") - private void notifyAllListenersForDeviceLocked(MonitoredDeviceState deviceState) { - if (DEBUG) Slog.d(TAG, "Notifying all listeners of battery state: " + deviceState); + private void notifyAllListenersForDeviceLocked(State state) { + if (DEBUG) Slog.d(TAG, "Notifying all listeners of battery state: " + state); mListenerRecords.forEach((pid, listenerRecord) -> { - if (listenerRecord.mMonitoredDevices.contains(deviceState.mState.deviceId)) { - notifyBatteryListener(listenerRecord, deviceState); + if (listenerRecord.mMonitoredDevices.contains(state.deviceId)) { + notifyBatteryListener(listenerRecord, state); } }); } @GuardedBy("mLock") private void updatePollingLocked(boolean delayStart) { - if (mMonitoredDeviceStates.isEmpty() || !mIsInteractive) { + if (mDeviceMonitors.isEmpty() || !mIsInteractive) { // Stop polling. mIsPolling = false; mHandler.removeCallbacks(this::handlePollEvent); @@ -198,8 +200,8 @@ final class BatteryController implements InputManager.InputDeviceListener { } @GuardedBy("mLock") - private MonitoredDeviceState getDeviceStateOrThrowLocked(int deviceId) { - return Objects.requireNonNull(mMonitoredDeviceStates.get(deviceId), + private DeviceMonitor getDeviceMonitorOrThrowLocked(int deviceId) { + return Objects.requireNonNull(mDeviceMonitors.get(deviceId), "Maps are out of sync: Cannot find device state for deviceId " + deviceId); } @@ -209,8 +211,8 @@ final class BatteryController implements InputManager.InputDeviceListener { * removed. */ @BinderThread - void unregisterBatteryListener(int deviceId, @NonNull IInputDeviceBatteryListener listener, - int pid) { + public void unregisterBatteryListener(int deviceId, + @NonNull IInputDeviceBatteryListener listener, int pid) { synchronized (mLock) { final ListenerRecord listenerRecord = mListenerRecords.get(pid); if (listenerRecord == null) { @@ -249,9 +251,9 @@ final class BatteryController implements InputManager.InputDeviceListener { if (!hasRegisteredListenerForDeviceLocked(deviceId)) { // There are no more listeners monitoring this device. - final MonitoredDeviceState deviceState = getDeviceStateOrThrowLocked(deviceId); - deviceState.stopMonitoring(); - mMonitoredDeviceStates.remove(deviceId); + final DeviceMonitor monitor = getDeviceMonitorOrThrowLocked(deviceId); + monitor.stopMonitoring(); + mDeviceMonitors.remove(deviceId); } if (listenerRecord.mMonitoredDevices.isEmpty()) { @@ -290,15 +292,14 @@ final class BatteryController implements InputManager.InputDeviceListener { } } - // Query the battery state for the device and notify all listeners if there is a change. - private void handleBatteryChangeNotification(int deviceId, long eventTime) { + private void handleUEventNotification(int deviceId, long eventTime) { synchronized (mLock) { - final MonitoredDeviceState deviceState = mMonitoredDeviceStates.get(deviceId); - if (deviceState == null) { + final DeviceMonitor monitor = mDeviceMonitors.get(deviceId); + if (monitor == null) { return; } - if (deviceState.updateBatteryState(eventTime)) { - notifyAllListenersForDeviceLocked(deviceState); + if (monitor.updateBatteryState(eventTime)) { + notifyAllListenersForDeviceLocked(monitor.getBatteryStateForReporting()); } } } @@ -309,11 +310,11 @@ final class BatteryController implements InputManager.InputDeviceListener { return; } final long eventTime = SystemClock.uptimeMillis(); - mMonitoredDeviceStates.forEach((deviceId, deviceState) -> { + mDeviceMonitors.forEach((deviceId, monitor) -> { // Re-acquire lock in the lambda to silence error-prone build warnings. synchronized (mLock) { - if (deviceState.updateBatteryState(eventTime)) { - notifyAllListenersForDeviceLocked(deviceState); + if (monitor.updateBatteryState(eventTime)) { + notifyAllListenersForDeviceLocked(monitor.getBatteryStateForReporting()); } } }); @@ -322,31 +323,32 @@ final class BatteryController implements InputManager.InputDeviceListener { } /** Gets the current battery state of an input device. */ - IInputDeviceBatteryState getBatteryState(int deviceId) { + public IInputDeviceBatteryState getBatteryState(int deviceId) { synchronized (mLock) { final long updateTime = SystemClock.uptimeMillis(); - final MonitoredDeviceState deviceState = mMonitoredDeviceStates.get(deviceId); - if (deviceState == null) { + final DeviceMonitor monitor = mDeviceMonitors.get(deviceId); + if (monitor == null) { // The input device's battery is not being monitored by any listener. return queryBatteryStateFromNative(deviceId, updateTime); - } else { - // Force the battery state to update, and notify listeners if necessary. - if (deviceState.updateBatteryState(updateTime)) { - notifyAllListenersForDeviceLocked(deviceState); - } - return new State(deviceState.mState); } + // Force the battery state to update, and notify listeners if necessary. + final boolean stateChanged = monitor.updateBatteryState(updateTime); + final State state = monitor.getBatteryStateForReporting(); + if (stateChanged) { + notifyAllListenersForDeviceLocked(state); + } + return state; } } - void onInteractiveChanged(boolean interactive) { + public void onInteractiveChanged(boolean interactive) { synchronized (mLock) { mIsInteractive = interactive; updatePollingLocked(false /*delayStart*/); } } - void dump(PrintWriter pw, String prefix) { + public void dump(PrintWriter pw, String prefix) { synchronized (mLock) { final String indent = prefix + " "; final String indent2 = indent + " "; @@ -360,50 +362,50 @@ final class BatteryController implements InputManager.InputDeviceListener { pw.println(indent2 + i + ": " + mListenerRecords.valueAt(i)); } - pw.println(indent + "Monitored devices: " + mMonitoredDeviceStates.size() + " devices"); - for (int i = 0; i < mMonitoredDeviceStates.size(); i++) { - pw.println(indent2 + i + ": " + mMonitoredDeviceStates.valueAt(i)); + pw.println(indent + "Device Monitors: " + mDeviceMonitors.size() + " monitors"); + for (int i = 0; i < mDeviceMonitors.size(); i++) { + pw.println(indent2 + i + ": " + mDeviceMonitors.valueAt(i)); } } } @SuppressWarnings("all") - void monitor() { + public void monitor() { synchronized (mLock) { return; } } - @VisibleForTesting - @Override - public void onInputDeviceAdded(int deviceId) {} + private final InputManager.InputDeviceListener mInputDeviceListener = + new InputManager.InputDeviceListener() { + @Override + public void onInputDeviceAdded(int deviceId) {} - @VisibleForTesting - @Override - public void onInputDeviceRemoved(int deviceId) {} + @Override + public void onInputDeviceRemoved(int deviceId) {} - @VisibleForTesting - @Override - public void onInputDeviceChanged(int deviceId) { - synchronized (mLock) { - final MonitoredDeviceState deviceState = mMonitoredDeviceStates.get(deviceId); - if (deviceState == null) { - return; - } - final long eventTime = SystemClock.uptimeMillis(); - if (deviceState.updateBatteryState(eventTime)) { - notifyAllListenersForDeviceLocked(deviceState); + @Override + public void onInputDeviceChanged(int deviceId) { + synchronized (mLock) { + final DeviceMonitor monitor = mDeviceMonitors.get(deviceId); + if (monitor == null) { + return; + } + final long eventTime = SystemClock.uptimeMillis(); + if (monitor.updateBatteryState(eventTime)) { + notifyAllListenersForDeviceLocked(monitor.getBatteryStateForReporting()); + } } } - } + }; // A record of a registered battery listener from one process. private class ListenerRecord { - final int mPid; - final IInputDeviceBatteryListener mListener; - final IBinder.DeathRecipient mDeathRecipient; + public final int mPid; + public final IInputDeviceBatteryListener mListener; + public final IBinder.DeathRecipient mDeathRecipient; // The set of deviceIds that are currently being monitored by this listener. - final Set mMonitoredDevices; + public final Set mMonitoredDevices; ListenerRecord(int pid, IInputDeviceBatteryListener listener) { mPid = pid; @@ -431,14 +433,14 @@ final class BatteryController implements InputManager.InputDeviceListener { } // Holds the state of an InputDevice for which battery changes are currently being monitored. - private class MonitoredDeviceState { + private class DeviceMonitor { @NonNull private State mState; @Nullable private UEventListener mUEventListener; - MonitoredDeviceState(int deviceId) { + DeviceMonitor(int deviceId) { mState = new State(deviceId); // Load the initial battery state and start monitoring. @@ -447,7 +449,7 @@ final class BatteryController implements InputManager.InputDeviceListener { } // Returns true if the battery state changed since the last time it was updated. - boolean updateBatteryState(long updateTime) { + public boolean updateBatteryState(long updateTime) { mState.updateTime = updateTime; final State updatedState = queryBatteryStateFromNative(mState.deviceId, updateTime); @@ -470,23 +472,29 @@ final class BatteryController implements InputManager.InputDeviceListener { if (batteryPath == null) { return; } + final int deviceId = mState.deviceId; mUEventListener = new UEventListener() { @Override - void onUEvent(long eventTime) { - handleBatteryChangeNotification(mState.deviceId, eventTime); + public void onUEvent(long eventTime) { + handleUEventNotification(deviceId, eventTime); } }; mUEventManager.addListener(mUEventListener, "DEVPATH=" + batteryPath); } // This must be called when the device is no longer being monitored. - void stopMonitoring() { + public void stopMonitoring() { if (mUEventListener != null) { mUEventManager.removeListener(mUEventListener); mUEventListener = null; } } + // Returns the current battery state that can be used to notify listeners BatteryController. + public State getBatteryStateForReporting() { + return new State(mState); + } + @Override public String toString() { return "state=" + mState @@ -513,7 +521,7 @@ final class BatteryController implements InputManager.InputDeviceListener { } }; - abstract void onUEvent(long eventTime); + public abstract void onUEvent(long eventTime); } default void addListener(UEventListener listener, String match) {