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