Merge "Support multiple caches in NetworkScoreService." am: 78f3f0049e

am: a7c0b73971

Change-Id: Idf846f55436c44930f5db2a07b7362412274f46e
This commit is contained in:
Amin Shaikh
2016-12-08 02:24:59 +00:00
committed by android-build-merger
5 changed files with 566 additions and 42 deletions

View File

@@ -56,16 +56,25 @@ interface INetworkScoreService
void disableScoring();
/**
* Register a network subsystem for scoring.
* Register a cache to receive scoring updates.
*
* @param networkType the type of network this cache can handle. See {@link NetworkKey#type}.
* @param scoreCache implementation of {@link INetworkScoreCache} to store the scores.
* @throws SecurityException if the caller is not the system.
* @throws IllegalArgumentException if a score cache is already registed for this type.
* @hide
*/
void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache);
/**
* Unregister a cache to receive scoring updates.
*
* @param networkType the type of network this cache can handle. See {@link NetworkKey#type}.
* @param scoreCache implementation of {@link INetworkScoreCache} to store the scores.
* @throws SecurityException if the caller is not the system.
* @hide
*/
void unregisterNetworkScoreCache(int networkType, INetworkScoreCache scoreCache);
/**
* Request a recommendation for the best network to connect to
* taking into account the inputs from the {@link RecommendationRequest}.

View File

@@ -278,6 +278,24 @@ public class NetworkScoreManager {
}
}
/**
* Unregister a network score cache.
*
* @param networkType the type of network this cache can handle. See {@link NetworkKey#type}.
* @param scoreCache implementation of {@link INetworkScoreCache} to store the scores.
* @throws SecurityException if the caller does not hold the
* {@link android.Manifest.permission#BROADCAST_NETWORK_PRIVILEGED} permission.
* @throws IllegalArgumentException if a score cache is already registered for this type.
* @hide
*/
public void unregisterNetworkScoreCache(int networkType, INetworkScoreCache scoreCache) {
try {
mService.unregisterNetworkScoreCache(networkType, scoreCache);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Request a recommendation for which network to connect to.
*

View File

@@ -36,10 +36,12 @@ import android.net.ScoredNetwork;
import android.net.wifi.WifiConfiguration;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import com.android.internal.R;
@@ -52,11 +54,11 @@ import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
/**
* Backing service for {@link android.net.NetworkScoreManager}.
@@ -68,7 +70,8 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
private final Context mContext;
private final NetworkScorerAppManager mNetworkScorerAppManager;
private final Map<Integer, INetworkScoreCache> mScoreCaches;
@GuardedBy("mScoreCaches")
private final Map<Integer, RemoteCallbackList<INetworkScoreCache>> mScoreCaches;
/** Lock used to update mPackageMonitor when scorer package changes occur. */
private final Object mPackageMonitorLock = new Object[0];
@@ -166,7 +169,7 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
NetworkScoreService(Context context, NetworkScorerAppManager networkScoreAppManager) {
mContext = context;
mNetworkScorerAppManager = networkScoreAppManager;
mScoreCaches = new HashMap<>();
mScoreCaches = new ArrayMap<>();
IntentFilter filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED);
// TODO: Need to update when we support per-user scorers. http://b/23422763
mContext.registerReceiverAsUser(
@@ -276,7 +279,7 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
}
// Separate networks by type.
Map<Integer, List<ScoredNetwork>> networksByType = new HashMap<>();
Map<Integer, List<ScoredNetwork>> networksByType = new ArrayMap<>();
for (ScoredNetwork network : networks) {
List<ScoredNetwork> networkList = networksByType.get(network.networkKey.type);
if (networkList == null) {
@@ -287,19 +290,32 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
}
// Pass the scores of each type down to the appropriate network scorer.
for (Map.Entry<Integer, List<ScoredNetwork>> entry : networksByType.entrySet()) {
INetworkScoreCache scoreCache = mScoreCaches.get(entry.getKey());
if (scoreCache != null) {
try {
scoreCache.updateScores(entry.getValue());
} catch (RemoteException e) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Unable to update scores of type " + entry.getKey(), e);
for (final Map.Entry<Integer, List<ScoredNetwork>> entry : networksByType.entrySet()) {
final RemoteCallbackList<INetworkScoreCache> callbackList;
final boolean isEmpty;
synchronized (mScoreCaches) {
callbackList = mScoreCaches.get(entry.getKey());
isEmpty = callbackList == null || callbackList.getRegisteredCallbackCount() == 0;
}
if (isEmpty) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "No scorer registered for type " + entry.getKey() + ", discarding");
}
continue;
}
sendCallback(new Consumer<INetworkScoreCache>() {
@Override
public void accept(INetworkScoreCache networkScoreCache) {
try {
networkScoreCache.updateScores(entry.getValue());
} catch (RemoteException e) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Unable to update scores of type " + entry.getKey(), e);
}
}
}
} else if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "No scorer registered for type " + entry.getKey() + ", discarding");
}
}, Collections.singleton(callbackList));
}
return true;
@@ -394,28 +410,52 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
/** Clear scores. Callers are responsible for checking permissions as appropriate. */
private void clearInternal() {
Set<INetworkScoreCache> cachesToClear = getScoreCaches();
for (INetworkScoreCache scoreCache : cachesToClear) {
try {
scoreCache.clearScores();
} catch (RemoteException e) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Unable to clear scores", e);
sendCallback(new Consumer<INetworkScoreCache>() {
@Override
public void accept(INetworkScoreCache networkScoreCache) {
try {
networkScoreCache.clearScores();
} catch (RemoteException e) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Unable to clear scores", e);
}
}
}
}
}, getScoreCacheLists());
}
@Override
public void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache) {
mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG);
synchronized (mScoreCaches) {
if (mScoreCaches.containsKey(networkType)) {
throw new IllegalArgumentException(
"Score cache already registered for type " + networkType);
RemoteCallbackList<INetworkScoreCache> callbackList = mScoreCaches.get(networkType);
if (callbackList == null) {
callbackList = new RemoteCallbackList<>();
mScoreCaches.put(networkType, callbackList);
}
if (!callbackList.register(scoreCache)) {
if (callbackList.getRegisteredCallbackCount() == 0) {
mScoreCaches.remove(networkType);
}
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Unable to register NetworkScoreCache for type " + networkType);
}
}
}
}
@Override
public void unregisterNetworkScoreCache(int networkType, INetworkScoreCache scoreCache) {
mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG);
synchronized (mScoreCaches) {
RemoteCallbackList<INetworkScoreCache> callbackList = mScoreCaches.get(networkType);
if (callbackList == null || !callbackList.unregister(scoreCache)) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Unable to unregister NetworkScoreCache for type " + networkType);
}
} else if (callbackList.getRegisteredCallbackCount() == 0) {
mScoreCaches.remove(networkType);
}
mScoreCaches.put(networkType, scoreCache);
}
}
@@ -430,7 +470,7 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
}
@Override
protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
protected void dump(final FileDescriptor fd, final PrintWriter writer, final String[] args) {
mContext.enforceCallingOrSelfPermission(permission.DUMP, TAG);
NetworkScorerAppData currentScorer = mNetworkScorerAppManager.getActiveScorer();
if (currentScorer == null) {
@@ -439,13 +479,17 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
}
writer.println("Current scorer: " + currentScorer.mPackageName);
for (INetworkScoreCache scoreCache : getScoreCaches()) {
try {
TransferPipe.dumpAsync(scoreCache.asBinder(), fd, args);
} catch (IOException | RemoteException e) {
writer.println("Failed to dump score cache: " + e);
sendCallback(new Consumer<INetworkScoreCache>() {
@Override
public void accept(INetworkScoreCache networkScoreCache) {
try {
TransferPipe.dumpAsync(networkScoreCache.asBinder(), fd, args);
} catch (IOException | RemoteException e) {
writer.println("Failed to dump score cache: " + e);
}
}
}
}, getScoreCacheLists());
if (mServiceConnection != null) {
mServiceConnection.dump(fd, writer, args);
} else {
@@ -455,14 +499,30 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
}
/**
* Returns a set of all score caches that are currently active.
* Returns a {@link Collection} of all {@link RemoteCallbackList}s that are currently active.
*
* <p>May be used to perform an action on all score caches without potentially strange behavior
* if a new scorer is registered during that action's execution.
*/
private Set<INetworkScoreCache> getScoreCaches() {
private Collection<RemoteCallbackList<INetworkScoreCache>> getScoreCacheLists() {
synchronized (mScoreCaches) {
return new HashSet<>(mScoreCaches.values());
return new ArrayList<>(mScoreCaches.values());
}
}
private void sendCallback(Consumer<INetworkScoreCache> consumer,
Collection<RemoteCallbackList<INetworkScoreCache>> remoteCallbackLists) {
for (RemoteCallbackList<INetworkScoreCache> callbackList : remoteCallbackLists) {
synchronized (callbackList) { // Ensure only one active broadcast per RemoteCallbackList
final int count = callbackList.beginBroadcast();
try {
for (int i = 0; i < count; i++) {
consumer.accept(callbackList.getBroadcastItem(i));
}
} finally {
callbackList.finishBroadcast();
}
}
}
}

View File

@@ -0,0 +1,422 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyListOf;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.Manifest.permission;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.net.INetworkScoreCache;
import android.net.NetworkKey;
import android.net.NetworkScoreManager;
import android.net.NetworkScorerAppManager;
import android.net.NetworkScorerAppManager.NetworkScorerAppData;
import android.net.ScoredNetwork;
import android.net.WifiKey;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4;
import com.android.internal.R;
import com.android.server.devicepolicy.MockUtils;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
/**
* Tests for {@link NetworkScoreService}.
*/
@RunWith(AndroidJUnit4.class)
@MediumTest
public class NetworkScoreServiceTest {
private static final ScoredNetwork SCORED_NETWORK =
new ScoredNetwork(new NetworkKey(new WifiKey("\"ssid\"", "00:00:00:00:00:00")),
null /* rssiCurve*/);
private static final NetworkScorerAppData PREV_SCORER = new NetworkScorerAppData(
"prevPackageName", 0, "prevScorerName", null /* configurationActivityClassName */,
"prevScoringServiceClass");
private static final NetworkScorerAppData NEW_SCORER = new NetworkScorerAppData(
"newPackageName", 1, "newScorerName", null /* configurationActivityClassName */,
"newScoringServiceClass");
@Mock private PackageManager mPackageManager;
@Mock private NetworkScorerAppManager mNetworkScorerAppManager;
@Mock private Context mContext;
@Mock private Resources mResources;
@Mock private INetworkScoreCache.Stub mNetworkScoreCache, mNetworkScoreCache2;
@Mock private IBinder mIBinder, mIBinder2;
@Captor private ArgumentCaptor<List<ScoredNetwork>> mScoredNetworkCaptor;
private ContentResolver mContentResolver;
private NetworkScoreService mNetworkScoreService;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(mNetworkScoreCache.asBinder()).thenReturn(mIBinder);
when(mNetworkScoreCache2.asBinder()).thenReturn(mIBinder2);
mContentResolver = InstrumentationRegistry.getContext().getContentResolver();
when(mContext.getContentResolver()).thenReturn(mContentResolver);
when(mContext.getResources()).thenReturn(mResources);
mNetworkScoreService = new NetworkScoreService(mContext, mNetworkScorerAppManager);
}
@Test
public void testSystemReady_networkScorerProvisioned() throws Exception {
Settings.Global.putInt(mContentResolver, Global.NETWORK_SCORING_PROVISIONED, 1);
mNetworkScoreService.systemReady();
verify(mNetworkScorerAppManager, never()).setActiveScorer(anyString());
}
@Test
public void testSystemReady_networkScorerNotProvisioned_defaultScorer() throws Exception {
Settings.Global.putInt(mContentResolver, Global.NETWORK_SCORING_PROVISIONED, 0);
when(mResources.getString(R.string.config_defaultNetworkScorerPackageName))
.thenReturn(NEW_SCORER.mPackageName);
mNetworkScoreService.systemReady();
verify(mNetworkScorerAppManager).setActiveScorer(NEW_SCORER.mPackageName);
assertEquals(1,
Settings.Global.getInt(mContentResolver, Global.NETWORK_SCORING_PROVISIONED));
}
@Test
public void testSystemReady_networkScorerNotProvisioned_noDefaultScorer() throws Exception {
Settings.Global.putInt(mContentResolver, Global.NETWORK_SCORING_PROVISIONED, 0);
when(mResources.getString(R.string.config_defaultNetworkScorerPackageName))
.thenReturn(null);
mNetworkScoreService.systemReady();
verify(mNetworkScorerAppManager, never()).setActiveScorer(anyString());
assertEquals(1,
Settings.Global.getInt(mContentResolver, Global.NETWORK_SCORING_PROVISIONED));
}
@Test
public void testSystemRunning() {
when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER);
mNetworkScoreService.systemRunning();
verify(mContext).bindServiceAsUser(MockUtils.checkIntent(new Intent().setComponent(
new ComponentName(NEW_SCORER.mPackageName, NEW_SCORER.mScoringServiceClassName))),
any(ServiceConnection.class),
eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
eq(UserHandle.SYSTEM));
}
@Test
public void testUpdateScores_notActiveScorer() {
when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false);
try {
mNetworkScoreService.updateScores(new ScoredNetwork[0]);
fail("SecurityException expected");
} catch (SecurityException e) {
// expected
}
}
@Test
public void testUpdateScores_oneRegisteredCache() throws RemoteException {
when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(true);
mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache);
mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK});
verify(mNetworkScoreCache).updateScores(mScoredNetworkCaptor.capture());
assertEquals(1, mScoredNetworkCaptor.getValue().size());
assertEquals(SCORED_NETWORK, mScoredNetworkCaptor.getValue().get(0));
}
@Test
public void testUpdateScores_twoRegisteredCaches() throws RemoteException {
when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(true);
mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache);
mNetworkScoreService.registerNetworkScoreCache(
NetworkKey.TYPE_WIFI, mNetworkScoreCache2);
// updateScores should update both caches
mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK});
verify(mNetworkScoreCache).updateScores(anyListOf(ScoredNetwork.class));
verify(mNetworkScoreCache2).updateScores(anyListOf(ScoredNetwork.class));
mNetworkScoreService.unregisterNetworkScoreCache(
NetworkKey.TYPE_WIFI, mNetworkScoreCache2);
// updateScores should only update the first cache since the 2nd has been unregistered
mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK});
verify(mNetworkScoreCache, times(2)).updateScores(anyListOf(ScoredNetwork.class));
mNetworkScoreService.unregisterNetworkScoreCache(
NetworkKey.TYPE_WIFI, mNetworkScoreCache);
// updateScores should not update any caches since they are both unregistered
mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK});
verifyNoMoreInteractions(mNetworkScoreCache, mNetworkScoreCache2);
}
@Test
public void testClearScores_notActiveScorer_noBroadcastNetworkPermission() {
when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false);
when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED))
.thenReturn(PackageManager.PERMISSION_DENIED);
try {
mNetworkScoreService.clearScores();
fail("SecurityException expected");
} catch (SecurityException e) {
// expected
}
}
@Test
public void testClearScores_activeScorer_noBroadcastNetworkPermission() {
when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(true);
when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED))
.thenReturn(PackageManager.PERMISSION_DENIED);
mNetworkScoreService.clearScores();
}
@Test
public void testClearScores_activeScorer() throws RemoteException {
when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(true);
mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache);
mNetworkScoreService.clearScores();
verify(mNetworkScoreCache).clearScores();
}
@Test
public void testClearScores_notActiveScorer_hasBroadcastNetworkPermission()
throws RemoteException {
when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false);
when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED))
.thenReturn(PackageManager.PERMISSION_GRANTED);
mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache);
mNetworkScoreService.clearScores();
verify(mNetworkScoreCache).clearScores();
}
@Test
public void testSetActiveScorer_noScoreNetworksPermission() {
doThrow(new SecurityException()).when(mContext)
.enforceCallingOrSelfPermission(eq(permission.SCORE_NETWORKS), anyString());
try {
mNetworkScoreService.setActiveScorer(null);
fail("SecurityException expected");
} catch (SecurityException e) {
// expected
}
}
@Test
public void testSetActiveScorer_failure() throws RemoteException {
when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(PREV_SCORER);
when(mNetworkScorerAppManager.setActiveScorer(NEW_SCORER.mPackageName)).thenReturn(false);
mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache);
boolean success = mNetworkScoreService.setActiveScorer(NEW_SCORER.mPackageName);
assertFalse(success);
verify(mNetworkScoreCache).clearScores();
verify(mContext).bindServiceAsUser(MockUtils.checkIntent(new Intent().setComponent(
new ComponentName(PREV_SCORER.mPackageName, PREV_SCORER.mScoringServiceClassName))),
any(ServiceConnection.class),
eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
eq(UserHandle.SYSTEM));
}
@Test
public void testSetActiveScorer_success() throws RemoteException {
when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(PREV_SCORER, NEW_SCORER);
when(mNetworkScorerAppManager.setActiveScorer(NEW_SCORER.mPackageName)).thenReturn(true);
mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache);
boolean success = mNetworkScoreService.setActiveScorer(NEW_SCORER.mPackageName);
assertTrue(success);
verify(mNetworkScoreCache).clearScores();
verify(mContext).bindServiceAsUser(MockUtils.checkIntent(new Intent().setComponent(
new ComponentName(NEW_SCORER.mPackageName, NEW_SCORER.mScoringServiceClassName))),
any(ServiceConnection.class),
eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
eq(UserHandle.SYSTEM));
verify(mContext, times(2)).sendBroadcastAsUser(
MockUtils.checkIntentAction(NetworkScoreManager.ACTION_SCORER_CHANGED),
eq(UserHandle.SYSTEM));
}
@Test
public void testDisableScoring_notActiveScorer_noBroadcastNetworkPermission() {
when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false);
when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED))
.thenReturn(PackageManager.PERMISSION_DENIED);
try {
mNetworkScoreService.disableScoring();
fail("SecurityException expected");
} catch (SecurityException e) {
// expected
}
}
@Test
public void testDisableScoring_activeScorer() throws RemoteException {
when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(true);
when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(PREV_SCORER, null);
when(mNetworkScorerAppManager.setActiveScorer(null)).thenReturn(true);
mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache);
mNetworkScoreService.disableScoring();
verify(mNetworkScoreCache).clearScores();
verify(mContext).sendBroadcastAsUser(
MockUtils.checkIntent(new Intent(NetworkScoreManager.ACTION_SCORER_CHANGED)
.setPackage(PREV_SCORER.mPackageName)),
eq(UserHandle.SYSTEM));
verify(mContext, never()).bindServiceAsUser(any(Intent.class),
any(ServiceConnection.class), anyInt(), any(UserHandle.class));
}
@Test
public void testDisableScoring_notActiveScorer_hasBroadcastNetworkPermission()
throws RemoteException {
when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false);
when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED))
.thenReturn(PackageManager.PERMISSION_GRANTED);
when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(PREV_SCORER, null);
when(mNetworkScorerAppManager.setActiveScorer(null)).thenReturn(true);
mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache);
mNetworkScoreService.disableScoring();
verify(mNetworkScoreCache).clearScores();
verify(mContext).sendBroadcastAsUser(
MockUtils.checkIntent(new Intent(NetworkScoreManager.ACTION_SCORER_CHANGED)
.setPackage(PREV_SCORER.mPackageName)),
eq(UserHandle.SYSTEM));
verify(mContext, never()).bindServiceAsUser(any(Intent.class),
any(ServiceConnection.class), anyInt(), any(UserHandle.class));
}
@Test
public void testRegisterNetworkScoreCache_noBroadcastNetworkPermission() {
doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
eq(permission.BROADCAST_NETWORK_PRIVILEGED), anyString());
try {
mNetworkScoreService.registerNetworkScoreCache(
NetworkKey.TYPE_WIFI, mNetworkScoreCache);
fail("SecurityException expected");
} catch (SecurityException e) {
// expected
}
}
@Test
public void testUnregisterNetworkScoreCache_noBroadcastNetworkPermission() {
doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
eq(permission.BROADCAST_NETWORK_PRIVILEGED), anyString());
try {
mNetworkScoreService.unregisterNetworkScoreCache(
NetworkKey.TYPE_WIFI, mNetworkScoreCache);
fail("SecurityException expected");
} catch (SecurityException e) {
// expected
}
}
@Test
public void testDump_noDumpPermission() {
doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
eq(permission.DUMP), anyString());
try {
mNetworkScoreService.dump(
new FileDescriptor(), new PrintWriter(new StringWriter()), new String[0]);
fail("SecurityException expected");
} catch (SecurityException e) {
// expected
}
}
@Test
public void testDump_doesNotCrash() {
when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER);
StringWriter stringWriter = new StringWriter();
mNetworkScoreService.dump(
new FileDescriptor(), new PrintWriter(stringWriter), new String[0]);
assertFalse(stringWriter.toString().isEmpty());
}
}

View File

@@ -82,6 +82,21 @@ public class MockUtils {
return Mockito.argThat(m);
}
public static Intent checkIntent(final Intent intent) {
final Matcher<Intent> m = new BaseMatcher<Intent>() {
@Override
public boolean matches(Object item) {
if (item == null) return false;
return intent.filterEquals((Intent) item);
}
@Override
public void describeTo(Description description) {
description.appendText(intent.toString());
}
};
return Mockito.argThat(m);
}
public static Bundle checkUserRestrictions(String... keys) {
final Bundle expected = DpmTestUtils.newRestrictions(Preconditions.checkNotNull(keys));
final Matcher<Bundle> m = new BaseMatcher<Bundle>() {