getWifiMacAddress: Enable for profile owner on org-owned device
Allow the profile owner on an organization-owned device to call
getWifiMacAddress.
Part of this change is introducing a new DeviceAdminInfo policy,
USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER, which can be used
to find out if the admin is either device owner or profile owner
on organization-owned device.
Bug: 138709470
Bug: 145308393
Bug: 145336515
Test: atest CtsDevicePolicyManagerTestCases:com.android.cts.devicepolicy.MixedDeviceOwnerTest#testWifi
Test: atest CtsDevicePolicyManagerTestCases:com.android.cts.devicepolicy.MixedManagedProfileOwnerTest#testWifiMacAddress
Test: atest CtsDevicePolicyManagerTestCases:com.android.cts.devicepolicy.OrgOwnedProfileOwnerTest#testWifi
Change-Id: Id790408a07b9dd19530563bd2aa9216a7333e863
diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java
index 00903c4..63bc40b 100644
--- a/core/java/android/app/admin/DeviceAdminInfo.java
+++ b/core/java/android/app/admin/DeviceAdminInfo.java
@@ -55,6 +55,14 @@
static final String TAG = "DeviceAdminInfo";
/**
+ * A type of policy that this device admin can use: profile owner on an organization-owned
+ * device.
+ *
+ * @hide
+ */
+ public static final int USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER = -3;
+
+ /**
* A type of policy that this device admin can use: device owner meta-policy
* for an admin that is designated as owner of the device.
*
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 39dc51e..34ceb08 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -9135,7 +9135,14 @@
}
/**
- * Called by device owner to get the MAC address of the Wi-Fi device.
+ * Called by device owner, or profile owner on organization-owned device, to get the MAC
+ * address of the Wi-Fi device.
+ *
+ * NOTE: The MAC address returned here should only be used for inventory management and is
+ * not likely to be the MAC address used by the device to connect to Wi-Fi networks: MAC
+ * addresses used for scanning and connecting to Wi-Fi networks are randomized by default.
+ * To get the randomized MAC address used, call
+ * {@link android.net.wifi.WifiConfiguration#getRandomizedMacAddress}.
*
* @param admin Which device owner this request is associated with.
* @return the MAC address of the Wi-Fi device, or null when the information is not available.
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 2499ad8..c2993ae 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2748,6 +2748,9 @@
return null;
}
+ // Code for handling failure from getActiveAdminWithPolicyForUidLocked to find an admin
+ // that satisfies the required policy.
+ // Throws a security exception with the right error message.
if (who != null) {
final int userId = UserHandle.getUserId(callingUid);
final DevicePolicyData policy = getUserData(userId);
@@ -2763,6 +2766,10 @@
throw new SecurityException("Admin " + admin.info.getComponent()
+ " does not own the profile");
}
+ if (reqPolicy == DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER) {
+ throw new SecurityException("Admin " + admin.info.getComponent()
+ + " is not the profile owner on organization-owned device");
+ }
if (DA_DISALLOWED_POLICIES.contains(reqPolicy) && !isDeviceOwner && !isProfileOwner) {
throw new SecurityException("Admin " + admin.info.getComponent()
+ " is not a device owner or profile owner, so may not use policy: "
@@ -2869,12 +2876,16 @@
ensureLocked();
final boolean ownsDevice = isDeviceOwner(admin.info.getComponent(), userId);
final boolean ownsProfile = isProfileOwner(admin.info.getComponent(), userId);
+ final boolean ownsProfileOnOrganizationOwnedDevice =
+ isProfileOwnerOfOrganizationOwnedDevice(admin.info.getComponent(), userId);
if (reqPolicy == DeviceAdminInfo.USES_POLICY_DEVICE_OWNER) {
return ownsDevice;
+ } else if (reqPolicy == DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER) {
+ return ownsDevice || ownsProfileOnOrganizationOwnedDevice;
} else if (reqPolicy == DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) {
// DO always has the PO power.
- return ownsDevice || ownsProfile;
+ return ownsDevice || ownsProfileOnOrganizationOwnedDevice || ownsProfile;
} else {
boolean allowedToUsePolicy = ownsDevice || ownsProfile
|| !DA_DISALLOWED_POLICIES.contains(reqPolicy)
@@ -5574,6 +5585,13 @@
}
}
+ private void enforceDeviceOwnerOrProfileOwnerOnOrganizationOwnedDevice(ComponentName who) {
+ synchronized (getLockObject()) {
+ getActiveAdminForCallerLocked(
+ who, DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER);
+ }
+ }
+
private void enforceProfileOwnerOfOrganizationOwnedDevice(ActiveAdmin admin) {
if (!isProfileOwnerOfOrganizationOwnedDevice(admin)) {
throw new SecurityException(String.format("Provided admin %s is either not a profile "
@@ -8071,21 +8089,12 @@
return false;
}
- final int adminUserId = admin.getUserHandle().getIdentifier();
+ return isProfileOwnerOfOrganizationOwnedDevice(
+ admin.info.getComponent(), admin.getUserHandle().getIdentifier());
+ }
- if (!isProfileOwner(admin.info.getComponent(), adminUserId)) {
- Slog.w(LOG_TAG, String.format("%s is not profile owner of user %d",
- admin.info.getComponent(), adminUserId));
- return false;
- }
-
- if (!canProfileOwnerAccessDeviceIds(adminUserId)) {
- Slog.w(LOG_TAG, String.format("Profile owner of user %d does not own the device.",
- adminUserId));
- return false;
- }
-
- return true;
+ private boolean isProfileOwnerOfOrganizationOwnedDevice(ComponentName who, int userId) {
+ return isProfileOwner(who, userId) && canProfileOwnerAccessDeviceIds(userId);
}
@Override
@@ -12377,7 +12386,7 @@
@Override
public String getWifiMacAddress(ComponentName admin) {
// Make sure caller has DO.
- enforceDeviceOwner(admin);
+ enforceDeviceOwnerOrProfileOwnerOnOrganizationOwnedDevice(admin);
final long ident = mInjector.binderClearCallingIdentity();
try {
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 0590020..ba7d24b2 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -138,6 +138,8 @@
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 NOT_ORG_OWNED_PROFILE_OWNER_MSG =
+ "not the profile owner on organization-owned device";
public static final String ONGOING_CALL_MSG = "ongoing call on the device";
// TODO replace all instances of this with explicit {@link #mServiceContext}.
@@ -2114,12 +2116,14 @@
assertTrue(dpm.isAdminActive(admin1));
// Test 2. Caller has DA, but not DO.
- assertExpectException(SecurityException.class, /* messageRegex= */ NOT_DEVICE_OWNER_MSG,
+ assertExpectException(SecurityException.class,
+ /* messageRegex= */ NOT_ORG_OWNED_PROFILE_OWNER_MSG,
() -> dpm.getWifiMacAddress(admin1));
// Test 3. Caller has PO, but not DO.
assertTrue(dpm.setProfileOwner(admin1, null, UserHandle.USER_SYSTEM));
- assertExpectException(SecurityException.class, /* messageRegex= */ NOT_DEVICE_OWNER_MSG,
+ assertExpectException(SecurityException.class,
+ /* messageRegex= */ NOT_ORG_OWNED_PROFILE_OWNER_MSG,
() -> dpm.getWifiMacAddress(admin1));
// Remove PO.
@@ -2141,6 +2145,15 @@
assertEquals("11:22:33:44:55:66", dpm.getWifiMacAddress(admin1));
}
+ public void testGetMacAddressByOrgOwnedPO() throws Exception {
+ setupProfileOwner();
+ configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
+
+ final String[] macAddresses = new String[]{"11:22:33:44:55:66"};
+ when(getServices().wifiManager.getFactoryMacAddresses()).thenReturn(macAddresses);
+ assertEquals("11:22:33:44:55:66", dpm.getWifiMacAddress(admin1));
+ }
+
public void testReboot() throws Exception {
mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);