Rename MonitoredDeviceState to DeviceMonitor

Also:
- Don't make InputDevicesChangedListener part of the BatteryController
  interface, since it's not used for testing.
- Report a copy of the battery state when notifying components outside
  of BatteryController, becuase reporting a member object would
  leak the internal state to other components.
- Explicitly mark all interface methods as public.

Bug: 243005009
Test: atest FrameworkServicesTests
Test: atest FrameworkCoreTests

Change-Id: Iefa08f4f1b52b8dd48dc273e90e90c92d15d4ed4
This commit is contained in:
Prabir Pradhan
2022-09-13 21:04:39 +00:00
parent 8605f83e28
commit b92ff23bd8

View File

@@ -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<Integer, ListenerRecord> 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<Integer, MonitoredDeviceState> mMonitoredDeviceStates = new ArrayMap<>();
private final ArrayMap<Integer, DeviceMonitor> 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<Integer> mMonitoredDevices;
public final Set<Integer> 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) {