Remove network access for idle apps
Track apps going in and out of idle in the NetworkPolicyManagerService. Apply DROP rules in firewall controller if app is to be blacklisted for network access. Firewall can now be in whitelist (old) or blacklist mode. When in blacklist, it allows all by default and we can selectively DENY some uids. Track app idle in UsageStats and update periodically. Track charging/discharging states. TODO: Check for appidle temporary parole state Bug: 20066058 Change-Id: Ia65d7544204b3bcb78a517310ef4adcc05aac6fb
This commit is contained in:
@@ -41,6 +41,7 @@ import java.util.HashSet;
|
||||
*/
|
||||
public class NetworkPolicyManager {
|
||||
|
||||
/* POLICY_* are masks and can be ORed */
|
||||
/** No specific network policy, use system default. */
|
||||
public static final int POLICY_NONE = 0x0;
|
||||
/** Reject network usage on metered networks when application in background. */
|
||||
@@ -48,10 +49,17 @@ public class NetworkPolicyManager {
|
||||
/** Allow network use (metered or not) in the background in battery save mode. */
|
||||
public static final int POLICY_ALLOW_BACKGROUND_BATTERY_SAVE = 0x2;
|
||||
|
||||
/* RULE_* are not masks and they must be exclusive */
|
||||
/** All network traffic should be allowed. */
|
||||
public static final int RULE_ALLOW_ALL = 0x0;
|
||||
/** Reject traffic on metered networks. */
|
||||
public static final int RULE_REJECT_METERED = 0x1;
|
||||
/** Reject traffic on all networks. */
|
||||
public static final int RULE_REJECT_ALL = 0x2;
|
||||
|
||||
public static final int FIREWALL_RULE_DEFAULT = 0;
|
||||
public static final int FIREWALL_RULE_ALLOW = 1;
|
||||
public static final int FIREWALL_RULE_DENY = 2;
|
||||
|
||||
private static final boolean ALLOW_PLATFORM_APP_POLICY = true;
|
||||
|
||||
@@ -80,7 +88,7 @@ public class NetworkPolicyManager {
|
||||
* Set policy flags for specific UID.
|
||||
*
|
||||
* @param policy {@link #POLICY_NONE} or combination of flags like
|
||||
* {@link #POLICY_REJECT_METERED_BACKGROUND}, {@link #POLICY_ALLOW_BACKGROUND_BATTERY_SAVE}.
|
||||
* {@link #POLICY_REJECT_METERED_BACKGROUND} or {@link #POLICY_ALLOW_BACKGROUND_BATTERY_SAVE}.
|
||||
*/
|
||||
public void setUidPolicy(int uid, int policy) {
|
||||
try {
|
||||
@@ -322,6 +330,8 @@ public class NetworkPolicyManager {
|
||||
fout.write("[");
|
||||
if ((rules & RULE_REJECT_METERED) != 0) {
|
||||
fout.write("REJECT_METERED");
|
||||
} else if ((rules & RULE_REJECT_ALL) != 0) {
|
||||
fout.write("REJECT_ALL");
|
||||
}
|
||||
fout.write("]");
|
||||
}
|
||||
|
||||
@@ -342,7 +342,7 @@ interface INetworkManagementService
|
||||
void setFirewallInterfaceRule(String iface, boolean allow);
|
||||
void setFirewallEgressSourceRule(String addr, boolean allow);
|
||||
void setFirewallEgressDestRule(String addr, int port, boolean allow);
|
||||
void setFirewallUidRule(int uid, boolean allow);
|
||||
void setFirewallUidRule(int uid, int rule);
|
||||
|
||||
/**
|
||||
* Set all packets from users in ranges to go through VPN specified by netId.
|
||||
|
||||
@@ -24,6 +24,7 @@ import static android.net.ConnectivityManager.TYPE_VPN;
|
||||
import static android.net.ConnectivityManager.getNetworkTypeName;
|
||||
import static android.net.ConnectivityManager.isNetworkTypeValid;
|
||||
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
|
||||
import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
|
||||
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
@@ -832,7 +833,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
|
||||
}
|
||||
|
||||
if (networkCostly && (uidRules & RULE_REJECT_METERED) != 0) {
|
||||
if ((uidRules & RULE_REJECT_ALL) != 0
|
||||
|| (networkCostly && (uidRules & RULE_REJECT_METERED) != 0)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3490,7 +3492,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
synchronized(mRulesLock) {
|
||||
uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
|
||||
}
|
||||
if ((uidRules & RULE_REJECT_METERED) != 0) {
|
||||
if ((uidRules & (RULE_REJECT_METERED | RULE_REJECT_ALL)) != 0) {
|
||||
// we could silently fail or we can filter the available nets to only give
|
||||
// them those they have access to. Chose the more useful
|
||||
networkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
|
||||
|
||||
@@ -43,6 +43,7 @@ import android.net.InterfaceConfiguration;
|
||||
import android.net.IpPrefix;
|
||||
import android.net.LinkAddress;
|
||||
import android.net.Network;
|
||||
import android.net.NetworkPolicyManager;
|
||||
import android.net.NetworkStats;
|
||||
import android.net.NetworkUtils;
|
||||
import android.net.RouteInfo;
|
||||
@@ -107,8 +108,8 @@ import java.util.concurrent.CountDownLatch;
|
||||
*/
|
||||
public class NetworkManagementService extends INetworkManagementService.Stub
|
||||
implements Watchdog.Monitor {
|
||||
private static final String TAG = "NetworkManagementService";
|
||||
private static final boolean DBG = false;
|
||||
private static final String TAG = "NetworkManagement";
|
||||
private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
|
||||
private static final String NETD_TAG = "NetdConnector";
|
||||
private static final String NETD_SOCKET_NAME = "netd";
|
||||
|
||||
@@ -188,6 +189,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub
|
||||
/** Set of UIDs with cleartext penalties. */
|
||||
@GuardedBy("mQuotaLock")
|
||||
private SparseIntArray mUidCleartextPolicy = new SparseIntArray();
|
||||
/** Set of UIDs that are to be blocked/allowed by firewall controller. */
|
||||
@GuardedBy("mQuotaLock")
|
||||
private SparseIntArray mUidFirewallRules = new SparseIntArray();
|
||||
|
||||
private Object mIdleTimerLock = new Object();
|
||||
/** Set of interfaces with active idle timers. */
|
||||
@@ -563,10 +567,19 @@ public class NetworkManagementService extends INetworkManagementService.Stub
|
||||
setUidCleartextNetworkPolicy(local.keyAt(i), local.valueAt(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Push any existing firewall state
|
||||
setFirewallEnabled(mFirewallEnabled || LockdownVpnTracker.isEnabled());
|
||||
setFirewallEnabled(mFirewallEnabled || LockdownVpnTracker.isEnabled());
|
||||
|
||||
size = mUidFirewallRules.size();
|
||||
if (size > 0) {
|
||||
Slog.d(TAG, "Pushing " + size + " active firewall UID rules");
|
||||
final SparseIntArray uidFirewallRules = mUidFirewallRules;
|
||||
mUidFirewallRules = new SparseIntArray();
|
||||
for (int i = 0; i < uidFirewallRules.size(); i++) {
|
||||
setFirewallUidRule(uidFirewallRules.keyAt(i), uidFirewallRules.valueAt(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1899,7 +1912,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
|
||||
public void setFirewallEnabled(boolean enabled) {
|
||||
enforceSystemUid();
|
||||
try {
|
||||
mConnector.execute("firewall", enabled ? "enable" : "disable");
|
||||
mConnector.execute("firewall", "enable", enabled ? "whitelist" : "blacklist");
|
||||
mFirewallEnabled = enabled;
|
||||
} catch (NativeDaemonConnectorException e) {
|
||||
throw e.rethrowAsParcelableException();
|
||||
@@ -1949,14 +1962,48 @@ public class NetworkManagementService extends INetworkManagementService.Stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFirewallUidRule(int uid, boolean allow) {
|
||||
public void setFirewallUidRule(int uid, int rule) {
|
||||
enforceSystemUid();
|
||||
Preconditions.checkState(mFirewallEnabled);
|
||||
final String rule = allow ? "allow" : "deny";
|
||||
try {
|
||||
mConnector.execute("firewall", "set_uid_rule", uid, rule);
|
||||
} catch (NativeDaemonConnectorException e) {
|
||||
throw e.rethrowAsParcelableException();
|
||||
if (rule == NetworkPolicyManager.FIREWALL_RULE_ALLOW) {
|
||||
Preconditions.checkState(mFirewallEnabled);
|
||||
}
|
||||
synchronized (mQuotaLock) {
|
||||
final int oldUidFirewallRule = mUidFirewallRules.get(uid);
|
||||
if (DBG) {
|
||||
Slog.d(TAG, "oldRule = " + oldUidFirewallRule
|
||||
+ ", newRule=" + rule + " for uid=" + uid);
|
||||
}
|
||||
if (oldUidFirewallRule == rule) {
|
||||
if (DBG) Slog.d(TAG, "!!!!! Skipping change");
|
||||
// TODO: eventually consider throwing
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
String ruleName;
|
||||
if (isFirewallEnabled()) { // Whitelist mode
|
||||
if (rule == NetworkPolicyManager.FIREWALL_RULE_ALLOW) {
|
||||
ruleName = "allow";
|
||||
} else {
|
||||
ruleName = "deny";
|
||||
}
|
||||
} else { // Blacklist mode
|
||||
if (rule == NetworkPolicyManager.FIREWALL_RULE_DENY) {
|
||||
ruleName = "deny";
|
||||
} else {
|
||||
ruleName = "allow";
|
||||
}
|
||||
}
|
||||
|
||||
if (rule == NetworkPolicyManager.FIREWALL_RULE_DEFAULT) {
|
||||
mUidFirewallRules.delete(uid);
|
||||
} else {
|
||||
mUidFirewallRules.put(uid, rule);
|
||||
}
|
||||
mConnector.execute("firewall", "set_uid_rule", uid, ruleName);
|
||||
} catch (NativeDaemonConnectorException e) {
|
||||
throw e.rethrowAsParcelableException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2072,6 +2119,18 @@ public class NetworkManagementService extends INetworkManagementService.Stub
|
||||
pw.println("]");
|
||||
}
|
||||
|
||||
synchronized (mUidFirewallRules) {
|
||||
pw.print("UID firewall rule: [");
|
||||
final int size = mUidFirewallRules.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
pw.print(mUidFirewallRules.keyAt(i));
|
||||
pw.print(":");
|
||||
pw.print(mUidFirewallRules.valueAt(i));
|
||||
if (i < size - 1) pw.print(",");
|
||||
}
|
||||
pw.println("]");
|
||||
}
|
||||
|
||||
synchronized (mIdleTimerLock) {
|
||||
pw.println("Idle timers:");
|
||||
for (HashMap.Entry<String, IdleTimerParams> ent : mActiveIdleTimers.entrySet()) {
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
package com.android.server.net;
|
||||
|
||||
import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
|
||||
import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW;
|
||||
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
@@ -31,6 +33,7 @@ import android.net.LinkAddress;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.NetworkInfo.DetailedState;
|
||||
import android.net.NetworkInfo.State;
|
||||
import android.net.NetworkPolicyManager;
|
||||
import android.os.INetworkManagementService;
|
||||
import android.os.RemoteException;
|
||||
import android.security.Credentials;
|
||||
@@ -198,8 +201,8 @@ public class LockdownVpnTracker {
|
||||
setFirewallEgressSourceRule(addr, true);
|
||||
}
|
||||
|
||||
mNetService.setFirewallUidRule(ROOT_UID, true);
|
||||
mNetService.setFirewallUidRule(Os.getuid(), true);
|
||||
mNetService.setFirewallUidRule(ROOT_UID, FIREWALL_RULE_ALLOW);
|
||||
mNetService.setFirewallUidRule(Os.getuid(), FIREWALL_RULE_ALLOW);
|
||||
|
||||
mErrorCount = 0;
|
||||
mAcceptedIface = iface;
|
||||
@@ -288,8 +291,8 @@ public class LockdownVpnTracker {
|
||||
setFirewallEgressSourceRule(addr, false);
|
||||
}
|
||||
|
||||
mNetService.setFirewallUidRule(ROOT_UID, false);
|
||||
mNetService.setFirewallUidRule(Os.getuid(), false);
|
||||
mNetService.setFirewallUidRule(ROOT_UID, FIREWALL_RULE_DEFAULT);
|
||||
mNetService.setFirewallUidRule(Os.getuid(), FIREWALL_RULE_DEFAULT);
|
||||
|
||||
mAcceptedSourceAddr = null;
|
||||
}
|
||||
|
||||
@@ -36,11 +36,14 @@ import static android.net.NetworkPolicy.LIMIT_DISABLED;
|
||||
import static android.net.NetworkPolicy.SNOOZE_NEVER;
|
||||
import static android.net.NetworkPolicy.WARNING_DISABLED;
|
||||
import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
|
||||
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DENY;
|
||||
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
|
||||
import static android.net.NetworkPolicyManager.POLICY_ALLOW_BACKGROUND_BATTERY_SAVE;
|
||||
import static android.net.NetworkPolicyManager.POLICY_NONE;
|
||||
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
|
||||
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
|
||||
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
|
||||
import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
|
||||
import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
|
||||
import static android.net.NetworkPolicyManager.dumpPolicy;
|
||||
import static android.net.NetworkPolicyManager.dumpRules;
|
||||
@@ -80,6 +83,8 @@ import android.app.INotificationManager;
|
||||
import android.app.IProcessObserver;
|
||||
import android.app.Notification;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.usage.UsageStatsManagerInternal;
|
||||
import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
@@ -88,6 +93,7 @@ import android.content.IntentFilter;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.IPackageManager;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.net.ConnectivityManager;
|
||||
@@ -140,8 +146,6 @@ import android.util.SparseIntArray;
|
||||
import android.util.TrustedTime;
|
||||
import android.util.Xml;
|
||||
|
||||
import com.android.server.AppOpsService;
|
||||
import com.android.server.DeviceIdleController;
|
||||
import libcore.io.IoUtils;
|
||||
|
||||
import com.android.internal.R;
|
||||
@@ -149,6 +153,8 @@ import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.internal.util.FastXmlSerializer;
|
||||
import com.android.internal.util.IndentingPrintWriter;
|
||||
import com.android.server.AppOpsService;
|
||||
import com.android.server.DeviceIdleController;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.SystemConfig;
|
||||
import com.google.android.collect.Lists;
|
||||
@@ -176,7 +182,8 @@ import java.util.List;
|
||||
* and delivers to listeners, such as {@link ConnectivityManager}, for
|
||||
* enforcement.
|
||||
*/
|
||||
public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
|
||||
implements AppIdleStateChangeListener {
|
||||
private static final String TAG = "NetworkPolicy";
|
||||
private static final boolean LOGD = false;
|
||||
private static final boolean LOGV = false;
|
||||
@@ -244,6 +251,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
private final IPowerManager mPowerManager;
|
||||
private final INetworkStatsService mNetworkStats;
|
||||
private final INetworkManagementService mNetworkManager;
|
||||
private UsageStatsManagerInternal mUsageStats;
|
||||
private final TrustedTime mTime;
|
||||
|
||||
private IConnectivityManager mConnManager;
|
||||
@@ -368,6 +376,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
return;
|
||||
}
|
||||
|
||||
mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
|
||||
|
||||
final PackageManager pm = mContext.getPackageManager();
|
||||
|
||||
synchronized (mRulesLock) {
|
||||
updatePowerSaveWhitelistLocked();
|
||||
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
|
||||
@@ -460,6 +472,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
WifiManager.NETWORK_STATE_CHANGED_ACTION);
|
||||
mContext.registerReceiver(mWifiStateReceiver, wifiStateFilter, null, mHandler);
|
||||
|
||||
mUsageStats.addAppIdleStateChangeListener(this);
|
||||
|
||||
}
|
||||
|
||||
private IProcessObserver mProcessObserver = new IProcessObserver.Stub() {
|
||||
@@ -568,12 +582,17 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
|
||||
if (userId == -1) return;
|
||||
|
||||
synchronized (mRulesLock) {
|
||||
// Remove any policies for given user; both cleaning up after a
|
||||
// USER_REMOVED, and one last sanity check during USER_ADDED
|
||||
removePoliciesForUserLocked(userId);
|
||||
// Update global restrict for new user
|
||||
updateRulesForGlobalChangeLocked(true);
|
||||
switch (action) {
|
||||
case ACTION_USER_REMOVED:
|
||||
case ACTION_USER_ADDED:
|
||||
synchronized (mRulesLock) {
|
||||
// Remove any policies for given user; both cleaning up after a
|
||||
// USER_REMOVED, and one last sanity check during USER_ADDED
|
||||
removePoliciesForUserLocked(userId);
|
||||
// Update global restrict for new user
|
||||
updateRulesForGlobalChangeLocked(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -2040,6 +2059,22 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isUidIdle(int uid) {
|
||||
final String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
|
||||
final int userId = UserHandle.getUserId(uid);
|
||||
|
||||
for (String packageName : packages) {
|
||||
if (!mUsageStats.isAppIdle(packageName, userId)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies network rules to bandwidth and firewall controllers based on uid policy.
|
||||
* @param uid The uid for which to apply the latest policy
|
||||
*/
|
||||
void updateRulesForUidLocked(int uid) {
|
||||
if (!isUidValidForRules(uid)) return;
|
||||
|
||||
@@ -2056,10 +2091,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
|
||||
final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE);
|
||||
final boolean uidForeground = isUidForegroundLocked(uid);
|
||||
final boolean uidIdle = isUidIdle(uid);
|
||||
|
||||
// derive active rules based on policy and active state
|
||||
|
||||
int uidRules = RULE_ALLOW_ALL;
|
||||
if (!uidForeground && (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0) {
|
||||
if (uidIdle && !mPowerSaveWhitelistAppIds.get(UserHandle.getAppId(uid))) {
|
||||
uidRules = RULE_REJECT_ALL;
|
||||
} else if (!uidForeground && (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0) {
|
||||
// uid in background, and policy says to block metered data
|
||||
uidRules = RULE_REJECT_METERED;
|
||||
} else if (mRestrictBackground) {
|
||||
@@ -2078,7 +2117,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: only dispatch when rules actually change
|
||||
final int oldRules = mUidRules.get(uid);
|
||||
|
||||
if (uidRules == RULE_ALLOW_ALL) {
|
||||
mUidRules.delete(uid);
|
||||
@@ -2086,11 +2125,24 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
mUidRules.put(uid, uidRules);
|
||||
}
|
||||
|
||||
// Update bandwidth rules if necessary
|
||||
final boolean oldRejectMetered = (oldRules & RULE_REJECT_METERED) != 0;
|
||||
final boolean rejectMetered = (uidRules & RULE_REJECT_METERED) != 0;
|
||||
setUidNetworkRules(uid, rejectMetered);
|
||||
if (oldRejectMetered != rejectMetered) {
|
||||
setUidNetworkRules(uid, rejectMetered);
|
||||
}
|
||||
|
||||
// Update firewall rules if necessary
|
||||
final boolean oldFirewallReject = (oldRules & RULE_REJECT_ALL) != 0;
|
||||
final boolean firewallReject = (uidRules & RULE_REJECT_ALL) != 0;
|
||||
if (oldFirewallReject != firewallReject) {
|
||||
setUidFirewallRules(uid, firewallReject);
|
||||
}
|
||||
|
||||
// dispatch changed rule to existing listeners
|
||||
mHandler.obtainMessage(MSG_RULES_CHANGED, uid, uidRules).sendToTarget();
|
||||
if (oldRules != uidRules) {
|
||||
mHandler.obtainMessage(MSG_RULES_CHANGED, uid, uidRules).sendToTarget();
|
||||
}
|
||||
|
||||
try {
|
||||
// adjust stats accounting based on foreground status
|
||||
@@ -2100,6 +2152,18 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAppIdleStateChanged(String packageName, int userId, boolean idle) {
|
||||
try {
|
||||
int uid = mContext.getPackageManager().getPackageUid(packageName, userId);
|
||||
synchronized (mRulesLock) {
|
||||
updateRulesForUidLocked(uid);
|
||||
}
|
||||
} catch (NameNotFoundException nnfe) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private Handler.Callback mHandlerCallback = new Handler.Callback() {
|
||||
@Override
|
||||
public boolean handleMessage(Message msg) {
|
||||
@@ -2223,6 +2287,22 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or remove a uid to the firewall blacklist for all network ifaces.
|
||||
* @param uid
|
||||
* @param rejectOnAll
|
||||
*/
|
||||
private void setUidFirewallRules(int uid, boolean rejectOnAll) {
|
||||
try {
|
||||
mNetworkManager.setFirewallUidRule(uid,
|
||||
rejectOnAll ? FIREWALL_RULE_DENY : FIREWALL_RULE_DEFAULT);
|
||||
} catch (IllegalStateException e) {
|
||||
Log.wtf(TAG, "problem setting firewall uid rules", e);
|
||||
} catch (RemoteException e) {
|
||||
// ignored; service lives in system_server
|
||||
}
|
||||
}
|
||||
|
||||
private long getTotalBytes(NetworkTemplate template, long start, long end) {
|
||||
try {
|
||||
return mNetworkStats.getNetworkTotalBytes(template, start, end);
|
||||
|
||||
@@ -28,7 +28,6 @@ import android.app.usage.UsageEvents.Event;
|
||||
import android.app.usage.UsageStats;
|
||||
import android.app.usage.UsageStatsManagerInternal;
|
||||
import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
@@ -41,6 +40,7 @@ import android.content.pm.UserInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.database.ContentObserver;
|
||||
import android.net.Uri;
|
||||
import android.os.BatteryManager;
|
||||
import android.os.Binder;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
@@ -81,6 +81,8 @@ public class UsageStatsService extends SystemService implements
|
||||
private static final long TWENTY_MINUTES = 20 * 60 * 1000;
|
||||
private static final long FLUSH_INTERVAL = DEBUG ? TEN_SECONDS : TWENTY_MINUTES;
|
||||
private static final long TIME_CHANGE_THRESHOLD_MILLIS = 2 * 1000; // Two seconds.
|
||||
static final long DEFAULT_APP_IDLE_THRESHOLD_MILLIS = 2L * 24 * 60 * 60 * 1000; // 1 day
|
||||
static final long DEFAULT_CHECK_IDLE_INTERVAL = 8 * 3600 * 1000; // 8 hours
|
||||
|
||||
// Handler message types.
|
||||
static final int MSG_REPORT_EVENT = 0;
|
||||
@@ -88,6 +90,7 @@ public class UsageStatsService extends SystemService implements
|
||||
static final int MSG_REMOVE_USER = 2;
|
||||
static final int MSG_INFORM_LISTENERS = 3;
|
||||
static final int MSG_RESET_LAST_TIMESTAMP = 4;
|
||||
static final int MSG_CHECK_IDLE_STATES = 5;
|
||||
|
||||
private final Object mLock = new Object();
|
||||
Handler mHandler;
|
||||
@@ -98,9 +101,11 @@ public class UsageStatsService extends SystemService implements
|
||||
private File mUsageStatsDir;
|
||||
long mRealTimeSnapshot;
|
||||
long mSystemTimeSnapshot;
|
||||
boolean mAppIdleParoled;
|
||||
|
||||
private static final long DEFAULT_APP_IDLE_THRESHOLD_MILLIS = 1L * 24 * 60 * 60 * 1000; // 1 day
|
||||
private long mAppIdleDurationMillis;
|
||||
long mAppIdleDurationMillis;
|
||||
|
||||
long mCheckIdleIntervalMillis = DEFAULT_CHECK_IDLE_INTERVAL;
|
||||
|
||||
private ArrayList<UsageStatsManagerInternal.AppIdleStateChangeListener>
|
||||
mPackageAccessListeners = new ArrayList<>();
|
||||
@@ -113,6 +118,7 @@ public class UsageStatsService extends SystemService implements
|
||||
public void onStart() {
|
||||
mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
|
||||
mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
|
||||
|
||||
mHandler = new H(BackgroundThread.get().getLooper());
|
||||
|
||||
File systemDataDir = new File(Environment.getDataDirectory(), "system");
|
||||
@@ -123,9 +129,14 @@ public class UsageStatsService extends SystemService implements
|
||||
+ mUsageStatsDir.getAbsolutePath());
|
||||
}
|
||||
|
||||
getContext().registerReceiver(new UserRemovedReceiver(),
|
||||
new IntentFilter(Intent.ACTION_USER_REMOVED));
|
||||
IntentFilter userActions = new IntentFilter(Intent.ACTION_USER_REMOVED);
|
||||
userActions.addAction(Intent.ACTION_USER_STARTED);
|
||||
getContext().registerReceiverAsUser(new UserActionsReceiver(), UserHandle.ALL, userActions,
|
||||
null, null);
|
||||
|
||||
IntentFilter deviceStates = new IntentFilter(BatteryManager.ACTION_CHARGING);
|
||||
deviceStates.addAction(BatteryManager.ACTION_DISCHARGING);
|
||||
getContext().registerReceiver(new DeviceStateReceiver(), deviceStates);
|
||||
synchronized (mLock) {
|
||||
cleanUpRemovedUsersLocked();
|
||||
}
|
||||
@@ -147,18 +158,35 @@ public class UsageStatsService extends SystemService implements
|
||||
if (phase == PHASE_SYSTEM_SERVICES_READY) {
|
||||
// Observe changes to the threshold
|
||||
new SettingsObserver(mHandler).registerObserver();
|
||||
} else if (phase == PHASE_BOOT_COMPLETED) {
|
||||
setAppIdleParoled(getContext().getSystemService(BatteryManager.class).isCharging());
|
||||
}
|
||||
}
|
||||
|
||||
private class UserRemovedReceiver extends BroadcastReceiver {
|
||||
private class UserActionsReceiver extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent != null && intent.getAction().equals(Intent.ACTION_USER_REMOVED)) {
|
||||
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
|
||||
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
|
||||
if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
|
||||
if (userId >= 0) {
|
||||
mHandler.obtainMessage(MSG_REMOVE_USER, userId, 0).sendToTarget();
|
||||
}
|
||||
} else if (Intent.ACTION_USER_STARTED.equals(intent.getAction())) {
|
||||
if (userId >=0) {
|
||||
postCheckIdleStates();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class DeviceStateReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
final String action = intent.getAction();
|
||||
if (BatteryManager.ACTION_CHARGING.equals(action)
|
||||
|| BatteryManager.ACTION_DISCHARGING.equals(action)) {
|
||||
setAppIdleParoled(BatteryManager.ACTION_CHARGING.equals(action));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -195,6 +223,49 @@ public class UsageStatsService extends SystemService implements
|
||||
}
|
||||
}
|
||||
|
||||
void setAppIdleParoled(boolean paroled) {
|
||||
synchronized (mLock) {
|
||||
if (mAppIdleParoled != paroled) {
|
||||
mAppIdleParoled = paroled;
|
||||
postCheckIdleStates();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void postCheckIdleStates() {
|
||||
mHandler.removeMessages(MSG_CHECK_IDLE_STATES);
|
||||
mHandler.sendEmptyMessage(MSG_CHECK_IDLE_STATES);
|
||||
}
|
||||
|
||||
/** Check all running users' apps to see if they enter an idle state. */
|
||||
void checkIdleStates() {
|
||||
final int[] runningUsers;
|
||||
try {
|
||||
runningUsers = ActivityManagerNative.getDefault().getRunningUserIds();
|
||||
} catch (RemoteException re) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < runningUsers.length; i++) {
|
||||
final int userId = runningUsers[i];
|
||||
List<PackageInfo> packages =
|
||||
getContext().getPackageManager().getInstalledPackages(
|
||||
PackageManager.GET_DISABLED_COMPONENTS
|
||||
| PackageManager.GET_UNINSTALLED_PACKAGES,
|
||||
userId);
|
||||
synchronized (mLock) {
|
||||
final int packageCount = packages.size();
|
||||
for (int p = 0; p < packageCount; p++) {
|
||||
final String packageName = packages.get(p).packageName;
|
||||
final boolean isIdle = isAppIdle(packageName, userId);
|
||||
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS,
|
||||
userId, isIdle ? 1 : 0, packageName));
|
||||
}
|
||||
}
|
||||
}
|
||||
mHandler.sendEmptyMessageDelayed(MSG_CHECK_IDLE_STATES, mCheckIdleIntervalMillis);
|
||||
}
|
||||
|
||||
private static void deleteRecursively(File f) {
|
||||
File[] files = f.listFiles();
|
||||
if (files != null) {
|
||||
@@ -291,7 +362,7 @@ public class UsageStatsService extends SystemService implements
|
||||
void resetLastTimestamp(String packageName, int userId, boolean idle) {
|
||||
synchronized (mLock) {
|
||||
final long timeNow = checkAndGetTimeLocked();
|
||||
final long lastTimestamp = timeNow - (idle ? mAppIdleDurationMillis : 0);
|
||||
final long lastTimestamp = timeNow - (idle ? mAppIdleDurationMillis : 0) - 5000;
|
||||
|
||||
final UserUsageStatsService service =
|
||||
getUserDataAndInitializeIfNeededLocked(userId, timeNow);
|
||||
@@ -409,14 +480,22 @@ public class UsageStatsService extends SystemService implements
|
||||
|
||||
private boolean hasPassedIdleDuration(long lastUsed) {
|
||||
final long now = System.currentTimeMillis();
|
||||
return lastUsed < now - mAppIdleDurationMillis;
|
||||
return lastUsed <= now - mAppIdleDurationMillis;
|
||||
}
|
||||
|
||||
boolean isAppIdle(String packageName, int userId) {
|
||||
if (packageName == null) return false;
|
||||
synchronized (mLock) {
|
||||
// Temporary exemption, probably due to device charging or occasional allowance to
|
||||
// be allowed to sync, etc.
|
||||
if (mAppIdleParoled) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (SystemConfig.getInstance().getAllowInPowerSave().contains(packageName)) {
|
||||
return false;
|
||||
}
|
||||
// TODO: Optimize this check
|
||||
if (isActiveDeviceAdmin(packageName, userId)) {
|
||||
return false;
|
||||
}
|
||||
@@ -518,6 +597,9 @@ public class UsageStatsService extends SystemService implements
|
||||
resetLastTimestamp((String) msg.obj, msg.arg1, msg.arg2 == 1);
|
||||
break;
|
||||
|
||||
case MSG_CHECK_IDLE_STATES:
|
||||
checkIdleStates();
|
||||
break;
|
||||
default:
|
||||
super.handleMessage(msg);
|
||||
break;
|
||||
@@ -544,7 +626,9 @@ public class UsageStatsService extends SystemService implements
|
||||
mAppIdleDurationMillis = Settings.Secure.getLongForUser(getContext().getContentResolver(),
|
||||
Settings.Secure.APP_IDLE_DURATION, DEFAULT_APP_IDLE_THRESHOLD_MILLIS,
|
||||
UserHandle.USER_OWNER);
|
||||
// TODO: Check if we need to update idle states of all the apps
|
||||
mCheckIdleIntervalMillis = Math.min(DEFAULT_CHECK_IDLE_INTERVAL,
|
||||
mAppIdleDurationMillis / 4);
|
||||
postCheckIdleStates();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user