Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b87e44ce authored by Darryl Johnson's avatar Darryl Johnson Committed by Android (Google) Code Review
Browse files

Merge "Don't report device state until hardware state is known." into sc-dev

parents b92a4f2f 090b0afb
Loading
Loading
Loading
Loading
+14 −19
Original line number Original line Diff line number Diff line
@@ -179,8 +179,6 @@ public final class DeviceStateManagerGlobal {
    @VisibleForTesting(visibility = Visibility.PACKAGE)
    @VisibleForTesting(visibility = Visibility.PACKAGE)
    public void registerDeviceStateCallback(@NonNull DeviceStateCallback callback,
    public void registerDeviceStateCallback(@NonNull DeviceStateCallback callback,
            @NonNull Executor executor) {
            @NonNull Executor executor) {
        DeviceStateCallbackWrapper wrapper;
        DeviceStateInfo currentInfo;
        synchronized (mLock) {
        synchronized (mLock) {
            int index = findCallbackLocked(callback);
            int index = findCallbackLocked(callback);
            if (index != -1) {
            if (index != -1) {
@@ -189,25 +187,22 @@ public final class DeviceStateManagerGlobal {
            }
            }


            registerCallbackIfNeededLocked();
            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);
            // 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
            wrapper = new DeviceStateCallbackWrapper(callback, executor);
            // the same process as this instance.
            DeviceStateCallbackWrapper wrapper = new DeviceStateCallbackWrapper(callback, executor);
            mCallbacks.add(wrapper);
            mCallbacks.add(wrapper);
        }


        wrapper.notifySupportedStatesChanged(currentInfo.supportedStates);
            if (mLastReceivedInfo != null) {
        wrapper.notifyBaseStateChanged(currentInfo.baseState);
                // Copy the array to prevent the callback from modifying the internal state.
        wrapper.notifyStateChanged(currentInfo.currentState);
                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);
            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) {
        if ((diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES) > 0) {
            for (int i = 0; i < callbacks.size(); i++) {
            for (int i = 0; i < callbacks.size(); i++) {
                // Copy the array to prevent callbacks from modifying the internal state.
                // Copy the array to prevent callbacks from modifying the internal state.
+2 −1
Original line number Original line Diff line number Diff line
@@ -21,7 +21,8 @@ import android.hardware.devicestate.DeviceStateInfo;
/** @hide */
/** @hide */
interface IDeviceStateManagerCallback {
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.
     * @param info the new device state info.
     *
     *
+5 −0
Original line number Original line Diff line number Diff line
@@ -208,6 +208,11 @@ public final class DeviceStateManagerGlobalTest {
            }
            }


            mCallbacks.add(callback);
            mCallbacks.add(callback);
            try {
                callback.onDeviceStateInfoChanged(getInfo());
            } catch (RemoteException e) {
                // Do nothing. Should never happen.
            }
        }
        }


        @Override
        @Override
+47 −22
Original line number Original line Diff line number Diff line
@@ -78,9 +78,6 @@ import java.util.Optional;
public final class DeviceStateManagerService extends SystemService {
public final class DeviceStateManagerService extends SystemService {
    private static final String TAG = "DeviceStateManagerService";
    private static final String TAG = "DeviceStateManagerService";
    private static final boolean DEBUG = false;
    private static final boolean DEBUG = false;
    // The device state to use as a placeholder before callback from the DeviceStateProvider occurs.
    private static final DeviceState UNSPECIFIED_DEVICE_STATE =
            new DeviceState(MINIMUM_DEVICE_STATE, "UNSPECIFIED");


    private final Object mLock = new Object();
    private final Object mLock = new Object();
    @NonNull
    @NonNull
@@ -92,11 +89,11 @@ public final class DeviceStateManagerService extends SystemService {
    @GuardedBy("mLock")
    @GuardedBy("mLock")
    private SparseArray<DeviceState> mDeviceStates = new SparseArray<>();
    private SparseArray<DeviceState> mDeviceStates = new SparseArray<>();


    // The current committed device state. The default of UNSPECIFIED_DEVICE_STATE will be replaced
    // The current committed device state. Will be empty until the first device state provided by
    // by the current state after the initial callback from the DeviceStateProvider.
    // the DeviceStateProvider is committed.
    @GuardedBy("mLock")
    @GuardedBy("mLock")
    @NonNull
    @NonNull
    private DeviceState mCommittedState = UNSPECIFIED_DEVICE_STATE;
    private Optional<DeviceState> mCommittedState = Optional.empty();
    // The device state that is currently awaiting callback from the policy to be committed.
    // The device state that is currently awaiting callback from the policy to be committed.
    @GuardedBy("mLock")
    @GuardedBy("mLock")
    @NonNull
    @NonNull
@@ -105,10 +102,11 @@ public final class DeviceStateManagerService extends SystemService {
    @GuardedBy("mLock")
    @GuardedBy("mLock")
    private boolean mIsPolicyWaitingForState = false;
    private boolean mIsPolicyWaitingForState = false;


    // The device state that is set by the device state provider.
    // The device state that is set by the DeviceStateProvider. Will be empty until the first
    // callback from the provider and then will always contain the most recent value.
    @GuardedBy("mLock")
    @GuardedBy("mLock")
    @NonNull
    @NonNull
    private DeviceState mBaseState = UNSPECIFIED_DEVICE_STATE;
    private Optional<DeviceState> mBaseState = Optional.empty();


    // List of processes registered to receive notifications about changes to device state and
    // List of processes registered to receive notifications about changes to device state and
    // request status indexed by process id.
    // request status indexed by process id.
@@ -142,11 +140,14 @@ public final class DeviceStateManagerService extends SystemService {
    /**
    /**
     * Returns the current state the system is in. Note that the system may be in the process of
     * Returns the current state the system is in. Note that the system may be in the process of
     * configuring a different state.
     * configuring a different state.
     * <p>
     * Note: This method will return {@link Optional#empty()} if called before the first state has
     * been committed, otherwise it will return the last committed state.
     *
     *
     * @see #getPendingState()
     * @see #getPendingState()
     */
     */
    @NonNull
    @NonNull
    DeviceState getCommittedState() {
    Optional<DeviceState> getCommittedState() {
        synchronized (mLock) {
        synchronized (mLock) {
            return mCommittedState;
            return mCommittedState;
        }
        }
@@ -167,11 +168,15 @@ public final class DeviceStateManagerService extends SystemService {
    /**
    /**
     * Returns the base state. The service will configure the device to match the base state when
     * Returns the base state. The service will configure the device to match the base state when
     * there is no active request to override the base state.
     * there is no active request to override the base state.
     * <p>
     * Note: This method will return {@link Optional#empty()} if called before a base state is
     * provided to the service by the {@link DeviceStateProvider}, otherwise it will return the
     * most recent provided value.
     *
     *
     * @see #getOverrideState()
     * @see #getOverrideState()
     */
     */
    @NonNull
    @NonNull
    DeviceState getBaseState() {
    Optional<DeviceState> getBaseState() {
        synchronized (mLock) {
        synchronized (mLock) {
            return mBaseState;
            return mBaseState;
        }
        }
@@ -223,9 +228,14 @@ public final class DeviceStateManagerService extends SystemService {


    @NonNull
    @NonNull
    private DeviceStateInfo getDeviceStateInfoLocked() {
    private DeviceStateInfo getDeviceStateInfoLocked() {
        if (!mBaseState.isPresent() || !mCommittedState.isPresent()) {
            throw new IllegalStateException("Trying to get the current DeviceStateInfo before the"
                    + " initial state has been committed.");
        }

        final int[] supportedStates = getSupportedStateIdentifiersLocked();
        final int[] supportedStates = getSupportedStateIdentifiersLocked();
        final int baseState = mBaseState.getIdentifier();
        final int baseState = mBaseState.get().getIdentifier();
        final int currentState = mCommittedState.getIdentifier();
        final int currentState = mCommittedState.get().getIdentifier();


        return new DeviceStateInfo(supportedStates, baseState, currentState);
        return new DeviceStateInfo(supportedStates, baseState, currentState);
    }
    }
@@ -237,6 +247,7 @@ public final class DeviceStateManagerService extends SystemService {


    private void updateSupportedStates(DeviceState[] supportedDeviceStates) {
    private void updateSupportedStates(DeviceState[] supportedDeviceStates) {
        boolean updatedPendingState;
        boolean updatedPendingState;
        boolean hasBaseState;
        synchronized (mLock) {
        synchronized (mLock) {
            final int[] oldStateIdentifiers = getSupportedStateIdentifiersLocked();
            final int[] oldStateIdentifiers = getSupportedStateIdentifiersLocked();


@@ -260,9 +271,10 @@ public final class DeviceStateManagerService extends SystemService {
            }
            }


            updatedPendingState = updatePendingStateLocked();
            updatedPendingState = updatePendingStateLocked();
            hasBaseState = mBaseState.isPresent();
        }
        }


        if (!updatedPendingState) {
        if (hasBaseState && !updatedPendingState) {
            // If the change in the supported states didn't result in a change of the pending state
            // If the change in the supported states didn't result in a change of the pending state
            // commitPendingState() will never be called and the callbacks will never be notified
            // commitPendingState() will never be called and the callbacks will never be notified
            // of the change.
            // of the change.
@@ -306,11 +318,11 @@ public final class DeviceStateManagerService extends SystemService {
            }
            }


            final DeviceState baseState = baseStateOptional.get();
            final DeviceState baseState = baseStateOptional.get();
            if (mBaseState.equals(baseState)) {
            if (mBaseState.isPresent() && mBaseState.get().equals(baseState)) {
                // Base state hasn't changed. Nothing to do.
                // Base state hasn't changed. Nothing to do.
                return;
                return;
            }
            }
            mBaseState = baseState;
            mBaseState = Optional.of(baseState);


            final int requestSize = mRequestRecords.size();
            final int requestSize = mRequestRecords.size();
            for (int i = 0; i < requestSize; i++) {
            for (int i = 0; i < requestSize; i++) {
@@ -351,9 +363,10 @@ public final class DeviceStateManagerService extends SystemService {
        final DeviceState stateToConfigure;
        final DeviceState stateToConfigure;
        if (!mRequestRecords.isEmpty()) {
        if (!mRequestRecords.isEmpty()) {
            stateToConfigure = mRequestRecords.get(mRequestRecords.size() - 1).mRequestedState;
            stateToConfigure = mRequestRecords.get(mRequestRecords.size() - 1).mRequestedState;
        } else if (isSupportedStateLocked(mBaseState.getIdentifier())) {
        } else if (mBaseState.isPresent()
                && isSupportedStateLocked(mBaseState.get().getIdentifier())) {
            // Base state could have recently become unsupported after a change in supported states.
            // Base state could have recently become unsupported after a change in supported states.
            stateToConfigure = mBaseState;
            stateToConfigure = mBaseState.get();
        } else {
        } else {
            stateToConfigure = null;
            stateToConfigure = null;
        }
        }
@@ -363,7 +376,7 @@ public final class DeviceStateManagerService extends SystemService {
            return false;
            return false;
        }
        }


        if (stateToConfigure.equals(mCommittedState)) {
        if (mCommittedState.isPresent() && stateToConfigure.equals(mCommittedState.get())) {
            // The state requesting to be committed already matches the current committed state.
            // The state requesting to be committed already matches the current committed state.
            return false;
            return false;
        }
        }
@@ -417,15 +430,15 @@ public final class DeviceStateManagerService extends SystemService {
    private void commitPendingState() {
    private void commitPendingState() {
        // Update the current state.
        // Update the current state.
        synchronized (mLock) {
        synchronized (mLock) {
            final DeviceState newState = mPendingState.get();
            if (DEBUG) {
            if (DEBUG) {
                Slog.d(TAG, "Committing state: " + mPendingState);
                Slog.d(TAG, "Committing state: " + newState);
            }
            }
            mCommittedState = mPendingState.get();


            if (!mRequestRecords.isEmpty()) {
            if (!mRequestRecords.isEmpty()) {
                final OverrideRequestRecord topRequest =
                final OverrideRequestRecord topRequest =
                        mRequestRecords.get(mRequestRecords.size() - 1);
                        mRequestRecords.get(mRequestRecords.size() - 1);
                if (topRequest.mRequestedState.getIdentifier() == mCommittedState.getIdentifier()) {
                if (topRequest.mRequestedState.getIdentifier() == newState.getIdentifier()) {
                    // The top request could have come in while the service was awaiting callback
                    // The top request could have come in while the service was awaiting callback
                    // from the policy. In that case we only set it to active if it matches the
                    // from the policy. In that case we only set it to active if it matches the
                    // current committed state, otherwise it will be set to active when its
                    // current committed state, otherwise it will be set to active when its
@@ -434,6 +447,7 @@ public final class DeviceStateManagerService extends SystemService {
                }
                }
            }
            }


            mCommittedState = Optional.of(newState);
            mPendingState = Optional.empty();
            mPendingState = Optional.empty();
            updatePendingStateLocked();
            updatePendingStateLocked();
        }
        }
@@ -503,19 +517,30 @@ public final class DeviceStateManagerService extends SystemService {
    }
    }


    private void registerProcess(int pid, IDeviceStateManagerCallback callback) {
    private void registerProcess(int pid, IDeviceStateManagerCallback callback) {
        DeviceStateInfo currentInfo;
        ProcessRecord record;
        // Grab the lock to register the callback and get the current state.
        synchronized (mLock) {
        synchronized (mLock) {
            if (mProcessRecords.contains(pid)) {
            if (mProcessRecords.contains(pid)) {
                throw new SecurityException("The calling process has already registered an"
                throw new SecurityException("The calling process has already registered an"
                        + " IDeviceStateManagerCallback.");
                        + " IDeviceStateManagerCallback.");
            }
            }


            ProcessRecord record = new ProcessRecord(callback, pid);
            record = new ProcessRecord(callback, pid);
            try {
            try {
                callback.asBinder().linkToDeath(record, 0);
                callback.asBinder().linkToDeath(record, 0);
            } catch (RemoteException ex) {
            } catch (RemoteException ex) {
                throw new RuntimeException(ex);
                throw new RuntimeException(ex);
            }
            }
            mProcessRecords.put(pid, record);
            mProcessRecords.put(pid, record);

            currentInfo = mCommittedState.isPresent() ? getDeviceStateInfoLocked() : null;
        }

        if (currentInfo != null) {
            // If there is not a committed state we'll wait to notify the process of the initial
            // value.
            record.notifyDeviceStateInfoAsync(currentInfo);
        }
        }
    }
    }


+9 −4
Original line number Original line Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.devicestate;


import static android.Manifest.permission.CONTROL_DEVICE_STATE;
import static android.Manifest.permission.CONTROL_DEVICE_STATE;


import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.content.Context;
import android.content.Context;
import android.hardware.devicestate.DeviceStateManager;
import android.hardware.devicestate.DeviceStateManager;
@@ -63,14 +64,14 @@ public class DeviceStateManagerShellCommand extends ShellCommand {
    }
    }


    private void printState(PrintWriter pw) {
    private void printState(PrintWriter pw) {
        DeviceState committedState = mService.getCommittedState();
        Optional<DeviceState> committedState = mService.getCommittedState();
        DeviceState baseState = mService.getBaseState();
        Optional<DeviceState> baseState = mService.getBaseState();
        Optional<DeviceState> overrideState = mService.getOverrideState();
        Optional<DeviceState> overrideState = mService.getOverrideState();


        pw.println("Committed state: " + committedState);
        pw.println("Committed state: " + toString(committedState));
        if (overrideState.isPresent()) {
        if (overrideState.isPresent()) {
            pw.println("----------------------");
            pw.println("----------------------");
            pw.println("Base state: " + baseState);
            pw.println("Base state: " + toString(baseState));
            pw.println("Override state: " + overrideState.get());
            pw.println("Override state: " + overrideState.get());
        }
        }
    }
    }
@@ -143,4 +144,8 @@ public class DeviceStateManagerShellCommand extends ShellCommand {
        pw.println("  print-states");
        pw.println("  print-states");
        pw.println("    Return list of currently supported device states.");
        pw.println("    Return list of currently supported device states.");
    }
    }

    private static String toString(@NonNull Optional<DeviceState> state) {
        return state.isPresent() ? state.get().toString() : "(none)";
    }
}
}
Loading