Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5456cdbc authored by Amin Shaikh's avatar Amin Shaikh Committed by android-build-merger
Browse files

Merge "Support multiple caches in NetworkScoreService." am: 78f3f004 am: a7c0b739

am: b45a4a5d

Change-Id: If0080f344e53c4cddf4605879614a664c80b62ee
parents 7e789f3f b45a4a5d
Loading
Loading
Loading
Loading
+11 −2
Original line number Original line Diff line number Diff line
@@ -56,16 +56,25 @@ interface INetworkScoreService
    void disableScoring();
    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 networkType the type of network this cache can handle. See {@link NetworkKey#type}.
     * @param scoreCache implementation of {@link INetworkScoreCache} to store the scores.
     * @param scoreCache implementation of {@link INetworkScoreCache} to store the scores.
     * @throws SecurityException if the caller is not the system.
     * @throws SecurityException if the caller is not the system.
     * @throws IllegalArgumentException if a score cache is already registed for this type.
     * @hide
     * @hide
     */
     */
    void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache);
    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
     * Request a recommendation for the best network to connect to
     * taking into account the inputs from the {@link RecommendationRequest}.
     * taking into account the inputs from the {@link RecommendationRequest}.
+18 −0
Original line number Original line Diff line number Diff line
@@ -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.
     * Request a recommendation for which network to connect to.
     *
     *
+98 −38
Original line number Original line Diff line number Diff line
@@ -36,10 +36,12 @@ import android.net.ScoredNetwork;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration;
import android.os.Binder;
import android.os.Binder;
import android.os.IBinder;
import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings;
import android.text.TextUtils;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Log;


import com.android.internal.R;
import com.android.internal.R;
@@ -52,11 +54,11 @@ import java.io.FileDescriptor;
import java.io.IOException;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Collection;
import java.util.HashSet;
import java.util.Collections;
import java.util.List;
import java.util.List;
import java.util.Map;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;


/**
/**
 * Backing service for {@link android.net.NetworkScoreManager}.
 * Backing service for {@link android.net.NetworkScoreManager}.
@@ -68,7 +70,8 @@ public class NetworkScoreService extends INetworkScoreService.Stub {


    private final Context mContext;
    private final Context mContext;
    private final NetworkScorerAppManager mNetworkScorerAppManager;
    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. */
    /** Lock used to update mPackageMonitor when scorer package changes occur. */
    private final Object mPackageMonitorLock = new Object[0];
    private final Object mPackageMonitorLock = new Object[0];


