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