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

Commit 67580353 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Checks that state requested from top app is a state we allow" into tm-dev

parents 320c2e66 7f986775
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -5778,4 +5778,7 @@
    <string name="safety_protection_display_text"></string>
    <string name="safety_protection_display_text"></string>


    <!-- End safety protection resources to be overlaid -->
    <!-- End safety protection resources to be overlaid -->

    <!-- List of the labels of requestable device state config values -->
    <string-array name="config_deviceStatesAvailableForAppRequests"/>
</resources>
</resources>
+1 −0
Original line number Original line Diff line number Diff line
@@ -4774,6 +4774,7 @@
  <java-symbol type="bool" name="config_bg_current_drain_high_threshold_by_bg_location" />
  <java-symbol type="bool" name="config_bg_current_drain_high_threshold_by_bg_location" />
  <java-symbol type="drawable" name="ic_swap_horiz" />
  <java-symbol type="drawable" name="ic_swap_horiz" />
  <java-symbol type="bool" name="config_notificationForceUserSetOnUpgrade" />
  <java-symbol type="bool" name="config_notificationForceUserSetOnUpgrade" />
  <java-symbol type="array" name="config_deviceStatesAvailableForAppRequests" />


  <!-- For app language picker -->
  <!-- For app language picker -->
  <java-symbol type="string" name="system_locale_title" />
  <java-symbol type="string" name="system_locale_title" />
+74 −8
Original line number Original line Diff line number Diff line
@@ -43,6 +43,7 @@ import android.os.ShellCallback;
import android.util.Slog;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseArray;


import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.DumpUtils;
@@ -59,7 +60,9 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Optional;
import java.util.Optional;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.WeakHashMap;


