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

Commit a5626d74 authored by Android Build Merger (Role)'s avatar Android Build Merger (Role) Committed by Android (Google) Code Review
Browse files

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

Merge "Merge "Support multiple caches in NetworkScoreService." am: 78f3f004 am: a7c0b739 am: b45a4a5d am: 5456cdbc"
parents e691e4ff 38724a23
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>() {