DPM.isDeviceOwnerApp() and getDeviceOwner() now check calling user
- Previously on MNC, they would return the same result regardless who
the calling user is.
- Now they properly take DO user-id into account. Meaning, they'll
always return false and null respectively, if the calling user doesn't
run device owner.
- Note isDeviceOwnerApp() is a public API and getDeviceOwner() is
a system API. Meaning we're changing the behavior or non-private
APIs.
- Also cleaned up hidden APIs, and gave them explicit suffixes
to avoid confusion. Bundled code should prefer them for clarity.
Now we have:
* APIs that work cross-users: They all require MANAGE_USERS.
boolean isDeviceOwnerAppOnAnyUser(String packageName)
ComponentName getDeviceOwnerComponentOnAnyUser()
int getDeviceOwnerUserId()
boolean isDeviceOwnedByDeviceOwner()
String getDeviceOwnerNameOnAnyUser()
* APIs that work within user. No permissions are required.
boolean isDeviceOwnerAppOnCallingUser(String packageName)
ComponentName getDeviceOwnerComponentOnCallingUser()
Bug 24676413
Change-Id: I751a907c7aaf7b019335d67065d183236effaa80
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 0bd4896..79ba08d 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,7 @@
import android.content.ComponentName;
import android.content.pm.PackageManager;
import android.os.Bundle;
+import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Pair;
@@ -35,6 +36,7 @@
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -56,9 +58,9 @@
*
m FrameworksServicesTests &&
adb install \
- -r out/target/product/hammerhead/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
+ -r out/target/product/hammerhead/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
adb shell am instrument -e class com.android.server.devicepolicy.DevicePolicyManagerTest \
- -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
+ -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
(mmma frameworks/base/services/tests/servicestests/ for non-ninja build)
*/
@@ -458,6 +460,7 @@
*/
public void testSetDeviceOwner() throws Exception {
mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+ mContext.callerPermissions.add(permission.MANAGE_USERS);
mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
@@ -467,12 +470,29 @@
// Make sure admin1 is installed on system user.
setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
+ // Check various get APIs.
+ checkGetDeviceOwnerInfoApi(dpm, /* hasDeviceOwner =*/ false);
+
// DO needs to be an DA.
dpm.setActiveAdmin(admin1, /* replace =*/ false);
// Fire!
assertTrue(dpm.setDeviceOwner(admin1, "owner-name"));
+ // getDeviceOwnerComponent should return the admin1 component.
+ assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());
+ assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
+
+ // Check various get APIs.
+ checkGetDeviceOwnerInfoApi(dpm, /* hasDeviceOwner =*/ true);
+
+ // getDeviceOwnerComponent should *NOT* return the admin1 component for other users.
+ mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+ assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
+ assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
+
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
// Verify internal calls.
verify(mContext.iactivityManager, times(1)).updateDeviceOwner(
eq(admin1.getPackageName()));
@@ -485,7 +505,7 @@
MockUtils.checkIntentAction(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED),
MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
- assertEquals(admin1.getPackageName(), dpm.getDeviceOwner());
+ assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
// Try to set a profile owner on the same user, which should fail.
setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_SYSTEM_USER_UID);
@@ -502,11 +522,163 @@
// DPMS.getApplicationLabel() because Context.createPackageContextAsUser() is not mockable.
}
+ private void checkGetDeviceOwnerInfoApi(DevicePolicyManager dpm, boolean hasDeviceOwner) {
+ final int origCallingUser = mContext.binder.callingUid;
+ final List origPermissions = new ArrayList(mContext.callerPermissions);
+ mContext.callerPermissions.clear();
+
+ mContext.callerPermissions.add(permission.MANAGE_USERS);
+
+ mContext.binder.callingUid = Process.SYSTEM_UID;
+
+ // TODO Test getDeviceOwnerName() too. To do so, we need to change
+ // DPMS.getApplicationLabel() because Context.createPackageContextAsUser() is not mockable.
+ if (hasDeviceOwner) {
+ assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
+ assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
+ assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());
+
+ assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
+ assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
+ assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId());
+ } else {
+ assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
+ assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
+ assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
+
+ assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
+ assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser());
+ assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId());
+ }
+
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+ if (hasDeviceOwner) {
+ assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
+ assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
+ assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());
+
+ assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
+ assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
+ assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId());
+ } else {
+ assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
+ assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
+ assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
+
+ assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
+ assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser());
+ assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId());
+ }
+
+ mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+ // Still with MANAGE_USERS.
+ assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
+ assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
+ assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
+
+ if (hasDeviceOwner) {
+ assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
+ assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
+ assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId());
+ } else {
+ assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
+ assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser());
+ assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId());
+ }
+
+ mContext.binder.callingUid = Process.SYSTEM_UID;
+ mContext.callerPermissions.remove(permission.MANAGE_USERS);
+ // System can still call "OnAnyUser" without MANAGE_USERS.
+ if (hasDeviceOwner) {
+ assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
+ assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
+ assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());
+
+ assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
+ assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
+ assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId());
+ } else {
+ assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
+ assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
+ assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
+
+ assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
+ assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser());
+ assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId());
+ }
+
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+ // Still no MANAGE_USERS.
+ if (hasDeviceOwner) {
+ assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
+ assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
+ assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());
+ } else {
+ assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
+ assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
+ assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
+ }
+
+ try {
+ dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName());
+ fail();
+ } catch (SecurityException expected) {
+ }
+ try {
+ dpm.getDeviceOwnerComponentOnAnyUser();
+ fail();
+ } catch (SecurityException expected) {
+ }
+ try {
+ dpm.getDeviceOwnerUserId();
+ fail();
+ } catch (SecurityException expected) {
+ }
+ try {
+ dpm.getDeviceOwnerNameOnAnyUser();
+ fail();
+ } catch (SecurityException expected) {
+ }
+
+ mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+ // Still no MANAGE_USERS.
+ assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
+ assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
+ assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
+
+ try {
+ dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName());
+ fail();
+ } catch (SecurityException expected) {
+ }
+ try {
+ dpm.getDeviceOwnerComponentOnAnyUser();
+ fail();
+ } catch (SecurityException expected) {
+ }
+ try {
+ dpm.getDeviceOwnerUserId();
+ fail();
+ } catch (SecurityException expected) {
+ }
+ try {
+ dpm.getDeviceOwnerNameOnAnyUser();
+ fail();
+ } catch (SecurityException expected) {
+ }
+
+ // Restore.
+ mContext.binder.callingUid = origCallingUser;
+ mContext.callerPermissions.addAll(origPermissions);
+ }
+
+
/**
* Test for: {@link DevicePolicyManager#setDeviceOwner} Package doesn't exist.
*/
public void testSetDeviceOwner_noSuchPackage() {
mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+ mContext.callerPermissions.add(permission.MANAGE_USERS);
mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
@@ -528,6 +700,7 @@
public void testClearDeviceOwner() throws Exception {
mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+ mContext.callerPermissions.add(permission.MANAGE_USERS);
mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
@@ -547,7 +720,7 @@
verify(mContext.iactivityManager, times(1)).updateDeviceOwner(
eq(admin1.getPackageName()));
- assertEquals(admin1.getPackageName(), dpm.getDeviceOwner());
+ assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
// Set up other mocks.
when(mContext.userManager.getUserRestrictions()).thenReturn(new Bundle());
@@ -559,13 +732,14 @@
dpm.clearDeviceOwnerApp(admin1.getPackageName());
// Now DO shouldn't be set.
- assertNull(dpm.getDeviceOwner());
+ assertNull(dpm.getDeviceOwnerComponentOnAnyUser());
// TODO Check other calls.
}
public void testClearDeviceOwner_fromDifferentUser() throws Exception {
mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+ mContext.callerPermissions.add(permission.MANAGE_USERS);
mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
@@ -585,7 +759,7 @@
verify(mContext.iactivityManager, times(1)).updateDeviceOwner(
eq(admin1.getPackageName()));
- assertEquals(admin1.getPackageName(), dpm.getDeviceOwner());
+ assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
// Now call clear from the secondary user, which should throw.
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
@@ -601,8 +775,8 @@
assertEquals("clearDeviceOwner can only be called by the device owner", e.getMessage());
}
- // Now DO shouldn't be set.
- assertNotNull(dpm.getDeviceOwner());
+ // DO shouldn't be removed.
+ assertTrue(dpm.isDeviceManaged());
}
public void testSetProfileOwner() throws Exception {
@@ -639,6 +813,7 @@
mMockContext.addUser(ANOTHER_USER_ID, 0); // Add one more user.
mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+ mContext.callerPermissions.add(permission.MANAGE_USERS);
mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
@@ -667,8 +842,7 @@
mContext.setUserRunning(DpmMockContext.CALLER_USER_HANDLE, true);
assertTrue(dpm.setDeviceOwner(admin2, "owner-name", DpmMockContext.CALLER_USER_HANDLE));
- // Make sure it's set.
- assertEquals(admin2, dpm.getDeviceOwnerComponent());
+ assertEquals(admin2, dpms.getDeviceOwnerComponent(/* callingUserOnly =*/ false));
// Then check getDeviceOwnerAdminLocked().
assertEquals(admin2, dpms.getDeviceOwnerAdminLocked().info.getComponent());
@@ -692,7 +866,7 @@
dpms.mOwners.writeDeviceOwner();
// Make sure the DO component name doesn't have a class name.
- assertEquals("", dpms.getDeviceOwner().getClassName());
+ assertEquals("", dpms.getDeviceOwnerComponent(/* callingUserOnly =*/ false).getClassName());
// Then create a new DPMS to have it load the settings from files.
when(mContext.userManager.getUserRestrictions(any(UserHandle.class)))
@@ -702,7 +876,7 @@
// Now the DO component name is a full name.
// *BUT* because both admin1 and admin2 belong to the same package, we think admin1 is the
// DO.
- assertEquals(admin1, dpms.getDeviceOwner());
+ assertEquals(admin1, dpms.getDeviceOwnerComponent(/* callingUserOnly =*/ false));
}
public void testSetGetApplicationRestriction() {
@@ -740,6 +914,7 @@
public void testSetUserRestriction_asDo() throws Exception {
mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+ mContext.callerPermissions.add(permission.MANAGE_USERS);
mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);