Don't report device state until hardware state is known.

The previous implementation of DeviceStateProviderImpl would report the
current device state as soon as a listener was registered leading to a
series of device state changes on boot as the state of the hardware
becomes known. This changes the implementation to await callbacks before
notifying the listener of a change in device state.

Fixes: 181671216
Test: atest DeviceStateProviderImplTest
Test: atest DeviceStateManagerServiceTest
Test: atest DeviceStateManagerGlobalTest

Change-Id: I3f133b6d7135b829b79c9f225ae52c71061faa3e
This commit is contained in:
Darryl L Johnson
2021-03-08 08:38:57 -08:00
parent 5efdaa632b
commit 090b0afb1b
8 changed files with 172 additions and 106 deletions

View File

@@ -179,8 +179,6 @@ public final class DeviceStateManagerGlobal {
@VisibleForTesting(visibility = Visibility.PACKAGE)
public void registerDeviceStateCallback(@NonNull DeviceStateCallback callback,
@NonNull Executor executor) {
DeviceStateCallbackWrapper wrapper;
DeviceStateInfo currentInfo;
synchronized (mLock) {
int index = findCallbackLocked(callback);
if (index != -1) {
@@ -189,25 +187,22 @@ public final class DeviceStateManagerGlobal {
}
registerCallbackIfNeededLocked();
if (mLastReceivedInfo == null) {
// Initialize the last received info with the current info if this is the first
// callback being registered.
try {
mLastReceivedInfo = mDeviceStateManager.getDeviceStateInfo();
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
currentInfo = new DeviceStateInfo(mLastReceivedInfo);
wrapper = new DeviceStateCallbackWrapper(callback, executor);
// Add the callback wrapper to the mCallbacks array after registering the callback as
// the callback could be triggered immediately if the mDeviceStateManager IBinder is in
// the same process as this instance.
DeviceStateCallbackWrapper wrapper = new DeviceStateCallbackWrapper(callback, executor);
mCallbacks.add(wrapper);
}
wrapper.notifySupportedStatesChanged(currentInfo.supportedStates);
wrapper.notifyBaseStateChanged(currentInfo.baseState);
wrapper.notifyStateChanged(currentInfo.currentState);
if (mLastReceivedInfo != null) {
// Copy the array to prevent the callback from modifying the internal state.
final int[] supportedStates = Arrays.copyOf(mLastReceivedInfo.supportedStates,
mLastReceivedInfo.supportedStates.length);
wrapper.notifySupportedStatesChanged(supportedStates);
wrapper.notifyBaseStateChanged(mLastReceivedInfo.baseState);
wrapper.notifyStateChanged(mLastReceivedInfo.currentState);
}
}
}
/**
@@ -267,7 +262,7 @@ public final class DeviceStateManagerGlobal {
callbacks = new ArrayList<>(mCallbacks);
}
final int diff = oldInfo == null ? 1 : info.diff(oldInfo);
final int diff = oldInfo == null ? ~0 : info.diff(oldInfo);
if ((diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES) > 0) {
for (int i = 0; i < callbacks.size(); i++) {
// Copy the array to prevent callbacks from modifying the internal state.

View File

@@ -21,7 +21,8 @@ import android.hardware.devicestate.DeviceStateInfo;
/** @hide */
interface IDeviceStateManagerCallback {
/**
* Called in response to a change in {@link DeviceStateInfo}.
* Called in response to a change in {@link DeviceStateInfo}. Guaranteed to be called once
* after successful registration of the callback with the initial value.
*
* @param info the new device state info.
*