NetworkScoreServiceTest.java revision 9b442faa9193173753ea2669009bb5c2bed29079
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server; 18 19import static android.net.NetworkRecommendationProvider.EXTRA_RECOMMENDATION_RESULT; 20import static android.net.NetworkRecommendationProvider.EXTRA_SEQUENCE; 21import static android.net.NetworkScoreManager.CACHE_FILTER_NONE; 22 23import static junit.framework.Assert.assertEquals; 24import static junit.framework.Assert.assertFalse; 25import static junit.framework.Assert.assertNotNull; 26import static junit.framework.Assert.assertTrue; 27import static junit.framework.Assert.fail; 28 29import static org.mockito.Matchers.any; 30import static org.mockito.Matchers.anyInt; 31import static org.mockito.Matchers.anyListOf; 32import static org.mockito.Matchers.anyString; 33import static org.mockito.Matchers.eq; 34import static org.mockito.Matchers.isA; 35import static org.mockito.Mockito.atLeastOnce; 36import static org.mockito.Mockito.doAnswer; 37import static org.mockito.Mockito.doThrow; 38import static org.mockito.Mockito.mock; 39import static org.mockito.Mockito.times; 40import static org.mockito.Mockito.verify; 41import static org.mockito.Mockito.verifyNoMoreInteractions; 42import static org.mockito.Mockito.verifyZeroInteractions; 43import static org.mockito.Mockito.when; 44 45import android.Manifest.permission; 46import android.content.ComponentName; 47import android.content.ContentResolver; 48import android.content.Context; 49import android.content.Intent; 50import android.content.ServiceConnection; 51import android.content.pm.PackageManager; 52import android.content.res.Resources; 53import android.net.INetworkRecommendationProvider; 54import android.net.INetworkScoreCache; 55import android.net.NetworkKey; 56import android.net.NetworkScoreManager; 57import android.net.NetworkScorerAppManager; 58import android.net.NetworkScorerAppManager.NetworkScorerAppData; 59import android.net.RecommendationRequest; 60import android.net.RecommendationResult; 61import android.net.ScoredNetwork; 62import android.net.WifiKey; 63import android.net.wifi.WifiConfiguration; 64import android.os.Binder; 65import android.os.Bundle; 66import android.os.IBinder; 67import android.os.IRemoteCallback; 68import android.os.Looper; 69import android.os.RemoteException; 70import android.os.UserHandle; 71import android.support.test.InstrumentationRegistry; 72import android.support.test.filters.MediumTest; 73import android.support.test.runner.AndroidJUnit4; 74 75import com.android.server.devicepolicy.MockUtils; 76 77import org.junit.Before; 78import org.junit.Test; 79import org.junit.runner.RunWith; 80import org.mockito.ArgumentCaptor; 81import org.mockito.Captor; 82import org.mockito.Mock; 83import org.mockito.MockitoAnnotations; 84import org.mockito.invocation.InvocationOnMock; 85import org.mockito.stubbing.Answer; 86 87import java.io.FileDescriptor; 88import java.io.PrintWriter; 89import java.io.StringWriter; 90import java.util.List; 91 92/** 93 * Tests for {@link NetworkScoreService}. 94 */ 95@RunWith(AndroidJUnit4.class) 96@MediumTest 97public class NetworkScoreServiceTest { 98 private static final ScoredNetwork SCORED_NETWORK = 99 new ScoredNetwork(new NetworkKey(new WifiKey("\"ssid\"", "00:00:00:00:00:00")), 100 null /* rssiCurve*/); 101 private static final NetworkScorerAppData NEW_SCORER = 102 new NetworkScorerAppData("newPackageName", 1, "newScoringServiceClass"); 103 104 @Mock private PackageManager mPackageManager; 105 @Mock private NetworkScorerAppManager mNetworkScorerAppManager; 106 @Mock private Context mContext; 107 @Mock private Resources mResources; 108 @Mock private INetworkScoreCache.Stub mNetworkScoreCache, mNetworkScoreCache2; 109 @Mock private IBinder mIBinder, mIBinder2; 110 @Mock private INetworkRecommendationProvider mRecommendationProvider; 111 @Captor private ArgumentCaptor<List<ScoredNetwork>> mScoredNetworkCaptor; 112 113 private ContentResolver mContentResolver; 114 private NetworkScoreService mNetworkScoreService; 115 private RecommendationRequest mRecommendationRequest; 116 117 @Before 118 public void setUp() throws Exception { 119 MockitoAnnotations.initMocks(this); 120 when(mNetworkScoreCache.asBinder()).thenReturn(mIBinder); 121 when(mNetworkScoreCache2.asBinder()).thenReturn(mIBinder2); 122 mContentResolver = InstrumentationRegistry.getContext().getContentResolver(); 123 when(mContext.getContentResolver()).thenReturn(mContentResolver); 124 when(mContext.getResources()).thenReturn(mResources); 125 mNetworkScoreService = new NetworkScoreService(mContext, mNetworkScorerAppManager); 126 WifiConfiguration configuration = new WifiConfiguration(); 127 configuration.SSID = "NetworkScoreServiceTest_SSID"; 128 configuration.BSSID = "NetworkScoreServiceTest_BSSID"; 129 mRecommendationRequest = new RecommendationRequest.Builder() 130 .setCurrentRecommendedWifiConfig(configuration).build(); 131 } 132 133 @Test 134 public void testSystemRunning() { 135 when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER); 136 137 mNetworkScoreService.systemRunning(); 138 139 verify(mContext).bindServiceAsUser(MockUtils.checkIntent( 140 new Intent(NetworkScoreManager.ACTION_RECOMMEND_NETWORKS) 141 .setComponent(new ComponentName(NEW_SCORER.packageName, 142 NEW_SCORER.recommendationServiceClassName))), 143 any(ServiceConnection.class), 144 eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE), 145 eq(UserHandle.SYSTEM)); 146 } 147 148 @Test 149 public void testRequestScores_noPermission() throws Exception { 150 doThrow(new SecurityException()).when(mContext) 151 .enforceCallingOrSelfPermission(eq(permission.REQUEST_NETWORK_SCORES), 152 anyString()); 153 try { 154 mNetworkScoreService.requestScores(null); 155 fail("REQUEST_NETWORK_SCORES not enforced."); 156 } catch (SecurityException e) { 157 // expected 158 } 159 } 160 161 @Test 162 public void testRequestScores_providerNotConnected() throws Exception { 163 assertFalse(mNetworkScoreService.requestScores(new NetworkKey[0])); 164 verifyZeroInteractions(mRecommendationProvider); 165 } 166 167 @Test 168 public void testRequestScores_providerThrowsRemoteException() throws Exception { 169 injectProvider(); 170 doThrow(new RemoteException()).when(mRecommendationProvider) 171 .requestScores(any(NetworkKey[].class)); 172 173 assertFalse(mNetworkScoreService.requestScores(new NetworkKey[0])); 174 } 175 176 @Test 177 public void testRequestScores_providerAvailable() throws Exception { 178 injectProvider(); 179 180 final NetworkKey[] networks = new NetworkKey[0]; 181 assertTrue(mNetworkScoreService.requestScores(networks)); 182 verify(mRecommendationProvider).requestScores(networks); 183 } 184 185 @Test 186 public void testRequestRecommendation_noPermission() throws Exception { 187 doThrow(new SecurityException()).when(mContext) 188 .enforceCallingOrSelfPermission(eq(permission.REQUEST_NETWORK_SCORES), 189 anyString()); 190 try { 191 mNetworkScoreService.requestRecommendation(mRecommendationRequest); 192 fail("REQUEST_NETWORK_SCORES not enforced."); 193 } catch (SecurityException e) { 194 // expected 195 } 196 } 197 198 @Test 199 public void testRequestRecommendation_mainThread() throws Exception { 200 when(mContext.getMainLooper()).thenReturn(Looper.myLooper()); 201 try { 202 mNetworkScoreService.requestRecommendation(mRecommendationRequest); 203 fail("requestRecommendation run on main thread."); 204 } catch (RuntimeException e) { 205 // expected 206 } 207 } 208 209 @Test 210 public void testRequestRecommendation_providerNotConnected() throws Exception { 211 when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper()); 212 213 final RecommendationResult result = 214 mNetworkScoreService.requestRecommendation(mRecommendationRequest); 215 assertNotNull(result); 216 assertEquals(mRecommendationRequest.getCurrentSelectedConfig(), 217 result.getWifiConfiguration()); 218 } 219 220 @Test 221 public void testRequestRecommendation_providerThrowsRemoteException() throws Exception { 222 injectProvider(); 223 when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper()); 224 doThrow(new RemoteException()).when(mRecommendationProvider) 225 .requestRecommendation(eq(mRecommendationRequest), isA(IRemoteCallback.class), 226 anyInt()); 227 228 final RecommendationResult result = 229 mNetworkScoreService.requestRecommendation(mRecommendationRequest); 230 assertNotNull(result); 231 assertEquals(mRecommendationRequest.getCurrentSelectedConfig(), 232 result.getWifiConfiguration()); 233 } 234 235 @Test 236 public void testRequestRecommendation_resultReturned() throws Exception { 237 injectProvider(); 238 when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper()); 239 final WifiConfiguration wifiConfiguration = new WifiConfiguration(); 240 wifiConfiguration.SSID = "testRequestRecommendation_resultReturned_SSID"; 241 wifiConfiguration.BSSID = "testRequestRecommendation_resultReturned_BSSID"; 242 final RecommendationResult providerResult = RecommendationResult 243 .createConnectRecommendation(wifiConfiguration); 244 final Bundle bundle = new Bundle(); 245 bundle.putParcelable(EXTRA_RECOMMENDATION_RESULT, providerResult); 246 doAnswer(invocation -> { 247 bundle.putInt(EXTRA_SEQUENCE, invocation.getArgumentAt(2, int.class)); 248 invocation.getArgumentAt(1, IRemoteCallback.class).sendResult(bundle); 249 return null; 250 }).when(mRecommendationProvider) 251 .requestRecommendation(eq(mRecommendationRequest), isA(IRemoteCallback.class), 252 anyInt()); 253 254 final RecommendationResult result = 255 mNetworkScoreService.requestRecommendation(mRecommendationRequest); 256 assertNotNull(result); 257 assertEquals(providerResult.getWifiConfiguration().SSID, 258 result.getWifiConfiguration().SSID); 259 assertEquals(providerResult.getWifiConfiguration().BSSID, 260 result.getWifiConfiguration().BSSID); 261 } 262 263 @Test 264 public void testUpdateScores_notActiveScorer() { 265 bindToScorer(false /*callerIsScorer*/); 266 267 try { 268 mNetworkScoreService.updateScores(new ScoredNetwork[0]); 269 fail("SecurityException expected"); 270 } catch (SecurityException e) { 271 // expected 272 } 273 } 274 275 @Test 276 public void testUpdateScores_oneRegisteredCache() throws RemoteException { 277 bindToScorer(true /*callerIsScorer*/); 278 279 mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, 280 mNetworkScoreCache, CACHE_FILTER_NONE); 281 282 mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK}); 283 284 verify(mNetworkScoreCache).updateScores(mScoredNetworkCaptor.capture()); 285 286 assertEquals(1, mScoredNetworkCaptor.getValue().size()); 287 assertEquals(SCORED_NETWORK, mScoredNetworkCaptor.getValue().get(0)); 288 } 289 290 @Test 291 public void testUpdateScores_twoRegisteredCaches() throws RemoteException { 292 bindToScorer(true /*callerIsScorer*/); 293 294 mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, 295 mNetworkScoreCache, CACHE_FILTER_NONE); 296 mNetworkScoreService.registerNetworkScoreCache( 297 NetworkKey.TYPE_WIFI, mNetworkScoreCache2, CACHE_FILTER_NONE); 298 299 // updateScores should update both caches 300 mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK}); 301 302 verify(mNetworkScoreCache).updateScores(anyListOf(ScoredNetwork.class)); 303 verify(mNetworkScoreCache2).updateScores(anyListOf(ScoredNetwork.class)); 304 305 mNetworkScoreService.unregisterNetworkScoreCache( 306 NetworkKey.TYPE_WIFI, mNetworkScoreCache2); 307 308 // updateScores should only update the first cache since the 2nd has been unregistered 309 mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK}); 310 311 verify(mNetworkScoreCache, times(2)).updateScores(anyListOf(ScoredNetwork.class)); 312 313 mNetworkScoreService.unregisterNetworkScoreCache( 314 NetworkKey.TYPE_WIFI, mNetworkScoreCache); 315 316 // updateScores should not update any caches since they are both unregistered 317 mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK}); 318 319 // The register and unregister calls grab the binder from the score cache. 320 verify(mNetworkScoreCache, atLeastOnce()).asBinder(); 321 verify(mNetworkScoreCache2, atLeastOnce()).asBinder(); 322 verifyNoMoreInteractions(mNetworkScoreCache, mNetworkScoreCache2); 323 } 324 325 @Test 326 public void testClearScores_notActiveScorer_noRequestNetworkScoresPermission() { 327 bindToScorer(false /*callerIsScorer*/); 328 when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES)) 329 .thenReturn(PackageManager.PERMISSION_DENIED); 330 try { 331 mNetworkScoreService.clearScores(); 332 fail("SecurityException expected"); 333 } catch (SecurityException e) { 334 // expected 335 } 336 } 337 338 @Test 339 public void testClearScores_activeScorer_noRequestNetworkScoresPermission() { 340 bindToScorer(true /*callerIsScorer*/); 341 when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES)) 342 .thenReturn(PackageManager.PERMISSION_DENIED); 343 344 mNetworkScoreService.clearScores(); 345 } 346 347 @Test 348 public void testClearScores_activeScorer() throws RemoteException { 349 bindToScorer(true /*callerIsScorer*/); 350 351 mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache, 352 CACHE_FILTER_NONE); 353 mNetworkScoreService.clearScores(); 354 355 verify(mNetworkScoreCache).clearScores(); 356 } 357 358 @Test 359 public void testClearScores_notActiveScorer_hasRequestNetworkScoresPermission() 360 throws RemoteException { 361 bindToScorer(false /*callerIsScorer*/); 362 when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES)) 363 .thenReturn(PackageManager.PERMISSION_GRANTED); 364 365 mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache, 366 CACHE_FILTER_NONE); 367 mNetworkScoreService.clearScores(); 368 369 verify(mNetworkScoreCache).clearScores(); 370 } 371 372 @Test 373 public void testSetActiveScorer_noScoreNetworksPermission() { 374 doThrow(new SecurityException()).when(mContext) 375 .enforceCallingOrSelfPermission(eq(permission.SCORE_NETWORKS), anyString()); 376 377 try { 378 mNetworkScoreService.setActiveScorer(null); 379 fail("SecurityException expected"); 380 } catch (SecurityException e) { 381 // expected 382 } 383 } 384 385 @Test 386 public void testDisableScoring_notActiveScorer_noRequestNetworkScoresPermission() { 387 bindToScorer(false /*callerIsScorer*/); 388 when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES)) 389 .thenReturn(PackageManager.PERMISSION_DENIED); 390 391 try { 392 mNetworkScoreService.disableScoring(); 393 fail("SecurityException expected"); 394 } catch (SecurityException e) { 395 // expected 396 } 397 } 398 399 @Test 400 public void testRegisterNetworkScoreCache_noRequestNetworkScoresPermission() { 401 doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission( 402 eq(permission.REQUEST_NETWORK_SCORES), anyString()); 403 404 try { 405 mNetworkScoreService.registerNetworkScoreCache( 406 NetworkKey.TYPE_WIFI, mNetworkScoreCache, CACHE_FILTER_NONE); 407 fail("SecurityException expected"); 408 } catch (SecurityException e) { 409 // expected 410 } 411 } 412 413 @Test 414 public void testUnregisterNetworkScoreCache_noRequestNetworkScoresPermission() { 415 doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission( 416 eq(permission.REQUEST_NETWORK_SCORES), anyString()); 417 418 try { 419 mNetworkScoreService.unregisterNetworkScoreCache( 420 NetworkKey.TYPE_WIFI, mNetworkScoreCache); 421 fail("SecurityException expected"); 422 } catch (SecurityException e) { 423 // expected 424 } 425 } 426 427 @Test 428 public void testDump_noDumpPermission() { 429 doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission( 430 eq(permission.DUMP), anyString()); 431 432 try { 433 mNetworkScoreService.dump( 434 new FileDescriptor(), new PrintWriter(new StringWriter()), new String[0]); 435 fail("SecurityException expected"); 436 } catch (SecurityException e) { 437 // expected 438 } 439 } 440 441 @Test 442 public void testDump_doesNotCrash() { 443 when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER); 444 StringWriter stringWriter = new StringWriter(); 445 446 mNetworkScoreService.dump( 447 new FileDescriptor(), new PrintWriter(stringWriter), new String[0]); 448 449 assertFalse(stringWriter.toString().isEmpty()); 450 } 451 452 @Test 453 public void testIsCallerActiveScorer_noBoundService() throws Exception { 454 mNetworkScoreService.systemRunning(); 455 456 assertFalse(mNetworkScoreService.isCallerActiveScorer(Binder.getCallingUid())); 457 } 458 459 @Test 460 public void testIsCallerActiveScorer_boundServiceIsNotCaller() throws Exception { 461 bindToScorer(false /*callerIsScorer*/); 462 463 assertFalse(mNetworkScoreService.isCallerActiveScorer(Binder.getCallingUid())); 464 } 465 466 @Test 467 public void testIsCallerActiveScorer_boundServiceIsCaller() throws Exception { 468 bindToScorer(true /*callerIsScorer*/); 469 470 assertTrue(mNetworkScoreService.isCallerActiveScorer(Binder.getCallingUid())); 471 } 472 473 // "injects" the mock INetworkRecommendationProvider into the NetworkScoreService. 474 private void injectProvider() { 475 final ComponentName componentName = new ComponentName(NEW_SCORER.packageName, 476 NEW_SCORER.recommendationServiceClassName); 477 when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER); 478 when(mContext.bindServiceAsUser(isA(Intent.class), isA(ServiceConnection.class), anyInt(), 479 isA(UserHandle.class))).thenAnswer(new Answer<Boolean>() { 480 @Override 481 public Boolean answer(InvocationOnMock invocation) throws Throwable { 482 IBinder mockBinder = mock(IBinder.class); 483 when(mockBinder.queryLocalInterface(anyString())) 484 .thenReturn(mRecommendationProvider); 485 invocation.getArgumentAt(1, ServiceConnection.class) 486 .onServiceConnected(componentName, mockBinder); 487 return true; 488 } 489 }); 490 mNetworkScoreService.systemRunning(); 491 } 492 493 private void bindToScorer(boolean callerIsScorer) { 494 final int callingUid = callerIsScorer ? Binder.getCallingUid() : 0; 495 NetworkScorerAppData appData = new NetworkScorerAppData(NEW_SCORER.packageName, 496 callingUid, NEW_SCORER.recommendationServiceClassName); 497 when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(appData); 498 when(mContext.bindServiceAsUser(isA(Intent.class), isA(ServiceConnection.class), anyInt(), 499 isA(UserHandle.class))).thenReturn(true); 500 mNetworkScoreService.systemRunning(); 501 } 502} 503