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 
NetworkFactory(Looper looper, Context context, String logTag, NetworkCapabilities filter)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 
register()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 
unregister()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
handleMessage(Message msg)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 
NetworkRequestInfo(NetworkRequest request, int score)160         public NetworkRequestInfo(NetworkRequest request, int score) {
161             this.request = request;
162             this.score = score;
163             this.requested = false;
164         }
165 
166         @Override
toString()167         public String toString() {
168             return "{" + request + ", score=" + score + ", requested=" + requested + "}";
169         }
170     }
171 
172     @VisibleForTesting
handleAddRequest(NetworkRequest request, int score)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
handleRemoveRequest(NetworkRequest request)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 
handleSetScore(int score)197     private void handleSetScore(int score) {
198         mScore = score;
199         evalRequests();
200     }
201 
handleSetFilter(NetworkCapabilities netCap)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      */
acceptRequest(NetworkRequest request, int score)226     public boolean acceptRequest(NetworkRequest request, int score) {
227         return true;
228     }
229 
evalRequest(NetworkRequestInfo n)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 
evalRequests()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      */
reevaluateAllRequests()261     protected void reevaluateAllRequests() {
262         post(() -> {
263             evalRequests();
264         });
265     }
266 
267     // override to do simple mode (request independent)
startNetwork()268     protected void startNetwork() { }
stopNetwork()269     protected void stopNetwork() { }
270 
271     // override to do fancier stuff
needNetworkFor(NetworkRequest networkRequest, int score)272     protected void needNetworkFor(NetworkRequest networkRequest, int score) {
273         if (++mRefCount == 1) startNetwork();
274     }
275 
releaseNetworkFor(NetworkRequest networkRequest)276     protected void releaseNetworkFor(NetworkRequest networkRequest) {
277         if (--mRefCount == 0) stopNetwork();
278     }
279 
280 
addNetworkRequest(NetworkRequest networkRequest, int score)281     public void addNetworkRequest(NetworkRequest networkRequest, int score) {
282         sendMessage(obtainMessage(CMD_REQUEST_NETWORK,
283                 new NetworkRequestInfo(networkRequest, score)));
284     }
285 
removeNetworkRequest(NetworkRequest networkRequest)286     public void removeNetworkRequest(NetworkRequest networkRequest) {
287         sendMessage(obtainMessage(CMD_CANCEL_REQUEST, networkRequest));
288     }
289 
setScoreFilter(int score)290     public void setScoreFilter(int score) {
291         sendMessage(obtainMessage(CMD_SET_SCORE, score, 0));
292     }
293 
setCapabilityFilter(NetworkCapabilities netCap)294     public void setCapabilityFilter(NetworkCapabilities netCap) {
295         sendMessage(obtainMessage(CMD_SET_FILTER, new NetworkCapabilities(netCap)));
296     }
297 
298     @VisibleForTesting
getRequestCount()299     protected int getRequestCount() {
300         return mNetworkRequests.size();
301     }
302 
log(String s)303     protected void log(String s) {
304         Log.d(LOG_TAG, s);
305     }
306 
dump(FileDescriptor fd, PrintWriter writer, String[] args)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
toString()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