Add DPM API to block apps from using metered data.
Bug: 63700027
Test: cts-tradefed run singleCommand cts-dev -m CtsDevicePolicyManagerTestCases -t \
com.android.cts.devicepolicy.MixedDeviceOwnerTest#testSetMeteredDataDisabled
Test: cts-tradefed run singleCommand cts-dev -m CtsDevicePolicyManagerTestCases -t \
com.android.cts.devicepolicy.MixedProfileOwnerTest#testSetMeteredDataDisabled
Test: atest com.android.server.devicepolicy.DevicePolicyManagerTest#testSetGetMeteredDataDisabled
Change-Id: I147399d316f375c68b415dc6ede837c53cd1aad0
diff --git a/services/core/java/com/android/server/net/NetworkPolicyLogger.java b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
index 2bd9cab..b4bc7f5 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyLogger.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
@@ -37,6 +37,7 @@
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
+import java.util.Set;
public class NetworkPolicyLogger {
static final String TAG = "NetworkPolicy";
@@ -62,6 +63,7 @@
private static final int EVENT_TEMP_POWER_SAVE_WL_CHANGED = 10;
private static final int EVENT_UID_FIREWALL_RULE_CHANGED = 11;
private static final int EVENT_FIREWALL_CHAIN_ENABLED = 12;
+ private static final int EVENT_UPDATE_METERED_RESTRICTED_PKGS = 13;
static final int NTWK_BLOCKED_POWER = 0;
static final int NTWK_ALLOWED_NON_METERED = 1;
@@ -179,6 +181,14 @@
}
}
+ void meteredRestrictedPkgsChanged(Set<Integer> restrictedUids) {
+ synchronized (mLock) {
+ final String log = "Metered restricted uids: " + restrictedUids;
+ if (LOGD) Slog.d(TAG, log);
+ mEventsBuffer.event(log);
+ }
+ }
+
void dumpLogs(IndentingPrintWriter pw) {
synchronized (mLock) {
pw.println();
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
index 971ac8b..6490964 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
@@ -19,6 +19,8 @@
import android.net.Network;
import android.telephony.SubscriptionPlan;
+import java.util.Set;
+
/**
* Network Policy Manager local system service interface.
*
@@ -71,4 +73,21 @@
* Informs that admin data is loaded and available.
*/
public abstract void onAdminDataAvailable();
+
+ /**
+ * Sets a list of packages which are restricted by admin from accessing metered data.
+ *
+ * @param packageNames the list of restricted packages.
+ * @param userId the userId in which {@param packagesNames} are restricted.
+ */
+ public abstract void setMeteredRestrictedPackages(
+ Set<String> packageNames, int userId);
+
+
+ /**
+ * Similar to {@link #setMeteredRestrictedPackages(Set, int)} but updates the restricted
+ * packages list asynchronously.
+ */
+ public abstract void setMeteredRestrictedPackagesAsync(
+ Set<String> packageNames, int userId);
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index e406d51..0e54768 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -232,6 +232,7 @@
import java.util.Calendar;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -349,6 +350,7 @@
private static final int MSG_POLICIES_CHANGED = 13;
private static final int MSG_RESET_FIREWALL_RULES_BY_UID = 15;
private static final int MSG_SUBSCRIPTION_OVERRIDE = 16;
+ private static final int MSG_METERED_RESTRICTED_PACKAGES_CHANGED = 17;
private static final int UID_MSG_STATE_CHANGED = 100;
private static final int UID_MSG_GONE = 101;
@@ -480,6 +482,13 @@
@GuardedBy("mNetworkPoliciesSecondLock")
private final SparseIntArray mNetIdToSubId = new SparseIntArray();
+ /**
+ * Indicates the uids restricted by admin from accessing metered data. It's a mapping from
+ * userId to restricted uids which belong to that user.
+ */
+ @GuardedBy("mUidRulesFirstLock")
+ private final SparseArray<Set<Integer>> mMeteredRestrictedUids = new SparseArray<>();
+
private final RemoteCallbackList<INetworkPolicyListener>
mListeners = new RemoteCallbackList<>();
@@ -898,6 +907,9 @@
// Remove any persistable state for the given user; both cleaning up after a
// USER_REMOVED, and one last sanity check during USER_ADDED
removeUserStateUL(userId, true);
+ // Removing outside removeUserStateUL since that can also be called when
+ // user resets app preferences.
+ mMeteredRestrictedUids.remove(userId);
if (action == ACTION_USER_ADDED) {
// Add apps that are whitelisted by default.
addDefaultRestrictBackgroundWhitelistUidsUL(userId);
@@ -3137,6 +3149,15 @@
}
fout.decreaseIndent();
+ fout.println("Admin restricted uids for metered data:");
+ fout.increaseIndent();
+ size = mMeteredRestrictedUids.size();
+ for (int i = 0; i < size; ++i) {
+ fout.print("u" + mMeteredRestrictedUids.keyAt(i) + ": ");
+ fout.println(mMeteredRestrictedUids.valueAt(i));
+ }
+ fout.decreaseIndent();
+
mLogger.dumpLogs(fout);
}
}
@@ -3705,6 +3726,7 @@
final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE);
final int oldUidRules = mUidRules.get(uid, RULE_NONE);
final boolean isForeground = isUidForegroundOnRestrictBackgroundUL(uid);
+ final boolean isRestrictedByAdmin = isRestrictedByAdminUL(uid);
final boolean isBlacklisted = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0;
final boolean isWhitelisted = (uidPolicy & POLICY_ALLOW_METERED_BACKGROUND) != 0;
@@ -3712,7 +3734,9 @@
int newRule = RULE_NONE;
// First step: define the new rule based on user restrictions and foreground state.
- if (isForeground) {
+ if (isRestrictedByAdmin) {
+ newRule = RULE_REJECT_METERED;
+ } else if (isForeground) {
if (isBlacklisted || (mRestrictBackground && !isWhitelisted)) {
newRule = RULE_TEMPORARY_ALLOW_METERED;
} else if (isWhitelisted) {
@@ -3732,6 +3756,7 @@
+ ": isForeground=" +isForeground
+ ", isBlacklisted=" + isBlacklisted
+ ", isWhitelisted=" + isWhitelisted
+ + ", isRestrictedByAdmin=" + isRestrictedByAdmin
+ ", oldRule=" + uidRulesToString(oldRule)
+ ", newRule=" + uidRulesToString(newRule)
+ ", newUidRules=" + uidRulesToString(newUidRules)
@@ -3767,13 +3792,13 @@
if (!isWhitelisted) {
setMeteredNetworkWhitelist(uid, false);
}
- if (isBlacklisted) {
+ if (isBlacklisted || isRestrictedByAdmin) {
setMeteredNetworkBlacklist(uid, true);
}
} else if (hasRule(newRule, RULE_REJECT_METERED)
|| hasRule(oldRule, RULE_REJECT_METERED)) {
// Flip state because app was explicitly added or removed to blacklist.
- setMeteredNetworkBlacklist(uid, isBlacklisted);
+ setMeteredNetworkBlacklist(uid, (isBlacklisted || isRestrictedByAdmin));
if (hasRule(oldRule, RULE_REJECT_METERED) && isWhitelisted) {
// Since blacklist prevails over whitelist, we need to handle the special case
// where app is whitelisted and blacklisted at the same time (although such
@@ -3790,6 +3815,7 @@
+ ": foreground=" + isForeground
+ ", whitelisted=" + isWhitelisted
+ ", blacklisted=" + isBlacklisted
+ + ", isRestrictedByAdmin=" + isRestrictedByAdmin
+ ", newRule=" + uidRulesToString(newUidRules)
+ ", oldRule=" + uidRulesToString(oldUidRules));
}
@@ -4102,6 +4128,12 @@
mListeners.finishBroadcast();
return true;
}
+ case MSG_METERED_RESTRICTED_PACKAGES_CHANGED: {
+ final int userId = msg.arg1;
+ final Set<String> packageNames = (Set<String>) msg.obj;
+ setMeteredRestrictedPackagesInternal(packageNames, userId);
+ return true;
+ }
default: {
return false;
}
@@ -4605,6 +4637,42 @@
public void onAdminDataAvailable() {
mAdminDataAvailableLatch.countDown();
}
+
+ @Override
+ public void setMeteredRestrictedPackages(Set<String> packageNames, int userId) {
+ setMeteredRestrictedPackagesInternal(packageNames, userId);
+ }
+
+ @Override
+ public void setMeteredRestrictedPackagesAsync(Set<String> packageNames, int userId) {
+ mHandler.obtainMessage(MSG_METERED_RESTRICTED_PACKAGES_CHANGED,
+ userId, 0, packageNames).sendToTarget();
+ }
+ }
+
+ private void setMeteredRestrictedPackagesInternal(Set<String> packageNames, int userId) {
+ synchronized (mUidRulesFirstLock) {
+ final Set<Integer> newRestrictedUids = new ArraySet<>();
+ for (String packageName : packageNames) {
+ final int uid = getUidForPackage(packageName, userId);
+ if (uid >= 0) {
+ newRestrictedUids.add(uid);
+ }
+ }
+ final Set<Integer> oldRestrictedUids = mMeteredRestrictedUids.get(userId);
+ mMeteredRestrictedUids.put(userId, newRestrictedUids);
+ handleRestrictedPackagesChangeUL(oldRestrictedUids, newRestrictedUids);
+ mLogger.meteredRestrictedPkgsChanged(newRestrictedUids);
+ }
+ }
+
+ private int getUidForPackage(String packageName, int userId) {
+ try {
+ return mContext.getPackageManager().getPackageUidAsUser(packageName,
+ PackageManager.MATCH_KNOWN_PACKAGES, userId);
+ } catch (NameNotFoundException e) {
+ return -1;
+ }
}
private int parseSubId(NetworkState state) {
@@ -4642,6 +4710,32 @@
}
}
+ private void handleRestrictedPackagesChangeUL(Set<Integer> oldRestrictedUids,
+ Set<Integer> newRestrictedUids) {
+ if (oldRestrictedUids == null) {
+ for (int uid : newRestrictedUids) {
+ updateRulesForDataUsageRestrictionsUL(uid);
+ }
+ return;
+ }
+ for (int uid : oldRestrictedUids) {
+ if (!newRestrictedUids.contains(uid)) {
+ updateRulesForDataUsageRestrictionsUL(uid);
+ }
+ }
+ for (int uid : newRestrictedUids) {
+ if (!oldRestrictedUids.contains(uid)) {
+ updateRulesForDataUsageRestrictionsUL(uid);
+ }
+ }
+ }
+
+ private boolean isRestrictedByAdminUL(int uid) {
+ final Set<Integer> restrictedUids = mMeteredRestrictedUids.get(
+ UserHandle.getUserId(uid));
+ return restrictedUids != null && restrictedUids.contains(uid);
+ }
+
private static boolean hasRule(int uidRules, int rule) {
return (uidRules & rule) != 0;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index 7a0b1bf..4f2866b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -26,6 +26,7 @@
import com.android.internal.R;
import com.android.server.SystemService;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -135,4 +136,14 @@
public CharSequence getPrintingDisabledReason() {
return null;
}
+
+ @Override
+ public List<String> setMeteredDataDisabled(ComponentName admin, List<String> packageNames) {
+ return packageNames;
+ }
+
+ @Override
+ public List<String> getMeteredDataDisabled(ComponentName admin) {
+ return new ArrayList<>();
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 8d91288..137887c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -806,6 +806,8 @@
private static final String TAG_MANDATORY_BACKUP_TRANSPORT = "mandatory_backup_transport";
private static final String TAG_START_USER_SESSION_MESSAGE = "start_user_session_message";
private static final String TAG_END_USER_SESSION_MESSAGE = "end_user_session_message";
+ private static final String TAG_METERED_DATA_DISABLED_PACKAGES
+ = "metered_data_disabled_packages";
DeviceAdminInfo info;
@@ -872,6 +874,9 @@
}
}
+ // The list of packages which are not allowed to use metered data.
+ List<String> meteredDisabledPackages;
+
final Set<String> accountTypesWithManagementDisabled = new ArraySet<>();
// The list of permitted accessibility services package namesas set by a profile
@@ -1153,6 +1158,7 @@
writePackageListToXml(out, TAG_PERMITTED_NOTIFICATION_LISTENERS,
permittedNotificationListeners);
writePackageListToXml(out, TAG_KEEP_UNINSTALLED_PACKAGES, keepUninstalledPackages);
+ writePackageListToXml(out, TAG_METERED_DATA_DISABLED_PACKAGES, meteredDisabledPackages);
if (hasUserRestrictions()) {
UserRestrictionsUtils.writeRestrictions(
out, userRestrictions, TAG_USER_RESTRICTIONS);
@@ -1349,6 +1355,8 @@
permittedNotificationListeners = readPackageList(parser, tag);
} else if (TAG_KEEP_UNINSTALLED_PACKAGES.equals(tag)) {
keepUninstalledPackages = readPackageList(parser, tag);
+ } else if (TAG_METERED_DATA_DISABLED_PACKAGES.equals(tag)) {
+ meteredDisabledPackages = readPackageList(parser, tag);
} else if (TAG_USER_RESTRICTIONS.equals(tag)) {
userRestrictions = UserRestrictionsUtils.readRestrictions(parser);
} else if (TAG_DEFAULT_ENABLED_USER_RESTRICTIONS.equals(tag)) {
@@ -1647,6 +1655,7 @@
policy.mAdminList.remove(i);
policy.mAdminMap.remove(aa.info.getComponent());
pushActiveAdminPackagesLocked(userHandle);
+ pushMeteredDisabledPackagesLocked(userHandle);
}
}
} catch (RemoteException re) {
@@ -3502,6 +3511,7 @@
mInjector.postOnSystemServerInitThreadPool(() -> {
pushActiveAdminPackages();
mUsageStatsManagerInternal.onAdminDataAvailable();
+ pushAllMeteredRestrictedPackages();
mInjector.getNetworkPolicyManagerInternal().onAdminDataAvailable();
});
}
@@ -3517,6 +3527,17 @@
}
}
+ private void pushAllMeteredRestrictedPackages() {
+ synchronized (this) {
+ final List<UserInfo> users = mUserManager.getUsers();
+ for (int i = users.size() - 1; i >= 0; --i) {
+ final int userId = users.get(i).id;
+ mInjector.getNetworkPolicyManagerInternal().setMeteredRestrictedPackagesAsync(
+ getMeteredDisabledPackagesLocked(userId), userId);
+ }
+ }
+ }
+
private void pushActiveAdminPackagesLocked(int userId) {
mUsageStatsManagerInternal.setActiveAdminApps(
getActiveAdminPackagesLocked(userId), userId);
@@ -11028,6 +11049,93 @@
}
@Override
+ public List<String> setMeteredDataDisabled(ComponentName who, List<String> packageNames) {
+ Preconditions.checkNotNull(who);
+ Preconditions.checkNotNull(packageNames);
+
+ if (!mHasFeature) {
+ return packageNames;
+ }
+ synchronized (this) {
+ final ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ final int callingUserId = mInjector.userHandleGetCallingUserId();
+ final long identity = mInjector.binderClearCallingIdentity();
+ try {
+ final List<String> excludedPkgs
+ = removeInvalidPkgsForMeteredDataRestriction(callingUserId, packageNames);
+ admin.meteredDisabledPackages = packageNames;
+ pushMeteredDisabledPackagesLocked(callingUserId);
+ saveSettingsLocked(callingUserId);
+ return excludedPkgs;
+ } finally {
+ mInjector.binderRestoreCallingIdentity(identity);
+ }
+ }
+ }
+
+ private List<String> removeInvalidPkgsForMeteredDataRestriction(
+ int userId, List<String> pkgNames) {
+ final Set<String> activeAdmins = getActiveAdminPackagesLocked(userId);
+ final List<String> excludedPkgs = new ArrayList<>();
+ for (int i = pkgNames.size() - 1; i >= 0; --i) {
+ final String pkgName = pkgNames.get(i);
+ // If the package is an active admin, don't restrict it.
+ if (activeAdmins.contains(pkgName)) {
+ excludedPkgs.add(pkgName);
+ continue;
+ }
+ // If the package doesn't exist, don't restrict it.
+ try {
+ if (!mInjector.getIPackageManager().isPackageAvailable(pkgName, userId)) {
+ excludedPkgs.add(pkgName);
+ }
+ } catch (RemoteException e) {
+ // Should not happen
+ }
+ }
+ pkgNames.removeAll(excludedPkgs);
+ return excludedPkgs;
+ }
+
+ @Override
+ public List<String> getMeteredDataDisabled(ComponentName who) {
+ Preconditions.checkNotNull(who);
+
+ if (!mHasFeature) {
+ return new ArrayList<>();
+ }
+ synchronized (this) {
+ final ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ return admin.meteredDisabledPackages == null
+ ? new ArrayList<>() : admin.meteredDisabledPackages;
+ }
+ }
+
+ private void pushMeteredDisabledPackagesLocked(int userId) {
+ mInjector.getNetworkPolicyManagerInternal().setMeteredRestrictedPackages(
+ getMeteredDisabledPackagesLocked(userId), userId);
+ }
+
+ private Set<String> getMeteredDisabledPackagesLocked(int userId) {
+ final DevicePolicyData policy = getUserData(userId);
+ final Set<String> restrictedPkgs = new ArraySet<>();
+ for (int i = policy.mAdminList.size() - 1; i >= 0; --i) {
+ final ActiveAdmin admin = policy.mAdminList.get(i);
+ if (!isActiveAdminWithPolicyForUserLocked(admin,
+ DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, userId)) {
+ // Not a profile or device owner, ignore
+ continue;
+ }
+ if (admin.meteredDisabledPackages != null) {
+ restrictedPkgs.addAll(admin.meteredDisabledPackages);
+ }
+ }
+ return restrictedPkgs;
+ }
+
+ @Override
public void setAffiliationIds(ComponentName admin, List<String> ids) {
if (!mHasFeature) {
return;
@@ -11386,6 +11494,7 @@
resetGlobalProxyLocked(policy);
}
pushActiveAdminPackagesLocked(userHandle);
+ pushMeteredDisabledPackagesLocked(userHandle);
saveSettingsLocked(userHandle);
updateMaximumTimeToLockLocked(userHandle);
policy.mRemovingAdmins.remove(adminReceiver);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index d26a3c7..26da436 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -126,6 +126,7 @@
permission.MANAGE_DEVICE_ADMINS, permission.MANAGE_PROFILE_AND_DEVICE_OWNERS,
permission.MANAGE_USERS, permission.INTERACT_ACROSS_USERS_FULL);
public static final String NOT_DEVICE_OWNER_MSG = "does not own the device";
+ public static final String NOT_PROFILE_OWNER_MSG = "does not own the profile";
public static final String ONGOING_CALL_MSG = "ongoing call on the device";
// TODO replace all instances of this with explicit {@link #mServiceContext}.
@@ -301,10 +302,10 @@
// Verify
verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
- MockUtils.checkAdminApps(admin1.getPackageName()),
+ MockUtils.checkApps(admin1.getPackageName()),
eq(UserHandle.USER_SYSTEM));
verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
- MockUtils.checkAdminApps(admin2.getPackageName(),
+ MockUtils.checkApps(admin2.getPackageName(),
adminAnotherPackage.getPackageName()),
eq(DpmMockContext.CALLER_USER_HANDLE));
verify(getServices().usageStatsManagerInternal).onAdminDataAvailable();
@@ -705,7 +706,7 @@
assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE));
verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
- MockUtils.checkAdminApps(admin2.getPackageName()),
+ MockUtils.checkApps(admin2.getPackageName()),
eq(DpmMockContext.CALLER_USER_HANDLE));
// Again broadcast from saveSettingsLocked().
@@ -1360,6 +1361,7 @@
eq(packageName),
anyInt(),
eq(userId));
+ doReturn(true).when(getServices().ipackageManager).isPackageAvailable(packageName, userId);
// Setup application UID with the PackageManager
doReturn(uid).when(getServices().packageManager).getPackageUidAsUser(
eq(packageName),
@@ -2101,6 +2103,53 @@
}
}
+ public void testSetGetMeteredDataDisabled() throws Exception {
+ setAsProfileOwner(admin1);
+
+ final ArrayList<String> emptyList = new ArrayList<>();
+ assertEquals(emptyList, dpm.getMeteredDataDisabled(admin1));
+
+ // Setup
+ final ArrayList<String> pkgsToRestrict = new ArrayList<>();
+ final String package1 = "com.example.one";
+ final String package2 = "com.example.two";
+ pkgsToRestrict.add(package1);
+ pkgsToRestrict.add(package2);
+ setupPackageInPackageManager(package1, DpmMockContext.CALLER_USER_HANDLE, 123, 0);
+ setupPackageInPackageManager(package2, DpmMockContext.CALLER_USER_HANDLE, 456, 0);
+ List<String> excludedPkgs = dpm.setMeteredDataDisabled(admin1, pkgsToRestrict);
+
+ // Verify
+ assertEquals(emptyList, excludedPkgs);
+ assertEquals(pkgsToRestrict, dpm.getMeteredDataDisabled(admin1));
+ verify(getServices().networkPolicyManagerInternal).setMeteredRestrictedPackages(
+ MockUtils.checkApps(pkgsToRestrict.toArray(new String[0])),
+ eq(DpmMockContext.CALLER_USER_HANDLE));
+
+ // Setup
+ pkgsToRestrict.remove(package1);
+ excludedPkgs = dpm.setMeteredDataDisabled(admin1, pkgsToRestrict);
+
+ // Verify
+ assertEquals(emptyList, excludedPkgs);
+ assertEquals(pkgsToRestrict, dpm.getMeteredDataDisabled(admin1));
+ verify(getServices().networkPolicyManagerInternal).setMeteredRestrictedPackages(
+ MockUtils.checkApps(pkgsToRestrict.toArray(new String[0])),
+ eq(DpmMockContext.CALLER_USER_HANDLE));
+ }
+
+ public void testSetGetMeteredDataDisabled_deviceAdmin() {
+ mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+ dpm.setActiveAdmin(admin1, true);
+ assertTrue(dpm.isAdminActive(admin1));
+ mContext.callerPermissions.remove(permission.MANAGE_DEVICE_ADMINS);
+
+ assertExpectException(SecurityException.class, /* messageRegex= */ NOT_PROFILE_OWNER_MSG,
+ () -> dpm.setMeteredDataDisabled(admin1, new ArrayList<>()));
+ assertExpectException(SecurityException.class, /* messageRegex= */ NOT_PROFILE_OWNER_MSG,
+ () -> dpm.getMeteredDataDisabled(admin1));
+ }
+
public void testCreateAdminSupportIntent() throws Exception {
// Setup device owner.
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
index dec962e..92ea766 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
@@ -119,25 +119,25 @@
return MockitoHamcrest.argThat(m);
}
- public static Set<String> checkAdminApps(String... adminApps) {
+ public static Set<String> checkApps(String... adminApps) {
final Matcher<Set<String>> m = new BaseMatcher<Set<String>>() {
@Override
public boolean matches(Object item) {
if (item == null) return false;
- final Set<String> actualAdminApps = (Set<String>) item;
- if (adminApps.length != actualAdminApps.size()) {
+ final Set<String> actualApps = (Set<String>) item;
+ if (adminApps.length != actualApps.size()) {
return false;
}
- final Set<String> copyOfAdmins = new ArraySet<>(actualAdminApps);
+ final Set<String> copyOfApps = new ArraySet<>(actualApps);
for (String adminApp : adminApps) {
- copyOfAdmins.remove(adminApp);
+ copyOfApps.remove(adminApp);
}
- return copyOfAdmins.isEmpty();
+ return copyOfApps.isEmpty();
}
@Override
public void describeTo(Description description) {
- description.appendText("Admin apps=" + Arrays.toString(adminApps));
+ description.appendText("Apps=" + Arrays.toString(adminApps));
}
};
return MockitoHamcrest.argThat(m);