Home | History | Annotate | Download | only in net
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.net;
     18 
     19 import android.content.Context;
     20 import android.net.ConnectivityManager.PacketKeepalive;
     21 import android.os.Bundle;
     22 import android.os.Handler;
     23 import android.os.Looper;
     24 import android.os.Message;
     25 import android.os.Messenger;
     26 import android.util.Log;
     27 
     28 import com.android.internal.util.AsyncChannel;
     29 import com.android.internal.util.Protocol;
     30 
     31 import java.util.ArrayList;
     32 import java.util.concurrent.atomic.AtomicBoolean;
     33 
     34 /**
     35  * A Utility class for handling for communicating between bearer-specific
     36  * code and ConnectivityService.
     37  *
     38  * A bearer may have more than one NetworkAgent if it can simultaneously
     39  * support separate networks (IMS / Internet / MMS Apns on cellular, or
     40  * perhaps connections with different SSID or P2P for Wi-Fi).
     41  *
     42  * @hide
     43  */
     44 public abstract class NetworkAgent extends Handler {
     45     // Guaranteed to be valid (not NETID_UNSET), otherwise registerNetworkAgent() would have thrown
     46     // an exception.
     47     public final int netId;
     48 
     49     private volatile AsyncChannel mAsyncChannel;
     50     private final String LOG_TAG;
     51     private static final boolean DBG = true;
     52     private static final boolean VDBG = false;
     53     private final Context mContext;
     54     private final ArrayList<Message>mPreConnectedQueue = new ArrayList<Message>();
     55     private volatile long mLastBwRefreshTime = 0;
     56     private static final long BW_REFRESH_MIN_WIN_MS = 500;
     57     private boolean mPollLceScheduled = false;
     58     private AtomicBoolean mPollLcePending = new AtomicBoolean(false);
     59 
     60     private static final int BASE = Protocol.BASE_NETWORK_AGENT;
     61 
     62     /**
     63      * Sent by ConnectivityService to the NetworkAgent to inform it of
     64      * suspected connectivity problems on its network.  The NetworkAgent
     65      * should take steps to verify and correct connectivity.
     66      */
     67     public static final int CMD_SUSPECT_BAD = BASE;
     68 
     69     /**
     70      * Sent by the NetworkAgent (note the EVENT vs CMD prefix) to
     71      * ConnectivityService to pass the current NetworkInfo (connection state).
     72      * Sent when the NetworkInfo changes, mainly due to change of state.
     73      * obj = NetworkInfo
     74      */
     75     public static final int EVENT_NETWORK_INFO_CHANGED = BASE + 1;
     76 
     77     /**
     78      * Sent by the NetworkAgent to ConnectivityService to pass the current
     79      * NetworkCapabilties.
     80      * obj = NetworkCapabilities
     81      */
     82     public static final int EVENT_NETWORK_CAPABILITIES_CHANGED = BASE + 2;
     83 
     84     /**
     85      * Sent by the NetworkAgent to ConnectivityService to pass the current
     86      * NetworkProperties.
     87      * obj = NetworkProperties
     88      */
     89     public static final int EVENT_NETWORK_PROPERTIES_CHANGED = BASE + 3;
     90 
     91     /* centralize place where base network score, and network score scaling, will be
     92      * stored, so as we can consistently compare apple and oranges, or wifi, ethernet and LTE
     93      */
     94     public static final int WIFI_BASE_SCORE = 60;
     95 
     96     /**
     97      * Sent by the NetworkAgent to ConnectivityService to pass the current
     98      * network score.
     99      * obj = network score Integer
    100      */
    101     public static final int EVENT_NETWORK_SCORE_CHANGED = BASE + 4;
    102 
    103     /**
    104      * Sent by ConnectivityService to the NetworkAgent to inform the agent of the
    105      * networks status - whether we could use the network or could not, due to
    106      * either a bad network configuration (no internet link) or captive portal.
    107      *
    108      * arg1 = either {@code VALID_NETWORK} or {@code INVALID_NETWORK}
    109      * obj = Bundle containing map from {@code REDIRECT_URL_KEY} to {@code String}
    110      *       representing URL that Internet probe was redirect to, if it was redirected,
    111      *       or mapping to {@code null} otherwise.
    112      */
    113     public static final int CMD_REPORT_NETWORK_STATUS = BASE + 7;
    114 
    115     public static final int VALID_NETWORK = 1;
    116     public static final int INVALID_NETWORK = 2;
    117 
    118     public static String REDIRECT_URL_KEY = "redirect URL";
    119 
    120      /**
    121      * Sent by the NetworkAgent to ConnectivityService to indicate this network was
    122      * explicitly selected.  This should be sent before the NetworkInfo is marked
    123      * CONNECTED so it can be given special treatment at that time.
    124      *
    125      * obj = boolean indicating whether to use this network even if unvalidated
    126      */
    127     public static final int EVENT_SET_EXPLICITLY_SELECTED = BASE + 8;
    128 
    129     /**
    130      * Sent by ConnectivityService to the NetworkAgent to inform the agent of
    131      * whether the network should in the future be used even if not validated.
    132      * This decision is made by the user, but it is the network transport's
    133      * responsibility to remember it.
    134      *
    135      * arg1 = 1 if true, 0 if false
    136      */
    137     public static final int CMD_SAVE_ACCEPT_UNVALIDATED = BASE + 9;
    138 
    139     /**
    140      * Sent by ConnectivityService to the NetworkAgent to inform the agent to pull
    141      * the underlying network connection for updated bandwidth information.
    142      */
    143     public static final int CMD_REQUEST_BANDWIDTH_UPDATE = BASE + 10;
    144 
    145     /**
    146      * Sent by ConnectivityService to the NetworkAgent to request that the specified packet be sent
    147      * periodically on the given interval.
    148      *
    149      *   arg1 = the slot number of the keepalive to start
    150      *   arg2 = interval in seconds
    151      *   obj = KeepalivePacketData object describing the data to be sent
    152      *
    153      * Also used internally by ConnectivityService / KeepaliveTracker, with different semantics.
    154      */
    155     public static final int CMD_START_PACKET_KEEPALIVE = BASE + 11;
    156 
    157     /**
    158      * Requests that the specified keepalive packet be stopped.
    159      *
    160      * arg1 = slot number of the keepalive to stop.
    161      *
    162      * Also used internally by ConnectivityService / KeepaliveTracker, with different semantics.
    163      */
    164     public static final int CMD_STOP_PACKET_KEEPALIVE = BASE + 12;
    165 
    166     /**
    167      * Sent by the NetworkAgent to ConnectivityService to provide status on a packet keepalive
    168      * request. This may either be the reply to a CMD_START_PACKET_KEEPALIVE, or an asynchronous
    169      * error notification.
    170      *
    171      * This is also sent by KeepaliveTracker to the app's ConnectivityManager.PacketKeepalive to
    172      * so that the app's PacketKeepaliveCallback methods can be called.
    173      *
    174      * arg1 = slot number of the keepalive
    175      * arg2 = error code
    176      */
    177     public static final int EVENT_PACKET_KEEPALIVE = BASE + 13;
    178 
    179     /**
    180      * Sent by ConnectivityService to inform this network transport of signal strength thresholds
    181      * that when crossed should trigger a system wakeup and a NetworkCapabilities update.
    182      *
    183      *   obj = int[] describing signal strength thresholds.
    184      */
    185     public static final int CMD_SET_SIGNAL_STRENGTH_THRESHOLDS = BASE + 14;
    186 
    187     /**
    188      * Sent by ConnectivityService to the NeworkAgent to inform the agent to avoid
    189      * automatically reconnecting to this network (e.g. via autojoin).  Happens
    190      * when user selects "No" option on the "Stay connected?" dialog box.
    191      */
    192     public static final int CMD_PREVENT_AUTOMATIC_RECONNECT = BASE + 15;
    193 
    194     public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
    195             NetworkCapabilities nc, LinkProperties lp, int score) {
    196         this(looper, context, logTag, ni, nc, lp, score, null);
    197     }
    198 
    199     public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
    200             NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {
    201         super(looper);
    202         LOG_TAG = logTag;
    203         mContext = context;
    204         if (ni == null || nc == null || lp == null) {
    205             throw new IllegalArgumentException();
    206         }
    207 
    208         if (VDBG) log("Registering NetworkAgent");
    209         ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
    210                 Context.CONNECTIVITY_SERVICE);
    211         netId = cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni),
    212                 new LinkProperties(lp), new NetworkCapabilities(nc), score, misc);
    213     }
    214 
    215     @Override
    216     public void handleMessage(Message msg) {
    217         switch (msg.what) {
    218             case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
    219                 if (mAsyncChannel != null) {
    220                     log("Received new connection while already connected!");
    221                 } else {
    222                     if (VDBG) log("NetworkAgent fully connected");
    223                     AsyncChannel ac = new AsyncChannel();
    224                     ac.connected(null, this, msg.replyTo);
    225                     ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
    226                             AsyncChannel.STATUS_SUCCESSFUL);
    227                     synchronized (mPreConnectedQueue) {
    228                         mAsyncChannel = ac;
    229                         for (Message m : mPreConnectedQueue) {
    230                             ac.sendMessage(m);
    231                         }
    232                         mPreConnectedQueue.clear();
    233                     }
    234                 }
    235                 break;
    236             }
    237             case AsyncChannel.CMD_CHANNEL_DISCONNECT: {
    238                 if (VDBG) log("CMD_CHANNEL_DISCONNECT");
    239                 if (mAsyncChannel != null) mAsyncChannel.disconnect();
    240                 break;
    241             }
    242             case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
    243                 if (DBG) log("NetworkAgent channel lost");
    244                 // let the client know CS is done with us.
    245                 unwanted();
    246                 synchronized (mPreConnectedQueue) {
    247                     mAsyncChannel = null;
    248                 }
    249                 break;
    250             }
    251             case CMD_SUSPECT_BAD: {
    252                 log("Unhandled Message " + msg);
    253                 break;
    254             }
    255             case CMD_REQUEST_BANDWIDTH_UPDATE: {
    256                 long currentTimeMs = System.currentTimeMillis();
    257                 if (VDBG) {
    258                     log("CMD_REQUEST_BANDWIDTH_UPDATE request received.");
    259                 }
    260                 if (currentTimeMs >= (mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS)) {
    261                     mPollLceScheduled = false;
    262                     if (mPollLcePending.getAndSet(true) == false) {
    263                         pollLceData();
    264                     }
    265                 } else {
    266                     // deliver the request at a later time rather than discard it completely.
    267                     if (!mPollLceScheduled) {
    268                         long waitTime = mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS -
    269                                 currentTimeMs + 1;
    270                         mPollLceScheduled = sendEmptyMessageDelayed(
    271                                 CMD_REQUEST_BANDWIDTH_UPDATE, waitTime);
    272                     }
    273                 }
    274                 break;
    275             }
    276             case CMD_REPORT_NETWORK_STATUS: {
    277                 String redirectUrl = ((Bundle)msg.obj).getString(REDIRECT_URL_KEY);
    278                 if (VDBG) {
    279                     log("CMD_REPORT_NETWORK_STATUS(" +
    280                             (msg.arg1 == VALID_NETWORK ? "VALID, " : "INVALID, ") + redirectUrl);
    281                 }
    282                 networkStatus(msg.arg1, redirectUrl);
    283                 break;
    284             }
    285             case CMD_SAVE_ACCEPT_UNVALIDATED: {
    286                 saveAcceptUnvalidated(msg.arg1 != 0);
    287                 break;
    288             }
    289             case CMD_START_PACKET_KEEPALIVE: {
    290                 startPacketKeepalive(msg);
    291                 break;
    292             }
    293             case CMD_STOP_PACKET_KEEPALIVE: {
    294                 stopPacketKeepalive(msg);
    295                 break;
    296             }
    297 
    298             case CMD_SET_SIGNAL_STRENGTH_THRESHOLDS: {
    299                 ArrayList<Integer> thresholds =
    300                         ((Bundle) msg.obj).getIntegerArrayList("thresholds");
    301                 // TODO: Change signal strength thresholds API to use an ArrayList<Integer>
    302                 // rather than convert to int[].
    303                 int[] intThresholds = new int[(thresholds != null) ? thresholds.size() : 0];
    304                 for (int i = 0; i < intThresholds.length; i++) {
    305                     intThresholds[i] = thresholds.get(i);
    306                 }
    307                 setSignalStrengthThresholds(intThresholds);
    308                 break;
    309             }
    310             case CMD_PREVENT_AUTOMATIC_RECONNECT: {
    311                 preventAutomaticReconnect();
    312                 break;
    313             }
    314         }
    315     }
    316 
    317     private void queueOrSendMessage(int what, Object obj) {
    318         queueOrSendMessage(what, 0, 0, obj);
    319     }
    320 
    321     private void queueOrSendMessage(int what, int arg1, int arg2) {
    322         queueOrSendMessage(what, arg1, arg2, null);
    323     }
    324 
    325     private void queueOrSendMessage(int what, int arg1, int arg2, Object obj) {
    326         Message msg = Message.obtain();
    327         msg.what = what;
    328         msg.arg1 = arg1;
    329         msg.arg2 = arg2;
    330         msg.obj = obj;
    331         queueOrSendMessage(msg);
    332     }
    333 
    334     private void queueOrSendMessage(Message msg) {
    335         synchronized (mPreConnectedQueue) {
    336             if (mAsyncChannel != null) {
    337                 mAsyncChannel.sendMessage(msg);
    338             } else {
    339                 mPreConnectedQueue.add(msg);
    340             }
    341         }
    342     }
    343 
    344     /**
    345      * Called by the bearer code when it has new LinkProperties data.
    346      */
    347     public void sendLinkProperties(LinkProperties linkProperties) {
    348         queueOrSendMessage(EVENT_NETWORK_PROPERTIES_CHANGED, new LinkProperties(linkProperties));
    349     }
    350 
    351     /**
    352      * Called by the bearer code when it has new NetworkInfo data.
    353      */
    354     public void sendNetworkInfo(NetworkInfo networkInfo) {
    355         queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, new NetworkInfo(networkInfo));
    356     }
    357 
    358     /**
    359      * Called by the bearer code when it has new NetworkCapabilities data.
    360      */
    361     public void sendNetworkCapabilities(NetworkCapabilities networkCapabilities) {
    362         mPollLcePending.set(false);
    363         mLastBwRefreshTime = System.currentTimeMillis();
    364         queueOrSendMessage(EVENT_NETWORK_CAPABILITIES_CHANGED,
    365                 new NetworkCapabilities(networkCapabilities));
    366     }
    367 
    368     /**
    369      * Called by the bearer code when it has a new score for this network.
    370      */
    371     public void sendNetworkScore(int score) {
    372         if (score < 0) {
    373             throw new IllegalArgumentException("Score must be >= 0");
    374         }
    375         queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, new Integer(score));
    376     }
    377 
    378     /**
    379      * Called by the bearer to indicate this network was manually selected by the user.
    380      * This should be called before the NetworkInfo is marked CONNECTED so that this
    381      * Network can be given special treatment at that time. If {@code acceptUnvalidated} is
    382      * {@code true}, then the system will switch to this network. If it is {@code false} and the
    383      * network cannot be validated, the system will ask the user whether to switch to this network.
    384      * If the user confirms and selects "don't ask again", then the system will call
    385      * {@link #saveAcceptUnvalidated} to persist the user's choice. Thus, if the transport ever
    386      * calls this method with {@code acceptUnvalidated} set to {@code false}, it must also implement
    387      * {@link #saveAcceptUnvalidated} to respect the user's choice.
    388      */
    389     public void explicitlySelected(boolean acceptUnvalidated) {
    390         queueOrSendMessage(EVENT_SET_EXPLICITLY_SELECTED, acceptUnvalidated);
    391     }
    392 
    393     /**
    394      * Called when ConnectivityService has indicated they no longer want this network.
    395      * The parent factory should (previously) have received indication of the change
    396      * as well, either canceling NetworkRequests or altering their score such that this
    397      * network won't be immediately requested again.
    398      */
    399     abstract protected void unwanted();
    400 
    401     /**
    402      * Called when ConnectivityService request a bandwidth update. The parent factory
    403      * shall try to overwrite this method and produce a bandwidth update if capable.
    404      */
    405     protected void pollLceData() {
    406     }
    407 
    408     /**
    409      * Called when the system determines the usefulness of this network.
    410      *
    411      * Networks claiming internet connectivity will have their internet
    412      * connectivity verified.
    413      *
    414      * Currently there are two possible values:
    415      * {@code VALID_NETWORK} if the system is happy with the connection,
    416      * {@code INVALID_NETWORK} if the system is not happy.
    417      * TODO - add indications of captive portal-ness and related success/failure,
    418      * ie, CAPTIVE_SUCCESS_NETWORK, CAPTIVE_NETWORK for successful login and detection
    419      *
    420      * This may be called multiple times as the network status changes and may
    421      * generate false negatives if we lose ip connectivity before the link is torn down.
    422      *
    423      * @param status one of {@code VALID_NETWORK} or {@code INVALID_NETWORK}.
    424      * @param redirectUrl If the Internet probe was redirected, this is the destination it was
    425      *         redirected to, otherwise {@code null}.
    426      */
    427     protected void networkStatus(int status, String redirectUrl) {
    428     }
    429 
    430     /**
    431      * Called when the user asks to remember the choice to use this network even if unvalidated.
    432      * The transport is responsible for remembering the choice, and the next time the user connects
    433      * to the network, should explicitlySelected with {@code acceptUnvalidated} set to {@code true}.
    434      * This method will only be called if {@link #explicitlySelected} was called with
    435      * {@code acceptUnvalidated} set to {@code false}.
    436      */
    437     protected void saveAcceptUnvalidated(boolean accept) {
    438     }
    439 
    440     /**
    441      * Requests that the network hardware send the specified packet at the specified interval.
    442      */
    443     protected void startPacketKeepalive(Message msg) {
    444         onPacketKeepaliveEvent(msg.arg1, PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED);
    445     }
    446 
    447     /**
    448      * Requests that the network hardware send the specified packet at the specified interval.
    449      */
    450     protected void stopPacketKeepalive(Message msg) {
    451         onPacketKeepaliveEvent(msg.arg1, PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED);
    452     }
    453 
    454     /**
    455      * Called by the network when a packet keepalive event occurs.
    456      */
    457     public void onPacketKeepaliveEvent(int slot, int reason) {
    458         queueOrSendMessage(EVENT_PACKET_KEEPALIVE, slot, reason);
    459     }
    460 
    461     /**
    462      * Called by ConnectivityService to inform this network transport of signal strength thresholds
    463      * that when crossed should trigger a system wakeup and a NetworkCapabilities update.
    464      */
    465     protected void setSignalStrengthThresholds(int[] thresholds) {
    466     }
    467 
    468     /**
    469      * Called when the user asks to not stay connected to this network because it was found to not
    470      * provide Internet access.  Usually followed by call to {@code unwanted}.  The transport is
    471      * responsible for making sure the device does not automatically reconnect to the same network
    472      * after the {@code unwanted} call.
    473      */
    474     protected void preventAutomaticReconnect() {
    475     }
    476 
    477     protected void log(String s) {
    478         Log.d(LOG_TAG, "NetworkAgent: " + s);
    479     }
    480 }
    481