/**
/**
@@ -139,6 +142,8 @@ public final class DeviceStateManagerService extends SystemService {
    @GuardedBy("mLock")
    @GuardedBy("mLock")
    private final SparseArray<ProcessRecord> mProcessRecords = new SparseArray<>();
    private final SparseArray<ProcessRecord> mProcessRecords = new SparseArray<>();


    private Set<Integer> mDeviceStatesAvailableForAppRequests;

    public DeviceStateManagerService(@NonNull Context context) {
    public DeviceStateManagerService(@NonNull Context context) {
        this(context, DeviceStatePolicy.Provider
        this(context, DeviceStatePolicy.Provider
                .fromResources(context.getResources())
                .fromResources(context.getResources())
@@ -164,6 +169,10 @@ public final class DeviceStateManagerService extends SystemService {
    public void onStart() {
    public void onStart() {
        publishBinderService(Context.DEVICE_STATE_SERVICE, mBinderService);
        publishBinderService(Context.DEVICE_STATE_SERVICE, mBinderService);
        publishLocalService(DeviceStateManagerInternal.class, new LocalService());
        publishLocalService(DeviceStateManagerInternal.class, new LocalService());

        synchronized (mLock) {
            readStatesAvailableForRequestFromApps();
        }
    }
    }


    @VisibleForTesting
    @VisibleForTesting
@@ -626,21 +635,78 @@ public final class DeviceStateManagerService extends SystemService {


    /**
    /**
     * Allow top processes to request or cancel a device state change. If the calling process ID is
     * Allow top processes to request or cancel a device state change. If the calling process ID is
     * not the top app, then check if this process holds the
     * {@link android.Manifest.permission.CONTROL_DEVICE_STATE} permission. If the calling process
     * is the top app, check to verify they are requesting a state we've deemed to be able to be
     * available for an app process to request. States that can be requested are based around
     * features that we've created that require specific device state overrides.
     * @param callingPid Process ID that is requesting this state change
     * @param state state that is being requested.
     */
    private void assertCanRequestDeviceState(int callingPid, int state) {
        final WindowProcessController topApp = mActivityTaskManagerInternal.getTopApp();
        if (topApp == null || topApp.getPid() != callingPid
                || !isStateAvailableForAppRequests(state)) {
            getContext().enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE,
                    "Permission required to request device state, "
                            + "or the call must come from the top app "
                            + "and be a device state that is available for apps to request.");
        }
    }

    /**
     * Checks if the process can control the device state. If the calling process ID is
     * not the top app, then check if this process holds the CONTROL_DEVICE_STATE permission.
     * not the top app, then check if this process holds the CONTROL_DEVICE_STATE permission.
     * @param callingPid
     *
     * @param callingPid Process ID that is requesting this state change
     */
     */
    private void checkCanControlDeviceState(int callingPid) {
    private void assertCanControlDeviceState(int callingPid) {
        // Allow top processes to request a device state change
        // If the calling process ID is not the top app, then we check if this process
        // holds a permission to CONTROL_DEVICE_STATE
        final WindowProcessController topApp = mActivityTaskManagerInternal.getTopApp();
        final WindowProcessController topApp = mActivityTaskManagerInternal.getTopApp();
        if (topApp == null || topApp.getPid() != callingPid) {
        if (topApp == null || topApp.getPid() != callingPid) {
            getContext().enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE,
            getContext().enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE,
                    "Permission required to request device state, "
                    "Permission required to request device state, "
                            + "or the call must come from the top focused app.");
                            + "or the call must come from the top app.");
        }
        }
    }
    }


    private boolean isStateAvailableForAppRequests(int state) {
        synchronized (mLock) {
            return mDeviceStatesAvailableForAppRequests.contains(state);
        }
    }

    /**
     * Adds device state values that are available to be requested by the top level app.
     */
    @GuardedBy("mLock")
    private void readStatesAvailableForRequestFromApps() {
        mDeviceStatesAvailableForAppRequests = new HashSet<>();
        String[] availableAppStatesConfigIdentifiers = getContext().getResources()
                .getStringArray(R.array.config_deviceStatesAvailableForAppRequests);
        for (int i = 0; i < availableAppStatesConfigIdentifiers.length; i++) {
            String identifierToFetch = availableAppStatesConfigIdentifiers[i];
            int configValueIdentifier = getContext().getResources()
                    .getIdentifier(identifierToFetch, "integer", "android");
            int state = getContext().getResources().getInteger(configValueIdentifier);
            if (isValidState(state)) {
                mDeviceStatesAvailableForAppRequests.add(state);
            } else {
                Slog.e(TAG, "Invalid device state was found in the configuration file. State id: "
                        + state);
            }
        }
    }

    @GuardedBy("mLock")
    private boolean isValidState(int state) {
        for (int i = 0; i < mDeviceStates.size(); i++) {
            if (state == mDeviceStates.valueAt(i).getIdentifier()) {
                return true;
            }
        }
        return false;
    }

    private final class DeviceStateProviderListener implements DeviceStateProvider.Listener {
    private final class DeviceStateProviderListener implements DeviceStateProvider.Listener {
        @Override
        @Override
        public void onSupportedDeviceStatesChanged(DeviceState[] newDeviceStates) {
        public void onSupportedDeviceStatesChanged(DeviceState[] newDeviceStates) {
@@ -777,7 +843,7 @@ public final class DeviceStateManagerService extends SystemService {
            // Allow top processes to request a device state change
            // Allow top processes to request a device state change
            // If the calling process ID is not the top app, then we check if this process
            // If the calling process ID is not the top app, then we check if this process
            // holds a permission to CONTROL_DEVICE_STATE
            // holds a permission to CONTROL_DEVICE_STATE
            checkCanControlDeviceState(callingPid);
            assertCanRequestDeviceState(callingPid, state);


            if (token == null) {
            if (token == null) {
                throw new IllegalArgumentException("Request token must not be null.");
                throw new IllegalArgumentException("Request token must not be null.");
@@ -797,7 +863,7 @@ public final class DeviceStateManagerService extends SystemService {
            // Allow top processes to cancel a device state change
            // Allow top processes to cancel a device state change
            // If the calling process ID is not the top app, then we check if this process
            // If the calling process ID is not the top app, then we check if this process
            // holds a permission to CONTROL_DEVICE_STATE
            // holds a permission to CONTROL_DEVICE_STATE
            checkCanControlDeviceState(callingPid);
            assertCanControlDeviceState(callingPid);


            final long callingIdentity = Binder.clearCallingIdentity();
            final long callingIdentity = Binder.clearCallingIdentity();
            try {
            try {