@@ -166,7 +169,7 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
    NetworkScoreService(Context context, NetworkScorerAppManager networkScoreAppManager) {
    NetworkScoreService(Context context, NetworkScorerAppManager networkScoreAppManager) {
        mContext = context;
        mContext = context;
        mNetworkScorerAppManager = networkScoreAppManager;
        mNetworkScorerAppManager = networkScoreAppManager;
        mScoreCaches = new HashMap<>();
        mScoreCaches = new ArrayMap<>();
        IntentFilter filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED);
        IntentFilter filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED);
        // TODO: Need to update when we support per-user scorers. http://b/23422763
        // TODO: Need to update when we support per-user scorers. http://b/23422763
        mContext.registerReceiverAsUser(
        mContext.registerReceiverAsUser(
@@ -276,7 +279,7 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
        }
        }


        // Separate networks by type.
        // Separate networks by type.
        Map<Integer, List<ScoredNetwork>> networksByType = new HashMap<>();
        Map<Integer, List<ScoredNetwork>> networksByType = new ArrayMap<>();
        for (ScoredNetwork network : networks) {
        for (ScoredNetwork network : networks) {
            List<ScoredNetwork> networkList = networksByType.get(network.networkKey.type);
            List<ScoredNetwork> networkList = networksByType.get(network.networkKey.type);
            if (networkList == null) {
            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.
        // Pass the scores of each type down to the appropriate network scorer.
        for (Map.Entry<Integer, List<ScoredNetwork>> entry : networksByType.entrySet()) {
        for (final Map.Entry<Integer, List<ScoredNetwork>> entry : networksByType.entrySet()) {
            INetworkScoreCache scoreCache = mScoreCaches.get(entry.getKey());
            final RemoteCallbackList<INetworkScoreCache> callbackList;
            if (scoreCache != null) {
            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 {
                    try {
                    scoreCache.updateScores(entry.getValue());
                        networkScoreCache.updateScores(entry.getValue());
                    } catch (RemoteException e) {
                    } catch (RemoteException e) {
                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
                            Log.v(TAG, "Unable to update scores of type " + entry.getKey(), e);
                            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;
        return true;
@@ -394,28 +410,52 @@ public class NetworkScoreService extends INetworkScoreService.Stub {


    /** Clear scores. Callers are responsible for checking permissions as appropriate. */
    /** Clear scores. Callers are responsible for checking permissions as appropriate. */
    private void clearInternal() {
    private void clearInternal() {
        Set<INetworkScoreCache> cachesToClear = getScoreCaches();
        sendCallback(new Consumer<INetworkScoreCache>() {

            @Override
        for (INetworkScoreCache scoreCache : cachesToClear) {
            public void accept(INetworkScoreCache networkScoreCache) {
                try {
                try {
                scoreCache.clearScores();
                    networkScoreCache.clearScores();
                } catch (RemoteException e) {
                } catch (RemoteException e) {
                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
                        Log.v(TAG, "Unable to clear scores", e);
                        Log.v(TAG, "Unable to clear scores", e);
                    }
                    }
                }
                }
            }
            }
        }, getScoreCacheLists());
    }
    }


    @Override
    @Override
    public void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache) {
    public void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache) {
        mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG);
        mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG);
        synchronized (mScoreCaches) {
        synchronized (mScoreCaches) {
            if (mScoreCaches.containsKey(networkType)) {
            RemoteCallbackList<INetworkScoreCache> callbackList = mScoreCaches.get(networkType);
                throw new IllegalArgumentException(
            if (callbackList == null) {
                        "Score cache already registered for type " + networkType);
                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
    @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);
        mContext.enforceCallingOrSelfPermission(permission.DUMP, TAG);
        NetworkScorerAppData currentScorer = mNetworkScorerAppManager.getActiveScorer();
        NetworkScorerAppData currentScorer = mNetworkScorerAppManager.getActiveScorer();
        if (currentScorer == null) {
        if (currentScorer == null) {
@@ -439,13 +479,17 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
        }
        }
        writer.println("Current scorer: " + currentScorer.mPackageName);
        writer.println("Current scorer: " + currentScorer.mPackageName);


        for (INetworkScoreCache scoreCache : getScoreCaches()) {
        sendCallback(new Consumer<INetworkScoreCache>() {
            @Override
            public void accept(INetworkScoreCache networkScoreCache) {
                try {
                try {
                TransferPipe.dumpAsync(scoreCache.asBinder(), fd, args);
                  TransferPipe.dumpAsync(networkScoreCache.asBinder(), fd, args);
                } catch (IOException | RemoteException e) {
                } catch (IOException | RemoteException e) {
                  writer.println("Failed to dump score cache: " + e);
                  writer.println("Failed to dump score cache: " + e);
                }
                }
            }
            }
        }, getScoreCacheLists());

        if (mServiceConnection != null) {
        if (mServiceConnection != null) {
            mServiceConnection.dump(fd, writer, args);
            mServiceConnection.dump(fd, writer, args);
        } else {
        } 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
     * <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.
     * if a new scorer is registered during that action's execution.
     */
     */
    private Set<INetworkScoreCache> getScoreCaches() {
    private Collection<RemoteCallbackList<INetworkScoreCache>> getScoreCacheLists() {
        synchronized (mScoreCaches) {
        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();
                }
            }
        }
        }
    }
    }


+422 −0

File added.

Preview size limit exceeded, changes collapsed.

+15 −0
Original line number Original line Diff line number Diff line
@@ -82,6 +82,21 @@ public class MockUtils {
        return Mockito.argThat(m);
        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) {
    public static Bundle checkUserRestrictions(String... keys) {
        final Bundle expected = DpmTestUtils.newRestrictions(Preconditions.checkNotNull(keys));
        final Bundle expected = DpmTestUtils.newRestrictions(Preconditions.checkNotNull(keys));
        final Matcher<Bundle> m = new BaseMatcher<Bundle>() {
        final Matcher<Bundle> m = new BaseMatcher<Bundle>() {