summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Felipe Leme <felipeal@google.com> 2021-03-04 15:32:36 -0800
committer Felipe Leme <felipeal@google.com> 2021-03-11 15:20:13 -0800
commit4691ce920a25a05454b415634c884e0fbd316b7c (patch)
tree890eafb17c2ff4706bb2a6fe34dbf9efe78e066c
parente73587d10d05d2f4a92bf3a6b7bdb2da2f4a38dc (diff)
Created new @TestApi (and Shell command) to get policy-exempt apps.
Test: adb shell cmd device_policy list-policy-exempt-apps Test: atest FrameworksServicesTests:com.android.server.devicepolicy.DevicePolicyManagerTest#testGetPolicyExemptApps_noPermission,testGetPolicyExemptApps_empty,testGetPolicyExemptApps_baseOnly,testGetPolicyExemptApps_vendorOnly,testGetPolicyExemptApps_baseAndVendor Bug: 181238156 Fixes: 182373142 Change-Id: I990c53d1a2b9a6e15ad9fcae310badb7aae834d1
-rw-r--r--core/api/test-current.txt1
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java18
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl1
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java26
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java41
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java59
6 files changed, 135 insertions, 11 deletions
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 7b5b1989c1e5..f1cc45f2aa0f 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -414,6 +414,7 @@ package android.app.admin {
method public long getLastNetworkLogRetrievalTime();
method public long getLastSecurityLogRetrievalTime();
method public java.util.List<java.lang.String> getOwnerInstalledCaCerts(@NonNull android.os.UserHandle);
+ method @NonNull @RequiresPermission("android.permission.MANAGE_DEVICE_ADMINS") public java.util.Set<java.lang.String> getPolicyExemptApps();
method public boolean isCurrentInputMethodSetByOwner();
method public boolean isFactoryResetProtectionPolicySupported();
method @RequiresPermission(anyOf={"android.permission.MARK_DEVICE_ORGANIZATION_OWNED", "android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS"}, conditional=true) public void markProfileOwnerOnOrganizationOwnedDevice(@NonNull android.content.ComponentName);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index ccf41e5f3063..08e670fae2ec 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -13725,4 +13725,22 @@ public class DevicePolicyManager {
throw re.rethrowFromSystemServer();
}
}
+
+ /**
+ * Lists apps that are exempt from policies (such as
+ * {@link #setPackagesSuspended(ComponentName, String[], boolean)}).
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(value = android.Manifest.permission.MANAGE_DEVICE_ADMINS)
+ public @NonNull Set<String> getPolicyExemptApps() {
+ if (mService == null) return Collections.emptySet();
+
+ try {
+ return new HashSet<>(mService.listPolicyExemptApps());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 25ca59963d4b..e98720c0d96c 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -177,6 +177,7 @@ interface IDevicePolicyManager {
String[] setPackagesSuspended(in ComponentName admin, in String callerPackage, in String[] packageNames, boolean suspended);
boolean isPackageSuspended(in ComponentName admin, in String callerPackage, String packageName);
+ List<String> listPolicyExemptApps();
boolean installCaCert(in ComponentName admin, String callerPackage, in byte[] certBuffer);
void uninstallCaCerts(in ComponentName admin, String callerPackage, in String[] aliases);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 92bb51f18287..44b06c11c568 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1588,7 +1588,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
CryptoTestHelper.runAndLogSelfTest();
}
- public String[] getPersonalAppsForSuspension(int userId) {
+ public String[] getPersonalAppsForSuspension(@UserIdInt int userId) {
return PersonalAppsSuspensionHelper.forUser(mContext, userId)
.getPersonalAppsForSuspension();
}
@@ -10614,6 +10614,30 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
@Override
+ public List<String> listPolicyExemptApps() {
+ Preconditions.checkCallAuthorization(
+ hasCallingOrSelfPermission(permission.MANAGE_DEVICE_ADMINS));
+
+ // TODO(b/181238156): decide whether it should only list the apps set by the resources,
+ // or also the "critical" apps defined by PersonalAppsSuspensionHelper (like SMS app).
+ // If it's the latter, refactor PersonalAppsSuspensionHelper so it (or a superclass) takes
+ // the resources on constructor.
+ String[] core = mContext.getResources().getStringArray(R.array.policy_exempt_apps);
+ String[] vendor = mContext.getResources().getStringArray(R.array.vendor_policy_exempt_apps);
+
+ int size = core.length + vendor.length;
+ Set<String> apps = new ArraySet<>(size);
+ for (String app : core) {
+ apps.add(app);
+ }
+ for (String app : vendor) {
+ apps.add(app);
+ }
+
+ return new ArrayList<>(apps);
+ }
+
+ @Override
public void setUserRestriction(ComponentName who, String key, boolean enabledFromThisOwner,
boolean parent) {
Objects.requireNonNull(who, "ComponentName is null");
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
index 5484a148b0b6..8e31029769d0 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
@@ -21,6 +21,7 @@ import android.os.ShellCommand;
import com.android.server.devicepolicy.Owners.OwnerDto;
import java.io.PrintWriter;
+import java.util.Collection;
import java.util.List;
import java.util.Objects;
@@ -30,6 +31,7 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand {
private static final String CMD_IS_SAFE_OPERATION_BY_REASON = "is-operation-safe-by-reason";
private static final String CMD_SET_SAFE_OPERATION = "set-operation-safe";
private static final String CMD_LIST_OWNERS = "list-owners";
+ private static final String CMD_LIST_POLICY_EXEMPT_APPS = "list-policy-exempt-apps";
private final DevicePolicyManagerService mService;
@@ -60,6 +62,8 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand {
return runSetSafeOperation(pw);
case CMD_LIST_OWNERS:
return runListOwners(pw);
+ case CMD_LIST_POLICY_EXEMPT_APPS:
+ return runListPolicyExemptApps(pw);
default:
return onInvalidCommand(pw, cmd);
}
@@ -88,6 +92,8 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand {
+ " \n\n");
pw.printf(" %s\n", CMD_LIST_OWNERS);
pw.printf(" Lists the device / profile owners per user \n\n");
+ pw.printf(" %s\n", CMD_LIST_POLICY_EXEMPT_APPS);
+ pw.printf(" Lists the apps that are exempt from policies\n\n");
}
private int runIsSafeOperation(PrintWriter pw) {
@@ -119,18 +125,20 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand {
return 0;
}
- private int runListOwners(PrintWriter pw) {
- List<OwnerDto> owners = mService.listAllOwners();
- if (owners.isEmpty()) {
- pw.println("none");
+ private int printAndGetSize(PrintWriter pw, Collection<?> collection, String nameOnSingular) {
+ if (collection.isEmpty()) {
+ pw.printf("no %ss\n", nameOnSingular);
return 0;
}
- int size = owners.size();
- if (size == 1) {
- pw.println("1 owner:");
- } else {
- pw.printf("%d owners:\n", size);
- }
+ int size = collection.size();
+ pw.printf("%d %s%s:\n", size, nameOnSingular, (size == 1 ? "" : "s"));
+ return size;
+ }
+
+ private int runListOwners(PrintWriter pw) {
+ List<OwnerDto> owners = mService.listAllOwners();
+ int size = printAndGetSize(pw, owners, "owner");
+ if (size == 0) return 0;
for (int i = 0; i < size; i++) {
OwnerDto owner = owners.get(i);
@@ -150,4 +158,17 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand {
return 0;
}
+
+ private int runListPolicyExemptApps(PrintWriter pw) {
+ List<String> apps = mService.listPolicyExemptApps();
+ int size = printAndGetSize(pw, apps, "policy exempt app");
+
+ if (size == 0) return 0;
+
+ for (int i = 0; i < size; i++) {
+ String app = apps.get(i);
+ pw.printf(" %d: %s\n", i, app);
+ }
+ return 0;
+ }
}
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 87100a63e35e..318533f1ef63 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -107,6 +107,7 @@ import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
import android.test.MoreAsserts; // TODO(b/171932723): replace by Truth
import android.util.ArraySet;
+import android.util.Log;
import android.util.Pair;
import androidx.test.filters.SmallTest;
@@ -154,6 +155,9 @@ import java.util.concurrent.TimeUnit;
@SmallTest
@Presubmit
public class DevicePolicyManagerTest extends DpmTestBase {
+
+ private static final String TAG = DevicePolicyManagerTest.class.getSimpleName();
+
private static final List<String> OWNER_SETUP_PERMISSIONS = Arrays.asList(
permission.MANAGE_DEVICE_ADMINS, permission.MANAGE_PROFILE_AND_DEVICE_OWNERS,
permission.MANAGE_USERS, permission.INTERACT_ACROSS_USERS_FULL);
@@ -7215,6 +7219,47 @@ public class DevicePolicyManagerTest extends DpmTestBase {
assertThat(dpm.isUsbDataSignalingEnabled()).isEqualTo(enabled);
}
+ @Test
+ public void testGetPolicyExemptApps_noPermission() {
+ assertThrows(SecurityException.class, () -> dpm.getPolicyExemptApps());
+ }
+
+ @Test
+ public void testGetPolicyExemptApps_empty() {
+ grantManageDeviceAdmins();
+ mockPolicyExemptApps();
+ mockVendorPolicyExemptApps();
+
+ assertThat(dpm.getPolicyExemptApps()).isEmpty();
+ }
+
+ @Test
+ public void testGetPolicyExemptApps_baseOnly() {
+ grantManageDeviceAdmins();
+ mockPolicyExemptApps("foo");
+ mockVendorPolicyExemptApps();
+
+ assertThat(dpm.getPolicyExemptApps()).containsExactly("foo");
+ }
+
+ @Test
+ public void testGetPolicyExemptApps_vendorOnly() {
+ grantManageDeviceAdmins();
+ mockPolicyExemptApps();
+ mockVendorPolicyExemptApps("bar");
+
+ assertThat(dpm.getPolicyExemptApps()).containsExactly("bar");
+ }
+
+ @Test
+ public void testGetPolicyExemptApps_baseAndVendor() {
+ grantManageDeviceAdmins();
+ mockPolicyExemptApps("4", "23", "15", "42", "8");
+ mockVendorPolicyExemptApps("16", "15", "4");
+
+ assertThat(dpm.getPolicyExemptApps()).containsExactly("4", "8", "15", "16", "23", "42");
+ }
+
private void setUserUnlocked(int userHandle, boolean unlocked) {
when(getServices().userManager.isUserUnlocked(eq(userHandle))).thenReturn(unlocked);
}
@@ -7436,4 +7481,18 @@ public class DevicePolicyManagerTest extends DpmTestBase {
return new StringParceledListSlice(Arrays.asList(s));
}
+ private void grantManageDeviceAdmins() {
+ Log.d(TAG, "Granting " + permission.MANAGE_DEVICE_ADMINS);
+ mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+ }
+
+ private void mockPolicyExemptApps(String... apps) {
+ Log.d(TAG, "Mocking R.array.policy_exempt_apps to return " + Arrays.toString(apps));
+ when(mContext.resources.getStringArray(R.array.policy_exempt_apps)).thenReturn(apps);
+ }
+
+ private void mockVendorPolicyExemptApps(String... apps) {
+ Log.d(TAG, "Mocking R.array.vendor_policy_exempt_apps to return " + Arrays.toString(apps));
+ when(mContext.resources.getStringArray(R.array.vendor_policy_exempt_apps)).thenReturn(apps);
+ }
}