diff options
author | Bartosz Fabianowski <bartfab@google.com> | 2016-02-12 10:30:55 +0100 |
---|---|---|
committer | Bartosz Fabianowski <bartfab@google.com> | 2016-02-12 10:30:55 +0100 |
commit | 0fb9cf43830d67894b519c9a6271320c4842a5c0 (patch) | |
tree | 776bdaf325ad9741093e799ba774a7ea3090f112 | |
parent | 75ad7fa297007a0cfe1b5a02f45c78441d819d42 (diff) | |
download | android_frameworks_opt_net_wifi-0fb9cf43830d67894b519c9a6271320c4842a5c0.tar.gz android_frameworks_opt_net_wifi-0fb9cf43830d67894b519c9a6271320c4842a5c0.tar.bz2 android_frameworks_opt_net_wifi-0fb9cf43830d67894b519c9a6271320c4842a5c0.zip |
Allow managed profile to modify networks
If the current foreground user has a managed profile, apps running in that
profile should have the same permissions to add/remove/modify networks as
apps running as the foreground user itself.
This is a re-submit of
https://partner-android-review.googlesource.com/#/c/529950/
with updated unit tests that will also work after merging to N/master.
BUG=26867426
Change-Id: If97734abad801ae1264919c91c3ef4236469cfde
14 files changed, 673 insertions, 73 deletions
diff --git a/service/java/com/android/server/wifi/ConfigurationMap.java b/service/java/com/android/server/wifi/ConfigurationMap.java index 809952014..376e8e606 100644 --- a/service/java/com/android/server/wifi/ConfigurationMap.java +++ b/service/java/com/android/server/wifi/ConfigurationMap.java @@ -1,7 +1,9 @@ package com.android.server.wifi; +import android.content.pm.UserInfo; import android.net.wifi.WifiConfiguration; import android.os.UserHandle; +import android.os.UserManager; import java.util.ArrayList; import java.util.Collection; @@ -17,13 +19,20 @@ public class ConfigurationMap { private final Map<Integer, WifiConfiguration> mPerIDForCurrentUser = new HashMap<>(); private final Map<String, WifiConfiguration> mPerFQDNForCurrentUser = new HashMap<>(); + private final UserManager mUserManager; + private int mCurrentUserId = UserHandle.USER_SYSTEM; + ConfigurationMap(UserManager userManager) { + mUserManager = userManager; + } + // RW methods: public WifiConfiguration put(WifiConfiguration config) { final WifiConfiguration current = mPerID.put(config.networkId, config); mPerConfigKey.put(config.configKey().hashCode(), config); // This is ridiculous... - if (config.isVisibleToUser(mCurrentUserId)) { + if (WifiConfigurationUtil.isVisibleToAnyProfile(config, + mUserManager.getProfiles(mCurrentUserId))) { mPerIDForCurrentUser.put(config.networkId, config); if (config.FQDN != null && config.FQDN.length() > 0) { mPerFQDNForCurrentUser.put(config.FQDN, config); @@ -70,18 +79,19 @@ public class ConfigurationMap { mPerIDForCurrentUser.clear(); mPerFQDNForCurrentUser.clear(); - final int previousUserId = mCurrentUserId; + final List<UserInfo> previousUserProfiles = mUserManager.getProfiles(mCurrentUserId); mCurrentUserId = userId; + final List<UserInfo> currentUserProfiles = mUserManager.getProfiles(mCurrentUserId); final List<WifiConfiguration> hiddenConfigurations = new ArrayList<>(); for (Map.Entry<Integer, WifiConfiguration> entry : mPerID.entrySet()) { final WifiConfiguration config = entry.getValue(); - if (config.isVisibleToUser(mCurrentUserId)) { + if (WifiConfigurationUtil.isVisibleToAnyProfile(config, currentUserProfiles)) { mPerIDForCurrentUser.put(entry.getKey(), config); if (config.FQDN != null && config.FQDN.length() > 0) { mPerFQDNForCurrentUser.put(config.FQDN, config); } - } else if (config.isVisibleToUser(previousUserId)) { + } else if (WifiConfigurationUtil.isVisibleToAnyProfile(config, previousUserProfiles)) { hiddenConfigurations.add(config); } } diff --git a/service/java/com/android/server/wifi/FrameworkFacade.java b/service/java/com/android/server/wifi/FrameworkFacade.java index 2ecfe07cc..ef7d91dab 100644 --- a/service/java/com/android/server/wifi/FrameworkFacade.java +++ b/service/java/com/android/server/wifi/FrameworkFacade.java @@ -1,6 +1,7 @@ package com.android.server.wifi; +import android.app.AppGlobals; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; @@ -8,6 +9,7 @@ import android.net.TrafficStats; import android.net.ip.IpManager; import android.os.Handler; import android.os.IBinder; +import android.os.RemoteException; import android.os.ServiceManager; import android.provider.Settings; @@ -66,5 +68,15 @@ public class FrameworkFacade { Context context, String iface, IpManager.Callback callback) { return new IpManager(context, iface, callback); } -} + /** + * Checks whether the given uid has been granted the given permission. + * @param permName the permission to check + * @param uid The uid to check + * @return {@link PackageManager.PERMISSION_GRANTED} if the permission has been granted and + * {@link PackageManager.PERMISSION_DENIED} otherwise + */ + public int checkUidPermission(String permName, int uid) throws RemoteException { + return AppGlobals.getPackageManager().checkUidPermission(permName, uid); + } +} diff --git a/service/java/com/android/server/wifi/WifiConfigStore.java b/service/java/com/android/server/wifi/WifiConfigStore.java index cc9e5068f..124a6ad38 100644 --- a/service/java/com/android/server/wifi/WifiConfigStore.java +++ b/service/java/com/android/server/wifi/WifiConfigStore.java @@ -18,7 +18,6 @@ package com.android.server.wifi; import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID; -import android.app.AppGlobals; import android.app.admin.DeviceAdminInfo; import android.app.admin.DevicePolicyManagerInternal; import android.content.ContentResolver; @@ -49,6 +48,7 @@ import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; +import android.os.UserManager; import android.provider.Settings; import android.security.Credentials; import android.security.KeyChain; @@ -176,7 +176,7 @@ public class WifiConfigStore extends IpConfigStore { private static final String PPS_FILE = "/data/misc/wifi/PerProviderSubscription.conf"; /* configured networks with network id as the key */ - private final ConfigurationMap mConfiguredNetworks = new ConfigurationMap(); + private final ConfigurationMap mConfiguredNetworks; /* A network id is a unique identifier for a network configured in the * supplicant. Network ids are generated when the supplicant reads @@ -549,7 +549,8 @@ public class WifiConfigStore extends IpConfigStore { private WifiStateMachine mWifiStateMachine; private FrameworkFacade mFacade; - WifiConfigStore(Context c, WifiStateMachine w, WifiNative wn, FrameworkFacade f) { + WifiConfigStore(Context c, WifiStateMachine w, WifiNative wn, FrameworkFacade f, + UserManager userManager) { mContext = c; mFacade = f; mWifiNative = wn; @@ -681,6 +682,7 @@ public class WifiConfigStore extends IpConfigStore { boolean hs2on = mContext.getResources().getBoolean(R.bool.config_wifi_hotspot2_enabled); Log.d(Utils.hs2LogTag(getClass()), "Passpoint is " + (hs2on ? "enabled" : "disabled")); + mConfiguredNetworks = new ConfigurationMap(userManager); mMOManager = new PasspointManagementObjectManager(new File(PPS_FILE), hs2on); mEnableOsuQueries = true; mAnqpCache = new AnqpCache(); @@ -972,7 +974,8 @@ public class WifiConfigStore extends IpConfigStore { boolean selectNetwork(WifiConfiguration config, boolean updatePriorities, int uid) { if (VDBG) localLogNetwork("selectNetwork", config.networkId); if (config.networkId == INVALID_NETWORK_ID) return false; - if (!config.isVisibleToUser(mWifiStateMachine.getCurrentUserId())) { + if (!WifiConfigurationUtil.isVisibleToAnyProfile(config, + mWifiStateMachine.getCurrentUserProfiles())) { loge("selectNetwork " + Integer.toString(config.networkId) + ": Network config is not " + "visible to current user."); return false; @@ -1048,7 +1051,8 @@ public class WifiConfigStore extends IpConfigStore { return new NetworkUpdateResult(INVALID_NETWORK_ID); } - if (!config.isVisibleToUser(mWifiStateMachine.getCurrentUserId())) { + if (!WifiConfigurationUtil.isVisibleToAnyProfile(config, + mWifiStateMachine.getCurrentUserProfiles())) { return new NetworkUpdateResult(INVALID_NETWORK_ID); } @@ -1267,7 +1271,8 @@ public class WifiConfigStore extends IpConfigStore { * @return network Id */ int addOrUpdateNetwork(WifiConfiguration config, int uid) { - if (config == null || !config.isVisibleToUser(mWifiStateMachine.getCurrentUserId())) { + if (config == null || !WifiConfigurationUtil.isVisibleToAnyProfile(config, + mWifiStateMachine.getCurrentUserProfiles())) { return WifiConfiguration.INVALID_NETWORK_ID; } @@ -3393,7 +3398,8 @@ public class WifiConfigStore extends IpConfigStore { * @param config */ public void linkConfiguration(WifiConfiguration config) { - if (!config.isVisibleToUser(mWifiStateMachine.getCurrentUserId())) { + if (!WifiConfigurationUtil.isVisibleToAnyProfile(config, + mWifiStateMachine.getCurrentUserProfiles())) { loge("linkConfiguration: Attempting to link config " + config.configKey() + " that is not visible to the current user."); return; @@ -4611,7 +4617,7 @@ public class WifiConfigStore extends IpConfigStore { boolean checkConfigOverridePermission(int uid) { try { - return (AppGlobals.getPackageManager().checkUidPermission( + return (mFacade.checkUidPermission( android.Manifest.permission.OVERRIDE_WIFI_CONFIG, uid) == PackageManager.PERMISSION_GRANTED); } catch (RemoteException e) { diff --git a/service/java/com/android/server/wifi/WifiConfigurationUtil.java b/service/java/com/android/server/wifi/WifiConfigurationUtil.java new file mode 100644 index 000000000..7d0fb3cb3 --- /dev/null +++ b/service/java/com/android/server/wifi/WifiConfigurationUtil.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wifi; + +import android.content.pm.UserInfo; +import android.net.wifi.WifiConfiguration; +import android.os.UserHandle; + +import java.util.List; + +/** + * Helper for working with {@link android.net.wifi.WifiConfiguration} objects. + */ +public class WifiConfigurationUtil { + /** + * Check whether a network configuration is visible to a user or any of its managed profiles. + * @param config the network configuration whose visibility should be checked + * @param profiles the user IDs of the user itself and all its managed profiles (can be obtained + * via {@link android.os.UserManager.getProfiles}) + * @return whether the network configuration is visible to the user or any of its managed + * profiles + */ + public static boolean isVisibleToAnyProfile(WifiConfiguration config, List<UserInfo> profiles) { + if (config.shared) { + return true; + } + final int creatorUserId = UserHandle.getUserId(config.creatorUid); + for (UserInfo profile : profiles) { + if (profile.id == creatorUserId) { + return true; + } + } + return false; + } +} diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java index d752182c0..0bc8bb38a 100644 --- a/service/java/com/android/server/wifi/WifiServiceImpl.java +++ b/service/java/com/android/server/wifi/WifiServiceImpl.java @@ -313,13 +313,14 @@ public class WifiServiceImpl extends IWifiManager.Stub { mWifiMetrics = new WifiMetrics(); mTrafficPoller = new WifiTrafficPoller(mContext, wifiThread.getLooper(), WifiNative.getWlanNativeInterface().getInterfaceName()); - mWifiStateMachine = new WifiStateMachine(mContext, mTrafficPoller, facade, mWifiMetrics); + mUserManager = UserManager.get(mContext); + mWifiStateMachine = new WifiStateMachine(mContext, mTrafficPoller, facade, mWifiMetrics, + mUserManager); mSettingsStore = new WifiSettingsStore(mContext); mWifiStateMachine.enableRssiPolling(true); mBatteryStats = BatteryStatsService.getService(); mPowerManager = context.getSystemService(PowerManager.class); mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE); - mUserManager = UserManager.get(mContext); mNotificationController = new WifiNotificationController(mContext, mWifiStateMachine); diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java index 959ab19bd..c27ec2742 100644 --- a/service/java/com/android/server/wifi/WifiStateMachine.java +++ b/service/java/com/android/server/wifi/WifiStateMachine.java @@ -40,6 +40,7 @@ import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; +import android.content.pm.UserInfo; import android.database.ContentObserver; import android.net.ConnectivityManager; import android.net.DhcpResults; @@ -90,6 +91,7 @@ import android.os.RemoteException; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; +import android.os.UserManager; import android.os.WorkSource; import android.provider.Settings; import android.telephony.TelephonyManager; @@ -199,6 +201,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno private final AtomicBoolean mP2pConnected = new AtomicBoolean(false); private boolean mTemporarilyDisconnectWifi = false; private final String mPrimaryDeviceType; + private final UserManager mUserManager; /* Scan results handling */ private List<ScanDetail> mScanResults = new ArrayList<>(); @@ -1148,11 +1151,13 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno private FrameworkFacade mFacade; public WifiStateMachine(Context context, WifiTrafficPoller trafficPoller, - FrameworkFacade facade, WifiMetrics wifiMetrics) { + FrameworkFacade facade, WifiMetrics wifiMetrics, + UserManager userManager) { super("WifiStateMachine"); mWifiMetrics = wifiMetrics; mContext = context; mFacade = facade; + mUserManager = userManager; mWifiNative = WifiNative.getWlanNativeInterface(); // TODO refactor WifiNative use of context out into it's own class @@ -1168,7 +1173,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno mP2pSupported = mContext.getPackageManager().hasSystemFeature( PackageManager.FEATURE_WIFI_DIRECT); - mWifiConfigStore = new WifiConfigStore(context, this, mWifiNative, facade); + mWifiConfigStore = new WifiConfigStore(context, this, mWifiNative, facade, userManager); mWifiMonitor = WifiMonitor.getInstance(); @@ -7039,7 +7044,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno break; case CMD_ADD_OR_UPDATE_NETWORK: // Only the current foreground user can modify networks. - if (UserHandle.getUserId(message.sendingUid) != mCurrentUserId) { + if (!isCurrentUserProfile(UserHandle.getUserId(message.sendingUid))) { loge("Only the current foreground user can modify networks " + " currentUserId=" + mCurrentUserId + " sendingUserId=" + UserHandle.getUserId(message.sendingUid)); @@ -7090,7 +7095,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno break; case CMD_REMOVE_NETWORK: // Only the current foreground user can modify networks. - if (UserHandle.getUserId(message.sendingUid) != mCurrentUserId) { + if (!isCurrentUserProfile(UserHandle.getUserId(message.sendingUid))) { loge("Only the current foreground user can modify networks " + " currentUserId=" + mCurrentUserId + " sendingUserId=" + UserHandle.getUserId(message.sendingUid)); @@ -7116,7 +7121,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno break; case CMD_ENABLE_NETWORK: // Only the current foreground user can modify networks. - if (UserHandle.getUserId(message.sendingUid) != mCurrentUserId) { + if (!isCurrentUserProfile(UserHandle.getUserId(message.sendingUid))) { loge("Only the current foreground user can modify networks " + " currentUserId=" + mCurrentUserId + " sendingUserId=" + UserHandle.getUserId(message.sendingUid)); @@ -7385,7 +7390,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno // lastConnectUid on a per-user basis. int lastConnectUid = WifiConfiguration.UNKNOWN_UID; if (mWifiConfigStore.isLastSelectedConfiguration(config) - && UserHandle.getUserId(config.lastConnectUid) == mCurrentUserId) { + && isCurrentUserProfile(UserHandle.getUserId(config.lastConnectUid))) { lastConnectUid = config.lastConnectUid; } mWifiMetrics.startConnectionEvent(mWifiInfo, config, @@ -7451,7 +7456,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno break; case WifiManager.CONNECT_NETWORK: // Only the current foreground user can modify networks. - if (UserHandle.getUserId(message.sendingUid) != mCurrentUserId) { + if (!isCurrentUserProfile(UserHandle.getUserId(message.sendingUid))) { loge("Only the current foreground user can modify networks " + " currentUserId=" + mCurrentUserId + " sendingUserId=" + UserHandle.getUserId(message.sendingUid)); @@ -7599,7 +7604,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno // Fall thru case WifiStateMachine.CMD_AUTO_SAVE_NETWORK: // Only the current foreground user can modify networks. - if (UserHandle.getUserId(message.sendingUid) != mCurrentUserId) { + if (!isCurrentUserProfile(UserHandle.getUserId(message.sendingUid))) { loge("Only the current foreground user can modify networks " + " currentUserId=" + mCurrentUserId + " sendingUserId=" + UserHandle.getUserId(message.sendingUid)); @@ -7698,7 +7703,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno break; case WifiManager.FORGET_NETWORK: // Only the current foreground user can modify networks. - if (UserHandle.getUserId(message.sendingUid) != mCurrentUserId) { + if (!isCurrentUserProfile(UserHandle.getUserId(message.sendingUid))) { loge("Only the current foreground user can modify networks " + " currentUserId=" + mCurrentUserId + " sendingUserId=" + UserHandle.getUserId(message.sendingUid)); @@ -10051,6 +10056,18 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno return mCurrentUserId; } + private boolean isCurrentUserProfile(int userId) { + if (userId == mCurrentUserId) { + return true; + } + final UserInfo parent = mUserManager.getProfileParent(userId); + return parent != null && parent.id == mCurrentUserId; + } + + public List<UserInfo> getCurrentUserProfiles() { + return mUserManager.getProfiles(mCurrentUserId); + } + /** * @param reason reason code from supplicant on network disconnected event * @return true if this is a suspicious disconnect diff --git a/tests/wifitests/src/com/android/server/wifi/BinderUtil.java b/tests/wifitests/src/com/android/server/wifi/BinderUtil.java new file mode 100644 index 000000000..107de7c8d --- /dev/null +++ b/tests/wifitests/src/com/android/server/wifi/BinderUtil.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wifi; + +import android.os.Binder; + +/** + * Utilities for faking the calling uid in Binder. + */ +public class BinderUtil { + /** + * Fake the calling uid in Binder. + * @param uid the calling uid that Binder should return from now on + */ + public static void setUid(int uid) { + Binder.restoreCallingIdentity((((long) uid) << 32) | Binder.getCallingPid()); + } +} diff --git a/tests/wifitests/src/com/android/server/wifi/BinderUtilTest.java b/tests/wifitests/src/com/android/server/wifi/BinderUtilTest.java new file mode 100644 index 000000000..925bdc0c2 --- /dev/null +++ b/tests/wifitests/src/com/android/server/wifi/BinderUtilTest.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wifi; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + +import android.os.Binder; +import android.test.suitebuilder.annotation.SmallTest; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Unit tests for {@link com.android.server.wifi.BinderUtil}. + */ +@SmallTest +public class BinderUtilTest { + static final int FAKE_UID = 30000000; + + private long mToken; + + /** + * Sets up the test harness before running a test. + */ + @Before + public void setUp() { + mToken = Binder.clearCallingIdentity(); + } + + /** + * Cleans up the test harness after running a test. + */ + @After + public void cleanUp() { + Binder.restoreCallingIdentity(mToken); + } + + /** + * Test using {@link BinderUtil.setUid} to set and restore the Binder uid. + */ + @Test + public void setUid() { + final int pid = Binder.getCallingPid(); + final int uid = Binder.getCallingUid(); + assertFalse(uid == FAKE_UID); + + // Verify that setUid() can be used to fake the Binder uid without affecting the pid. + BinderUtil.setUid(FAKE_UID); + assertEquals(pid, Binder.getCallingPid()); + assertEquals(FAKE_UID, Binder.getCallingUid()); + + // Verify that setUid() can be used to restore the original Binder uid without affecting the + // pid. + BinderUtil.setUid(uid); + assertEquals(pid, Binder.getCallingPid()); + assertEquals(uid, Binder.getCallingUid()); + } + + /** + * Test using {@link BinderUtil.setUid} to set the Binder uid and + * {@link Binder.restoreCallingIdentity} to restore it. + */ + @Test + public void setUidAndRestoreCallingIdentity() { + final int pid = Binder.getCallingPid(); + final int uid = Binder.getCallingUid(); + assertFalse(uid == FAKE_UID); + + // Verify that setUid() can be used to fake the Binder uid without affecting the pid. + BinderUtil.setUid(FAKE_UID); + assertEquals(pid, Binder.getCallingPid()); + assertEquals(FAKE_UID, Binder.getCallingUid()); + + // Verify that the setUid() calls above did not break Binder.restoreCallingIdentity(). + Binder.restoreCallingIdentity(mToken); + assertEquals(pid, Binder.getCallingPid()); + assertEquals(uid, Binder.getCallingUid()); + } +} diff --git a/tests/wifitests/src/com/android/server/wifi/ConfigurationMapTest.java b/tests/wifitests/src/com/android/server/wifi/ConfigurationMapTest.java index 917fd77a7..328feaf75 100644 --- a/tests/wifitests/src/com/android/server/wifi/ConfigurationMapTest.java +++ b/tests/wifitests/src/com/android/server/wifi/ConfigurationMapTest.java @@ -18,12 +18,22 @@ package com.android.server.wifi; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.when; +import android.content.pm.UserInfo; import android.net.wifi.WifiConfiguration; import android.os.UserHandle; +import android.os.UserManager; import android.test.suitebuilder.annotation.SmallTest; +import android.util.SparseArray; +import com.android.server.wifi.MockAnswerUtil.AnswerWithArguments; + +import org.junit.Before; import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.Arrays; @@ -37,25 +47,56 @@ import java.util.Set; @SmallTest public class ConfigurationMapTest { private static final List<WifiConfiguration> CONFIGS = Arrays.asList( - WifiConfigurationUtil.generateWifiConfig(0, 1000000, "\"red\"", true, true, null, null), - WifiConfigurationUtil.generateWifiConfig( - 1, 1000001, "\"green\"", false, true, null, null), - WifiConfigurationUtil.generateWifiConfig( - 2, 1000002, "\"blue\"", true, false, "example.com", "Blue"), - WifiConfigurationUtil.generateWifiConfig( + WifiConfigurationTestUtil.generateWifiConfig( + 0, 1000000, "\"red\"", true, true, null, null), + WifiConfigurationTestUtil.generateWifiConfig( + 1, 1000001, "\"green\"", true, false, "example.com", "Green"), + WifiConfigurationTestUtil.generateWifiConfig( + 2, 1200000, "\"blue\"", false, true, null, null), + WifiConfigurationTestUtil.generateWifiConfig( 3, 1100000, "\"cyan\"", true, true, null, null), - WifiConfigurationUtil.generateWifiConfig( - 4, 1100001, "\"yellow\"", false, false, null, null), - WifiConfigurationUtil.generateWifiConfig( - 5, 1100002, "\"magenta\"", true, true, "example.org", "Magenta")); + WifiConfigurationTestUtil.generateWifiConfig( + 4, 1100001, "\"yellow\"", true, true, "example.org", "Yellow"), + WifiConfigurationTestUtil.generateWifiConfig( + 5, 1100002, "\"magenta\"", false, false, null, null)); + + private static final SparseArray<List<UserInfo>> USER_PROFILES = new SparseArray<>(); + static { + USER_PROFILES.put(UserHandle.USER_SYSTEM, Arrays.asList( + new UserInfo(UserHandle.USER_SYSTEM, "Owner", 0), + new UserInfo(12, "Managed Profile", 0))); + USER_PROFILES.put(10, Arrays.asList(new UserInfo(10, "Alice", 0))); + USER_PROFILES.put(11, Arrays.asList(new UserInfo(11, "Bob", 0))); + } + + @Mock UserManager mUserManager; private int mCurrentUserId = UserHandle.USER_SYSTEM; - private final ConfigurationMap mConfigs = new ConfigurationMap(); + private ConfigurationMap mConfigs; + + /** + * Sets up the test harness before running a test. + */ + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + when(mUserManager.getProfiles(anyInt())) + .then(new AnswerWithArguments() { + public List<UserInfo> answer(int userId) { + return USER_PROFILES.get(userId); + } + }); + mConfigs = new ConfigurationMap(mUserManager); + } public void switchUser(int newUserId) { Set<WifiConfiguration> hiddenConfigurations = new HashSet<>(); for (WifiConfiguration config : mConfigs.valuesForAllUsers()) { - if (config.isVisibleToUser(mCurrentUserId) && !config.isVisibleToUser(newUserId)) { + if (WifiConfigurationUtil.isVisibleToAnyProfile(config, + USER_PROFILES.get(mCurrentUserId)) + && !WifiConfigurationUtil.isVisibleToAnyProfile(config, + USER_PROFILES.get(newUserId))) { hiddenConfigurations.add(config); } } @@ -73,7 +114,8 @@ public class ConfigurationMapTest { // user. Also, check that *ForAllUsers() methods can be used to access all network // configurations, irrespective of their visibility to the current user. for (WifiConfiguration config : configs) { - if (config.isVisibleToUser(mCurrentUserId)) { + if (WifiConfigurationUtil.isVisibleToAnyProfile(config, + USER_PROFILES.get(mCurrentUserId))) { configsForCurrentUser.add(config); if (config.status != WifiConfiguration.Status.DISABLED) { enabledConfigsForCurrentUser.add(config); @@ -176,7 +218,7 @@ public class ConfigurationMapTest { configs.add(config2); verifyGetters(configs); - // Add |config3|. + // Add |config3|, which belongs to a managed profile of the current user. final WifiConfiguration config3 = CONFIGS.get(2); assertNull(mConfigs.put(config3)); // Verify that the getters return |config2| and |config3|. diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java index 98cd4e09f..5e24aa0d7 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java @@ -37,6 +37,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; +import android.content.pm.UserInfo; import android.net.wifi.FakeKeys; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiConfiguration.KeyMgmt; @@ -45,11 +46,13 @@ import android.net.wifi.WifiEnterpriseConfig.Eap; import android.net.wifi.WifiEnterpriseConfig.Phase2; import android.os.Process; import android.os.UserHandle; +import android.os.UserManager; import android.security.Credentials; import android.support.test.InstrumentationRegistry; import android.test.suitebuilder.annotation.SmallTest; import android.text.TextUtils; import android.util.Log; +import android.util.SparseArray; import com.android.server.net.DelayedDiskWrite; import com.android.server.wifi.MockAnswerUtil.AnswerWithArguments; @@ -94,20 +97,33 @@ import java.util.TreeMap; @SmallTest public class WifiConfigStoreTest { private static final List<WifiConfiguration> CONFIGS = Arrays.asList( - WifiConfigurationUtil.generateWifiConfig( + WifiConfigurationTestUtil.generateWifiConfig( 0, 1000000, "\"red\"", true, true, null, null), - WifiConfigurationUtil.generateWifiConfig( + WifiConfigurationTestUtil.generateWifiConfig( 1, 1000001, "\"green\"", true, true, "example.com", "Green"), - WifiConfigurationUtil.generateWifiConfig( - 2, 1100000, "\"blue\"", false, true, "example.org", "Blue")); + WifiConfigurationTestUtil.generateWifiConfig( + 2, 1100000, "\"blue\"", false, true, "example.org", "Blue"), + WifiConfigurationTestUtil.generateWifiConfig( + 3, 1200000, "\"cyan\"", false, true, null, null)); private static final int[] USER_IDS = {0, 10, 11}; + private static final int MANAGED_PROFILE_USER_ID = 12; + private static final int MANAGED_PROFILE_PARENT_USER_ID = 0; + private static final SparseArray<List<UserInfo>> USER_PROFILES = new SparseArray<>(); + static { + USER_PROFILES.put(0, Arrays.asList(new UserInfo(0, "Owner", 0), + new UserInfo(12, "Managed Profile", 0))); + USER_PROFILES.put(10, Arrays.asList(new UserInfo(10, "Alice", 0))); + USER_PROFILES.put(11, Arrays.asList(new UserInfo(11, "Bob", 0))); + } + private static final Map<Integer, List<WifiConfiguration>> VISIBLE_CONFIGS = new HashMap<>(); static { for (int userId : USER_IDS) { List<WifiConfiguration> configs = new ArrayList<>(); for (int i = 0; i < CONFIGS.size(); ++i) { - if (CONFIGS.get(i).isVisibleToUser(userId)) { + if (WifiConfigurationUtil.isVisibleToAnyProfile(CONFIGS.get(i), + USER_PROFILES.get(userId))) { configs.add(CONFIGS.get(i)); } } @@ -120,6 +136,7 @@ public class WifiConfigStoreTest { @Mock private WifiStateMachine mWifiStateMachine; @Mock private WifiNative mWifiNative; @Mock private FrameworkFacade mFrameworkFacade; + @Mock private UserManager mUserManager; @Mock private DelayedDiskWrite mWriter; @Mock private PasspointManagementObjectManager mMOManager; private WifiConfigStore mConfigStore; @@ -140,9 +157,15 @@ public class WifiConfigStoreTest { when(mContext.getPackageManager()).thenReturn(realContext.getPackageManager()); when(mWifiStateMachine.getCurrentUserId()).thenReturn(UserHandle.USER_SYSTEM); + when(mWifiStateMachine.getCurrentUserProfiles()) + .thenReturn(USER_PROFILES.get(UserHandle.USER_SYSTEM)); + + for (int userId : USER_IDS) { + when(mUserManager.getProfiles(userId)).thenReturn(USER_PROFILES.get(userId)); + } mConfigStore = new WifiConfigStore(mContext, mWifiStateMachine, mWifiNative, - mFrameworkFacade); + mFrameworkFacade, mUserManager); final Field configuredNetworksField = WifiConfigStore.class.getDeclaredField("mConfiguredNetworks"); @@ -175,11 +198,18 @@ public class WifiConfigStoreTest { private void switchUser(int newUserId) { when(mWifiStateMachine.getCurrentUserId()).thenReturn(newUserId); + when(mWifiStateMachine.getCurrentUserProfiles()) + .thenReturn(USER_PROFILES.get(newUserId)); mConfigStore.handleUserSwitch(); } - private void switchUserToCreatorOf(WifiConfiguration config) { - switchUser(UserHandle.getUserId(config.creatorUid)); + private void switchUserToCreatorOrParentOf(WifiConfiguration config) { + final int creatorUserId = UserHandle.getUserId(config.creatorUid); + if (creatorUserId == MANAGED_PROFILE_USER_ID) { + switchUser(MANAGED_PROFILE_PARENT_USER_ID); + } else { + switchUser(creatorUserId); + } } private void addNetworks() throws Exception { @@ -190,7 +220,7 @@ public class WifiConfigStoreTest { .thenReturn(true); for (int i = 0; i < CONFIGS.size(); ++i) { assertEquals(i, CONFIGS.get(i).networkId); - switchUserToCreatorOf(CONFIGS.get(i)); + switchUserToCreatorOrParentOf(CONFIGS.get(i)); final WifiConfiguration config = new WifiConfiguration(CONFIGS.get(i)); config.networkId = -1; when(mWifiNative.addNetwork()).thenReturn(i); @@ -293,7 +323,8 @@ public class WifiConfigStoreTest { for (WifiConfiguration expectedConfig: CONFIGS) { final WifiConfiguration actualConfig = mConfigStore.getWifiConfiguration(expectedConfig.networkId); - if (expectedConfig.isVisibleToUser(userId)) { + if (WifiConfigurationUtil.isVisibleToAnyProfile(expectedConfig, + USER_PROFILES.get(userId))) { verifyNetworkConfig(expectedConfig, actualConfig); } else { assertNull(actualConfig); @@ -314,7 +345,8 @@ public class WifiConfigStoreTest { for (WifiConfiguration expectedConfig: CONFIGS) { final WifiConfiguration actualConfig = mConfigStore.getWifiConfiguration(expectedConfig.configKey()); - if (expectedConfig.isVisibleToUser(userId)) { + if (WifiConfigurationUtil.isVisibleToAnyProfile(expectedConfig, + USER_PROFILES.get(userId))) { verifyNetworkConfig(expectedConfig, actualConfig); } else { assertNull(actualConfig); @@ -347,7 +379,8 @@ public class WifiConfigStoreTest { mConfigStore.enableAllNetworks(); for (WifiConfiguration config : mConfiguredNetworks.valuesForAllUsers()) { - assertEquals(config.isVisibleToUser(userId), + assertEquals(WifiConfigurationUtil.isVisibleToAnyProfile(config, + USER_PROFILES.get(userId)), config.getNetworkSelectionStatus().isNetworkEnabled()); } } @@ -374,7 +407,8 @@ public class WifiConfigStoreTest { final WifiNative wifiNative = createNewWifiNativeMock(); final boolean success = mConfigStore.selectNetwork(config, false, config.creatorUid); - if (!config.isVisibleToUser(userId)) { + if (!WifiConfigurationUtil.isVisibleToAnyProfile(config, + USER_PROFILES.get(userId))) { // If the network configuration is not visible to the current user, verify that // nothing changed. assertFalse(success); @@ -395,7 +429,8 @@ public class WifiConfigStoreTest { verify(wifiNative, never()).enableNetwork(intThat(not(config.networkId)), anyBoolean()); for (WifiConfiguration config2 : mConfiguredNetworks.valuesForAllUsers()) { - if (config2.isVisibleToUser(userId) + if (WifiConfigurationUtil.isVisibleToAnyProfile(config2, + USER_PROFILES.get(userId)) && config2.networkId != config.networkId) { assertEquals(WifiConfiguration.Status.DISABLED, config2.status); } else { @@ -416,7 +451,7 @@ public class WifiConfigStoreTest { */ private void verifySaveNetwork(int network) throws Exception { // Switch to the correct user. - switchUserToCreatorOf(CONFIGS.get(network)); + switchUserToCreatorOrParentOf(CONFIGS.get(network)); // Set up wpa_supplicant. when(mWifiNative.addNetwork()).thenReturn(0); @@ -543,14 +578,21 @@ public class WifiConfigStoreTest { .thenReturn(null); when(mWifiNative.getNetworkVariable(1, WifiConfigStore.ID_STRING_VAR_NAME)) .thenReturn('"' + CONFIGS.get(1).FQDN + '"'); - // Up-to-date configuration: Metadata in "id_str". - final Map<String, String> metadata = new HashMap<String, String>(); + // Up-to-date Hotspot 2.0 network configuration: Metadata in "id_str". + Map<String, String> metadata = new HashMap<String, String>(); metadata.put(WifiConfigStore.ID_STRING_KEY_CONFIG_KEY, CONFIGS.get(2).configKey()); metadata.put(WifiConfigStore.ID_STRING_KEY_CREATOR_UID, Integer.toString(CONFIGS.get(2).creatorUid)); metadata.put(WifiConfigStore.ID_STRING_KEY_FQDN, CONFIGS.get(2).FQDN); when(mWifiNative.getNetworkExtra(2, WifiConfigStore.ID_STRING_VAR_NAME)) .thenReturn(metadata); + // Up-to-date regular network configuration: Metadata in "id_str". + metadata = new HashMap<String, String>(); + metadata.put(WifiConfigStore.ID_STRING_KEY_CONFIG_KEY, CONFIGS.get(3).configKey()); + metadata.put(WifiConfigStore.ID_STRING_KEY_CREATOR_UID, + Integer.toString(CONFIGS.get(3).creatorUid)); + when(mWifiNative.getNetworkExtra(3, WifiConfigStore.ID_STRING_VAR_NAME)) + .thenReturn(metadata); // Set up networkHistory.txt file. final File file = File.createTempFile("networkHistory.txt", null); @@ -647,9 +689,10 @@ public class WifiConfigStoreTest { final Collection<WifiConfiguration> oldConfigs = mConfiguredNetworks.valuesForAllUsers(); int expectedNumberOfConfigs = oldConfigs.size(); for (WifiConfiguration config : oldConfigs) { - if (config.isVisibleToUser(oldUserId)) { + if (WifiConfigurationUtil.isVisibleToAnyProfile(config, USER_PROFILES.get(oldUserId))) { config.status = WifiConfiguration.Status.ENABLED; - if (config.isVisibleToUser(newUserId)) { + if (WifiConfigurationUtil.isVisibleToAnyProfile(config, + USER_PROFILES.get(newUserId))) { if (makeOneConfigEphemeral && removedEphemeralConfig == null) { config.ephemeral = true; lastSelectedConfigurationField.set(mConfigStore, config.configKey()); @@ -660,7 +703,8 @@ public class WifiConfigStoreTest { } } else { config.status = WifiConfiguration.Status.DISABLED; - if (config.isVisibleToUser(newUserId)) { + if (WifiConfigurationUtil.isVisibleToAnyProfile(config, + USER_PROFILES.get(newUserId))) { newUserOnlyConfigs.add(config); } else { neitherUserConfigs.add(config); diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtil.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java index 1368fc1c2..7117c2a61 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtil.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java @@ -11,7 +11,7 @@ * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and - * limitations under the License + * limitations under the License. */ package com.android.server.wifi; @@ -22,7 +22,7 @@ import android.net.wifi.WifiEnterpriseConfig; /** * Helper for creating and populating WifiConfigurations in unit tests. */ -public class WifiConfigurationUtil { +public class WifiConfigurationTestUtil { /** * These values are used to describe AP's security setting. One AP can support multiple of them, * only if there is no conflict. @@ -32,6 +32,17 @@ public class WifiConfigurationUtil { public static final int SECURITY_PSK = 1 << 1; public static final int SECURITY_EAP = 1 << 2; + /** + * Construct a {@link android.net.wifi.WifiConfiguration}. + * @param networkId the configuration's networkId + * @param uid the configuration's creator uid + * @param ssid the configuration's ssid + * @param shared whether the configuration is shared with other users on the device + * @param enabled whether the configuration is enabled + * @param fqdn the configuration's FQDN (Hotspot 2.0 only) + * @param providerFriendlyName the configuration's provider's friendly name (Hotspot 2.0 only) + * @return the constructed {@link android.net.wifi.WifiConfiguration} + */ public static WifiConfiguration generateWifiConfig(int networkId, int uid, String ssid, boolean shared, boolean enabled, String fqdn, String providerFriendlyName) { final WifiConfiguration config = new WifiConfiguration(); @@ -49,6 +60,18 @@ public class WifiConfigurationUtil { return config; } + /** + * Construct a {@link android.net.wifi.WifiConfiguration}. + * @param networkId the configuration's networkId + * @param uid the configuration's creator uid + * @param ssid the configuration's ssid + * @param shared whether the configuration is shared with other users on the device + * @param enabled whether the configuration is enabled + * @param fqdn the configuration's FQDN (Hotspot 2.0 only) + * @param providerFriendlyName the configuration's provider's friendly name (Hotspot 2.0 only) + * @param security the configuration's security type + * @return the constructed {@link android.net.wifi.WifiConfiguration} + */ public static WifiConfiguration generateWifiConfig(int networkId, int uid, String ssid, boolean shared, boolean enabled, String fqdn, String providerFriendlyName, int security) { diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java new file mode 100644 index 000000000..c5b50300e --- /dev/null +++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wifi; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import android.content.pm.UserInfo; +import android.net.wifi.WifiConfiguration; +import android.os.UserHandle; +import android.test.suitebuilder.annotation.SmallTest; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; + +/** + * Unit tests for {@link com.android.server.wifi.WifiConfigurationUtil}. + */ +@SmallTest +public class WifiConfigurationUtilTest { + static final int CURRENT_USER_ID = 0; + static final int CURRENT_USER_MANAGED_PROFILE_USER_ID = 10; + static final int OTHER_USER_ID = 11; + static final List<UserInfo> PROFILES = Arrays.asList( + new UserInfo(CURRENT_USER_ID, "owner", 0), + new UserInfo(CURRENT_USER_MANAGED_PROFILE_USER_ID, "managed profile", 0)); + + /** + * Test for {@link WifiConfigurationUtil.isVisibleToAnyProfile}. + */ + @Test + public void isVisibleToAnyProfile() { + // Shared network configuration created by another user. + final WifiConfiguration configuration = new WifiConfiguration(); + configuration.creatorUid = UserHandle.getUid(OTHER_USER_ID, 0); + assertTrue(WifiConfigurationUtil.isVisibleToAnyProfile(configuration, PROFILES)); + + // Private network configuration created by another user. + configuration.shared = false; + assertFalse(WifiConfigurationUtil.isVisibleToAnyProfile(configuration, PROFILES)); + + // Private network configuration created by the current user. + configuration.creatorUid = UserHandle.getUid(CURRENT_USER_ID, 0); + assertTrue(WifiConfigurationUtil.isVisibleToAnyProfile(configuration, PROFILES)); + + // Private network configuration created by the current user's managed profile. + configuration.creatorUid = UserHandle.getUid(CURRENT_USER_MANAGED_PROFILE_USER_ID, 0); + assertTrue(WifiConfigurationUtil.isVisibleToAnyProfile(configuration, PROFILES)); + } +} diff --git a/tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectionTest.java b/tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectionTest.java index 0d35f5fcb..f6967aa74 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectionTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectionTest.java @@ -16,10 +16,10 @@ package com.android.server.wifi; -import static com.android.server.wifi.WifiConfigurationUtil.SECURITY_EAP; -import static com.android.server.wifi.WifiConfigurationUtil.SECURITY_NONE; -import static com.android.server.wifi.WifiConfigurationUtil.SECURITY_PSK; -import static com.android.server.wifi.WifiConfigurationUtil.generateWifiConfig; +import static com.android.server.wifi.WifiConfigurationTestUtil.SECURITY_EAP; +import static com.android.server.wifi.WifiConfigurationTestUtil.SECURITY_NONE; +import static com.android.server.wifi.WifiConfigurationTestUtil.SECURITY_PSK; +import static com.android.server.wifi.WifiConfigurationTestUtil.generateWifiConfig; import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.anyInt; diff --git a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java index 200dc9348..183b15618 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java @@ -17,13 +17,16 @@ package com.android.server.wifi; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.anyObject; import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.Mockito.withSettings; @@ -31,6 +34,7 @@ import static org.mockito.Mockito.withSettings; import android.content.ContentResolver; import android.content.Context; import android.content.pm.PackageManager; +import android.content.pm.UserInfo; import android.content.res.Resources; import android.net.ConnectivityManager; import android.net.DhcpResults; @@ -43,6 +47,7 @@ import android.net.wifi.WifiManager; import android.net.wifi.WifiSsid; import android.net.wifi.p2p.IWifiP2pManager; import android.os.BatteryStats; +import android.os.Binder; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; @@ -54,6 +59,7 @@ import android.os.Message; import android.os.Messenger; import android.os.PowerManager; import android.os.UserHandle; +import android.os.UserManager; import android.provider.Settings; import android.test.suitebuilder.annotation.SmallTest; import android.util.Log; @@ -81,6 +87,7 @@ import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -92,6 +99,11 @@ import java.util.Map; public class WifiStateMachineTest { public static final String TAG = "WifiStateMachineTest"; + private static final int MANAGED_PROFILE_UID = 1100000; + private static final int OTHER_USER_UID = 1200000; + + private long mBinderToken; + private static <T> T mockWithInterfaces(Class<T> class1, Class<?>... interfaces) { return mock(class1, withSettings().extraInterfaces(interfaces)); } @@ -135,7 +147,7 @@ public class WifiStateMachineTest { } } - private FrameworkFacade getFrameworkFacade() throws InterruptedException { + private FrameworkFacade getFrameworkFacade() throws Exception { FrameworkFacade facade = mock(FrameworkFacade.class); when(facade.makeBaseLogger()).thenReturn(mock(BaseWifiLogger.class)); @@ -178,6 +190,9 @@ public class WifiStateMachineTest { } }); + when(facade.checkUidPermission(eq(android.Manifest.permission.OVERRIDE_WIFI_CONFIG), + anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); + return facade; } @@ -300,6 +315,7 @@ public class WifiStateMachineTest { @Mock WifiNative mWifiNative; @Mock SupplicantStateTracker mSupplicantStateTracker; @Mock WifiMetrics mWifiMetrics; + @Mock UserManager mUserManager; public WifiStateMachineTest() throws Exception { } @@ -337,7 +353,13 @@ public class WifiStateMachineTest { any(Context.class), any(WifiStateMachine.class), any(WifiConfigStore.class), any(Handler.class))).thenReturn(mSupplicantStateTracker); - mWsm = new WifiStateMachine(context, null, factory, mWifiMetrics); + when(mUserManager.getProfileParent(11)) + .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "owner", 0)); + when(mUserManager.getProfiles(UserHandle.USER_SYSTEM)).thenReturn(Arrays.asList( + new UserInfo(UserHandle.USER_SYSTEM, "owner", 0), + new UserInfo(11, "managed profile", 0))); + + mWsm = new WifiStateMachine(context, null, factory, mWifiMetrics, mUserManager); mWsmThread = getWsmHandlerThread(mWsm); final Object sync = new Object(); @@ -372,10 +394,13 @@ public class WifiStateMachineTest { } /* Now channel is supposed to be connected */ + + mBinderToken = Binder.clearCallingIdentity(); } @After public void cleanUp() throws Exception { + Binder.restoreCallingIdentity(mBinderToken); if (mSyncThread != null) stopLooper(mSyncThread.getLooper()); if (mWsmThread != null) stopLooper(mWsmThread.getLooper()); @@ -447,8 +472,7 @@ public class WifiStateMachineTest { assertEquals("InitialState", getCurrentState().getName()); } - @Test - public void addNetwork() throws Exception { + private void addNetworkAndVerifySuccess() throws Exception { loadComponents(); @@ -516,10 +540,189 @@ public class WifiStateMachineTest { assertTrue(config2.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.NONE)); } + private void addNetworkAndVerifyFailure() throws Exception { + loadComponents(); + + final WifiConfiguration config = new WifiConfiguration(); + config.SSID = sSSID; + config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); + + mWsm.syncAddOrUpdateNetwork(mWsmAsyncChannel, config); + wait(200); + + verify(mWifiNative, never()).addNetwork(); + verify(mWifiNative, never()).setNetworkVariable(anyInt(), anyString(), anyString()); + + assertTrue(mWsm.syncGetConfiguredNetworks(-1, mWsmAsyncChannel).isEmpty()); + } + + /** + * Verifies that the current foreground user is allowed to add a network. + */ + @Test + public void addNetworkAsCurrentUser() throws Exception { + addNetworkAndVerifySuccess(); + } + + /** + * Verifies that a managed profile of the current foreground user is allowed to add a network. + */ + @Test + public void addNetworkAsCurrentUsersManagedProfile() throws Exception { + BinderUtil.setUid(MANAGED_PROFILE_UID); + addNetworkAndVerifySuccess(); + } + + /** + * Verifies that a background user is not allowed to add a network. + */ + @Test + public void addNetworkAsOtherUser() throws Exception { + BinderUtil.setUid(OTHER_USER_UID); + addNetworkAndVerifyFailure(); + } + + private void removeNetworkAndVerifySuccess() throws Exception { + when(mWifiNative.removeNetwork(0)).thenReturn(true); + assertTrue(mWsm.syncRemoveNetwork(mWsmAsyncChannel, 0)); + wait(200); + assertTrue(mWsm.syncGetConfiguredNetworks(-1, mWsmAsyncChannel).isEmpty()); + } + + private void removeNetworkAndVerifyFailure() throws Exception { + assertFalse(mWsm.syncRemoveNetwork(mWsmAsyncChannel, 0)); + wait(200); + assertEquals(1, mWsm.syncGetConfiguredNetworks(-1, mWsmAsyncChannel).size()); + verify(mWifiNative, never()).removeNetwork(anyInt()); + } + + /** + * Verifies that the current foreground user is allowed to remove a network. + */ + @Test + public void removeNetworkAsCurrentUser() throws Exception { + addNetworkAndVerifySuccess(); + removeNetworkAndVerifySuccess(); + } + + /** + * Verifies that a managed profile of the current foreground user is allowed to remove a + * network. + */ + @Test + public void removeNetworkAsCurrentUsersManagedProfile() throws Exception { + addNetworkAndVerifySuccess(); + BinderUtil.setUid(MANAGED_PROFILE_UID); + removeNetworkAndVerifySuccess(); + } + + /** + * Verifies that a background user is not allowed to remove a network. + */ + @Test + public void removeNetworkAsOtherUser() throws Exception { + addNetworkAndVerifySuccess(); + BinderUtil.setUid(OTHER_USER_UID); + removeNetworkAndVerifyFailure(); + } + + private void enableNetworkAndVerifySuccess() throws Exception { + when(mWifiNative.enableNetwork(0, true)).thenReturn(true); + assertTrue(mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true)); + wait(200); + verify(mWifiNative).enableNetwork(0, true); + } + + private void enableNetworkAndVerifyFailure() throws Exception { + assertFalse(mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true)); + wait(200); + verify(mWifiNative, never()).enableNetwork(anyInt(), anyBoolean()); + } + + /** + * Verifies that the current foreground user is allowed to enable a network. + */ + @Test + public void enableNetworkAsCurrentUser() throws Exception { + addNetworkAndVerifySuccess(); + enableNetworkAndVerifySuccess(); + } + + /** + * Verifies that a managed profile of the current foreground user is allowed to enable a + * network. + */ + @Test + public void enableNetworkAsCurrentUsersManagedProfile() throws Exception { + addNetworkAndVerifySuccess(); + BinderUtil.setUid(MANAGED_PROFILE_UID); + enableNetworkAndVerifySuccess(); + } + + /** + * Verifies that a background user is not allowed to enable a network. + */ + @Test + public void enableNetworkAsOtherUser() throws Exception { + addNetworkAndVerifySuccess(); + BinderUtil.setUid(OTHER_USER_UID); + enableNetworkAndVerifyFailure(); + } + + private void forgetNetworkAndVerifySuccess() throws Exception { + when(mWifiNative.removeNetwork(0)).thenReturn(true); + final Message result = + mWsmAsyncChannel.sendMessageSynchronously(WifiManager.FORGET_NETWORK, 0); + assertEquals(WifiManager.FORGET_NETWORK_SUCCEEDED, result.what); + result.recycle(); + wait(200); + assertTrue(mWsm.syncGetConfiguredNetworks(-1, mWsmAsyncChannel).isEmpty()); + } + + private void forgetNetworkAndVerifyFailure() throws Exception { + final Message result = + mWsmAsyncChannel.sendMessageSynchronously(WifiManager.FORGET_NETWORK, 0); + assertEquals(WifiManager.FORGET_NETWORK_FAILED, result.what); + result.recycle(); + wait(200); + assertEquals(1, mWsm.syncGetConfiguredNetworks(-1, mWsmAsyncChannel).size()); + verify(mWifiNative, never()).removeNetwork(anyInt()); + } + + /** + * Verifies that the current foreground user is allowed to forget a network. + */ + @Test + public void forgetNetworkAsCurrentUser() throws Exception { + addNetworkAndVerifySuccess(); + forgetNetworkAndVerifySuccess(); + } + + /** + * Verifies that a managed profile of the current foreground user is allowed to forget a + * network. + */ + @Test + public void forgetNetworkAsCurrentUsersManagedProfile() throws Exception { + addNetworkAndVerifySuccess(); + BinderUtil.setUid(MANAGED_PROFILE_UID); + forgetNetworkAndVerifySuccess(); + } + + /** + * Verifies that a background user is not allowed to forget a network. + */ + @Test + public void forgetNetworkAsOtherUser() throws Exception { + addNetworkAndVerifySuccess(); + BinderUtil.setUid(OTHER_USER_UID); + forgetNetworkAndVerifyFailure(); + } + @Test public void scan() throws Exception { - addNetwork(); + addNetworkAndVerifySuccess(); mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE); @@ -539,7 +742,7 @@ public class WifiStateMachineTest { @Test public void connect() throws Exception { - addNetwork(); + addNetworkAndVerifySuccess(); mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE); mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true); @@ -568,7 +771,7 @@ public class WifiStateMachineTest { @Test public void testDhcpFailure() throws Exception { - addNetwork(); + addNetworkAndVerifySuccess(); mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE); mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true); @@ -592,7 +795,7 @@ public class WifiStateMachineTest { @Test public void testBadNetworkEvent() throws Exception { - addNetwork(); + addNetworkAndVerifySuccess(); mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE); mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true); @@ -635,7 +838,7 @@ public class WifiStateMachineTest { @Test public void iconQueryTest() throws Exception { /* enable wi-fi */ - addNetwork(); + addNetworkAndVerifySuccess(); long bssid = 0x1234567800FFL; String filename = "iconFileName.png"; |