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

Commit 287a3a7b authored by Robert Horvath's avatar Robert Horvath
Browse files

Allowlist active voice interaction session from Low Power Standby

If a voice interaction session is started, then it should be allowed to
use the network & wakelocks unrestricted while it is ongoing, since it
is direct user interaction.

Bug: 190822356
Test: atest LowPowerStandbyControllerTest PowerManagerServiceTest
Test: With reference VIS: adb shell cmd voiceinteraction show
      To verify allowlist/wakelock state: adb shell dumpsys power
Change-Id: I63cd0cf2e97b574ba8fa6c6caa8f046cce2bb821
parent 57064556
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -184,6 +184,13 @@ public abstract class PowerManagerInternal {

    public abstract void setDeviceIdleTempWhitelist(int[] appids);

    /**
     * Updates the Low Power Standby allowlist.
     *
     * @param uids UIDs that are exempt from Low Power Standby restrictions
     */
    public abstract void setLowPowerStandbyAllowlist(int[] uids);

    /**
     * Used by LowPowerStandbyController to notify the power manager that Low Power Standby's
     * active state has changed.
+4 −1
Original line number Diff line number Diff line
@@ -461,5 +461,8 @@ message LowPowerStandbyControllerDumpProto {
    // True if the device is currently in idle mode
    optional int32 is_device_idle = 9;

    // Next tag: 10
    // Set of app ids that are exempt form low power standby
    repeated int32 allowlist = 10;

    // Next tag: 11
}
+78 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.util.IndentingPrintWriter;
import android.util.Slog;
import android.util.SparseBooleanArray;
import android.util.proto.ProtoOutputStream;

import com.android.internal.R;
@@ -43,6 +44,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.server.LocalServices;

import java.io.PrintWriter;
import java.util.Arrays;

/**
 * Controls Low Power Standby state.
@@ -71,6 +73,7 @@ public final class LowPowerStandbyController {

    private static final int MSG_STANDBY_TIMEOUT = 0;
    private static final int MSG_NOTIFY_ACTIVE_CHANGED = 1;
    private static final int MSG_NOTIFY_ALLOWLIST_CHANGED = 2;

    private final Handler mHandler;
    private final SettingsObserver mSettingsObserver;
@@ -80,6 +83,8 @@ public final class LowPowerStandbyController {
    private final Clock mClock;
    private final AlarmManager.OnAlarmListener mOnStandbyTimeoutExpired =
            this::onStandbyTimeoutExpired;
    private final LowPowerStandbyControllerInternal mLocalService = new LocalService();
    private final SparseBooleanArray mAllowlistUids = new SparseBooleanArray();

    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
@@ -187,6 +192,8 @@ public final class LowPowerStandbyController {
                registerBroadcastReceiver();
            }
        }

        LocalServices.addService(LowPowerStandbyControllerInternal.class, mLocalService);
    }

    @GuardedBy("mLock")
@@ -431,6 +438,10 @@ public final class LowPowerStandbyController {
                ipw.print("mIsDeviceIdle=");
                ipw.println(mIsDeviceIdle);
            }

            final int[] allowlistUids = getAllowlistUidsLocked();
            ipw.print("mAllowlistUids=");
            ipw.println(Arrays.toString(allowlistUids));
        }
        ipw.decreaseIndent();
    }
@@ -452,6 +463,11 @@ public final class LowPowerStandbyController {
                    mIdleSinceNonInteractive);
            proto.write(LowPowerStandbyControllerDumpProto.IS_DEVICE_IDLE, mIsDeviceIdle);

            final int[] allowlistUids = getAllowlistUidsLocked();
            for (int appId : allowlistUids) {
                proto.write(LowPowerStandbyControllerDumpProto.ALLOWLIST, appId);
            }

            proto.end(token);
        }
    }
@@ -471,10 +487,72 @@ public final class LowPowerStandbyController {
                    boolean active = (boolean) msg.obj;
                    notifyActiveChanged(active);
                    break;
                case MSG_NOTIFY_ALLOWLIST_CHANGED:
                    final int[] allowlistUids = (int[]) msg.obj;
                    notifyAllowlistChanged(allowlistUids);
                    break;
            }
        }
    }

    private void addToAllowlistInternal(int uid) {
        if (DEBUG) {
            Slog.i(TAG, "Adding to allowlist: " + uid);
        }
        synchronized (mLock) {
            if (mSupportedConfig && !mAllowlistUids.get(uid)) {
                mAllowlistUids.append(uid, true);
                enqueueNotifyAllowlistChangedLocked();
            }
        }
    }

    private void removeFromAllowlistInternal(int uid) {
        if (DEBUG) {
            Slog.i(TAG, "Removing from allowlist: " + uid);
        }
        synchronized (mLock) {
            if (mSupportedConfig && mAllowlistUids.get(uid)) {
                mAllowlistUids.delete(uid);
                enqueueNotifyAllowlistChangedLocked();
            }
        }
    }

    @GuardedBy("mLock")
    private int[] getAllowlistUidsLocked() {
        final int[] uids = new int[mAllowlistUids.size()];
        for (int i = 0; i < mAllowlistUids.size(); i++) {
            uids[i] = mAllowlistUids.keyAt(i);
        }
        return uids;
    }

    @GuardedBy("mLock")
    private void enqueueNotifyAllowlistChangedLocked() {
        final long now = mClock.elapsedRealtime();
        final int[] allowlistUids = getAllowlistUidsLocked();
        final Message msg = mHandler.obtainMessage(MSG_NOTIFY_ALLOWLIST_CHANGED, allowlistUids);
        mHandler.sendMessageAtTime(msg, now);
    }

    private void notifyAllowlistChanged(int[] allowlistUids) {
        final PowerManagerInternal pmi = LocalServices.getService(PowerManagerInternal.class);
        pmi.setLowPowerStandbyAllowlist(allowlistUids);
    }

    private final class LocalService extends LowPowerStandbyControllerInternal {
        @Override
        public void addToAllowlist(int uid) {
            addToAllowlistInternal(uid);
        }

        @Override
        public void removeFromAllowlist(int uid) {
            removeFromAllowlistInternal(uid);
        }
    }

    private final class SettingsObserver extends ContentObserver {
        SettingsObserver(Handler handler) {
            super(handler);
+37 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.power;

/**
 * @hide Only for use within the system server.
 */
public abstract class LowPowerStandbyControllerInternal {
    /**
     * Adds an application to the Low Power Standby allowlist,
     * exempting it from Low Power Standby restrictions.
     *
     * @param uid UID to add to allowlist.
     */
    public abstract void addToAllowlist(int uid);

    /**
     * Removes an application from the Low Power Standby allowlist.
     *
     * @param uid UID to remove from allowlist.
     */
    public abstract void removeFromAllowlist(int uid);
}
+19 −1
Original line number Diff line number Diff line
@@ -617,6 +617,9 @@ public final class PowerManagerService extends SystemService
    // Set of app ids that are temporarily allowed to acquire wakelocks due to high-pri message
    int[] mDeviceIdleTempWhitelist = new int[0];

    // Set of app ids that are allowed to acquire wakelocks while low power standby is active
    int[] mLowPowerStandbyAllowlist = new int[0];

    private boolean mLowPowerStandbyActive;

    private final SparseArray<UidState> mUidState = new SparseArray<>();
@@ -3874,6 +3877,15 @@ public final class PowerManagerService extends SystemService
        }
    }

    void setLowPowerStandbyAllowlistInternal(int[] appids) {
        synchronized (mLock) {
            mLowPowerStandbyAllowlist = appids;
            if (mLowPowerStandbyActive) {
                updateWakeLockDisabledStatesLocked();
            }
        }
    }

    void setLowPowerStandbyActiveInternal(boolean active) {
        synchronized (mLock) {
            if (mLowPowerStandbyActive != active) {
@@ -4026,7 +4038,8 @@ public final class PowerManagerService extends SystemService
                }
                if (mLowPowerStandbyActive) {
                    final UidState state = wakeLock.mUidState;
                    if (state.mProcState != ActivityManager.PROCESS_STATE_NONEXISTENT
                    if (Arrays.binarySearch(mLowPowerStandbyAllowlist, appid) < 0
                            && state.mProcState != ActivityManager.PROCESS_STATE_NONEXISTENT
                            && state.mProcState > ActivityManager.PROCESS_STATE_BOUND_TOP) {
                        disabled = true;
                    }
@@ -6350,6 +6363,11 @@ public final class PowerManagerService extends SystemService
            setDeviceIdleTempWhitelistInternal(appids);
        }

        @Override
        public void setLowPowerStandbyAllowlist(int[] appids) {
            setLowPowerStandbyAllowlistInternal(appids);
        }

        @Override
        public void setLowPowerStandbyActive(boolean enabled) {
            setLowPowerStandbyActiveInternal(enabled);
Loading