19bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline/*
29bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline * Copyright (C) 2017 The Android Open Source Project
39bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline *
49bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline * Licensed under the Apache License, Version 2.0 (the "License");
59bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline * you may not use this file except in compliance with the License.
69bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline * You may obtain a copy of the License at
79bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline *
89bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline *      http://www.apache.org/licenses/LICENSE-2.0
99bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline *
109bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline * Unless required by applicable law or agreed to in writing, software
119bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline * distributed under the License is distributed on an "AS IS" BASIS,
129bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline * See the License for the specific language governing permissions and
149bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline * limitations under the License.
159bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline */
169bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
179bba340fd4edd5aea91d612a332f964b0d63cf34Erik Klinepackage com.android.server.connectivity.tethering;
189bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
193760999e347ae1cfa25087451638de8ddc79c9f6Erik Klineimport static android.net.ConnectivityManager.getNetworkTypeName;
203760999e347ae1cfa25087451638de8ddc79c9f6Erik Klineimport static android.net.ConnectivityManager.TYPE_NONE;
21dd8e8911c69dd68d268f892373b174bc7b422db8Erik Klineimport static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
22dd8e8911c69dd68d268f892373b174bc7b422db8Erik Klineimport static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
23dd8e8911c69dd68d268f892373b174bc7b422db8Erik Kline
249bba340fd4edd5aea91d612a332f964b0d63cf34Erik Klineimport android.content.Context;
25b583b03675492280ab87f1eff30c05709cafba23Erik Klineimport android.os.Handler;
26b583b03675492280ab87f1eff30c05709cafba23Erik Klineimport android.os.Looper;
27f94833df7dbead3ebce2efeeae2b57fa0613c743Erik Klineimport android.os.Process;
289bba340fd4edd5aea91d612a332f964b0d63cf34Erik Klineimport android.net.ConnectivityManager;
299bba340fd4edd5aea91d612a332f964b0d63cf34Erik Klineimport android.net.ConnectivityManager.NetworkCallback;
303a5278f2c4d71a8f69ce1085da42904283d62785Erik Klineimport android.net.IpPrefix;
313a5278f2c4d71a8f69ce1085da42904283d62785Erik Klineimport android.net.LinkAddress;
329bba340fd4edd5aea91d612a332f964b0d63cf34Erik Klineimport android.net.LinkProperties;
339bba340fd4edd5aea91d612a332f964b0d63cf34Erik Klineimport android.net.Network;
349bba340fd4edd5aea91d612a332f964b0d63cf34Erik Klineimport android.net.NetworkCapabilities;
359bba340fd4edd5aea91d612a332f964b0d63cf34Erik Klineimport android.net.NetworkRequest;
369bba340fd4edd5aea91d612a332f964b0d63cf34Erik Klineimport android.net.NetworkState;
373a5278f2c4d71a8f69ce1085da42904283d62785Erik Klineimport android.net.util.NetworkConstants;
3832179ff81511e00aef31e8fda705be3df074ece6Erik Klineimport android.net.util.PrefixUtils;
397747fd4ce055e8e1f6381062a58b867728f57d85Erik Klineimport android.net.util.SharedLog;
409bba340fd4edd5aea91d612a332f964b0d63cf34Erik Klineimport android.util.Log;
419bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
42885a9098cf19eaee5a164c5ca771aec5926f2efdErik Klineimport com.android.internal.annotations.VisibleForTesting;
439bba340fd4edd5aea91d612a332f964b0d63cf34Erik Klineimport com.android.internal.util.StateMachine;
449bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
453a5278f2c4d71a8f69ce1085da42904283d62785Erik Klineimport java.util.Collections;
469bba340fd4edd5aea91d612a332f964b0d63cf34Erik Klineimport java.util.HashMap;
473a5278f2c4d71a8f69ce1085da42904283d62785Erik Klineimport java.util.HashSet;
483a5278f2c4d71a8f69ce1085da42904283d62785Erik Klineimport java.util.Set;
499bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
509bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
519bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline/**
529bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline * A class to centralize all the network and link properties information
539bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline * pertaining to the current and any potential upstream network.
549bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline *
559bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline * Calling #start() registers two callbacks: one to track the system default
56d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline * network and a second to observe all networks.  The latter is necessary
57d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline * while the expression of preferred upstreams remains a list of legacy
58d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline * connectivity types.  In future, this can be revisited.
599bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline *
609bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline * The methods and data members of this class are only to be accessed and
619bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline * modified from the tethering master state machine thread. Any other
629bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline * access semantics would necessitate the addition of locking.
639bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline *
649bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline * TODO: Move upstream selection logic here.
659bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline *
66d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline * All callback methods are run on the same thread as the specified target
67d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline * state machine.  This class does not require locking when accessed from this
68d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline * thread.  Access from other threads is not advised.
69d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline *
709bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline * @hide
719bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline */
729bba340fd4edd5aea91d612a332f964b0d63cf34Erik Klinepublic class UpstreamNetworkMonitor {
739bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    private static final String TAG = UpstreamNetworkMonitor.class.getSimpleName();
749bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    private static final boolean DBG = false;
759bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    private static final boolean VDBG = false;
769bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
779bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    public static final int EVENT_ON_AVAILABLE      = 1;
789bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    public static final int EVENT_ON_CAPABILITIES   = 2;
799bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    public static final int EVENT_ON_LINKPROPERTIES = 3;
809bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    public static final int EVENT_ON_LOST           = 4;
8132179ff81511e00aef31e8fda705be3df074ece6Erik Kline    public static final int NOTIFY_LOCAL_PREFIXES   = 10;
829bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
8335bf06c968ecbae502efd9cfb13fff9b7ddf9d6aErik Kline    private static final int CALLBACK_LISTEN_ALL = 1;
8435bf06c968ecbae502efd9cfb13fff9b7ddf9d6aErik Kline    private static final int CALLBACK_TRACK_DEFAULT = 2;
8535bf06c968ecbae502efd9cfb13fff9b7ddf9d6aErik Kline    private static final int CALLBACK_MOBILE_REQUEST = 3;
86d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline
879bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    private final Context mContext;
887747fd4ce055e8e1f6381062a58b867728f57d85Erik Kline    private final SharedLog mLog;
899bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    private final StateMachine mTarget;
90b583b03675492280ab87f1eff30c05709cafba23Erik Kline    private final Handler mHandler;
919bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    private final int mWhat;
929bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    private final HashMap<Network, NetworkState> mNetworkMap = new HashMap<>();
9332179ff81511e00aef31e8fda705be3df074ece6Erik Kline    private HashSet<IpPrefix> mLocalPrefixes;
949bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    private ConnectivityManager mCM;
95d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline    private NetworkCallback mListenAllCallback;
969bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    private NetworkCallback mDefaultNetworkCallback;
979bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    private NetworkCallback mMobileNetworkCallback;
989bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    private boolean mDunRequired;
9960caf7d29132262dd4a077b68daa807d22773524Erik Kline    // The current system default network (not really used yet).
10060caf7d29132262dd4a077b68daa807d22773524Erik Kline    private Network mDefaultInternetNetwork;
10160caf7d29132262dd4a077b68daa807d22773524Erik Kline    // The current upstream network used for tethering.
10260caf7d29132262dd4a077b68daa807d22773524Erik Kline    private Network mTetheringUpstreamNetwork;
1039bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
1043a5278f2c4d71a8f69ce1085da42904283d62785Erik Kline    public UpstreamNetworkMonitor(Context ctx, StateMachine tgt, SharedLog log, int what) {
1059bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        mContext = ctx;
1069bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        mTarget = tgt;
107b583b03675492280ab87f1eff30c05709cafba23Erik Kline        mHandler = mTarget.getHandler();
1087747fd4ce055e8e1f6381062a58b867728f57d85Erik Kline        mLog = log.forSubComponent(TAG);
1093a5278f2c4d71a8f69ce1085da42904283d62785Erik Kline        mWhat = what;
11032179ff81511e00aef31e8fda705be3df074ece6Erik Kline        mLocalPrefixes = new HashSet<>();
1119bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    }
1129bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
113885a9098cf19eaee5a164c5ca771aec5926f2efdErik Kline    @VisibleForTesting
1147747fd4ce055e8e1f6381062a58b867728f57d85Erik Kline    public UpstreamNetworkMonitor(
1153a5278f2c4d71a8f69ce1085da42904283d62785Erik Kline            ConnectivityManager cm, StateMachine tgt, SharedLog log, int what) {
1163a5278f2c4d71a8f69ce1085da42904283d62785Erik Kline        this((Context) null, tgt, log, what);
117885a9098cf19eaee5a164c5ca771aec5926f2efdErik Kline        mCM = cm;
118885a9098cf19eaee5a164c5ca771aec5926f2efdErik Kline    }
119885a9098cf19eaee5a164c5ca771aec5926f2efdErik Kline
1209bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    public void start() {
1219bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        stop();
1229bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
123d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        final NetworkRequest listenAllRequest = new NetworkRequest.Builder()
124d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline                .clearCapabilities().build();
12535bf06c968ecbae502efd9cfb13fff9b7ddf9d6aErik Kline        mListenAllCallback = new UpstreamNetworkCallback(CALLBACK_LISTEN_ALL);
126b583b03675492280ab87f1eff30c05709cafba23Erik Kline        cm().registerNetworkCallback(listenAllRequest, mListenAllCallback, mHandler);
1279bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
12835bf06c968ecbae502efd9cfb13fff9b7ddf9d6aErik Kline        mDefaultNetworkCallback = new UpstreamNetworkCallback(CALLBACK_TRACK_DEFAULT);
129b583b03675492280ab87f1eff30c05709cafba23Erik Kline        cm().registerDefaultNetworkCallback(mDefaultNetworkCallback, mHandler);
1309bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    }
1319bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
1329bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    public void stop() {
1339bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        releaseMobileNetworkRequest();
1349bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
1359bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        releaseCallback(mDefaultNetworkCallback);
1369bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        mDefaultNetworkCallback = null;
13760caf7d29132262dd4a077b68daa807d22773524Erik Kline        mDefaultInternetNetwork = null;
1389bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
139d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        releaseCallback(mListenAllCallback);
140d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        mListenAllCallback = null;
1419bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
14260caf7d29132262dd4a077b68daa807d22773524Erik Kline        mTetheringUpstreamNetwork = null;
1439bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        mNetworkMap.clear();
1449bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    }
1459bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
146efdd3f4ce04d3e1741831982ff86a58da6b542d3Erik Kline    public void updateMobileRequiresDun(boolean dunRequired) {
1479bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        final boolean valueChanged = (mDunRequired != dunRequired);
1489bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        mDunRequired = dunRequired;
1499bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        if (valueChanged && mobileNetworkRequested()) {
1509bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline            releaseMobileNetworkRequest();
1519bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline            registerMobileNetworkRequest();
1529bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        }
1539bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    }
1549bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
1559bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    public boolean mobileNetworkRequested() {
1569bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        return (mMobileNetworkCallback != null);
1579bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    }
1589bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
1599bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    public void registerMobileNetworkRequest() {
160efdd3f4ce04d3e1741831982ff86a58da6b542d3Erik Kline        if (mMobileNetworkCallback != null) {
1617747fd4ce055e8e1f6381062a58b867728f57d85Erik Kline            mLog.e("registerMobileNetworkRequest() already registered");
162efdd3f4ce04d3e1741831982ff86a58da6b542d3Erik Kline            return;
163efdd3f4ce04d3e1741831982ff86a58da6b542d3Erik Kline        }
1649bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
16535bf06c968ecbae502efd9cfb13fff9b7ddf9d6aErik Kline        // The following use of the legacy type system cannot be removed until
16635bf06c968ecbae502efd9cfb13fff9b7ddf9d6aErik Kline        // after upstream selection no longer finds networks by legacy type.
16735bf06c968ecbae502efd9cfb13fff9b7ddf9d6aErik Kline        // See also http://b/34364553 .
16835bf06c968ecbae502efd9cfb13fff9b7ddf9d6aErik Kline        final int legacyType = mDunRequired ? TYPE_MOBILE_DUN : TYPE_MOBILE_HIPRI;
16935bf06c968ecbae502efd9cfb13fff9b7ddf9d6aErik Kline
17035bf06c968ecbae502efd9cfb13fff9b7ddf9d6aErik Kline        final NetworkRequest mobileUpstreamRequest = new NetworkRequest.Builder()
17135bf06c968ecbae502efd9cfb13fff9b7ddf9d6aErik Kline                .setCapabilities(ConnectivityManager.networkCapabilitiesForType(legacyType))
17235bf06c968ecbae502efd9cfb13fff9b7ddf9d6aErik Kline                .build();
1739bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
1749bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        // The existing default network and DUN callbacks will be notified.
1759bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        // Therefore, to avoid duplicate notifications, we only register a no-op.
17635bf06c968ecbae502efd9cfb13fff9b7ddf9d6aErik Kline        mMobileNetworkCallback = new UpstreamNetworkCallback(CALLBACK_MOBILE_REQUEST);
1779bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
178efdd3f4ce04d3e1741831982ff86a58da6b542d3Erik Kline        // TODO: Change the timeout from 0 (no onUnavailable callback) to some
179efdd3f4ce04d3e1741831982ff86a58da6b542d3Erik Kline        // moderate callback timeout. This might be useful for updating some UI.
180efdd3f4ce04d3e1741831982ff86a58da6b542d3Erik Kline        // Additionally, we log a message to aid in any subsequent debugging.
1817747fd4ce055e8e1f6381062a58b867728f57d85Erik Kline        mLog.i("requesting mobile upstream network: " + mobileUpstreamRequest);
1829bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
183b583b03675492280ab87f1eff30c05709cafba23Erik Kline        cm().requestNetwork(mobileUpstreamRequest, mMobileNetworkCallback, 0, legacyType, mHandler);
1849bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    }
1859bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
1869bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    public void releaseMobileNetworkRequest() {
1879bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        if (mMobileNetworkCallback == null) return;
1889bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
1899bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        cm().unregisterNetworkCallback(mMobileNetworkCallback);
1909bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        mMobileNetworkCallback = null;
1919bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    }
1929bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
1933760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline    // So many TODOs here, but chief among them is: make this functionality an
1943760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline    // integral part of this class such that whenever a higher priority network
1953760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline    // becomes available and useful we (a) file a request to keep it up as
1963760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline    // necessary and (b) change all upstream tracking state accordingly (by
1973760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline    // passing LinkProperties up to Tethering).
1983760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline    //
1993760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline    // Next TODO: return NetworkState instead of just the type.
2001e2897dcff865cc0f00079f2a3c7d5188811544fErik Kline    public NetworkState selectPreferredUpstreamType(Iterable<Integer> preferredTypes) {
2013760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline        final TypeStatePair typeStatePair = findFirstAvailableUpstreamByType(
2023760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline                mNetworkMap.values(), preferredTypes);
2033760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline
2043760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline        mLog.log("preferred upstream type: " + getNetworkTypeName(typeStatePair.type));
2053760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline
2063760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline        switch (typeStatePair.type) {
2073760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline            case TYPE_MOBILE_DUN:
2083760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline            case TYPE_MOBILE_HIPRI:
2093760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline                // If we're on DUN, put our own grab on it.
2103760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline                registerMobileNetworkRequest();
2113760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline                break;
2123760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline            case TYPE_NONE:
2133760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline                break;
2143760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline            default:
2153760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline                /* If we've found an active upstream connection that's not DUN/HIPRI
21660caf7d29132262dd4a077b68daa807d22773524Erik Kline                 * we should stop any outstanding DUN/HIPRI requests.
2173760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline                 *
2183760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline                 * If we found NONE we don't want to do this as we want any previous
2193760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline                 * requests to keep trying to bring up something we can use.
2203760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline                 */
2213760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline                releaseMobileNetworkRequest();
2223760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline                break;
2233760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline        }
2243760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline
2251e2897dcff865cc0f00079f2a3c7d5188811544fErik Kline        return typeStatePair.ns;
2263760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline    }
2273760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline
22860caf7d29132262dd4a077b68daa807d22773524Erik Kline    public void setCurrentUpstream(Network upstream) {
22960caf7d29132262dd4a077b68daa807d22773524Erik Kline        mTetheringUpstreamNetwork = upstream;
23060caf7d29132262dd4a077b68daa807d22773524Erik Kline    }
23160caf7d29132262dd4a077b68daa807d22773524Erik Kline
23232179ff81511e00aef31e8fda705be3df074ece6Erik Kline    public Set<IpPrefix> getLocalPrefixes() {
23332179ff81511e00aef31e8fda705be3df074ece6Erik Kline        return (Set<IpPrefix>) mLocalPrefixes.clone();
2343a5278f2c4d71a8f69ce1085da42904283d62785Erik Kline    }
2353a5278f2c4d71a8f69ce1085da42904283d62785Erik Kline
236d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline    private void handleAvailable(int callbackType, Network network) {
237d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        if (VDBG) Log.d(TAG, "EVENT_ON_AVAILABLE for " + network);
238d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline
2399bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        if (!mNetworkMap.containsKey(network)) {
2409bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline            mNetworkMap.put(network,
2419bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline                    new NetworkState(null, null, null, network, null, null));
2429bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        }
2439bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
244d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        // Always request whatever extra information we can, in case this
245d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        // was already up when start() was called, in which case we would
246d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        // not have been notified of any information that had not changed.
24735bf06c968ecbae502efd9cfb13fff9b7ddf9d6aErik Kline        switch (callbackType) {
24835bf06c968ecbae502efd9cfb13fff9b7ddf9d6aErik Kline            case CALLBACK_LISTEN_ALL:
24935bf06c968ecbae502efd9cfb13fff9b7ddf9d6aErik Kline                break;
250465c46d555c867caf40333db197ef97cff75a754Erik Kline
25135bf06c968ecbae502efd9cfb13fff9b7ddf9d6aErik Kline            case CALLBACK_TRACK_DEFAULT:
25232858e14caa09fbb3eb4081f114f2a99181c9643Erik Kline                if (mDefaultNetworkCallback == null) {
25332858e14caa09fbb3eb4081f114f2a99181c9643Erik Kline                    // The callback was unregistered in the interval between
254b583b03675492280ab87f1eff30c05709cafba23Erik Kline                    // ConnectivityService enqueueing onAvailable() and our
255b583b03675492280ab87f1eff30c05709cafba23Erik Kline                    // handling of it here on the mHandler thread.
256b583b03675492280ab87f1eff30c05709cafba23Erik Kline                    //
25732858e14caa09fbb3eb4081f114f2a99181c9643Erik Kline                    // Clean-up of this network entry is deferred to the
25832858e14caa09fbb3eb4081f114f2a99181c9643Erik Kline                    // handling of onLost() by other callbacks.
259b583b03675492280ab87f1eff30c05709cafba23Erik Kline                    //
260b583b03675492280ab87f1eff30c05709cafba23Erik Kline                    // These request*() calls can be deleted post oag/339444.
26132858e14caa09fbb3eb4081f114f2a99181c9643Erik Kline                    return;
26232858e14caa09fbb3eb4081f114f2a99181c9643Erik Kline                }
26360caf7d29132262dd4a077b68daa807d22773524Erik Kline                mDefaultInternetNetwork = network;
26435bf06c968ecbae502efd9cfb13fff9b7ddf9d6aErik Kline                break;
265465c46d555c867caf40333db197ef97cff75a754Erik Kline
26635bf06c968ecbae502efd9cfb13fff9b7ddf9d6aErik Kline            case CALLBACK_MOBILE_REQUEST:
26732858e14caa09fbb3eb4081f114f2a99181c9643Erik Kline                if (mMobileNetworkCallback == null) {
26832858e14caa09fbb3eb4081f114f2a99181c9643Erik Kline                    // The callback was unregistered in the interval between
269b583b03675492280ab87f1eff30c05709cafba23Erik Kline                    // ConnectivityService enqueueing onAvailable() and our
270b583b03675492280ab87f1eff30c05709cafba23Erik Kline                    // handling of it here on the mHandler thread.
271b583b03675492280ab87f1eff30c05709cafba23Erik Kline                    //
27232858e14caa09fbb3eb4081f114f2a99181c9643Erik Kline                    // Clean-up of this network entry is deferred to the
27332858e14caa09fbb3eb4081f114f2a99181c9643Erik Kline                    // handling of onLost() by other callbacks.
27432858e14caa09fbb3eb4081f114f2a99181c9643Erik Kline                    return;
27532858e14caa09fbb3eb4081f114f2a99181c9643Erik Kline                }
27635bf06c968ecbae502efd9cfb13fff9b7ddf9d6aErik Kline                break;
277d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        }
2789bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
279d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        // Requesting updates for mListenAllCallback is not currently possible
280d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        // because it's a "listen". Two possible solutions to getting updates
281d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        // about networks without waiting for a change (which might never come)
282d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        // are:
283d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        //
284d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        //     [1] extend request{NetworkCapabilities,LinkProperties}() to
285d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        //         take a Network argument and have ConnectivityService do
286d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        //         what's required (if the network satisfies the request)
287d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        //
288d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        //     [2] explicitly file a NetworkRequest for each connectivity type
289d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        //         listed as a preferred upstream and wait for these callbacks
290d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        //         to be notified (requires tracking many more callbacks).
291d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        //
292d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        // Until this is addressed, networks that exist prior to the "listen"
293d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        // registration and which do not subsequently change will not cause
294d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        // us to learn their NetworkCapabilities nor their LinkProperties.
295d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline
296d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        // TODO: If sufficient information is available to select a more
297d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        // preferable upstream, do so now and notify the target.
2989bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        notifyTarget(EVENT_ON_AVAILABLE, network);
2999bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    }
3009bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
3019bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    private void handleNetCap(Network network, NetworkCapabilities newNc) {
302d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        final NetworkState prev = mNetworkMap.get(network);
303d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        if (prev == null || newNc.equals(prev.networkCapabilities)) {
304d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline            // Ignore notifications about networks for which we have not yet
305d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline            // received onAvailable() (should never happen) and any duplicate
306d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline            // notifications (e.g. matching more than one of our callbacks).
3079bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline            return;
3089bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        }
309d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline
3109bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        if (VDBG) {
3119bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline            Log.d(TAG, String.format("EVENT_ON_CAPABILITIES for %s: %s",
3129bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline                    network, newNc));
3139bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        }
3149bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
31560caf7d29132262dd4a077b68daa807d22773524Erik Kline        // Log changes in upstream network signal strength, if available.
31660caf7d29132262dd4a077b68daa807d22773524Erik Kline        if (network.equals(mTetheringUpstreamNetwork) && newNc.hasSignalStrength()) {
31760caf7d29132262dd4a077b68daa807d22773524Erik Kline            final int newSignal = newNc.getSignalStrength();
31860caf7d29132262dd4a077b68daa807d22773524Erik Kline            final String prevSignal = getSignalStrength(prev.networkCapabilities);
31960caf7d29132262dd4a077b68daa807d22773524Erik Kline            mLog.logf("upstream network signal strength: %s -> %s", prevSignal, newSignal);
32060caf7d29132262dd4a077b68daa807d22773524Erik Kline        }
32160caf7d29132262dd4a077b68daa807d22773524Erik Kline
322d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        mNetworkMap.put(network, new NetworkState(
323d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline                null, prev.linkProperties, newNc, network, null, null));
324d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        // TODO: If sufficient information is available to select a more
325d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        // preferable upstream, do so now and notify the target.
3269bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        notifyTarget(EVENT_ON_CAPABILITIES, network);
3279bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    }
3289bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
3299bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    private void handleLinkProp(Network network, LinkProperties newLp) {
330d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        final NetworkState prev = mNetworkMap.get(network);
331d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        if (prev == null || newLp.equals(prev.linkProperties)) {
332d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline            // Ignore notifications about networks for which we have not yet
333d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline            // received onAvailable() (should never happen) and any duplicate
334d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline            // notifications (e.g. matching more than one of our callbacks).
3359bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline            return;
3369bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        }
337d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline
3389bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        if (VDBG) {
3399bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline            Log.d(TAG, String.format("EVENT_ON_LINKPROPERTIES for %s: %s",
3409bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline                    network, newLp));
3419bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        }
3429bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
343d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        mNetworkMap.put(network, new NetworkState(
344d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline                null, newLp, prev.networkCapabilities, network, null, null));
345d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        // TODO: If sufficient information is available to select a more
346d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        // preferable upstream, do so now and notify the target.
3479bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        notifyTarget(EVENT_ON_LINKPROPERTIES, network);
3489bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    }
3499bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
35060caf7d29132262dd4a077b68daa807d22773524Erik Kline    private void handleSuspended(int callbackType, Network network) {
35160caf7d29132262dd4a077b68daa807d22773524Erik Kline        if (callbackType != CALLBACK_LISTEN_ALL) return;
35260caf7d29132262dd4a077b68daa807d22773524Erik Kline        if (!network.equals(mTetheringUpstreamNetwork)) return;
35360caf7d29132262dd4a077b68daa807d22773524Erik Kline        mLog.log("SUSPENDED current upstream: " + network);
35460caf7d29132262dd4a077b68daa807d22773524Erik Kline    }
35560caf7d29132262dd4a077b68daa807d22773524Erik Kline
35660caf7d29132262dd4a077b68daa807d22773524Erik Kline    private void handleResumed(int callbackType, Network network) {
35760caf7d29132262dd4a077b68daa807d22773524Erik Kline        if (callbackType != CALLBACK_LISTEN_ALL) return;
35860caf7d29132262dd4a077b68daa807d22773524Erik Kline        if (!network.equals(mTetheringUpstreamNetwork)) return;
35960caf7d29132262dd4a077b68daa807d22773524Erik Kline        mLog.log("RESUMED current upstream: " + network);
36060caf7d29132262dd4a077b68daa807d22773524Erik Kline    }
36160caf7d29132262dd4a077b68daa807d22773524Erik Kline
362d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline    private void handleLost(int callbackType, Network network) {
36335bf06c968ecbae502efd9cfb13fff9b7ddf9d6aErik Kline        if (callbackType == CALLBACK_TRACK_DEFAULT) {
36460caf7d29132262dd4a077b68daa807d22773524Erik Kline            mDefaultInternetNetwork = null;
365d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline            // Receiving onLost() for a default network does not necessarily
366d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline            // mean the network is gone.  We wait for a separate notification
367d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline            // on either the LISTEN_ALL or MOBILE_REQUEST callbacks before
368d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline            // clearing all state.
3699bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline            return;
3709bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        }
371d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline
372d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        if (!mNetworkMap.containsKey(network)) {
373d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline            // Ignore loss of networks about which we had not previously
374d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline            // learned any information or for which we have already processed
375d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline            // an onLost() notification.
376d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline            return;
3779bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        }
378d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline
379d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        if (VDBG) Log.d(TAG, "EVENT_ON_LOST for " + network);
380d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline
381d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        // TODO: If sufficient information is available to select a more
382d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        // preferable upstream, do so now and notify the target.  Likewise,
383d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        // if the current upstream network is gone, notify the target of the
384d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        // fact that we now have no upstream at all.
3859bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        notifyTarget(EVENT_ON_LOST, mNetworkMap.remove(network));
3869bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    }
3879bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
38832179ff81511e00aef31e8fda705be3df074ece6Erik Kline    private void recomputeLocalPrefixes() {
38932179ff81511e00aef31e8fda705be3df074ece6Erik Kline        final HashSet<IpPrefix> localPrefixes = allLocalPrefixes(mNetworkMap.values());
39032179ff81511e00aef31e8fda705be3df074ece6Erik Kline        if (!mLocalPrefixes.equals(localPrefixes)) {
39132179ff81511e00aef31e8fda705be3df074ece6Erik Kline            mLocalPrefixes = localPrefixes;
39232179ff81511e00aef31e8fda705be3df074ece6Erik Kline            notifyTarget(NOTIFY_LOCAL_PREFIXES, localPrefixes.clone());
3933a5278f2c4d71a8f69ce1085da42904283d62785Erik Kline        }
3943a5278f2c4d71a8f69ce1085da42904283d62785Erik Kline    }
3953a5278f2c4d71a8f69ce1085da42904283d62785Erik Kline
3969bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    // Fetch (and cache) a ConnectivityManager only if and when we need one.
3979bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    private ConnectivityManager cm() {
3989bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        if (mCM == null) {
399ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline            // MUST call the String variant to be able to write unittests.
400ea9cc488eb0f096c9fd402eff49e3d30f5b6de2eErik Kline            mCM = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
4019bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        }
4029bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        return mCM;
4039bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    }
4049bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
4059bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    /**
406b583b03675492280ab87f1eff30c05709cafba23Erik Kline     * A NetworkCallback class that handles information of interest directly
407b583b03675492280ab87f1eff30c05709cafba23Erik Kline     * in the thread on which it is invoked. To avoid locking, this MUST be
408b583b03675492280ab87f1eff30c05709cafba23Erik Kline     * run on the same thread as the target state machine's handler.
4099bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline     */
4109bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    private class UpstreamNetworkCallback extends NetworkCallback {
411d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        private final int mCallbackType;
412d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline
413d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        UpstreamNetworkCallback(int callbackType) {
414d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline            mCallbackType = callbackType;
415d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline        }
416d2ec3919cb87931b2c143d0c1b98caf37039d882Erik Kline
4179bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        @Override
4189bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        public void onAvailable(Network network) {
419b583b03675492280ab87f1eff30c05709cafba23Erik Kline            handleAvailable(mCallbackType, network);
4209bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        }
4219bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
4229bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        @Override
4239bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        public void onCapabilitiesChanged(Network network, NetworkCapabilities newNc) {
424b583b03675492280ab87f1eff30c05709cafba23Erik Kline            handleNetCap(network, newNc);
4259bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        }
4269bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
4279bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        @Override
4289bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        public void onLinkPropertiesChanged(Network network, LinkProperties newLp) {
429b583b03675492280ab87f1eff30c05709cafba23Erik Kline            handleLinkProp(network, newLp);
43032179ff81511e00aef31e8fda705be3df074ece6Erik Kline            recomputeLocalPrefixes();
4319bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        }
4329bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
43360caf7d29132262dd4a077b68daa807d22773524Erik Kline        @Override
43460caf7d29132262dd4a077b68daa807d22773524Erik Kline        public void onNetworkSuspended(Network network) {
43560caf7d29132262dd4a077b68daa807d22773524Erik Kline            handleSuspended(mCallbackType, network);
43660caf7d29132262dd4a077b68daa807d22773524Erik Kline        }
43760caf7d29132262dd4a077b68daa807d22773524Erik Kline
43860caf7d29132262dd4a077b68daa807d22773524Erik Kline        @Override
43960caf7d29132262dd4a077b68daa807d22773524Erik Kline        public void onNetworkResumed(Network network) {
44060caf7d29132262dd4a077b68daa807d22773524Erik Kline            handleResumed(mCallbackType, network);
44160caf7d29132262dd4a077b68daa807d22773524Erik Kline        }
442b583b03675492280ab87f1eff30c05709cafba23Erik Kline
4439bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        @Override
4449bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        public void onLost(Network network) {
445b583b03675492280ab87f1eff30c05709cafba23Erik Kline            handleLost(mCallbackType, network);
44632179ff81511e00aef31e8fda705be3df074ece6Erik Kline            recomputeLocalPrefixes();
447b583b03675492280ab87f1eff30c05709cafba23Erik Kline        }
4489bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    }
4499bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
4509bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    private void releaseCallback(NetworkCallback cb) {
4519bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        if (cb != null) cm().unregisterNetworkCallback(cb);
4529bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    }
4539bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
4549bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    private void notifyTarget(int which, Network network) {
4559bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline        notifyTarget(which, mNetworkMap.get(network));
4569bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    }
4579bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline
4583a5278f2c4d71a8f69ce1085da42904283d62785Erik Kline    private void notifyTarget(int which, Object obj) {
4593a5278f2c4d71a8f69ce1085da42904283d62785Erik Kline        mTarget.sendMessage(mWhat, which, 0, obj);
4609bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline    }
4613760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline
4623a5278f2c4d71a8f69ce1085da42904283d62785Erik Kline    private static class TypeStatePair {
4633760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline        public int type = TYPE_NONE;
4643760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline        public NetworkState ns = null;
4653760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline    }
4663760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline
4673a5278f2c4d71a8f69ce1085da42904283d62785Erik Kline    private static TypeStatePair findFirstAvailableUpstreamByType(
4683760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline            Iterable<NetworkState> netStates, Iterable<Integer> preferredTypes) {
4693760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline        final TypeStatePair result = new TypeStatePair();
4703760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline
4713760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline        for (int type : preferredTypes) {
4723760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline            NetworkCapabilities nc;
4733760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline            try {
4743760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline                nc = ConnectivityManager.networkCapabilitiesForType(type);
4753760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline            } catch (IllegalArgumentException iae) {
4763760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline                Log.e(TAG, "No NetworkCapabilities mapping for legacy type: " +
4773760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline                       ConnectivityManager.getNetworkTypeName(type));
4783760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline                continue;
4793760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline            }
480f94833df7dbead3ebce2efeeae2b57fa0613c743Erik Kline            nc.setSingleUid(Process.myUid());
4813760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline
4823760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline            for (NetworkState value : netStates) {
4833760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline                if (!nc.satisfiedByNetworkCapabilities(value.networkCapabilities)) {
4843760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline                    continue;
4853760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline                }
4863760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline
4873760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline                result.type = type;
4883760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline                result.ns = value;
4893760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline                return result;
4903760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline            }
4913760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline        }
4923760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline
4933760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline        return result;
4943760999e347ae1cfa25087451638de8ddc79c9f6Erik Kline    }
4953a5278f2c4d71a8f69ce1085da42904283d62785Erik Kline
49632179ff81511e00aef31e8fda705be3df074ece6Erik Kline    private static HashSet<IpPrefix> allLocalPrefixes(Iterable<NetworkState> netStates) {
4973a5278f2c4d71a8f69ce1085da42904283d62785Erik Kline        final HashSet<IpPrefix> prefixSet = new HashSet<>();
4983a5278f2c4d71a8f69ce1085da42904283d62785Erik Kline
4993a5278f2c4d71a8f69ce1085da42904283d62785Erik Kline        for (NetworkState ns : netStates) {
50032179ff81511e00aef31e8fda705be3df074ece6Erik Kline            final LinkProperties lp = ns.linkProperties;
50132179ff81511e00aef31e8fda705be3df074ece6Erik Kline            if (lp == null) continue;
50232179ff81511e00aef31e8fda705be3df074ece6Erik Kline            prefixSet.addAll(PrefixUtils.localPrefixesFrom(lp));
5033a5278f2c4d71a8f69ce1085da42904283d62785Erik Kline        }
5043a5278f2c4d71a8f69ce1085da42904283d62785Erik Kline
5053a5278f2c4d71a8f69ce1085da42904283d62785Erik Kline        return prefixSet;
5063a5278f2c4d71a8f69ce1085da42904283d62785Erik Kline    }
50760caf7d29132262dd4a077b68daa807d22773524Erik Kline
50860caf7d29132262dd4a077b68daa807d22773524Erik Kline    private static String getSignalStrength(NetworkCapabilities nc) {
50960caf7d29132262dd4a077b68daa807d22773524Erik Kline        if (nc == null || !nc.hasSignalStrength()) return "unknown";
51060caf7d29132262dd4a077b68daa807d22773524Erik Kline        return Integer.toString(nc.getSignalStrength());
51160caf7d29132262dd4a077b68daa807d22773524Erik Kline    }
5129bba340fd4edd5aea91d612a332f964b0d63cf34Erik Kline}
513