Move NetworkPolicy from apps to UID.

For multi-user devices, switch to storing policy per-user instead of
per-app.  Also watch for user added/removed broadcasts to clean up
policies and apply global restrictions.

Bug: 7121279
Change-Id: Ia7326bd0ebe0586fa4ec6d3a62f6313dc8814007
This commit is contained in:
Jeff Sharkey
2012-09-14 16:26:37 -07:00
parent ee100445b7
commit d0c6ccbafd
6 changed files with 177 additions and 155 deletions

View File

@ -1473,7 +1473,7 @@ public class Intent implements Parcelable, Cloneable {
* Broadcast Action: A new application package has been installed on the * Broadcast Action: A new application package has been installed on the
* device. The data contains the name of the package. Note that the * device. The data contains the name of the package. Note that the
* newly installed package does <em>not</em> receive this broadcast. * newly installed package does <em>not</em> receive this broadcast.
* <p>My include the following extras: * <p>May include the following extras:
* <ul> * <ul>
* <li> {@link #EXTRA_UID} containing the integer uid assigned to the new package. * <li> {@link #EXTRA_UID} containing the integer uid assigned to the new package.
* <li> {@link #EXTRA_REPLACING} is set to true if this is following * <li> {@link #EXTRA_REPLACING} is set to true if this is following
@ -1489,7 +1489,7 @@ public class Intent implements Parcelable, Cloneable {
* Broadcast Action: A new version of an application package has been * Broadcast Action: A new version of an application package has been
* installed, replacing an existing version that was previously installed. * installed, replacing an existing version that was previously installed.
* The data contains the name of the package. * The data contains the name of the package.
* <p>My include the following extras: * <p>May include the following extras:
* <ul> * <ul>
* <li> {@link #EXTRA_UID} containing the integer uid assigned to the new package. * <li> {@link #EXTRA_UID} containing the integer uid assigned to the new package.
* </ul> * </ul>

View File

@ -30,9 +30,9 @@ import android.net.NetworkTemplate;
interface INetworkPolicyManager { interface INetworkPolicyManager {
/** Control UID policies. */ /** Control UID policies. */
void setAppPolicy(int appId, int policy); void setUidPolicy(int uid, int policy);
int getAppPolicy(int appId); int getUidPolicy(int uid);
int[] getAppsWithPolicy(int policy); int[] getUidsWithPolicy(int policy);
boolean isUidForeground(int uid); boolean isUidForeground(int uid);

View File

@ -26,6 +26,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature; import android.content.pm.Signature;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.UserHandle;
import android.text.format.Time; import android.text.format.Time;
import com.google.android.collect.Sets; import com.google.android.collect.Sets;
@ -72,29 +73,29 @@ public class NetworkPolicyManager {
} }
/** /**
* Set policy flags for specific application. * Set policy flags for specific UID.
* *
* @param policy {@link #POLICY_NONE} or combination of flags like * @param policy {@link #POLICY_NONE} or combination of flags like
* {@link #POLICY_REJECT_METERED_BACKGROUND}. * {@link #POLICY_REJECT_METERED_BACKGROUND}.
*/ */
public void setAppPolicy(int appId, int policy) { public void setUidPolicy(int uid, int policy) {
try { try {
mService.setAppPolicy(appId, policy); mService.setUidPolicy(uid, policy);
} catch (RemoteException e) { } catch (RemoteException e) {
} }
} }
public int getAppPolicy(int appId) { public int getUidPolicy(int uid) {
try { try {
return mService.getAppPolicy(appId); return mService.getUidPolicy(uid);
} catch (RemoteException e) { } catch (RemoteException e) {
return POLICY_NONE; return POLICY_NONE;
} }
} }
public int[] getAppsWithPolicy(int policy) { public int[] getUidsWithPolicy(int policy) {
try { try {
return mService.getAppsWithPolicy(policy); return mService.getUidsWithPolicy(policy);
} catch (RemoteException e) { } catch (RemoteException e) {
return new int[0]; return new int[0];
} }
@ -236,8 +237,7 @@ public class NetworkPolicyManager {
@Deprecated @Deprecated
public static boolean isUidValidForPolicy(Context context, int uid) { public static boolean isUidValidForPolicy(Context context, int uid) {
// first, quick-reject non-applications // first, quick-reject non-applications
if (uid < android.os.Process.FIRST_APPLICATION_UID if (!UserHandle.isApp(uid)) {
|| uid > android.os.Process.LAST_APPLICATION_UID) {
return false; return false;
} }

View File

@ -87,15 +87,19 @@ public final class UserHandle implements Parcelable {
/** @hide */ /** @hide */
public static final boolean isIsolated(int uid) { public static final boolean isIsolated(int uid) {
uid = getAppId(uid); if (uid > 0) {
return uid >= Process.FIRST_ISOLATED_UID && uid <= Process.LAST_ISOLATED_UID; final int appId = getAppId(uid);
return appId >= Process.FIRST_ISOLATED_UID && appId <= Process.LAST_ISOLATED_UID;
} else {
return false;
}
} }
/** @hide */ /** @hide */
public static boolean isApp(int uid) { public static boolean isApp(int uid) {
if (uid > 0) { if (uid > 0) {
uid = UserHandle.getAppId(uid); final int appId = getAppId(uid);
return uid >= Process.FIRST_APPLICATION_UID && uid <= Process.LAST_APPLICATION_UID; return appId >= Process.FIRST_APPLICATION_UID && appId <= Process.LAST_APPLICATION_UID;
} else { } else {
return false; return false;
} }

View File

@ -24,6 +24,8 @@ import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
import static android.Manifest.permission.READ_PHONE_STATE; import static android.Manifest.permission.READ_PHONE_STATE;
import static android.content.Intent.ACTION_PACKAGE_ADDED; import static android.content.Intent.ACTION_PACKAGE_ADDED;
import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.ACTION_UID_REMOVED;
import static android.content.Intent.ACTION_USER_ADDED;
import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.Intent.EXTRA_UID; import static android.content.Intent.EXTRA_UID;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_ETHERNET;
@ -179,7 +181,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private static final int VERSION_ADDED_INFERRED = 7; private static final int VERSION_ADDED_INFERRED = 7;
private static final int VERSION_SWITCH_APP_ID = 8; private static final int VERSION_SWITCH_APP_ID = 8;
private static final int VERSION_ADDED_NETWORK_ID = 9; private static final int VERSION_ADDED_NETWORK_ID = 9;
private static final int VERSION_LATEST = VERSION_ADDED_NETWORK_ID; private static final int VERSION_SWITCH_UID = 10;
private static final int VERSION_LATEST = VERSION_SWITCH_UID;
// @VisibleForTesting // @VisibleForTesting
public static final int TYPE_WARNING = 0x1; public static final int TYPE_WARNING = 0x1;
@ -250,8 +253,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
/** Currently active network rules for ifaces. */ /** Currently active network rules for ifaces. */
private HashMap<NetworkPolicy, String[]> mNetworkRules = Maps.newHashMap(); private HashMap<NetworkPolicy, String[]> mNetworkRules = Maps.newHashMap();
/** Defined app policies. */ /** Defined UID policies. */
private SparseIntArray mAppPolicy = new SparseIntArray(); private SparseIntArray mUidPolicy = new SparseIntArray();
/** Currently derived rules for each UID. */ /** Currently derived rules for each UID. */
private SparseIntArray mUidRules = new SparseIntArray(); private SparseIntArray mUidRules = new SparseIntArray();
@ -357,12 +360,22 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION_IMMEDIATE); final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION_IMMEDIATE);
mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler); mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
// listen for package/uid changes to update policy // listen for package changes to update policy
final IntentFilter packageFilter = new IntentFilter(); final IntentFilter packageFilter = new IntentFilter();
packageFilter.addAction(ACTION_PACKAGE_ADDED); packageFilter.addAction(ACTION_PACKAGE_ADDED);
packageFilter.addAction(ACTION_UID_REMOVED); packageFilter.addDataScheme("package");
mContext.registerReceiver(mPackageReceiver, packageFilter, null, mHandler); mContext.registerReceiver(mPackageReceiver, packageFilter, null, mHandler);
// listen for UID changes to update policy
mContext.registerReceiver(
mUidRemovedReceiver, new IntentFilter(ACTION_UID_REMOVED), null, mHandler);
// listen for user changes to update policy
final IntentFilter userFilter = new IntentFilter();
userFilter.addAction(ACTION_USER_ADDED);
userFilter.addAction(ACTION_USER_REMOVED);
mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
// listen for stats update events // listen for stats update events
final IntentFilter statsFilter = new IntentFilter(ACTION_NETWORK_STATS_UPDATED); final IntentFilter statsFilter = new IntentFilter(ACTION_NETWORK_STATS_UPDATED);
mContext.registerReceiver( mContext.registerReceiver(
@ -421,34 +434,59 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private BroadcastReceiver mPackageReceiver = new BroadcastReceiver() { private BroadcastReceiver mPackageReceiver = new BroadcastReceiver() {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
// on background handler thread, and PACKAGE_ADDED and UID_REMOVED // on background handler thread, and PACKAGE_ADDED is protected
// are protected broadcasts.
final String action = intent.getAction(); final String action = intent.getAction();
final int uid = intent.getIntExtra(EXTRA_UID, 0); final int uid = intent.getIntExtra(EXTRA_UID, -1);
final int appId = UserHandle.getAppId(uid); if (uid == -1) return;
synchronized (mRulesLock) {
if (ACTION_PACKAGE_ADDED.equals(action)) { if (ACTION_PACKAGE_ADDED.equals(action)) {
// NOTE: PACKAGE_ADDED is currently only sent once, and is
// not broadcast when users are added.
// update rules for UID, since it might be subject to // update rules for UID, since it might be subject to
// global background data policy. // global background data policy
if (LOGV) Slog.v(TAG, "ACTION_PACKAGE_ADDED for uid=" + uid); if (LOGV) Slog.v(TAG, "ACTION_PACKAGE_ADDED for uid=" + uid);
updateRulesForAppLocked(appId); synchronized (mRulesLock) {
updateRulesForUidLocked(uid);
}
}
}
};
} else if (ACTION_UID_REMOVED.equals(action)) { private BroadcastReceiver mUidRemovedReceiver = new BroadcastReceiver() {
// NOTE: UID_REMOVED is currently only sent once, and is not @Override
// broadcast when users are removed. public void onReceive(Context context, Intent intent) {
// on background handler thread, and UID_REMOVED is protected
// remove any policy and update rules to clean up. final int uid = intent.getIntExtra(EXTRA_UID, -1);
if (uid == -1) return;
// remove any policy and update rules to clean up
if (LOGV) Slog.v(TAG, "ACTION_UID_REMOVED for uid=" + uid); if (LOGV) Slog.v(TAG, "ACTION_UID_REMOVED for uid=" + uid);
synchronized (mRulesLock) {
mAppPolicy.delete(appId); mUidPolicy.delete(uid);
updateRulesForAppLocked(appId); updateRulesForUidLocked(uid);
writePolicyLocked(); writePolicyLocked();
} }
} }
};
private BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// on background handler thread, and USER_ADDED and USER_REMOVED
// broadcasts are protected
final String action = intent.getAction();
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
if (userId == -1) return;
// 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
synchronized (mRulesLock) {
updateRulesForRestrictBackgroundLocked();
}
} }
}; };
@ -1107,7 +1145,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// clear any existing policy and read from disk // clear any existing policy and read from disk
mNetworkPolicy.clear(); mNetworkPolicy.clear();
mAppPolicy.clear(); mUidPolicy.clear();
FileInputStream fis = null; FileInputStream fis = null;
try { try {
@ -1188,24 +1226,25 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
cycleTimezone, warningBytes, limitBytes, lastWarningSnooze, cycleTimezone, warningBytes, limitBytes, lastWarningSnooze,
lastLimitSnooze, metered, inferred)); lastLimitSnooze, metered, inferred));
} else if (TAG_UID_POLICY.equals(tag) && version < VERSION_SWITCH_APP_ID) { } else if (TAG_UID_POLICY.equals(tag)) {
final int uid = readIntAttribute(in, ATTR_UID); final int uid = readIntAttribute(in, ATTR_UID);
final int policy = readIntAttribute(in, ATTR_POLICY); final int policy = readIntAttribute(in, ATTR_POLICY);
final int appId = UserHandle.getAppId(uid); if (UserHandle.isApp(uid)) {
if (UserHandle.isApp(appId)) { setUidPolicyUnchecked(uid, policy, false);
setAppPolicyUnchecked(appId, policy, false);
} else { } else {
Slog.w(TAG, "unable to apply policy to UID " + uid + "; ignoring"); Slog.w(TAG, "unable to apply policy to UID " + uid + "; ignoring");
} }
} else if (TAG_APP_POLICY.equals(tag) && version >= VERSION_SWITCH_APP_ID) { } else if (TAG_APP_POLICY.equals(tag)) {
final int appId = readIntAttribute(in, ATTR_APP_ID); final int appId = readIntAttribute(in, ATTR_APP_ID);
final int policy = readIntAttribute(in, ATTR_POLICY); final int policy = readIntAttribute(in, ATTR_POLICY);
if (UserHandle.isApp(appId)) { // TODO: set for other users during upgrade
setAppPolicyUnchecked(appId, policy, false); final int uid = UserHandle.getUid(UserHandle.USER_OWNER, appId);
if (UserHandle.isApp(uid)) {
setUidPolicyUnchecked(uid, policy, false);
} else { } else {
Slog.w(TAG, "unable to apply policy to appId " + appId + "; ignoring"); Slog.w(TAG, "unable to apply policy to UID " + uid + "; ignoring");
} }
} }
} }
@ -1280,17 +1319,17 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
} }
// write all known uid policies // write all known uid policies
for (int i = 0; i < mAppPolicy.size(); i++) { for (int i = 0; i < mUidPolicy.size(); i++) {
final int appId = mAppPolicy.keyAt(i); final int uid = mUidPolicy.keyAt(i);
final int policy = mAppPolicy.valueAt(i); final int policy = mUidPolicy.valueAt(i);
// skip writing empty policies // skip writing empty policies
if (policy == POLICY_NONE) continue; if (policy == POLICY_NONE) continue;
out.startTag(null, TAG_APP_POLICY); out.startTag(null, TAG_UID_POLICY);
writeIntAttribute(out, ATTR_APP_ID, appId); writeIntAttribute(out, ATTR_UID, uid);
writeIntAttribute(out, ATTR_POLICY, policy); writeIntAttribute(out, ATTR_POLICY, policy);
out.endTag(null, TAG_APP_POLICY); out.endTag(null, TAG_UID_POLICY);
} }
out.endTag(null, TAG_POLICY_LIST); out.endTag(null, TAG_POLICY_LIST);
@ -1305,24 +1344,24 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
} }
@Override @Override
public void setAppPolicy(int appId, int policy) { public void setUidPolicy(int uid, int policy) {
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
if (!UserHandle.isApp(appId)) { if (!UserHandle.isApp(uid)) {
throw new IllegalArgumentException("cannot apply policy to appId " + appId); throw new IllegalArgumentException("cannot apply policy to UID " + uid);
} }
setAppPolicyUnchecked(appId, policy, true); setUidPolicyUnchecked(uid, policy, true);
} }
private void setAppPolicyUnchecked(int appId, int policy, boolean persist) { private void setUidPolicyUnchecked(int uid, int policy, boolean persist) {
final int oldPolicy; final int oldPolicy;
synchronized (mRulesLock) { synchronized (mRulesLock) {
oldPolicy = getAppPolicy(appId); oldPolicy = getUidPolicy(uid);
mAppPolicy.put(appId, policy); mUidPolicy.put(uid, policy);
// uid policy changed, recompute rules and persist policy. // uid policy changed, recompute rules and persist policy.
updateRulesForAppLocked(appId); updateRulesForUidLocked(uid);
if (persist) { if (persist) {
writePolicyLocked(); writePolicyLocked();
} }
@ -1330,29 +1369,53 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
} }
@Override @Override
public int getAppPolicy(int appId) { public int getUidPolicy(int uid) {
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
synchronized (mRulesLock) { synchronized (mRulesLock) {
return mAppPolicy.get(appId, POLICY_NONE); return mUidPolicy.get(uid, POLICY_NONE);
} }
} }
@Override @Override
public int[] getAppsWithPolicy(int policy) { public int[] getUidsWithPolicy(int policy) {
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
int[] appIds = new int[0]; int[] uids = new int[0];
synchronized (mRulesLock) { synchronized (mRulesLock) {
for (int i = 0; i < mAppPolicy.size(); i++) { for (int i = 0; i < mUidPolicy.size(); i++) {
final int appId = mAppPolicy.keyAt(i); final int uid = mUidPolicy.keyAt(i);
final int appPolicy = mAppPolicy.valueAt(i); final int uidPolicy = mUidPolicy.valueAt(i);
if (appPolicy == policy) { if (uidPolicy == policy) {
appIds = appendInt(appIds, appId); uids = appendInt(uids, uid);
} }
} }
} }
return appIds; return uids;
}
/**
* Remove any policies associated with given {@link UserHandle}, persisting
* if any changes are made.
*/
private void removePoliciesForUserLocked(int userId) {
if (LOGV) Slog.v(TAG, "removePoliciesForUserLocked()");
int[] uids = new int[0];
for (int i = 0; i < mUidPolicy.size(); i++) {
final int uid = mUidPolicy.keyAt(i);
if (UserHandle.getUserId(uid) == userId) {
uids = appendInt(uids, uid);
}
}
if (uids.length > 0) {
for (int uid : uids) {
mUidPolicy.delete(uid);
updateRulesForUidLocked(uid);
}
writePolicyLocked();
}
} }
@Override @Override
@ -1586,14 +1649,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
} }
fout.decreaseIndent(); fout.decreaseIndent();
fout.println("Policy for apps:"); fout.println("Policy for UIDs:");
fout.increaseIndent(); fout.increaseIndent();
int size = mAppPolicy.size(); int size = mUidPolicy.size();
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
final int appId = mAppPolicy.keyAt(i); final int uid = mUidPolicy.keyAt(i);
final int policy = mAppPolicy.valueAt(i); final int policy = mUidPolicy.valueAt(i);
fout.print("appId="); fout.print("UID=");
fout.print(appId); fout.print(uid);
fout.print(" policy="); fout.print(" policy=");
dumpPolicy(fout, policy); dumpPolicy(fout, policy);
fout.println(); fout.println();
@ -1698,12 +1761,19 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
* Update rules that might be changed by {@link #mRestrictBackground} value. * Update rules that might be changed by {@link #mRestrictBackground} value.
*/ */
private void updateRulesForRestrictBackgroundLocked() { private void updateRulesForRestrictBackgroundLocked() {
// update rules for all installed applications
final PackageManager pm = mContext.getPackageManager(); final PackageManager pm = mContext.getPackageManager();
final List<ApplicationInfo> apps = pm.getInstalledApplications(0); final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
// update rules for all installed applications
final List<UserInfo> users = um.getUsers();
final List<ApplicationInfo> apps = pm.getInstalledApplications(
PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_DISABLED_COMPONENTS);
for (UserInfo user : users) {
for (ApplicationInfo app : apps) { for (ApplicationInfo app : apps) {
final int appId = UserHandle.getAppId(app.uid); final int uid = UserHandle.getUid(user.id, app.uid);
updateRulesForAppLocked(appId); updateRulesForUidLocked(uid);
}
} }
// limit data usage for some internal system services // limit data usage for some internal system services
@ -1711,14 +1781,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
updateRulesForUidLocked(android.os.Process.DRM_UID); updateRulesForUidLocked(android.os.Process.DRM_UID);
} }
private void updateRulesForAppLocked(int appId) {
UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
for (UserInfo user : um.getUsers()) {
final int uid = UserHandle.getUid(user.id, appId);
updateRulesForUidLocked(uid);
}
}
private static boolean isUidValidForRules(int uid) { private static boolean isUidValidForRules(int uid) {
// allow rules on specific system services, and any apps // allow rules on specific system services, and any apps
if (uid == android.os.Process.MEDIA_UID || uid == android.os.Process.DRM_UID if (uid == android.os.Process.MEDIA_UID || uid == android.os.Process.DRM_UID
@ -1732,13 +1794,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private void updateRulesForUidLocked(int uid) { private void updateRulesForUidLocked(int uid) {
if (!isUidValidForRules(uid)) return; if (!isUidValidForRules(uid)) return;
final int appId = UserHandle.getAppId(uid); final int uidPolicy = getUidPolicy(uid);
final int appPolicy = getAppPolicy(appId);
final boolean uidForeground = isUidForeground(uid); final boolean uidForeground = isUidForeground(uid);
// derive active rules based on policy and active state // derive active rules based on policy and active state
int uidRules = RULE_ALLOW_ALL; int uidRules = RULE_ALLOW_ALL;
if (!uidForeground && (appPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0) { if (!uidForeground && (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0) {
// uid in background, and policy says to block metered data // uid in background, and policy says to block metered data
uidRules = RULE_REJECT_METERED; uidRules = RULE_REJECT_METERED;
} }

View File

@ -54,7 +54,6 @@ import android.content.Intent;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.Signature; import android.content.pm.Signature;
import android.content.pm.UserInfo;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.IConnectivityManager; import android.net.IConnectivityManager;
import android.net.INetworkManagementEventObserver; import android.net.INetworkManagementEventObserver;
@ -87,9 +86,7 @@ import org.easymock.EasyMock;
import org.easymock.IAnswer; import org.easymock.IAnswer;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -133,15 +130,12 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
private long mElapsedRealtime; private long mElapsedRealtime;
private static final int USER_ID = 0; private static final int USER_ID = 0;
private static final int USER_ID_GUEST = 1;
private static final int APP_ID_A = android.os.Process.FIRST_APPLICATION_UID + 800; private static final int APP_ID_A = android.os.Process.FIRST_APPLICATION_UID + 800;
private static final int APP_ID_B = android.os.Process.FIRST_APPLICATION_UID + 801; private static final int APP_ID_B = android.os.Process.FIRST_APPLICATION_UID + 801;
private static final int UID_A = UserHandle.getUid(USER_ID, APP_ID_A); private static final int UID_A = UserHandle.getUid(USER_ID, APP_ID_A);
private static final int UID_B = UserHandle.getUid(USER_ID, APP_ID_B); private static final int UID_B = UserHandle.getUid(USER_ID, APP_ID_B);
private static final int UID_A_GUEST = UserHandle.getUid(USER_ID_GUEST, APP_ID_A);
private static final int UID_B_GUEST = UserHandle.getUid(USER_ID_GUEST, APP_ID_B);
private static final int PID_1 = 400; private static final int PID_1 = 400;
private static final int PID_2 = 401; private static final int PID_2 = 401;
@ -258,13 +252,13 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
@Suppress @Suppress
public void testPolicyChangeTriggersBroadcast() throws Exception { public void testPolicyChangeTriggersBroadcast() throws Exception {
mService.setAppPolicy(APP_ID_A, POLICY_NONE); mService.setUidPolicy(APP_ID_A, POLICY_NONE);
// change background policy and expect broadcast // change background policy and expect broadcast
final Future<Intent> backgroundChanged = mServiceContext.nextBroadcastIntent( final Future<Intent> backgroundChanged = mServiceContext.nextBroadcastIntent(
ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED); ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED);
mService.setAppPolicy(APP_ID_A, POLICY_REJECT_METERED_BACKGROUND); mService.setUidPolicy(APP_ID_A, POLICY_REJECT_METERED_BACKGROUND);
backgroundChanged.get(); backgroundChanged.get();
} }
@ -318,7 +312,6 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
public void testScreenChangesRules() throws Exception { public void testScreenChangesRules() throws Exception {
Future<Void> future; Future<Void> future;
Future<Void> futureGuest;
expectSetUidNetworkRules(UID_A, false); expectSetUidNetworkRules(UID_A, false);
expectSetUidForeground(UID_A, true); expectSetUidForeground(UID_A, true);
@ -331,14 +324,10 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
// push strict policy for foreground uid, verify ALLOW rule // push strict policy for foreground uid, verify ALLOW rule
expectSetUidNetworkRules(UID_A, false); expectSetUidNetworkRules(UID_A, false);
expectSetUidForeground(UID_A, true); expectSetUidForeground(UID_A, true);
expectSetUidNetworkRules(UID_A_GUEST, true);
expectSetUidForeground(UID_A_GUEST, false);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL); future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
futureGuest = expectRulesChanged(UID_A_GUEST, RULE_REJECT_METERED);
replay(); replay();
mService.setAppPolicy(APP_ID_A, POLICY_REJECT_METERED_BACKGROUND); mService.setUidPolicy(APP_ID_A, POLICY_REJECT_METERED_BACKGROUND);
future.get(); future.get();
futureGuest.get();
verifyAndReset(); verifyAndReset();
// now turn screen off and verify REJECT rule // now turn screen off and verify REJECT rule
@ -364,7 +353,6 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
public void testPolicyNone() throws Exception { public void testPolicyNone() throws Exception {
Future<Void> future; Future<Void> future;
Future<Void> futureGuest;
expectSetUidNetworkRules(UID_A, false); expectSetUidNetworkRules(UID_A, false);
expectSetUidForeground(UID_A, true); expectSetUidForeground(UID_A, true);
@ -377,14 +365,10 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
// POLICY_NONE should RULE_ALLOW in foreground // POLICY_NONE should RULE_ALLOW in foreground
expectSetUidNetworkRules(UID_A, false); expectSetUidNetworkRules(UID_A, false);
expectSetUidForeground(UID_A, true); expectSetUidForeground(UID_A, true);
expectSetUidNetworkRules(UID_A_GUEST, false);
expectSetUidForeground(UID_A_GUEST, false);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL); future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
futureGuest = expectRulesChanged(UID_A_GUEST, RULE_ALLOW_ALL);
replay(); replay();
mService.setAppPolicy(APP_ID_A, POLICY_NONE); mService.setUidPolicy(APP_ID_A, POLICY_NONE);
future.get(); future.get();
futureGuest.get();
verifyAndReset(); verifyAndReset();
// POLICY_NONE should RULE_ALLOW in background // POLICY_NONE should RULE_ALLOW in background
@ -399,19 +383,14 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
public void testPolicyReject() throws Exception { public void testPolicyReject() throws Exception {
Future<Void> future; Future<Void> future;
Future<Void> futureGuest;
// POLICY_REJECT should RULE_ALLOW in background // POLICY_REJECT should RULE_ALLOW in background
expectSetUidNetworkRules(UID_A, true); expectSetUidNetworkRules(UID_A, true);
expectSetUidForeground(UID_A, false); expectSetUidForeground(UID_A, false);
expectSetUidNetworkRules(UID_A_GUEST, true);
expectSetUidForeground(UID_A_GUEST, false);
future = expectRulesChanged(UID_A, RULE_REJECT_METERED); future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
futureGuest = expectRulesChanged(UID_A_GUEST, RULE_REJECT_METERED);
replay(); replay();
mService.setAppPolicy(APP_ID_A, POLICY_REJECT_METERED_BACKGROUND); mService.setUidPolicy(APP_ID_A, POLICY_REJECT_METERED_BACKGROUND);
future.get(); future.get();
futureGuest.get();
verifyAndReset(); verifyAndReset();
// POLICY_REJECT should RULE_ALLOW in foreground // POLICY_REJECT should RULE_ALLOW in foreground
@ -435,46 +414,33 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
public void testPolicyRejectAddRemove() throws Exception { public void testPolicyRejectAddRemove() throws Exception {
Future<Void> future; Future<Void> future;
Future<Void> futureGuest;
// POLICY_NONE should have RULE_ALLOW in background // POLICY_NONE should have RULE_ALLOW in background
expectSetUidNetworkRules(UID_A, false); expectSetUidNetworkRules(UID_A, false);
expectSetUidForeground(UID_A, false); expectSetUidForeground(UID_A, false);
expectSetUidNetworkRules(UID_A_GUEST, false);
expectSetUidForeground(UID_A_GUEST, false);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL); future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
futureGuest = expectRulesChanged(UID_A_GUEST, RULE_ALLOW_ALL);
replay(); replay();
mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false); mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
mService.setAppPolicy(APP_ID_A, POLICY_NONE); mService.setUidPolicy(APP_ID_A, POLICY_NONE);
future.get(); future.get();
futureGuest.get();
verifyAndReset(); verifyAndReset();
// adding POLICY_REJECT should cause RULE_REJECT // adding POLICY_REJECT should cause RULE_REJECT
expectSetUidNetworkRules(UID_A, true); expectSetUidNetworkRules(UID_A, true);
expectSetUidForeground(UID_A, false); expectSetUidForeground(UID_A, false);
expectSetUidNetworkRules(UID_A_GUEST, true);
expectSetUidForeground(UID_A_GUEST, false);
future = expectRulesChanged(UID_A, RULE_REJECT_METERED); future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
futureGuest = expectRulesChanged(UID_A_GUEST, RULE_REJECT_METERED);
replay(); replay();
mService.setAppPolicy(APP_ID_A, POLICY_REJECT_METERED_BACKGROUND); mService.setUidPolicy(APP_ID_A, POLICY_REJECT_METERED_BACKGROUND);
future.get(); future.get();
futureGuest.get();
verifyAndReset(); verifyAndReset();
// removing POLICY_REJECT should return us to RULE_ALLOW // removing POLICY_REJECT should return us to RULE_ALLOW
expectSetUidNetworkRules(UID_A, false); expectSetUidNetworkRules(UID_A, false);
expectSetUidForeground(UID_A, false); expectSetUidForeground(UID_A, false);
expectSetUidNetworkRules(UID_A_GUEST, false);
expectSetUidForeground(UID_A_GUEST, false);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL); future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
futureGuest = expectRulesChanged(UID_A_GUEST, RULE_ALLOW_ALL);
replay(); replay();
mService.setAppPolicy(APP_ID_A, POLICY_NONE); mService.setUidPolicy(APP_ID_A, POLICY_NONE);
future.get(); future.get();
futureGuest.get();
verifyAndReset(); verifyAndReset();
} }
@ -645,34 +611,25 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
public void testUidRemovedPolicyCleared() throws Exception { public void testUidRemovedPolicyCleared() throws Exception {
Future<Void> future; Future<Void> future;
Future<Void> futureGuest;
// POLICY_REJECT should RULE_REJECT in background // POLICY_REJECT should RULE_REJECT in background
expectSetUidNetworkRules(UID_A, true); expectSetUidNetworkRules(UID_A, true);
expectSetUidForeground(UID_A, false); expectSetUidForeground(UID_A, false);
expectSetUidNetworkRules(UID_A_GUEST, true);
expectSetUidForeground(UID_A_GUEST, false);
future = expectRulesChanged(UID_A, RULE_REJECT_METERED); future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
futureGuest = expectRulesChanged(UID_A_GUEST, RULE_REJECT_METERED);
replay(); replay();
mService.setAppPolicy(APP_ID_A, POLICY_REJECT_METERED_BACKGROUND); mService.setUidPolicy(APP_ID_A, POLICY_REJECT_METERED_BACKGROUND);
future.get(); future.get();
futureGuest.get();
verifyAndReset(); verifyAndReset();
// uninstall should clear RULE_REJECT // uninstall should clear RULE_REJECT
expectSetUidNetworkRules(UID_A, false); expectSetUidNetworkRules(UID_A, false);
expectSetUidForeground(UID_A, false); expectSetUidForeground(UID_A, false);
expectSetUidNetworkRules(UID_A_GUEST, false);
expectSetUidForeground(UID_A_GUEST, false);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL); future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
futureGuest = expectRulesChanged(UID_A_GUEST, RULE_ALLOW_ALL);
replay(); replay();
final Intent intent = new Intent(ACTION_UID_REMOVED); final Intent intent = new Intent(ACTION_UID_REMOVED);
intent.putExtra(EXTRA_UID, UID_A); intent.putExtra(EXTRA_UID, UID_A);
mServiceContext.sendBroadcast(intent); mServiceContext.sendBroadcast(intent);
future.get(); future.get();
futureGuest.get();
verifyAndReset(); verifyAndReset();
} }
@ -880,8 +837,8 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
private Future<Void> expectClearNotifications() throws Exception { private Future<Void> expectClearNotifications() throws Exception {
final FutureAnswer future = new FutureAnswer(); final FutureAnswer future = new FutureAnswer();
mNotifManager.cancelNotificationWithTag(isA(String.class), isA(String.class), anyInt(), mNotifManager.cancelNotificationWithTag(
UserHandle.myUserId()); isA(String.class), isA(String.class), anyInt(), anyInt());
expectLastCall().andAnswer(future).anyTimes(); expectLastCall().andAnswer(future).anyTimes();
return future; return future;
} }