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.NetworkScoreManager.CACHE_FILTER_NONE;
20
21import static junit.framework.Assert.assertEquals;
22import static junit.framework.Assert.assertFalse;
23import static junit.framework.Assert.assertTrue;
24import static junit.framework.Assert.fail;
25
26import static org.mockito.Matchers.any;
27import static org.mockito.Matchers.anyListOf;
28import static org.mockito.Matchers.anyString;
29import static org.mockito.Matchers.eq;
30import static org.mockito.Mockito.atLeastOnce;
31import static org.mockito.Mockito.doThrow;
32import static org.mockito.Mockito.never;
33import static org.mockito.Mockito.times;
34import static org.mockito.Mockito.verify;
35import static org.mockito.Mockito.verifyNoMoreInteractions;
36import static org.mockito.Mockito.verifyZeroInteractions;
37import static org.mockito.Mockito.when;
38
39import android.Manifest.permission;
40import android.content.ComponentName;
41import android.content.ContentResolver;
42import android.content.Context;
43import android.content.Intent;
44import android.content.pm.PackageManager;
45import android.content.res.Resources;
46import android.net.INetworkRecommendationProvider;
47import android.net.INetworkScoreCache;
48import android.net.NetworkKey;
49import android.net.NetworkScoreManager;
50import android.net.NetworkScorerAppData;
51import android.net.ScoredNetwork;
52import android.net.Uri;
53import android.net.WifiKey;
54import android.net.wifi.ScanResult;
55import android.net.wifi.WifiConfiguration;
56import android.net.wifi.WifiInfo;
57import android.net.wifi.WifiSsid;
58import android.os.Binder;
59import android.os.Bundle;
60import android.os.Handler;
61import android.os.HandlerThread;
62import android.os.IBinder;
63import android.os.Looper;
64import android.os.Message;
65import android.os.RemoteCallback;
66import android.os.RemoteException;
67import android.os.UserHandle;
68import android.support.test.InstrumentationRegistry;
69import android.support.test.filters.MediumTest;
70import android.support.test.runner.AndroidJUnit4;
71
72import com.android.server.devicepolicy.MockUtils;
73
74import com.google.android.collect.Lists;
75
76import org.junit.After;
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;
84
85import java.io.FileDescriptor;
86import java.io.PrintWriter;
87import java.io.StringWriter;
88import java.util.ArrayList;
89import java.util.Collections;
90import java.util.List;
91import java.util.concurrent.CountDownLatch;
92import java.util.concurrent.TimeUnit;
93import java.util.function.UnaryOperator;
94
95/**
96 * Tests for {@link NetworkScoreService}.
97 */
98@RunWith(AndroidJUnit4.class)
99@MediumTest
100public class NetworkScoreServiceTest {
101    private static final String SSID = "ssid";
102    private static final String SSID_2 = "ssid_2";
103    private static final String SSID_3 = "ssid_3";
104    private static final String INVALID_BSSID = "invalid_bssid";
105    private static final ComponentName RECOMMENDATION_SERVICE_COMP =
106            new ComponentName("newPackageName", "newScoringServiceClass");
107    private static final String RECOMMENDATION_SERVICE_LABEL = "Test Recommendation Service";
108    private static final ComponentName USE_WIFI_ENABLE_ACTIVITY_COMP =
109            new ComponentName("useWifiPackageName", "enableUseWifiActivityClass");
110    private static final ScoredNetwork SCORED_NETWORK =
111            new ScoredNetwork(new NetworkKey(new WifiKey(quote(SSID), "00:00:00:00:00:00")),
112                    null /* rssiCurve*/);
113    private static final ScoredNetwork SCORED_NETWORK_2 =
114            new ScoredNetwork(new NetworkKey(new WifiKey(quote(SSID_2), "00:00:00:00:00:00")),
115                    null /* rssiCurve*/);
116    private static final String NETWORK_AVAILABLE_NOTIFICATION_CHANNEL_ID =
117            "networkAvailableNotificationChannelId";
118    private static final NetworkScorerAppData NEW_SCORER = new NetworkScorerAppData(
119            1, RECOMMENDATION_SERVICE_COMP, RECOMMENDATION_SERVICE_LABEL,
120            USE_WIFI_ENABLE_ACTIVITY_COMP, NETWORK_AVAILABLE_NOTIFICATION_CHANNEL_ID);
121
122    @Mock private NetworkScorerAppManager mNetworkScorerAppManager;
123    @Mock private Context mContext;
124    @Mock private Resources mResources;
125    @Mock private INetworkScoreCache.Stub mNetworkScoreCache, mNetworkScoreCache2;
126    @Mock private IBinder mScoreCacheIBinder, mScoreCacheIBinder2;
127    @Mock private IBinder mServiceConnectionIBinder;
128    @Mock private INetworkRecommendationProvider mRecommendationProvider;
129    @Mock private UnaryOperator<List<ScoredNetwork>> mCurrentNetworkFilter;
130    @Mock private UnaryOperator<List<ScoredNetwork>> mScanResultsFilter;
131    @Mock private WifiInfo mWifiInfo;
132    @Mock private NetworkScoreService.ScoringServiceConnection mServiceConnection;
133    @Captor private ArgumentCaptor<List<ScoredNetwork>> mScoredNetworkCaptor;
134
135    private ContentResolver mContentResolver;
136    private NetworkScoreService mNetworkScoreService;
137    private HandlerThread mHandlerThread;
138    private List<ScanResult> mScanResults;
139
140    private static String quote(String str) {
141        return String.format("\"%s\"", str);
142    }
143
144    @Before
145    public void setUp() throws Exception {
146        MockitoAnnotations.initMocks(this);
147        when(mNetworkScoreCache.asBinder()).thenReturn(mScoreCacheIBinder);
148        when(mNetworkScoreCache2.asBinder()).thenReturn(mScoreCacheIBinder2);
149        when(mServiceConnectionIBinder.queryLocalInterface(anyString()))
150                .thenReturn(mRecommendationProvider);
151        mContentResolver = InstrumentationRegistry.getContext().getContentResolver();
152        when(mContext.getContentResolver()).thenReturn(mContentResolver);
153        when(mContext.getResources()).thenReturn(mResources);
154        when(mWifiInfo.getSSID()).thenReturn(SCORED_NETWORK.networkKey.wifiKey.ssid);
155        when(mWifiInfo.getBSSID()).thenReturn(SCORED_NETWORK.networkKey.wifiKey.bssid);
156        when(mServiceConnection.getAppData()).thenReturn(NEW_SCORER);
157        when(mServiceConnection.getRecommendationProvider()).thenReturn(mRecommendationProvider);
158        when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER);
159        mHandlerThread = new HandlerThread("NetworkScoreServiceTest");
160        mHandlerThread.start();
161        mNetworkScoreService = new NetworkScoreService(mContext, mNetworkScorerAppManager,
162                networkScorerAppData -> mServiceConnection, mHandlerThread.getLooper());
163        WifiConfiguration configuration = new WifiConfiguration();
164        configuration.SSID = "NetworkScoreServiceTest_SSID";
165        configuration.BSSID = "NetworkScoreServiceTest_BSSID";
166        populateScanResults();
167    }
168
169    private void populateScanResults() {
170        mScanResults = new ArrayList<>();
171        mScanResults.add(createScanResult(SSID, SCORED_NETWORK.networkKey.wifiKey.bssid));
172        mScanResults.add(createScanResult(SSID_2, SCORED_NETWORK_2.networkKey.wifiKey.bssid));
173        mScanResults.add(createScanResult(SSID_3, "10:10:00:00:10:10"));
174    }
175
176    private ScanResult createScanResult(String ssid, String bssid) {
177        ScanResult result = new ScanResult();
178        result.wifiSsid = WifiSsid.createFromAsciiEncoded(ssid);
179        result.BSSID = bssid;
180        return result;
181    }
182
183    @After
184    public void tearDown() throws Exception {
185        mHandlerThread.quitSafely();
186    }
187
188    @Test
189    public void testOnUserUnlocked() {
190        when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER);
191
192        mNetworkScoreService.onUserUnlocked(0);
193
194        verify(mNetworkScorerAppManager).updateState();
195        verify(mNetworkScorerAppManager).migrateNetworkScorerAppSettingIfNeeded();
196        verify(mServiceConnection).bind(mContext);
197    }
198
199    @Test
200    public void testRequestScores_noPermission() throws Exception {
201        doThrow(new SecurityException()).when(mContext)
202            .enforceCallingOrSelfPermission(eq(permission.REQUEST_NETWORK_SCORES),
203                anyString());
204        try {
205            mNetworkScoreService.requestScores(null);
206            fail("REQUEST_NETWORK_SCORES not enforced.");
207        } catch (SecurityException e) {
208            // expected
209        }
210    }
211
212    @Test
213    public void testRequestScores_providerNotConnected() throws Exception {
214        assertFalse(mNetworkScoreService.requestScores(new NetworkKey[0]));
215        verifyZeroInteractions(mRecommendationProvider);
216    }
217
218    @Test
219    public void testRequestScores_providerThrowsRemoteException() throws Exception {
220        doThrow(new RemoteException()).when(mRecommendationProvider)
221            .requestScores(any(NetworkKey[].class));
222        mNetworkScoreService.onUserUnlocked(0);
223
224        assertFalse(mNetworkScoreService.requestScores(new NetworkKey[0]));
225    }
226
227    @Test
228    public void testRequestScores_providerAvailable() throws Exception {
229        mNetworkScoreService.onUserUnlocked(0);
230
231        final NetworkKey[] networks = new NetworkKey[0];
232        assertTrue(mNetworkScoreService.requestScores(networks));
233        verify(mRecommendationProvider).requestScores(networks);
234    }
235
236    @Test
237    public void dispatchingContentObserver_nullUri() throws Exception {
238        NetworkScoreService.DispatchingContentObserver observer =
239                new NetworkScoreService.DispatchingContentObserver(mContext, null /*handler*/);
240
241        observer.onChange(false, null);
242        // nothing to assert or verify but since we passed in a null handler we'd see a NPE
243        // if it were interacted with.
244    }
245
246    @Test
247    public void dispatchingContentObserver_dispatchUri() throws Exception {
248        final CountDownHandler handler = new CountDownHandler(mHandlerThread.getLooper());
249        NetworkScoreService.DispatchingContentObserver observer =
250                new NetworkScoreService.DispatchingContentObserver(mContext, handler);
251        Uri uri = Uri.parse("content://settings/global/network_score_service_test");
252        int expectedWhat = 24;
253        observer.observe(uri, expectedWhat);
254
255        observer.onChange(false, uri);
256        final boolean msgHandled = handler.latch.await(3, TimeUnit.SECONDS);
257        assertTrue(msgHandled);
258        assertEquals(expectedWhat, handler.receivedWhat);
259    }
260
261    @Test
262    public void testUpdateScores_notActiveScorer() {
263        bindToScorer(false /*callerIsScorer*/);
264
265        try {
266            mNetworkScoreService.updateScores(new ScoredNetwork[0]);
267            fail("SecurityException expected");
268        } catch (SecurityException e) {
269            // expected
270        }
271    }
272
273    @Test
274    public void testUpdateScores_oneRegisteredCache() throws RemoteException {
275        bindToScorer(true /*callerIsScorer*/);
276
277        mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI,
278                mNetworkScoreCache, CACHE_FILTER_NONE);
279
280        mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK});
281
282        verify(mNetworkScoreCache).updateScores(mScoredNetworkCaptor.capture());
283
284        assertEquals(1, mScoredNetworkCaptor.getValue().size());
285        assertEquals(SCORED_NETWORK, mScoredNetworkCaptor.getValue().get(0));
286    }
287
288    @Test
289    public void testUpdateScores_twoRegisteredCaches() throws RemoteException {
290        bindToScorer(true /*callerIsScorer*/);
291
292        mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI,
293                mNetworkScoreCache, CACHE_FILTER_NONE);
294        mNetworkScoreService.registerNetworkScoreCache(
295                NetworkKey.TYPE_WIFI, mNetworkScoreCache2, CACHE_FILTER_NONE);
296
297        // updateScores should update both caches
298        mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK});
299
300        verify(mNetworkScoreCache).updateScores(anyListOf(ScoredNetwork.class));
301        verify(mNetworkScoreCache2).updateScores(anyListOf(ScoredNetwork.class));
302
303        mNetworkScoreService.unregisterNetworkScoreCache(
304                NetworkKey.TYPE_WIFI, mNetworkScoreCache2);
305
306        // updateScores should only update the first cache since the 2nd has been unregistered
307        mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK});
308
309        verify(mNetworkScoreCache, times(2)).updateScores(anyListOf(ScoredNetwork.class));
310
311        mNetworkScoreService.unregisterNetworkScoreCache(
312                NetworkKey.TYPE_WIFI, mNetworkScoreCache);
313
314        // updateScores should not update any caches since they are both unregistered
315        mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK});
316
317        // The register and unregister calls grab the binder from the score cache.
318        verify(mNetworkScoreCache, atLeastOnce()).asBinder();
319        verify(mNetworkScoreCache2, atLeastOnce()).asBinder();
320        verifyNoMoreInteractions(mNetworkScoreCache, mNetworkScoreCache2);
321    }
322
323    @Test
324    public void testClearScores_notActiveScorer_noRequestNetworkScoresPermission() {
325        bindToScorer(false /*callerIsScorer*/);
326        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
327            .thenReturn(PackageManager.PERMISSION_DENIED);
328        try {
329            mNetworkScoreService.clearScores();
330            fail("SecurityException expected");
331        } catch (SecurityException e) {
332            // expected
333        }
334    }
335
336    @Test
337    public void testClearScores_activeScorer_noRequestNetworkScoresPermission() {
338        bindToScorer(true /*callerIsScorer*/);
339        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
340            .thenReturn(PackageManager.PERMISSION_DENIED);
341
342        mNetworkScoreService.clearScores();
343    }
344
345    @Test
346    public void testClearScores_activeScorer() throws RemoteException {
347        bindToScorer(true /*callerIsScorer*/);
348
349        mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache,
350                CACHE_FILTER_NONE);
351        mNetworkScoreService.clearScores();
352
353        verify(mNetworkScoreCache).clearScores();
354    }
355
356    @Test
357    public void testClearScores_notActiveScorer_hasRequestNetworkScoresPermission()
358            throws RemoteException {
359        bindToScorer(false /*callerIsScorer*/);
360        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
361                .thenReturn(PackageManager.PERMISSION_GRANTED);
362
363        mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache,
364                CACHE_FILTER_NONE);
365        mNetworkScoreService.clearScores();
366
367        verify(mNetworkScoreCache).clearScores();
368    }
369
370    @Test
371    public void testSetActiveScorer_noScoreNetworksPermission() {
372        when(mContext.checkCallingOrSelfPermission(permission.SCORE_NETWORKS))
373                .thenReturn(PackageManager.PERMISSION_DENIED);
374
375        try {
376            mNetworkScoreService.setActiveScorer(null);
377            fail("SecurityException expected");
378        } catch (SecurityException e) {
379            // expected
380        }
381    }
382
383    @Test
384    public void testSetActiveScorer_requestNetworkScoresPermission() {
385        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
386                .thenReturn(PackageManager.PERMISSION_GRANTED);
387
388        mNetworkScoreService.setActiveScorer(null);
389    }
390
391    @Test
392    public void testDisableScoring_notActiveScorer_noRequestNetworkScoresPermission() {
393        bindToScorer(false /*callerIsScorer*/);
394        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
395                .thenReturn(PackageManager.PERMISSION_DENIED);
396
397        try {
398            mNetworkScoreService.disableScoring();
399            fail("SecurityException expected");
400        } catch (SecurityException e) {
401            // expected
402        }
403    }
404
405    @Test
406    public void testDisableScoring_activeScorer_noRequestNetworkScoresPermission() {
407        bindToScorer(true /*callerIsScorer*/);
408        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
409                .thenReturn(PackageManager.PERMISSION_DENIED);
410
411        mNetworkScoreService.disableScoring();
412    }
413
414    @Test
415    public void testGetAllValidScorer_noRequestNetworkScoresPermission() {
416        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
417                .thenReturn(PackageManager.PERMISSION_DENIED);
418
419        try {
420            mNetworkScoreService.getAllValidScorers();
421            fail("SecurityException expected");
422        } catch (SecurityException e) {
423            // expected
424        }
425    }
426
427    @Test
428    public void testGetAllValidScorer_requestNetworkScoresPermission() {
429        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
430                .thenReturn(PackageManager.PERMISSION_GRANTED);
431
432        mNetworkScoreService.getAllValidScorers();
433    }
434
435    @Test
436    public void testRegisterNetworkScoreCache_noRequestNetworkScoresPermission() {
437        doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
438                eq(permission.REQUEST_NETWORK_SCORES), anyString());
439
440        try {
441            mNetworkScoreService.registerNetworkScoreCache(
442                NetworkKey.TYPE_WIFI, mNetworkScoreCache, CACHE_FILTER_NONE);
443            fail("SecurityException expected");
444        } catch (SecurityException e) {
445            // expected
446        }
447    }
448
449    @Test
450    public void testUnregisterNetworkScoreCache_noRequestNetworkScoresPermission() {
451        doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
452                eq(permission.REQUEST_NETWORK_SCORES), anyString());
453
454        try {
455            mNetworkScoreService.unregisterNetworkScoreCache(
456                    NetworkKey.TYPE_WIFI, mNetworkScoreCache);
457            fail("SecurityException expected");
458        } catch (SecurityException e) {
459            // expected
460        }
461    }
462
463    @Test
464    public void testDump_doesNotCrash() {
465        when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER);
466        StringWriter stringWriter = new StringWriter();
467
468        mNetworkScoreService.dump(
469                new FileDescriptor(), new PrintWriter(stringWriter), new String[0]);
470
471        assertFalse(stringWriter.toString().isEmpty());
472    }
473
474    @Test
475    public void testIsCallerActiveScorer_noBoundService() throws Exception {
476        // No active scorer.
477        when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(null);
478        mNetworkScoreService.onUserUnlocked(0);
479
480        mNetworkScoreService.isCallerActiveScorer(Binder.getCallingUid());
481
482        verify(mServiceConnection, never()).getAppData();
483    }
484
485    @Test
486    public void testIsCallerActiveScorer_boundServiceIsNotCaller() throws Exception {
487        bindToScorer(false /*callerIsScorer*/);
488
489        assertFalse(mNetworkScoreService.isCallerActiveScorer(Binder.getCallingUid()));
490    }
491
492    @Test
493    public void testIsCallerActiveScorer_boundServiceIsCaller() throws Exception {
494        bindToScorer(true /*callerIsScorer*/);
495
496        assertTrue(mNetworkScoreService.isCallerActiveScorer(Binder.getCallingUid()));
497    }
498
499    @Test
500    public void testGetActiveScorerPackage_notActive() throws Exception {
501        // No active scorer.
502        when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(null);
503        mNetworkScoreService.onUserUnlocked(0);
504
505        mNetworkScoreService.getActiveScorerPackage();
506
507        verify(mServiceConnection, never()).getPackageName();
508    }
509
510    @Test
511    public void testGetActiveScorerPackage_active() throws Exception {
512        when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER);
513        mNetworkScoreService.onUserUnlocked(0);
514
515        mNetworkScoreService.getActiveScorerPackage();
516
517        verify(mServiceConnection).getPackageName();
518    }
519
520    @Test
521    public void testCacheUpdatingConsumer_nullFilter() throws Exception {
522        List<ScoredNetwork> scoredNetworkList = Lists.newArrayList(SCORED_NETWORK);
523        NetworkScoreService.FilteringCacheUpdatingConsumer consumer =
524                new NetworkScoreService.FilteringCacheUpdatingConsumer(mContext,
525                        new ArrayList<>(scoredNetworkList), NetworkKey.TYPE_WIFI,
526                        mCurrentNetworkFilter, mScanResultsFilter);
527
528        consumer.accept(mNetworkScoreCache, null /*cookie*/);
529
530        verify(mNetworkScoreCache).updateScores(scoredNetworkList);
531        verifyZeroInteractions(mCurrentNetworkFilter, mScanResultsFilter);
532    }
533
534    @Test
535    public void testCacheUpdatingConsumer_noneFilter() throws Exception {
536        List<ScoredNetwork> scoredNetworkList = Lists.newArrayList(SCORED_NETWORK);
537        NetworkScoreService.FilteringCacheUpdatingConsumer
538                consumer = new NetworkScoreService.FilteringCacheUpdatingConsumer(mContext,
539                new ArrayList<>(scoredNetworkList),
540                NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter);
541
542        consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_NONE);
543
544        verify(mNetworkScoreCache).updateScores(scoredNetworkList);
545        verifyZeroInteractions(mCurrentNetworkFilter, mScanResultsFilter);
546    }
547
548    @Test
549    public void testCacheUpdatingConsumer_unknownFilter() throws Exception {
550        List<ScoredNetwork> scoredNetworkList = Lists.newArrayList(SCORED_NETWORK);
551        NetworkScoreService.FilteringCacheUpdatingConsumer
552                consumer = new NetworkScoreService.FilteringCacheUpdatingConsumer(mContext,
553                new ArrayList<>(scoredNetworkList),
554                NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter);
555
556        consumer.accept(mNetworkScoreCache, -1 /*cookie*/);
557
558        verify(mNetworkScoreCache).updateScores(scoredNetworkList);
559        verifyZeroInteractions(mCurrentNetworkFilter, mScanResultsFilter);
560    }
561
562    @Test
563    public void testCacheUpdatingConsumer_nonIntFilter() throws Exception {
564        List<ScoredNetwork> scoredNetworkList = Lists.newArrayList(SCORED_NETWORK);
565        NetworkScoreService.FilteringCacheUpdatingConsumer
566                consumer = new NetworkScoreService.FilteringCacheUpdatingConsumer(mContext,
567                new ArrayList<>(scoredNetworkList),
568                NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter);
569
570        consumer.accept(mNetworkScoreCache, "not an int" /*cookie*/);
571
572        verify(mNetworkScoreCache).updateScores(scoredNetworkList);
573        verifyZeroInteractions(mCurrentNetworkFilter, mScanResultsFilter);
574    }
575
576    @Test
577    public void testCacheUpdatingConsumer_emptyScoreList() throws Exception {
578        NetworkScoreService.FilteringCacheUpdatingConsumer
579                consumer = new NetworkScoreService.FilteringCacheUpdatingConsumer(mContext,
580                Collections.emptyList(),
581                NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter);
582
583        consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_NONE);
584
585        verifyZeroInteractions(mNetworkScoreCache, mCurrentNetworkFilter, mScanResultsFilter);
586    }
587
588    @Test
589    public void testCacheUpdatingConsumer_currentNetworkFilter() throws Exception {
590        List<ScoredNetwork> scoredNetworkList =
591                Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2);
592        NetworkScoreService.FilteringCacheUpdatingConsumer
593                consumer = new NetworkScoreService.FilteringCacheUpdatingConsumer(mContext,
594                new ArrayList<>(scoredNetworkList),
595                NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter);
596
597        List<ScoredNetwork> filteredList = new ArrayList<>(scoredNetworkList);
598        filteredList.remove(SCORED_NETWORK);
599        when(mCurrentNetworkFilter.apply(scoredNetworkList)).thenReturn(filteredList);
600        consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_CURRENT_NETWORK);
601
602        verify(mNetworkScoreCache).updateScores(filteredList);
603        verifyZeroInteractions(mScanResultsFilter);
604    }
605
606    @Test
607    public void testCacheUpdatingConsumer_scanResultsFilter() throws Exception {
608        List<ScoredNetwork> scoredNetworkList =
609                Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2);
610        NetworkScoreService.FilteringCacheUpdatingConsumer
611                consumer = new NetworkScoreService.FilteringCacheUpdatingConsumer(mContext,
612                new ArrayList<>(scoredNetworkList),
613                NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter);
614
615        List<ScoredNetwork> filteredList = new ArrayList<>(scoredNetworkList);
616        filteredList.remove(SCORED_NETWORK);
617        when(mScanResultsFilter.apply(scoredNetworkList)).thenReturn(filteredList);
618        consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_SCAN_RESULTS);
619
620        verify(mNetworkScoreCache).updateScores(filteredList);
621        verifyZeroInteractions(mCurrentNetworkFilter);
622    }
623
624    @Test
625    public void testCurrentNetworkScoreCacheFilter_nullWifiInfo() throws Exception {
626        NetworkScoreService.CurrentNetworkScoreCacheFilter cacheFilter =
627                new NetworkScoreService.CurrentNetworkScoreCacheFilter(() -> null /*WifiInfo*/);
628
629        List<ScoredNetwork> actualList =
630                cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2));
631
632        assertTrue(actualList.isEmpty());
633    }
634
635    @Test
636    public void testCurrentNetworkScoreCacheFilter_invalidWifiInfo_nullSsid() throws Exception {
637        when(mWifiInfo.getSSID()).thenReturn(null);
638        NetworkScoreService.CurrentNetworkScoreCacheFilter cacheFilter =
639                new NetworkScoreService.CurrentNetworkScoreCacheFilter(() -> mWifiInfo);
640
641        List<ScoredNetwork> actualList =
642                cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2));
643
644        assertTrue(actualList.isEmpty());
645    }
646
647    @Test
648    public void testCurrentNetworkScoreCacheFilter_invalidWifiInfo_noneSsid() throws Exception {
649        when(mWifiInfo.getSSID()).thenReturn(WifiSsid.NONE);
650        NetworkScoreService.CurrentNetworkScoreCacheFilter cacheFilter =
651                new NetworkScoreService.CurrentNetworkScoreCacheFilter(() -> mWifiInfo);
652
653        List<ScoredNetwork> actualList =
654                cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2));
655
656        assertTrue(actualList.isEmpty());
657    }
658
659    @Test
660    public void testCurrentNetworkScoreCacheFilter_invalidWifiInfo_emptySsid() throws Exception {
661        when(mWifiInfo.getSSID()).thenReturn("");
662        NetworkScoreService.CurrentNetworkScoreCacheFilter cacheFilter =
663                new NetworkScoreService.CurrentNetworkScoreCacheFilter(() -> mWifiInfo);
664
665        List<ScoredNetwork> actualList =
666                cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2));
667
668        assertTrue(actualList.isEmpty());
669    }
670
671    @Test
672    public void testCurrentNetworkScoreCacheFilter_invalidWifiInfo_invalidBssid() throws Exception {
673        when(mWifiInfo.getBSSID()).thenReturn(INVALID_BSSID);
674        NetworkScoreService.CurrentNetworkScoreCacheFilter cacheFilter =
675                new NetworkScoreService.CurrentNetworkScoreCacheFilter(() -> mWifiInfo);
676
677        List<ScoredNetwork> actualList =
678                cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2));
679
680        assertTrue(actualList.isEmpty());
681    }
682
683    @Test
684    public void testCurrentNetworkScoreCacheFilter_scoreFiltered() throws Exception {
685        NetworkScoreService.CurrentNetworkScoreCacheFilter cacheFilter =
686                new NetworkScoreService.CurrentNetworkScoreCacheFilter(() -> mWifiInfo);
687
688        List<ScoredNetwork> actualList =
689                cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2));
690
691        List<ScoredNetwork> expectedList = Collections.singletonList(SCORED_NETWORK);
692        assertEquals(expectedList, actualList);
693    }
694
695    @Test
696    public void testCurrentNetworkScoreCacheFilter_currentNetworkNotInList() throws Exception {
697        when(mWifiInfo.getSSID()).thenReturn("\"notInList\"");
698        NetworkScoreService.CurrentNetworkScoreCacheFilter cacheFilter =
699                new NetworkScoreService.CurrentNetworkScoreCacheFilter(() -> mWifiInfo);
700
701        List<ScoredNetwork> actualList =
702                cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2));
703
704        assertTrue(actualList.isEmpty());
705    }
706
707    @Test
708    public void testScanResultsScoreCacheFilter_emptyScanResults() throws Exception {
709        NetworkScoreService.ScanResultsScoreCacheFilter cacheFilter =
710                new NetworkScoreService.ScanResultsScoreCacheFilter(Collections::emptyList);
711
712        List<ScoredNetwork> actualList =
713                cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2));
714
715        assertTrue(actualList.isEmpty());
716    }
717
718    @Test
719    public void testScanResultsScoreCacheFilter_invalidScanResults() throws Exception {
720        List<ScanResult> invalidScanResults = Lists.newArrayList(
721                new ScanResult(),
722                createScanResult("", SCORED_NETWORK.networkKey.wifiKey.bssid),
723                createScanResult(WifiSsid.NONE, SCORED_NETWORK.networkKey.wifiKey.bssid),
724                createScanResult(SSID, null),
725                createScanResult(SSID, INVALID_BSSID)
726        );
727        NetworkScoreService.ScanResultsScoreCacheFilter cacheFilter =
728                new NetworkScoreService.ScanResultsScoreCacheFilter(() -> invalidScanResults);
729
730        List<ScoredNetwork> actualList =
731                cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2));
732
733        assertTrue(actualList.isEmpty());
734    }
735
736    @Test
737    public void testScanResultsScoreCacheFilter_scoresFiltered() throws Exception {
738        NetworkScoreService.ScanResultsScoreCacheFilter cacheFilter =
739                new NetworkScoreService.ScanResultsScoreCacheFilter(() -> mScanResults);
740
741        ScoredNetwork unmatchedScore =
742                new ScoredNetwork(new NetworkKey(new WifiKey(quote("newSsid"),
743                        "00:00:00:00:00:00")), null /* rssiCurve*/);
744
745        List<ScoredNetwork> actualList =
746                cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2,
747                        unmatchedScore));
748
749        List<ScoredNetwork> expectedList = Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2);
750        assertEquals(expectedList, actualList);
751    }
752
753    @Test
754    public void testGetActiveScorer_notConnected_canRequestScores() throws Exception {
755        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
756                .thenReturn(PackageManager.PERMISSION_GRANTED);
757        when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(null);
758        mNetworkScoreService.onUserUnlocked(0);
759
760        mNetworkScoreService.getActiveScorer();
761
762        verify(mServiceConnection, never()).getAppData();
763    }
764
765    @Test
766    public void testGetActiveScorer_notConnected_canNotRequestScores() throws Exception {
767        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
768                .thenReturn(PackageManager.PERMISSION_DENIED);
769        try {
770            mNetworkScoreService.getActiveScorer();
771            fail("SecurityException expected.");
772        } catch (SecurityException e) {
773            // expected
774        }
775    }
776
777    @Test
778    public void testGetActiveScorer_connected_canRequestScores()
779            throws Exception {
780        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
781                .thenReturn(PackageManager.PERMISSION_GRANTED);
782        mNetworkScoreService.onUserUnlocked(0);
783
784        mNetworkScoreService.getActiveScorer();
785
786        verify(mServiceConnection).getAppData();
787    }
788
789    @Test
790    public void testGetActiveScorer_connected_canNotRequestScores()
791            throws Exception {
792        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
793                .thenReturn(PackageManager.PERMISSION_DENIED);
794        bindToScorer(false);
795        try {
796            mNetworkScoreService.getActiveScorer();
797            fail("SecurityException expected.");
798        } catch (SecurityException e) {
799            // expected
800        }
801    }
802
803    @Test
804    public void testServiceConnection_bind_notBound() throws Exception {
805        NetworkScoreService.ScoringServiceConnection connection = new NetworkScoreService
806                .ScoringServiceConnection(NEW_SCORER);
807        connection.bind(mContext);
808
809        verify(mContext).bindServiceAsUser(MockUtils.checkIntent(
810                new Intent(NetworkScoreManager.ACTION_RECOMMEND_NETWORKS)
811                        .setComponent(RECOMMENDATION_SERVICE_COMP)),
812                eq(connection),
813                eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
814                eq(UserHandle.SYSTEM));
815    }
816
817    @Test
818    public void testServiceConnection_bind_alreadyBound() throws Exception {
819        NetworkScoreService.ScoringServiceConnection connection = new NetworkScoreService
820                .ScoringServiceConnection(NEW_SCORER);
821
822        when(mContext.bindServiceAsUser(MockUtils.checkIntent(
823                new Intent(NetworkScoreManager.ACTION_RECOMMEND_NETWORKS)
824                        .setComponent(RECOMMENDATION_SERVICE_COMP)),
825                eq(connection),
826                eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
827                eq(UserHandle.SYSTEM))).thenReturn(true /*bound*/);
828
829        // Calling bind more than once should only result in 1 bindService call.
830        connection.bind(mContext);
831        connection.bind(mContext);
832
833        verify(mContext, times(1)).bindServiceAsUser(MockUtils.checkIntent(
834                new Intent(NetworkScoreManager.ACTION_RECOMMEND_NETWORKS)
835                        .setComponent(RECOMMENDATION_SERVICE_COMP)),
836                eq(connection),
837                eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
838                eq(UserHandle.SYSTEM));
839    }
840
841    @Test
842    public void testServiceConnection_bindFails() throws Exception {
843        NetworkScoreService.ScoringServiceConnection connection = new NetworkScoreService
844                .ScoringServiceConnection(NEW_SCORER);
845
846        when(mContext.bindServiceAsUser(MockUtils.checkIntent(
847                new Intent(NetworkScoreManager.ACTION_RECOMMEND_NETWORKS)
848                        .setComponent(RECOMMENDATION_SERVICE_COMP)),
849                eq(connection),
850                eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
851                eq(UserHandle.SYSTEM))).thenReturn(false /*bound*/);
852
853        connection.bind(mContext);
854
855        verify(mContext).unbindService(connection);
856    }
857
858    @Test
859    public void testServiceConnection_unbind_notBound() throws Exception {
860        NetworkScoreService.ScoringServiceConnection connection = new NetworkScoreService
861                .ScoringServiceConnection(NEW_SCORER);
862
863        connection.unbind(mContext);
864
865        verify(mContext, never()).unbindService(connection);
866    }
867
868    @Test
869    public void testServiceConnection_unbind_alreadyBound() throws Exception {
870        NetworkScoreService.ScoringServiceConnection connection = new NetworkScoreService
871                .ScoringServiceConnection(NEW_SCORER);
872
873        when(mContext.bindServiceAsUser(MockUtils.checkIntent(
874                new Intent(NetworkScoreManager.ACTION_RECOMMEND_NETWORKS)
875                        .setComponent(RECOMMENDATION_SERVICE_COMP)),
876                eq(connection),
877                eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
878                eq(UserHandle.SYSTEM))).thenReturn(true /*bound*/);
879
880        connection.bind(mContext);
881        connection.unbind(mContext);
882
883        verify(mContext).unbindService(connection);
884    }
885
886    @Test
887    public void testServiceConnection_dump_doesNotCrash() throws Exception {
888        NetworkScoreService.ScoringServiceConnection connection = new NetworkScoreService
889                .ScoringServiceConnection(NEW_SCORER);
890        final StringWriter stringWriter = new StringWriter();
891
892        connection.dump(new FileDescriptor(), new PrintWriter(stringWriter), new String[0]);
893
894        assertFalse(stringWriter.toString().isEmpty());
895    }
896
897    private void bindToScorer(boolean callerIsScorer) {
898        final int callingUid = callerIsScorer ? Binder.getCallingUid() : Binder.getCallingUid() + 1;
899        NetworkScorerAppData appData = new NetworkScorerAppData(callingUid,
900                RECOMMENDATION_SERVICE_COMP, RECOMMENDATION_SERVICE_LABEL,
901                USE_WIFI_ENABLE_ACTIVITY_COMP, NETWORK_AVAILABLE_NOTIFICATION_CHANNEL_ID);
902        when(mServiceConnection.getAppData()).thenReturn(appData);
903        mNetworkScoreService.onUserUnlocked(0);
904    }
905
906    private static class CountDownHandler extends Handler {
907        CountDownLatch latch = new CountDownLatch(1);
908        int receivedWhat;
909
910        CountDownHandler(Looper looper) {
911            super(looper);
912        }
913
914        @Override
915        public void handleMessage(Message msg) {
916            latch.countDown();
917            receivedWhat = msg.what;
918        }
919    }
920}
921