DA receiver should be protected with BIND_DEVICE_ADMIN.

- DPM.setActiveAdmin() will not accept DAs without BIND_DEVICE_ADMIN
when it's targeting NYC or above.

- DAs without BIND_DEVICE_ADMIN targeting MNC or below will still be
accepted. (with a logcat warning)

- DAs that are already set on a device without BIND_DEVICE_ADMIN
will still be accepted regardless of the target API level, even when
it's upgraded to a version targeting NYC.

Bug 24168653

Change-Id: I1914c2ec99135d9dd8cbac3f6914f9e43bafacc8
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 0159356..565ef4b 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -27,6 +27,8 @@
 import android.content.ComponentName;
 import android.content.pm.PackageManager;
 import android.net.wifi.WifiInfo;
+import android.os.Build;
+import android.os.Build.VERSION_CODES;
 import android.os.Bundle;
 import android.os.Process;
 import android.os.UserHandle;
@@ -85,6 +87,7 @@
         setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID);
         setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID);
         setUpPackageManagerForAdmin(admin3, DpmMockContext.CALLER_UID);
+        setUpPackageManagerForAdmin(adminNoPerm, DpmMockContext.CALLER_UID);
 
         setUpUserManager();
     }
@@ -338,6 +341,33 @@
 
     /**
      * Test for:
+     * {@link DevicePolicyManager#setActiveAdmin} when the admin isn't protected with
+     * BIND_DEVICE_ADMIN.
+     */
+    public void testSetActiveAdmin_permissionCheck() throws Exception {
+        // 1. Make sure the caller has proper permissions.
+        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+
+        try {
+            dpm.setActiveAdmin(adminNoPerm, /* replace =*/ false);
+            fail();
+        } catch (IllegalArgumentException expected) {
+            assertTrue(expected.getMessage().contains(permission.BIND_DEVICE_ADMIN));
+        }
+        assertFalse(dpm.isAdminActive(adminNoPerm));
+
+        // Change the target API level to MNC.  Now it can be set as DA.
+        setUpPackageManagerForAdmin(adminNoPerm, DpmMockContext.CALLER_UID, null,
+                VERSION_CODES.M);
+        dpm.setActiveAdmin(adminNoPerm, /* replace =*/ false);
+        assertTrue(dpm.isAdminActive(adminNoPerm));
+
+        // TODO Test the "load from the file" case where DA will still be loaded even without
+        // BIND_DEVICE_ADMIN and target API is N.
+    }
+
+    /**
+     * Test for:
      * {@link DevicePolicyManager#removeActiveAdmin}
      */
     public void testRemoveActiveAdmin_SecurityException() {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
index e11f3fb..5b33e4d 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
@@ -43,6 +43,7 @@
     public ComponentName admin1;
     public ComponentName admin2;
     public ComponentName admin3;
+    public ComponentName adminNoPerm;
 
     @Override
     protected void setUp() throws Exception {
@@ -56,6 +57,7 @@
         admin1 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin1.class);
         admin2 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin2.class);
         admin3 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin3.class);
+        adminNoPerm = new ComponentName(mRealTestContext, DummyDeviceAdmins.AdminNoPerm.class);
     }
 
     @Override
@@ -67,11 +69,36 @@
     protected void setUpPackageManagerForAdmin(ComponentName admin, int packageUid)
             throws Exception {
         setUpPackageManagerForAdmin(admin, packageUid,
-                PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED);
+                /* enabledSetting =*/ null, /* appTargetSdk = */ null);
     }
 
     protected void setUpPackageManagerForAdmin(ComponentName admin, int packageUid,
             int enabledSetting) throws Exception {
+        setUpPackageManagerForAdmin(admin, packageUid, enabledSetting, /* appTargetSdk = */ null);
+    }
+
+    protected void setUpPackageManagerForAdmin(ComponentName admin, int packageUid,
+            Integer enabledSetting, Integer appTargetSdk) throws Exception {
+
+        // Set up getApplicationInfo().
+
+        final ApplicationInfo ai = DpmTestUtils.cloneParcelable(
+                mRealTestContext.getPackageManager().getApplicationInfo(
+                        admin.getPackageName(),
+                        PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS));
+
+        ai.enabledSetting = enabledSetting == null
+                ? PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED
+                : enabledSetting;
+        if (appTargetSdk != null) {
+            ai.targetSdkVersion = appTargetSdk;
+        }
+        ai.uid = packageUid;
+
+        doReturn(ai).when(mMockContext.ipackageManager).getApplicationInfo(
+                eq(admin.getPackageName()),
+                eq(PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS),
+                eq(UserHandle.getUserId(packageUid)));
 
         // Set up queryBroadcastReceivers().
 
@@ -88,7 +115,7 @@
         realResolveInfo.set(0, DpmTestUtils.cloneParcelable(realResolveInfo.get(0)));
 
         // We need to rewrite the UID in the activity info.
-        realResolveInfo.get(0).activityInfo.applicationInfo.uid = packageUid;
+        realResolveInfo.get(0).activityInfo.applicationInfo = ai;
 
         doReturn(realResolveInfo).when(mMockContext.packageManager).queryBroadcastReceivers(
                 MockUtils.checkIntentComponent(admin),
@@ -96,21 +123,6 @@
                         | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS),
                 eq(UserHandle.getUserId(packageUid)));
 
-        // Set up getApplicationInfo().
-
-        final ApplicationInfo ai = DpmTestUtils.cloneParcelable(
-                mRealTestContext.getPackageManager().getApplicationInfo(
-                        admin.getPackageName(),
-                        PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS));
-
-        ai.enabledSetting = enabledSetting;
-        ai.uid = packageUid;
-
-        doReturn(ai).when(mMockContext.ipackageManager).getApplicationInfo(
-                eq(admin.getPackageName()),
-                eq(PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS),
-                eq(UserHandle.getUserId(packageUid)));
-
         // Set up getPackageInfo().
 
         final PackageInfo pi = DpmTestUtils.cloneParcelable(
@@ -118,7 +130,7 @@
                         admin.getPackageName(), 0));
         assertTrue(pi.applicationInfo.flags != 0);
 
-        pi.applicationInfo.uid = packageUid;
+        pi.applicationInfo = ai;
 
         doReturn(pi).when(mMockContext.ipackageManager).getPackageInfo(
                 eq(admin.getPackageName()),
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java
index 08293a2..a0f4d97 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java
@@ -24,4 +24,6 @@
     }
     public static class Admin3 extends DeviceAdminReceiver {
     }
+    public static class AdminNoPerm extends DeviceAdminReceiver {
+    }
 }