* commit '3184b28648a782a3a037de90bc76f64839b91560': Remove network access for idle apps
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