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.os.Handler;
     21 import android.os.Looper;
     22 import android.os.Message;
     23 import android.os.Messenger;
     24 import android.util.Log;
     25 import android.util.SparseArray;
     26 
     27 import com.android.internal.annotations.VisibleForTesting;
     28 import com.android.internal.util.IndentingPrintWriter;
     29 import com.android.internal.util.Protocol;
     30 
     31 import java.io.FileDescriptor;
     32 import java.io.PrintWriter;
     33 
     34 /**
     35  * A NetworkFactory is an entity that creates NetworkAgent objects.
     36  * The bearers register with ConnectivityService using {@link #register} and
     37  * their factory will start receiving scored NetworkRequests.  NetworkRequests
     38  * can be filtered 3 ways: by NetworkCapabilities, by score and more complexly by
     39  * overridden function.  All of these can be dynamic - changing NetworkCapabilities
     40  * or score forces re-evaluation of all current requests.
     41  *
     42  * If any requests pass the filter some overrideable functions will be called.
     43  * If the bearer only cares about very simple start/stopNetwork callbacks, those
     44  * functions can be overridden.  If the bearer needs more interaction, it can
     45  * override addNetworkRequest and removeNetworkRequest which will give it each
     46  * request that passes their current filters.
     47  * @hide
     48  **/
     49 public class NetworkFactory extends Handler {
     50     private static final boolean DBG = true;
     51     private static final boolean VDBG = false;
     52 
     53     private static final int BASE = Protocol.BASE_NETWORK_FACTORY;
     54     /**
     55      * Pass a network request to the bearer.  If the bearer believes it can
     56      * satisfy the request it should connect to the network and create a
     57      * NetworkAgent.  Once the NetworkAgent is fully functional it will
     58      * register itself with ConnectivityService using registerNetworkAgent.
     59      * If the bearer cannot immediately satisfy the request (no network,
     60      * user disabled the radio, lower-scored network) it should remember
     61      * any NetworkRequests it may be able to satisfy in the future.  It may
     62      * disregard any that it will never be able to service, for example
     63      * those requiring a different bearer.
     64      * msg.obj = NetworkRequest
     65      * msg.arg1 = score - the score of the any network currently satisfying this
     66      *            request.  If this bearer knows in advance it cannot
     67      *            exceed this score it should not try to connect, holding the request
     68      *            for the future.
     69      *            Note that subsequent events may give a different (lower
     70      *            or higher) score for this request, transmitted to each
     71      *            NetworkFactory through additional CMD_REQUEST_NETWORK msgs
     72      *            with the same NetworkRequest but an updated score.
     73      *            Also, network conditions may change for this bearer
     74      *            allowing for a better score in the future.
     75      */
     76     public static final int CMD_REQUEST_NETWORK = BASE;
     77 
     78     /**
     79      * Cancel a network request
     80      * msg.obj = NetworkRequest
     81      */
     82     public static final int CMD_CANCEL_REQUEST = BASE + 1;
     83 
     84     /**
     85      * Internally used to set our best-guess score.
     86      * msg.arg1 = new score
     87      */
     88     private static final int CMD_SET_SCORE = BASE + 2;
     89 
     90     /**
     91      * Internally used to set our current filter for coarse bandwidth changes with
     92      * technology changes.
     93      * msg.obj = new filter
     94      */
     95     private static final int CMD_SET_FILTER = BASE + 3;
     96 
     97     private final Context mContext;
     98     private final String LOG_TAG;
     99 
    100     private final SparseArray<NetworkRequestInfo> mNetworkRequests =
    101             new SparseArray<NetworkRequestInfo>();
    102 
    103     private int mScore;
    104     private NetworkCapabilities mCapabilityFilter;
    105 
    106     private int mRefCount = 0;
    107     private Messenger mMessenger = null;
    108 
    109     public NetworkFactory(Looper looper, Context context, String logTag,
    110             NetworkCapabilities filter) {
    111         super(looper);
    112         LOG_TAG = logTag;
    113         mContext = context;
    114         mCapabilityFilter = filter;
    115     }
    116 
    117     public void register() {
    118         if (DBG) log("Registering NetworkFactory");
    119         if (mMessenger == null) {
    120             mMessenger = new Messenger(this);
    121             ConnectivityManager.from(mContext).registerNetworkFactory(mMessenger, LOG_TAG);
    122         }
    123     }
    124 
    125     public void unregister() {
    126         if (DBG) log("Unregistering NetworkFactory");
    127         if (mMessenger != null) {
    128             ConnectivityManager.from(mContext).unregisterNetworkFactory(mMessenger);
    129             mMessenger = null;
    130         }
    131     }
    132 
    133     @Override
    134     public void handleMessage(Message msg) {
    135         switch (msg.what) {
    136             case CMD_REQUEST_NETWORK: {
    137                 handleAddRequest((NetworkRequest)msg.obj, msg.arg1);
    138                 break;
    139             }
    140             case CMD_CANCEL_REQUEST: {
    141                 handleRemoveRequest((NetworkRequest) msg.obj);
    142                 break;
    143             }
    144             case CMD_SET_SCORE: {
    145                 handleSetScore(msg.arg1);
    146                 break;
    147             }
    148             case CMD_SET_FILTER: {
    149                 handleSetFilter((NetworkCapabilities) msg.obj);
    150                 break;
    151             }
    152         }
    153     }
    154 
    155     private class NetworkRequestInfo {
    156         public final NetworkRequest request;
    157         public int score;
    158         public boolean requested; // do we have a request outstanding, limited by score
    159 
    160         public NetworkRequestInfo(NetworkRequest request, int score) {
    161             this.request = request;
    162             this.score = score;
    163             this.requested = false;
    164         }
    165 
    166         @Override
    167         public String toString() {
    168             return "{" + request + ", score=" + score + ", requested=" + requested + "}";
    169         }
    170     }
    171 
    172     @VisibleForTesting
    173     protected void handleAddRequest(NetworkRequest request, int score) {
    174         NetworkRequestInfo n = mNetworkRequests.get(request.requestId);
    175         if (n == null) {
    176             if (DBG) log("got request " + request + " with score " + score);
    177             n = new NetworkRequestInfo(request, score);
    178             mNetworkRequests.put(n.request.requestId, n);
    179         } else {
    180             if (VDBG) log("new score " + score + " for exisiting request " + request);
    181             n.score = score;
    182         }
    183         if (VDBG) log("  my score=" + mScore + ", my filter=" + mCapabilityFilter);
    184 
    185         evalRequest(n);
    186     }
    187 
    188     @VisibleForTesting
    189     protected void handleRemoveRequest(NetworkRequest request) {
    190         NetworkRequestInfo n = mNetworkRequests.get(request.requestId);
    191         if (n != null) {
    192             mNetworkRequests.remove(request.requestId);
    193             if (n.requested) releaseNetworkFor(n.request);
    194         }
    195     }
    196 
    197     private void handleSetScore(int score) {
    198         mScore = score;
    199         evalRequests();
    200     }
    201 
    202     private void handleSetFilter(NetworkCapabilities netCap) {
    203         mCapabilityFilter = netCap;
    204         evalRequests();
    205     }
    206 
    207     /**
    208      * Overridable function to provide complex filtering.
    209      * Called for every request every time a new NetworkRequest is seen
    210      * and whenever the filterScore or filterNetworkCapabilities change.
    211      *
    212      * acceptRequest can be overriden to provide complex filter behavior
    213      * for the incoming requests
    214      *
    215      * For output, this class will call {@link #needNetworkFor} and
    216      * {@link #releaseNetworkFor} for every request that passes the filters.
    217      * If you don't need to see every request, you can leave the base
    218      * implementations of those two functions and instead override
    219      * {@link #startNetwork} and {@link #stopNetwork}.
    220      *
    221      * If you want to see every score fluctuation on every request, set
    222      * your score filter to a very high number and watch {@link #needNetworkFor}.
    223      *
    224      * @return {@code true} to accept the request.
    225      */
    226     public boolean acceptRequest(NetworkRequest request, int score) {
    227         return true;
    228     }
    229 
    230     private void evalRequest(NetworkRequestInfo n) {
    231         if (VDBG) log("evalRequest");
    232         if (n.requested == false && n.score < mScore &&
    233                 n.request.networkCapabilities.satisfiedByNetworkCapabilities(
    234                 mCapabilityFilter) && acceptRequest(n.request, n.score)) {
    235             if (VDBG) log("  needNetworkFor");
    236             needNetworkFor(n.request, n.score);
    237             n.requested = true;
    238         } else if (n.requested == true &&
    239                 (n.score > mScore || n.request.networkCapabilities.satisfiedByNetworkCapabilities(
    240                 mCapabilityFilter) == false || acceptRequest(n.request, n.score) == false)) {
    241             if (VDBG) log("  releaseNetworkFor");
    242             releaseNetworkFor(n.request);
    243             n.requested = false;
    244         } else {
    245             if (VDBG) log("  done");
    246         }
    247     }
    248 
    249     private void evalRequests() {
    250         for (int i = 0; i < mNetworkRequests.size(); i++) {
    251             NetworkRequestInfo n = mNetworkRequests.valueAt(i);
    252 
    253             evalRequest(n);
    254         }
    255     }
    256 
    257     /**
    258      * Post a command, on this NetworkFactory Handler, to re-evaluate all
    259      * oustanding requests. Can be called from a factory implementation.
    260      */
    261     protected void reevaluateAllRequests() {
    262         post(() -> {
    263             evalRequests();
    264         });
    265     }
    266 
    267     // override to do simple mode (request independent)
    268     protected void startNetwork() { }
    269     protected void stopNetwork() { }
    270 
    271     // override to do fancier stuff
    272     protected void needNetworkFor(NetworkRequest networkRequest, int score) {
    273         if (++mRefCount == 1) startNetwork();
    274     }
    275 
    276     protected void releaseNetworkFor(NetworkRequest networkRequest) {
    277         if (--mRefCount == 0) stopNetwork();
    278     }
    279 
    280 
    281     public void addNetworkRequest(NetworkRequest networkRequest, int score) {
    282         sendMessage(obtainMessage(CMD_REQUEST_NETWORK,
    283                 new NetworkRequestInfo(networkRequest, score)));
    284     }
    285 
    286     public void removeNetworkRequest(NetworkRequest networkRequest) {
    287         sendMessage(obtainMessage(CMD_CANCEL_REQUEST, networkRequest));
    288     }
    289 
    290     public void setScoreFilter(int score) {
    291         sendMessage(obtainMessage(CMD_SET_SCORE, score, 0));
    292     }
    293 
    294     public void setCapabilityFilter(NetworkCapabilities netCap) {
    295         sendMessage(obtainMessage(CMD_SET_FILTER, new NetworkCapabilities(netCap)));
    296     }
    297 
    298     @VisibleForTesting
    299     protected int getRequestCount() {
    300         return mNetworkRequests.size();
    301     }
    302 
    303     protected void log(String s) {
    304         Log.d(LOG_TAG, s);
    305     }
    306 
    307     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
    308         final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
    309         pw.println(toString());
    310         pw.increaseIndent();
    311         for (int i = 0; i < mNetworkRequests.size(); i++) {
    312             pw.println(mNetworkRequests.valueAt(i));
    313         }
    314         pw.decreaseIndent();
    315     }
    316 
    317     @Override
    318     public String toString() {
    319         StringBuilder sb = new StringBuilder("{").append(LOG_TAG).append(" - ScoreFilter=").
    320                 append(mScore).append(", Filter=").append(mCapabilityFilter).append(", requests=").
    321                 append(mNetworkRequests.size()).append(", refCount=").append(mRefCount).
    322                 append("}");
    323         return sb.toString();
    324     }
    325 }
    326