Add DO API to get wifi mac address

Bug 25496044

Change-Id: Ib1f0ce4ca10951edcfaa0aa79ae5c2d142a74599
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index b3b647f..5c3a55d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -71,6 +71,8 @@
 import android.net.ConnectivityManager;
 import android.net.ProxyInfo;
 import android.net.Uri;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
 import android.os.AsyncTask;
 import android.os.Binder;
 import android.os.Bundle;
@@ -1121,6 +1123,10 @@
             return Looper.myLooper();
         }
 
+        WifiManager getWifiManager() {
+            return mContext.getSystemService(WifiManager.class);
+        }
+
         long binderClearCallingIdentity() {
             return Binder.clearCallingIdentity();
         }
@@ -6871,6 +6877,25 @@
         return true;
     }
 
+    @Override
+    public String getWifiMacAddress() {
+        // Make sure caller has DO.
+        synchronized (this) {
+            getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+        }
+
+        final long ident = mInjector.binderClearCallingIdentity();
+        try {
+            final WifiInfo wifiInfo = mInjector.getWifiManager().getConnectionInfo();
+            if (wifiInfo == null) {
+                return null;
+            }
+            return wifiInfo.hasRealMacAddress() ? wifiInfo.getMacAddress() : null;
+        } finally {
+            mInjector.binderRestoreCallingIdentity(ident);
+        }
+    }
+
     /**
      * Returns the target sdk version number that the given packageName was built for
      * in the given user.
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 79ba08d..0159356 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -26,10 +26,12 @@
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.pm.PackageManager;
+import android.net.wifi.WifiInfo;
 import android.os.Bundle;
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.test.MoreAsserts;
 import android.util.Pair;
 
 import org.mockito.ArgumentCaptor;
@@ -1175,4 +1177,64 @@
 
         // TODO Make sure restrictions are written to the file.
     }
+
+    public void testGetMacAddress() throws Exception {
+        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
+
+        // In this test, change the caller user to "system".
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+        // Make sure admin1 is installed on system user.
+        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
+
+        // Test 1. Caller doesn't have DO or DA.
+        try {
+            dpm.getWifiMacAddress();
+            fail();
+        } catch (SecurityException e) {
+            MoreAsserts.assertContainsRegex("No active admin owned", e.getMessage());
+        }
+
+        // DO needs to be an DA.
+        dpm.setActiveAdmin(admin1, /* replace =*/ false);
+        assertTrue(dpm.isAdminActive(admin1));
+
+        // Test 2. Caller has DA, but not DO.
+        try {
+            dpm.getWifiMacAddress();
+            fail();
+        } catch (SecurityException e) {
+            MoreAsserts.assertContainsRegex("No active admin owned", e.getMessage());
+        }
+
+        // Test 3. Caller has PO, but not DO.
+        assertTrue(dpm.setProfileOwner(admin1, null, UserHandle.USER_SYSTEM));
+        try {
+            dpm.getWifiMacAddress();
+            fail();
+        } catch (SecurityException e) {
+            MoreAsserts.assertContainsRegex("No active admin owned", e.getMessage());
+        }
+
+        // Remove PO.
+        dpm.clearProfileOwner(admin1);
+
+        // Test 4, Caller is DO now.
+        assertTrue(dpm.setDeviceOwner(admin1, null, UserHandle.USER_SYSTEM));
+
+        // 4-1.  But no WifiInfo.
+        assertNull(dpm.getWifiMacAddress());
+
+        // 4-2.  Returns WifiInfo, but with the default MAC.
+        when(mContext.wifiManager.getConnectionInfo()).thenReturn(new WifiInfo());
+        assertNull(dpm.getWifiMacAddress());
+
+        // 4-3. With a real MAC address.
+        final WifiInfo wi = new WifiInfo();
+        wi.setMacAddress("11:22:33:44:55:66");
+        when(mContext.wifiManager.getConnectionInfo()).thenReturn(wi);
+        assertEquals("11:22:33:44:55:66", dpm.getWifiMacAddress());
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index bb1e06d..66d701d 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -31,6 +31,7 @@
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.UserInfo;
 import android.media.IAudioService;
+import android.net.wifi.WifiManager;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.PowerManager.WakeLock;
@@ -217,6 +218,7 @@
     public final IBackupManager ibackupManager;
     public final IAudioService iaudioService;
     public final LockPatternUtils lockPatternUtils;
+    public final WifiManager wifiManager;
     public final SettingsForMock settings;
     public final MockContentResolver contentResolver;
 
@@ -249,6 +251,7 @@
         ibackupManager = mock(IBackupManager.class);
         iaudioService = mock(IAudioService.class);
         lockPatternUtils = mock(LockPatternUtils.class);
+        wifiManager = mock(WifiManager.class);
         settings = mock(SettingsForMock.class);
 
         // Package manager is huge, so we use a partial mock instead.
@@ -303,6 +306,8 @@
                 return userManager;
             case Context.POWER_SERVICE:
                 return powerManager;
+            case Context.WIFI_SERVICE:
+                return wifiManager;
         }
         throw new UnsupportedOperationException();
     }