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

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

Merge "Ability to grant apps in app idle mode network."

parents c74e1a67 a9e55bcc
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ public class NetworkPolicyLogger {
    private static final int EVENT_UID_FIREWALL_RULE_CHANGED = 11;
    private static final int EVENT_FIREWALL_CHAIN_ENABLED = 12;
    private static final int EVENT_UPDATE_METERED_RESTRICTED_PKGS = 13;
    private static final int EVENT_APP_IDLE_WL_CHANGED = 14;

    static final int NTWK_BLOCKED_POWER = 0;
    static final int NTWK_ALLOWED_NON_METERED = 1;
@@ -145,6 +146,13 @@ public class NetworkPolicyLogger {
        }
    }

    void appIdleWlChanged(int uid, boolean isWhitelisted) {
        synchronized (mLock) {
            if (LOGD) Slog.d(TAG, getAppIdleWlChangedLog(uid, isWhitelisted));
            mEventsBuffer.appIdleWlChanged(uid, isWhitelisted);
        }
    }

    void paroleStateChanged(boolean paroleOn) {
        synchronized (mLock) {
            if (LOGD) Slog.d(TAG, getParoleStateChanged(paroleOn));
@@ -259,6 +267,10 @@ public class NetworkPolicyLogger {
        return "App idle state of uid " + uid + ": " + idle;
    }

    private static String getAppIdleWlChangedLog(int uid, boolean isWhitelisted) {
        return "App idle whitelist state of uid " + uid + ": " + isWhitelisted;
    }

    private static String getParoleStateChanged(boolean paroleOn) {
        return "Parole state: " + paroleOn;
    }
@@ -409,6 +421,17 @@ public class NetworkPolicyLogger {
            data.timeStamp = System.currentTimeMillis();
        }

        public void appIdleWlChanged(int uid, boolean isWhitelisted) {
            final Data data = getNextSlot();
            if (data == null) return;

            data.reset();
            data.type = EVENT_APP_IDLE_WL_CHANGED;
            data.ifield1 = uid;
            data.bfield1 = isWhitelisted;
            data.timeStamp = System.currentTimeMillis();
        }

        public void paroleStateChanged(boolean paroleOn) {
            final Data data = getNextSlot();
            if (data == null) return;
@@ -487,6 +510,8 @@ public class NetworkPolicyLogger {
                    return getDeviceIdleModeEnabled(data.bfield1);
                case EVENT_APP_IDLE_STATE_CHANGED:
                    return getAppIdleChangedLog(data.ifield1, data.bfield1);
                case EVENT_APP_IDLE_WL_CHANGED:
                    return getAppIdleWlChangedLog(data.ifield1, data.bfield1);
                case EVENT_PAROLE_STATE_CHANGED:
                    return getParoleStateChanged(data.bfield1);
                case EVENT_TEMP_POWER_SAVE_WL_CHANGED:
+6 −0
Original line number Diff line number Diff line
@@ -104,6 +104,12 @@ public abstract class NetworkPolicyManagerInternal {
     */
    public abstract void onAdminDataAvailable();

    /**
     * Control if a UID should be whitelisted even if it's in app idle mode. Other restrictions may
     * still be in effect.
     */
    public abstract void setAppIdleWhitelist(int uid, boolean shouldWhitelist);

    /**
     * Sets a list of packages which are restricted by admin from accessing metered data.
     *
+93 −5
Original line number Diff line number Diff line
@@ -464,6 +464,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    @GuardedBy("mUidRulesFirstLock")
    final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray();

    // "Power save mode" is the concept used in the DeviceIdleController that includes various
    // features including Doze and Battery Saver. It include Battery Saver, but "power save mode"
    // and "battery saver" are not equivalent.

    /**
     * UIDs that have been white-listed to always be able to have network access
     * in power save mode, except device idle (doze) still applies.
@@ -483,6 +487,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    @GuardedBy("mUidRulesFirstLock")
    private final SparseBooleanArray mPowerSaveTempWhitelistAppIds = new SparseBooleanArray();

    /**
     * UIDs that have been white-listed temporarily to be able to have network access despite being
     * idle. Other power saving restrictions still apply.
     */
    @GuardedBy("mUidRulesFirstLock")
    private final SparseBooleanArray mAppIdleTempWhitelistAppIds = new SparseBooleanArray();

    /**
     * UIDs that have been initially white-listed by system to avoid restricted background.
     */
@@ -3372,6 +3383,20 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                    fout.decreaseIndent();
                }

                size = mAppIdleTempWhitelistAppIds.size();
                if (size > 0) {
                    fout.println("App idle whitelist app ids:");
                    fout.increaseIndent();
                    for (int i = 0; i < size; i++) {
                        fout.print("UID=");
                        fout.print(mAppIdleTempWhitelistAppIds.keyAt(i));
                        fout.print(": ");
                        fout.print(mAppIdleTempWhitelistAppIds.valueAt(i));
                        fout.println();
                    }
                    fout.decreaseIndent();
                }

                size = mDefaultRestrictBackgroundWhitelistUids.size();
                if (size > 0) {
                    fout.println("Default restrict background whitelist uids:");
@@ -3640,12 +3665,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    }

    /**
     * Returns whether a uid is whitelisted from power saving restrictions (eg: Battery Saver, Doze
     * mode, and app idle).
     *
     * @param deviceIdleMode if true then we don't consider
     *        {@link #mPowerSaveWhitelistExceptIdleAppIds} for checking if the {@param uid} is
     *        whitelisted.
     */
    @GuardedBy("mUidRulesFirstLock")
    private boolean isWhitelistedBatterySaverUL(int uid, boolean deviceIdleMode) {
    private boolean isWhitelistedFromPowerSaveUL(int uid, boolean deviceIdleMode) {
        final int appId = UserHandle.getAppId(uid);
        boolean isWhitelisted = mPowerSaveTempWhitelistAppIds.get(appId)
                || mPowerSaveWhitelistAppIds.get(appId);
@@ -3660,7 +3688,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    @GuardedBy("mUidRulesFirstLock")
    private void updateRulesForWhitelistedPowerSaveUL(int uid, boolean enabled, int chain) {
        if (enabled) {
            final boolean isWhitelisted = isWhitelistedBatterySaverUL(uid,
            final boolean isWhitelisted = isWhitelistedFromPowerSaveUL(uid,
                    chain == FIREWALL_CHAIN_DOZABLE);
            if (isWhitelisted || isUidForegroundOnRestrictPowerUL(uid)) {
                setUidFirewallRule(chain, uid, FIREWALL_RULE_ALLOW);
@@ -3712,8 +3740,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
            if (!mPowerSaveTempWhitelistAppIds.get(appId) && isUidIdle(uid)
                    && !isUidForegroundOnRestrictPowerUL(uid)) {
                setUidFirewallRule(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DENY);
                if (LOGD) Log.d(TAG, "updateRuleForAppIdleUL DENY " + uid);
            } else {
                setUidFirewallRule(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DEFAULT);
                if (LOGD) Log.d(TAG, "updateRuleForAppIdleUL " + uid + " to DEFAULT");
            }
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
@@ -3896,7 +3926,59 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        return UserHandle.isApp(uid) && hasInternetPermissions(uid);
    }

    private boolean isUidIdle(int uid) {
    /**
     * Set whether or not an app should be whitelisted for network access while in app idle. Other
     * power saving restrictions may still apply.
     */
    @VisibleForTesting
    public void setAppIdleWhitelist(int uid, boolean shouldWhitelist) {
        synchronized (mUidRulesFirstLock) {
            if (mAppIdleTempWhitelistAppIds.get(uid) == shouldWhitelist) {
                // No change.
                return;
            }

            final long token = Binder.clearCallingIdentity();
            try {
                mLogger.appIdleWlChanged(uid, shouldWhitelist);
                if (shouldWhitelist) {
                    mAppIdleTempWhitelistAppIds.put(uid, true);
                } else {
                    mAppIdleTempWhitelistAppIds.delete(uid);
                }
                updateRuleForAppIdleUL(uid);
                updateRulesForPowerRestrictionsUL(uid);
            } finally {
                Binder.restoreCallingIdentity(token);
            }
        }
    }

    /** Return the list of UIDs currently in the app idle whitelist. */
    @VisibleForTesting
    public int[] getAppIdleWhitelist() {
        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);

        synchronized (mUidRulesFirstLock) {
            final int len = mAppIdleTempWhitelistAppIds.size();
            int[] uids = new int[len];
            for (int i = 0; i < len; ++i) {
                uids[i] = mAppIdleTempWhitelistAppIds.keyAt(i);
            }
            return uids;
        }
    }

    /** Returns if the UID is currently considered idle. */
    @VisibleForTesting
    public boolean isUidIdle(int uid) {
        synchronized (mUidRulesFirstLock) {
            if (mAppIdleTempWhitelistAppIds.get(uid)) {
                // UID is temporarily whitelisted.
                return false;
            }
        }

        final String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
        final int userId = UserHandle.getUserId(uid);

@@ -3940,6 +4022,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        mPowerSaveWhitelistExceptIdleAppIds.delete(uid);
        mPowerSaveWhitelistAppIds.delete(uid);
        mPowerSaveTempWhitelistAppIds.delete(uid);
        mAppIdleTempWhitelistAppIds.delete(uid);

        // ...then update iptables asynchronously.
        mHandler.obtainMessage(MSG_RESET_FIREWALL_RULES_BY_UID, uid, 0).sendToTarget();
@@ -3984,7 +4067,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
     * <li>@{code bw_happy_box}: UIDs added to this chain have access (whitelist), unless they're
     *     also blacklisted.
     * <li>@{code bw_data_saver}: when enabled (through {@link #setRestrictBackground(boolean)}),
     *     no UIDs other those whitelisted will have access.
     *     no UIDs other than those whitelisted will have access.
     * <ul>
     *
     * <p>The @{code bw_penalty_box} and @{code bw_happy_box} are primarily managed through the
@@ -4194,7 +4277,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        final boolean restrictMode = isIdle || mRestrictPower || mDeviceIdleMode;
        final boolean isForeground = isUidForegroundOnRestrictPowerUL(uid);

        final boolean isWhitelisted = isWhitelistedBatterySaverUL(uid, mDeviceIdleMode);
        final boolean isWhitelisted = isWhitelistedFromPowerSaveUL(uid, mDeviceIdleMode);
        final int oldRule = oldUidRules & MASK_ALL_NETWORKS;
        int newRule = RULE_NONE;

@@ -5022,6 +5105,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
            mAdminDataAvailableLatch.countDown();
        }

        @Override
        public void setAppIdleWhitelist(int uid, boolean shouldWhitelist) {
            NetworkPolicyManagerService.this.setAppIdleWhitelist(uid, shouldWhitelist);
        }

        @Override
        public void setMeteredRestrictedPackages(Set<String> packageNames, int userId) {
            setMeteredRestrictedPackagesInternal(packageNames, userId);
+38 −1
Original line number Diff line number Diff line
@@ -78,6 +78,8 @@ class NetworkPolicyManagerShellCommand extends ShellCommand {
        pw.println("    Adds a UID to the whitelist for restrict background usage.");
        pw.println("  add restrict-background-blacklist UID");
        pw.println("    Adds a UID to the blacklist for restrict background usage.");
        pw.println("  add app-idle-whitelist UID");
        pw.println("    Adds a UID to the temporary app idle whitelist.");
        pw.println("  get restrict-background");
        pw.println("    Gets the global restrict background usage status.");
        pw.println("  list wifi-networks [true|false]");
@@ -92,6 +94,8 @@ class NetworkPolicyManagerShellCommand extends ShellCommand {
        pw.println("    Removes a UID from the whitelist for restrict background usage.");
        pw.println("  remove restrict-background-blacklist UID");
        pw.println("    Removes a UID from the blacklist for restrict background usage.");
        pw.println("  remove app-idle-whitelist UID");
        pw.println("    Removes a UID from the temporary app idle whitelist.");
        pw.println("  set metered-network ID [undefined|true|false]");
        pw.println("    Toggles whether the given wi-fi network is metered.");
        pw.println("  set restrict-background BOOLEAN");
@@ -142,6 +146,8 @@ class NetworkPolicyManagerShellCommand extends ShellCommand {
            return -1;
        }
        switch(type) {
            case "app-idle-whitelist":
                return listAppIdleWhitelist();
            case "wifi-networks":
                return listWifiNetworks();
            case "restrict-background-whitelist":
@@ -165,6 +171,8 @@ class NetworkPolicyManagerShellCommand extends ShellCommand {
                return addRestrictBackgroundWhitelist();
            case "restrict-background-blacklist":
                return addRestrictBackgroundBlacklist();
            case "app-idle-whitelist":
                return addAppIdleWhitelist();
        }
        pw.println("Error: unknown add type '" + type + "'");
        return -1;
@@ -182,14 +190,20 @@ class NetworkPolicyManagerShellCommand extends ShellCommand {
                return removeRestrictBackgroundWhitelist();
            case "restrict-background-blacklist":
                return removeRestrictBackgroundBlacklist();
            case "app-idle-whitelist":
                return removeAppIdleWhitelist();
        }
        pw.println("Error: unknown remove type '" + type + "'");
        return -1;
    }

    private int listUidPolicies(String msg, int policy) throws RemoteException {
        final PrintWriter pw = getOutPrintWriter();
        final int[] uids = mInterface.getUidsWithPolicy(policy);
        return listUidList(msg, uids);
    }

    private int listUidList(String msg, int[] uids) {
        final PrintWriter pw = getOutPrintWriter();
        pw.print(msg); pw.print(": ");
        if (uids.length == 0) {
            pw.println("none");
@@ -214,6 +228,12 @@ class NetworkPolicyManagerShellCommand extends ShellCommand {
                POLICY_REJECT_METERED_BACKGROUND);
    }

    private int listAppIdleWhitelist() throws RemoteException {
        final PrintWriter pw = getOutPrintWriter();
        final int[] uids = mInterface.getAppIdleWhitelist();
        return listUidList("App Idle whitelisted UIDs", uids);
    }

    private int getRestrictBackground() throws RemoteException {
        final PrintWriter pw = getOutPrintWriter();
        pw.print("Restrict background status: ");
@@ -277,6 +297,23 @@ class NetworkPolicyManagerShellCommand extends ShellCommand {
        return resetUidPolicy("not blacklisted", POLICY_REJECT_METERED_BACKGROUND);
    }

    private int setAppIdleWhitelist(boolean isWhitelisted) {
        final int uid = getUidFromNextArg();
        if (uid < 0) {
            return uid;
        }
        mInterface.setAppIdleWhitelist(uid, isWhitelisted);
        return 0;
    }

    private int addAppIdleWhitelist() throws RemoteException {
        return setAppIdleWhitelist(true);
    }

    private int removeAppIdleWhitelist() throws RemoteException {
        return setAppIdleWhitelist(false);
    }

    private int listWifiNetworks() {
        final PrintWriter pw = getOutPrintWriter();
        final String arg = getNextArg();
+15 −3
Original line number Diff line number Diff line
@@ -148,6 +148,9 @@ import com.android.server.net.NetworkStatsManagerInternal;

import com.google.common.util.concurrent.AbstractFuture;

import libcore.io.IoUtils;
import libcore.io.Streams;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -162,9 +165,6 @@ import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

import libcore.io.IoUtils;
import libcore.io.Streams;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
@@ -843,6 +843,18 @@ public class NetworkPolicyManagerServiceTest {
        assertTrue(mService.isUidForeground(UID_B));
    }

    @Test
    public void testAppIdleTempWhitelisting() throws Exception {
        mService.setAppIdleWhitelist(UID_A, true);
        mService.setAppIdleWhitelist(UID_B, false);
        int[] whitelistedIds = mService.getAppIdleWhitelist();
        assertTrue(Arrays.binarySearch(whitelistedIds, UID_A) >= 0);
        assertTrue(Arrays.binarySearch(whitelistedIds, UID_B) < 0);
        assertFalse(mService.isUidIdle(UID_A));
        // Can't currently guarantee UID_B's app idle state.
        // TODO: expand with multiple app idle states.
    }

    private static long computeLastCycleBoundary(long currentTime, NetworkPolicy policy) {
        RecurrenceRule.sClock = Clock.fixed(Instant.ofEpochMilli(currentTime),
                ZoneId.systemDefault());