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.annotation.UnsupportedAppUsage;
20 import android.content.Context;
21 import android.os.Build;
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 import android.util.SparseArray;
28 
29 import com.android.internal.annotations.VisibleForTesting;
30 import com.android.internal.util.AsyncChannel;
31 import com.android.internal.util.IndentingPrintWriter;
32 import com.android.internal.util.Protocol;
33 
34 import java.io.FileDescriptor;
35 import java.io.PrintWriter;
36 import java.util.ArrayList;
37 import java.util.concurrent.atomic.AtomicInteger;
38 
39 /**
40  * A NetworkFactory is an entity that creates NetworkAgent objects.
41  * The bearers register with ConnectivityService using {@link #register} and
42  * their factory will start receiving scored NetworkRequests.  NetworkRequests
43  * can be filtered 3 ways: by NetworkCapabilities, by score and more complexly by
44  * overridden function.  All of these can be dynamic - changing NetworkCapabilities
45  * or score forces re-evaluation of all current requests.
46  *
47  * If any requests pass the filter some overrideable functions will be called.
48  * If the bearer only cares about very simple start/stopNetwork callbacks, those
49  * functions can be overridden.  If the bearer needs more interaction, it can
50  * override addNetworkRequest and removeNetworkRequest which will give it each
51  * request that passes their current filters.
52  * @hide
53  **/
54 public class NetworkFactory extends Handler {
55     /** @hide */
56     public static class SerialNumber {
57         // Guard used by no network factory.
58         public static final int NONE = -1;
59         // A hardcoded serial number for NetworkAgents representing VPNs. These agents are
60         // not created by any factory, so they use this constant for clarity instead of NONE.
61         public static final int VPN = -2;
62         private static final AtomicInteger sNetworkFactorySerialNumber = new AtomicInteger(1);
63         /** Returns a unique serial number for a factory. */
nextSerialNumber()64         public static final int nextSerialNumber() {
65             return sNetworkFactorySerialNumber.getAndIncrement();
66         }
67     }
68 
69     private static final boolean DBG = true;
70     private static final boolean VDBG = false;
71 
72     private static final int BASE = Protocol.BASE_NETWORK_FACTORY;
73     /**
74      * Pass a network request to the bearer.  If the bearer believes it can
75      * satisfy the request it should connect to the network and create a
76      * NetworkAgent.  Once the NetworkAgent is fully functional it will
77      * register itself with ConnectivityService using registerNetworkAgent.
78      * If the bearer cannot immediately satisfy the request (no network,
79      * user disabled the radio, lower-scored network) it should remember
80      * any NetworkRequests it may be able to satisfy in the future.  It may
81      * disregard any that it will never be able to service, for example
82      * those requiring a different bearer.
83      * msg.obj = NetworkRequest
84      * msg.arg1 = score - the score of the network currently satisfying this
85      *            request.  If this bearer knows in advance it cannot
86      *            exceed this score it should not try to connect, holding the request
87      *            for the future.
88      *            Note that subsequent events may give a different (lower
89      *            or higher) score for this request, transmitted to each
90      *            NetworkFactory through additional CMD_REQUEST_NETWORK msgs
91      *            with the same NetworkRequest but an updated score.
92      *            Also, network conditions may change for this bearer
93      *            allowing for a better score in the future.
94      * msg.arg2 = the serial number of the factory currently responsible for the
95      *            NetworkAgent handling this request, or SerialNumber.NONE if none.
96      */
97     public static final int CMD_REQUEST_NETWORK = BASE;
98 
99     /**
100      * Cancel a network request
101      * msg.obj = NetworkRequest
102      */
103     public static final int CMD_CANCEL_REQUEST = BASE + 1;
104 
105     /**
106      * Internally used to set our best-guess score.
107      * msg.arg1 = new score
108      */
109     private static final int CMD_SET_SCORE = BASE + 2;
110 
111     /**
112      * Internally used to set our current filter for coarse bandwidth changes with
113      * technology changes.
114      * msg.obj = new filter
115      */
116     private static final int CMD_SET_FILTER = BASE + 3;
117 
118     /**
119      * Sent by NetworkFactory to ConnectivityService to indicate that a request is
120      * unfulfillable.
121      * @see #releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest).
122      */
123     public static final int EVENT_UNFULFILLABLE_REQUEST = BASE + 4;
124 
125     private final Context mContext;
126     private final ArrayList<Message> mPreConnectedQueue = new ArrayList<Message>();
127     private AsyncChannel mAsyncChannel;
128     private final String LOG_TAG;
129 
130     private final SparseArray<NetworkRequestInfo> mNetworkRequests =
131             new SparseArray<NetworkRequestInfo>();
132 
133     private int mScore;
134     private NetworkCapabilities mCapabilityFilter;
135 
136     private int mRefCount = 0;
137     private Messenger mMessenger = null;
138     private int mSerialNumber;
139 
140     @UnsupportedAppUsage
NetworkFactory(Looper looper, Context context, String logTag, NetworkCapabilities filter)141     public NetworkFactory(Looper looper, Context context, String logTag,
142             NetworkCapabilities filter) {
143         super(looper);
144         LOG_TAG = logTag;
145         mContext = context;
146         mCapabilityFilter = filter;
147     }
148 
register()149     public void register() {
150         if (DBG) log("Registering NetworkFactory");
151         if (mMessenger == null) {
152             mMessenger = new Messenger(this);
153             mSerialNumber = ConnectivityManager.from(mContext).registerNetworkFactory(mMessenger,
154                     LOG_TAG);
155         }
156     }
157 
unregister()158     public void unregister() {
159         if (DBG) log("Unregistering NetworkFactory");
160         if (mMessenger != null) {
161             ConnectivityManager.from(mContext).unregisterNetworkFactory(mMessenger);
162             mMessenger = null;
163         }
164     }
165 
166     @Override
handleMessage(Message msg)167     public void handleMessage(Message msg) {
168         switch (msg.what) {
169             case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
170                 if (mAsyncChannel != null) {
171                     log("Received new connection while already connected!");
172                     break;
173                 }
174                 if (VDBG) log("NetworkFactory fully connected");
175                 AsyncChannel ac = new AsyncChannel();
176                 ac.connected(null, this, msg.replyTo);
177                 ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
178                         AsyncChannel.STATUS_SUCCESSFUL);
179                 mAsyncChannel = ac;
180                 for (Message m : mPreConnectedQueue) {
181                     ac.sendMessage(m);
182                 }
183                 mPreConnectedQueue.clear();
184                 break;
185             }
186             case AsyncChannel.CMD_CHANNEL_DISCONNECT: {
187                 if (VDBG) log("CMD_CHANNEL_DISCONNECT");
188                 if (mAsyncChannel != null) {
189                     mAsyncChannel.disconnect();
190                     mAsyncChannel = null;
191                 }
192                 break;
193             }
194             case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
195                 if (DBG) log("NetworkFactory channel lost");
196                 mAsyncChannel = null;
197                 break;
198             }
199             case CMD_REQUEST_NETWORK: {
200                 handleAddRequest((NetworkRequest) msg.obj, msg.arg1, msg.arg2);
201                 break;
202             }
203             case CMD_CANCEL_REQUEST: {
204                 handleRemoveRequest((NetworkRequest) msg.obj);
205                 break;
206             }
207             case CMD_SET_SCORE: {
208                 handleSetScore(msg.arg1);
209                 break;
210             }
211             case CMD_SET_FILTER: {
212                 handleSetFilter((NetworkCapabilities) msg.obj);
213                 break;
214             }
215         }
216     }
217 
218     private class NetworkRequestInfo {
219         public final NetworkRequest request;
220         public int score;
221         public boolean requested; // do we have a request outstanding, limited by score
222         public int factorySerialNumber;
223 
NetworkRequestInfo(NetworkRequest request, int score, int factorySerialNumber)224         NetworkRequestInfo(NetworkRequest request, int score, int factorySerialNumber) {
225             this.request = request;
226             this.score = score;
227             this.requested = false;
228             this.factorySerialNumber = factorySerialNumber;
229         }
230 
231         @Override
toString()232         public String toString() {
233             return "{" + request + ", score=" + score + ", requested=" + requested + "}";
234         }
235     }
236 
237     /**
238      * Add a NetworkRequest that the bearer may want to attempt to satisfy.
239      * @see #CMD_REQUEST_NETWORK
240      *
241      * @param request the request to handle.
242      * @param score the score of the NetworkAgent currently satisfying this request.
243      * @param servingFactorySerialNumber the serial number of the NetworkFactory that
244      *         created the NetworkAgent currently satisfying this request.
245      */
246     // TODO : remove this method. It is a stopgap measure to help sheperding a number
247     // of dependent changes that would conflict throughout the automerger graph. Having this
248     // temporarily helps with the process of going through with all these dependent changes across
249     // the entire tree.
250     @VisibleForTesting
handleAddRequest(NetworkRequest request, int score)251     protected void handleAddRequest(NetworkRequest request, int score) {
252         handleAddRequest(request, score, SerialNumber.NONE);
253     }
254 
255     /**
256      * Add a NetworkRequest that the bearer may want to attempt to satisfy.
257      * @see #CMD_REQUEST_NETWORK
258      *
259      * @param request the request to handle.
260      * @param score the score of the NetworkAgent currently satisfying this request.
261      * @param servingFactorySerialNumber the serial number of the NetworkFactory that
262      *         created the NetworkAgent currently satisfying this request.
263      */
264     @VisibleForTesting
handleAddRequest(NetworkRequest request, int score, int servingFactorySerialNumber)265     protected void handleAddRequest(NetworkRequest request, int score,
266             int servingFactorySerialNumber) {
267         NetworkRequestInfo n = mNetworkRequests.get(request.requestId);
268         if (n == null) {
269             if (DBG) {
270                 log("got request " + request + " with score " + score
271                         + " and serial " + servingFactorySerialNumber);
272             }
273             n = new NetworkRequestInfo(request, score, servingFactorySerialNumber);
274             mNetworkRequests.put(n.request.requestId, n);
275         } else {
276             if (VDBG) {
277                 log("new score " + score + " for exisiting request " + request
278                         + " with serial " + servingFactorySerialNumber);
279             }
280             n.score = score;
281             n.factorySerialNumber = servingFactorySerialNumber;
282         }
283         if (VDBG) log("  my score=" + mScore + ", my filter=" + mCapabilityFilter);
284 
285         evalRequest(n);
286     }
287 
288     @VisibleForTesting
handleRemoveRequest(NetworkRequest request)289     protected void handleRemoveRequest(NetworkRequest request) {
290         NetworkRequestInfo n = mNetworkRequests.get(request.requestId);
291         if (n != null) {
292             mNetworkRequests.remove(request.requestId);
293             if (n.requested) releaseNetworkFor(n.request);
294         }
295     }
296 
handleSetScore(int score)297     private void handleSetScore(int score) {
298         mScore = score;
299         evalRequests();
300     }
301 
handleSetFilter(NetworkCapabilities netCap)302     private void handleSetFilter(NetworkCapabilities netCap) {
303         mCapabilityFilter = netCap;
304         evalRequests();
305     }
306 
307     /**
308      * Overridable function to provide complex filtering.
309      * Called for every request every time a new NetworkRequest is seen
310      * and whenever the filterScore or filterNetworkCapabilities change.
311      *
312      * acceptRequest can be overridden to provide complex filter behavior
313      * for the incoming requests
314      *
315      * For output, this class will call {@link #needNetworkFor} and
316      * {@link #releaseNetworkFor} for every request that passes the filters.
317      * If you don't need to see every request, you can leave the base
318      * implementations of those two functions and instead override
319      * {@link #startNetwork} and {@link #stopNetwork}.
320      *
321      * If you want to see every score fluctuation on every request, set
322      * your score filter to a very high number and watch {@link #needNetworkFor}.
323      *
324      * @return {@code true} to accept the request.
325      */
acceptRequest(NetworkRequest request, int score)326     public boolean acceptRequest(NetworkRequest request, int score) {
327         return true;
328     }
329 
evalRequest(NetworkRequestInfo n)330     private void evalRequest(NetworkRequestInfo n) {
331         if (VDBG) {
332             log("evalRequest");
333             log(" n.requests = " + n.requested);
334             log(" n.score = " + n.score);
335             log(" mScore = " + mScore);
336             log(" n.factorySerialNumber = " + n.factorySerialNumber);
337             log(" mSerialNumber = " + mSerialNumber);
338         }
339         if (shouldNeedNetworkFor(n)) {
340             if (VDBG) log("  needNetworkFor");
341             needNetworkFor(n.request, n.score);
342             n.requested = true;
343         } else if (shouldReleaseNetworkFor(n)) {
344             if (VDBG) log("  releaseNetworkFor");
345             releaseNetworkFor(n.request);
346             n.requested = false;
347         } else {
348             if (VDBG) log("  done");
349         }
350     }
351 
shouldNeedNetworkFor(NetworkRequestInfo n)352     private boolean shouldNeedNetworkFor(NetworkRequestInfo n) {
353         // If this request is already tracked, it doesn't qualify for need
354         return !n.requested
355             // If the score of this request is higher or equal to that of this factory and some
356             // other factory is responsible for it, then this factory should not track the request
357             // because it has no hope of satisfying it.
358             && (n.score < mScore || n.factorySerialNumber == mSerialNumber)
359             // If this factory can't satisfy the capability needs of this request, then it
360             // should not be tracked.
361             && n.request.networkCapabilities.satisfiedByNetworkCapabilities(mCapabilityFilter)
362             // Finally if the concrete implementation of the factory rejects the request, then
363             // don't track it.
364             && acceptRequest(n.request, n.score);
365     }
366 
shouldReleaseNetworkFor(NetworkRequestInfo n)367     private boolean shouldReleaseNetworkFor(NetworkRequestInfo n) {
368         // Don't release a request that's not tracked.
369         return n.requested
370             // The request should be released if it can't be satisfied by this factory. That
371             // means either of the following conditions are met :
372             // - Its score is too high to be satisfied by this factory and it's not already
373             //   assigned to the factory
374             // - This factory can't satisfy the capability needs of the request
375             // - The concrete implementation of the factory rejects the request
376             && ((n.score > mScore && n.factorySerialNumber != mSerialNumber)
377                     || !n.request.networkCapabilities.satisfiedByNetworkCapabilities(
378                             mCapabilityFilter)
379                     || !acceptRequest(n.request, n.score));
380     }
381 
evalRequests()382     private void evalRequests() {
383         for (int i = 0; i < mNetworkRequests.size(); i++) {
384             NetworkRequestInfo n = mNetworkRequests.valueAt(i);
385             evalRequest(n);
386         }
387     }
388 
389     /**
390      * Post a command, on this NetworkFactory Handler, to re-evaluate all
391      * oustanding requests. Can be called from a factory implementation.
392      */
reevaluateAllRequests()393     protected void reevaluateAllRequests() {
394         post(() -> {
395             evalRequests();
396         });
397     }
398 
399     /**
400      * Can be called by a factory to release a request as unfulfillable: the request will be
401      * removed, and the caller will get a
402      * {@link ConnectivityManager.NetworkCallback#onUnavailable()} callback after this function
403      * returns.
404      *
405      * Note: this should only be called by factory which KNOWS that it is the ONLY factory which
406      * is able to fulfill this request!
407      */
releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest r)408     protected void releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest r) {
409         post(() -> {
410             if (DBG) log("releaseRequestAsUnfulfillableByAnyFactory: " + r);
411             Message msg = obtainMessage(EVENT_UNFULFILLABLE_REQUEST, r);
412             if (mAsyncChannel != null) {
413                 mAsyncChannel.sendMessage(msg);
414             } else {
415                 mPreConnectedQueue.add(msg);
416             }
417         });
418     }
419 
420     // override to do simple mode (request independent)
startNetwork()421     protected void startNetwork() { }
stopNetwork()422     protected void stopNetwork() { }
423 
424     // override to do fancier stuff
needNetworkFor(NetworkRequest networkRequest, int score)425     protected void needNetworkFor(NetworkRequest networkRequest, int score) {
426         if (++mRefCount == 1) startNetwork();
427     }
428 
releaseNetworkFor(NetworkRequest networkRequest)429     protected void releaseNetworkFor(NetworkRequest networkRequest) {
430         if (--mRefCount == 0) stopNetwork();
431     }
432 
433     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
setScoreFilter(int score)434     public void setScoreFilter(int score) {
435         sendMessage(obtainMessage(CMD_SET_SCORE, score, 0));
436     }
437 
setCapabilityFilter(NetworkCapabilities netCap)438     public void setCapabilityFilter(NetworkCapabilities netCap) {
439         sendMessage(obtainMessage(CMD_SET_FILTER, new NetworkCapabilities(netCap)));
440     }
441 
442     @VisibleForTesting
getRequestCount()443     protected int getRequestCount() {
444         return mNetworkRequests.size();
445     }
446 
getSerialNumber()447     public int getSerialNumber() {
448         return mSerialNumber;
449     }
450 
log(String s)451     protected void log(String s) {
452         Log.d(LOG_TAG, s);
453     }
454 
455     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
dump(FileDescriptor fd, PrintWriter writer, String[] args)456     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
457         final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
458         pw.println(toString());
459         pw.increaseIndent();
460         for (int i = 0; i < mNetworkRequests.size(); i++) {
461             pw.println(mNetworkRequests.valueAt(i));
462         }
463         pw.decreaseIndent();
464     }
465 
466     @Override
toString()467     public String toString() {
468         StringBuilder sb = new StringBuilder("{").append(LOG_TAG).append(" - mSerialNumber=")
469                 .append(mSerialNumber).append(", ScoreFilter=")
470                 .append(mScore).append(", Filter=").append(mCapabilityFilter).append(", requests=")
471                 .append(mNetworkRequests.size()).append(", refCount=").append(mRefCount)
472                 .append("}");
473         return sb.toString();
474     }
475 }
476