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