blob: 1c18ba564009e404aec2277c7d158a56a6ff2f6d [file] [log] [blame]
Robert Greenwalt7b816022014-04-18 15:25:25 -07001/*
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
32import java.util.concurrent.atomic.AtomicBoolean;
33
34/**
35 * A Utility class for handling NetworkRequests.
36 *
37 * Created by bearer-specific code to handle tracking requests, scores,
38 * network data and handle communicating with ConnectivityService. Two
39 * abstract methods: connect and disconnect are used to act on the
40 * underlying bearer code. Connect is called when we have a NetworkRequest
41 * and our score is better than the current handling network's score, while
42 * disconnect is used when ConnectivityService requests a disconnect.
43 *
44 * A bearer may have more than one NetworkAgent if it can simultaneously
45 * support separate networks (IMS / Internet / MMS Apns on cellular, or
46 * perhaps connections with different SSID or P2P for Wi-Fi). The bearer
47 * code should pass its NetworkAgents the NetworkRequests each NetworkAgent
48 * can handle, demultiplexing for different network types. The bearer code
49 * can also filter out requests it can never handle.
50 *
51 * Each NetworkAgent needs to be given a score and NetworkCapabilities for
52 * their potential network. While disconnected, the NetworkAgent will check
53 * each time its score changes or a NetworkRequest changes to see if
54 * the NetworkAgent can provide a higher scored network for a NetworkRequest
55 * that the NetworkAgent's NetworkCapabilties can satisfy. This condition will
56 * trigger a connect request via connect(). After connection, connection data
57 * should be given to the NetworkAgent by the bearer, including LinkProperties
58 * NetworkCapabilties and NetworkInfo. After that the NetworkAgent will register
59 * with ConnectivityService and forward the data on.
60 * @hide
61 */
62public abstract class NetworkAgent extends Handler {
63 private final SparseArray<NetworkRequestAndScore> mNetworkRequests = new SparseArray<>();
64 private boolean mConnectionRequested = false;
65
66 private AsyncChannel mAsyncChannel;
67 private final String LOG_TAG;
68 private static final boolean DBG = true;
Robert Greenwalt4064af82014-05-16 08:54:07 -070069 private static final boolean VDBG = true;
Robert Greenwalt7b816022014-04-18 15:25:25 -070070 // TODO - this class shouldn't cache data or it runs the risk of getting out of sync
71 // Make the API require each of these when any is updated so we have the data we need,
72 // without caching.
73 private LinkProperties mLinkProperties;
74 private NetworkInfo mNetworkInfo;
75 private NetworkCapabilities mNetworkCapabilities;
76 private int mNetworkScore;
77 private boolean mRegistered = false;
78 private final Context mContext;
79 private AtomicBoolean mHasRequests = new AtomicBoolean(false);
80
81 // TODO - add a name member for logging purposes.
82
83 protected final Object mLockObj = new Object();
84
85
86 private static final int BASE = Protocol.BASE_NETWORK_AGENT;
87
88 /**
89 * Sent by self to queue up a new/modified request.
90 * obj = NetworkRequestAndScore
91 */
92 private static final int CMD_ADD_REQUEST = BASE + 1;
93
94 /**
95 * Sent by self to queue up the removal of a request.
96 * obj = NetworkRequest
97 */
98 private static final int CMD_REMOVE_REQUEST = BASE + 2;
99
100 /**
101 * Sent by ConnectivityService to the NetworkAgent to inform it of
102 * suspected connectivity problems on its network. The NetworkAgent
103 * should take steps to verify and correct connectivity.
104 */
105 public static final int CMD_SUSPECT_BAD = BASE + 3;
106
107 /**
108 * Sent by the NetworkAgent (note the EVENT vs CMD prefix) to
109 * ConnectivityService to pass the current NetworkInfo (connection state).
110 * Sent when the NetworkInfo changes, mainly due to change of state.
111 * obj = NetworkInfo
112 */
113 public static final int EVENT_NETWORK_INFO_CHANGED = BASE + 4;
114
115 /**
116 * Sent by the NetworkAgent to ConnectivityService to pass the current
117 * NetworkCapabilties.
118 * obj = NetworkCapabilities
119 */
120 public static final int EVENT_NETWORK_CAPABILITIES_CHANGED = BASE + 5;
121
122 /**
123 * Sent by the NetworkAgent to ConnectivityService to pass the current
124 * NetworkProperties.
125 * obj = NetworkProperties
126 */
127 public static final int EVENT_NETWORK_PROPERTIES_CHANGED = BASE + 6;
128
129 /**
130 * Sent by the NetworkAgent to ConnectivityService to pass the current
131 * network score.
132 * arg1 = network score int
133 */
134 public static final int EVENT_NETWORK_SCORE_CHANGED = BASE + 7;
135
136 public NetworkAgent(Looper looper, Context context, String logTag) {
137 super(looper);
138 LOG_TAG = logTag;
139 mContext = context;
140 }
141
142 /**
143 * When conditions are right, register with ConnectivityService.
144 * Connditions include having a well defined network and a request
145 * that justifies it. The NetworkAgent will remain registered until
146 * disconnected.
147 * TODO - this should have all data passed in rather than caching
148 */
149 private void registerSelf() {
150 synchronized(mLockObj) {
151 if (!mRegistered && mConnectionRequested &&
152 mNetworkInfo != null && mNetworkInfo.isConnected() &&
153 mNetworkCapabilities != null &&
154 mLinkProperties != null &&
155 mNetworkScore != 0) {
156 if (DBG) log("Registering NetworkAgent");
157 mRegistered = true;
158 ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
159 Context.CONNECTIVITY_SERVICE);
160 cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(mNetworkInfo),
161 new LinkProperties(mLinkProperties),
162 new NetworkCapabilities(mNetworkCapabilities), mNetworkScore);
163 } else if (DBG && !mRegistered) {
164 String err = "Not registering due to ";
165 if (mConnectionRequested == false) err += "no Connect requested ";
166 if (mNetworkInfo == null) err += "null NetworkInfo ";
167 if (mNetworkInfo != null && mNetworkInfo.isConnected() == false) {
168 err += "NetworkInfo disconnected ";
169 }
170 if (mLinkProperties == null) err += "null LinkProperties ";
171 if (mNetworkCapabilities == null) err += "null NetworkCapabilities ";
172 if (mNetworkScore == 0) err += "null NetworkScore";
173 log(err);
174 }
175 }
176 }
177
178 @Override
179 public void handleMessage(Message msg) {
180 switch (msg.what) {
181 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
182 synchronized (mLockObj) {
183 if (mAsyncChannel != null) {
184 log("Received new connection while already connected!");
185 } else {
186 if (DBG) log("NetworkAgent fully connected");
187 mAsyncChannel = new AsyncChannel();
188 mAsyncChannel.connected(null, this, msg.replyTo);
189 mAsyncChannel.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
190 AsyncChannel.STATUS_SUCCESSFUL);
191 }
192 }
193 break;
194 }
195 case AsyncChannel.CMD_CHANNEL_DISCONNECT: {
196 if (DBG) log("CMD_CHANNEL_DISCONNECT");
197 if (mAsyncChannel != null) mAsyncChannel.disconnect();
198 break;
199 }
200 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
201 if (DBG) log("NetworkAgent channel lost");
202 disconnect();
203 clear();
204 break;
205 }
206 case CMD_SUSPECT_BAD: {
207 log("Unhandled Message " + msg);
208 break;
209 }
210 case CMD_ADD_REQUEST: {
211 handleAddRequest(msg);
212 break;
213 }
214 case CMD_REMOVE_REQUEST: {
215 handleRemoveRequest(msg);
216 break;
217 }
218 }
219 }
220
221 private void clear() {
222 synchronized(mLockObj) {
223 mNetworkRequests.clear();
224 mHasRequests.set(false);
225 mConnectionRequested = false;
226 mAsyncChannel = null;
227 mRegistered = false;
228 }
229 }
230
231 private static class NetworkRequestAndScore {
232 NetworkRequest req;
233 int score;
234
235 NetworkRequestAndScore(NetworkRequest networkRequest, int score) {
236 req = networkRequest;
237 this.score = score;
238 }
239 }
240
241 private void handleAddRequest(Message msg) {
242 NetworkRequestAndScore n = (NetworkRequestAndScore)msg.obj;
243 // replaces old request, updating score
244 mNetworkRequests.put(n.req.requestId, n);
245 mHasRequests.set(true);
246 evalScores();
247 }
248
249 private void handleRemoveRequest(Message msg) {
250 NetworkRequest networkRequest = (NetworkRequest)msg.obj;
251
252 if (mNetworkRequests.get(networkRequest.requestId) != null) {
253 mNetworkRequests.remove(networkRequest.requestId);
254 if (mNetworkRequests.size() == 0) mHasRequests.set(false);
255 evalScores();
256 }
257 }
258
259 /**
Lorenzo Colitti9a6a11a2014-05-24 02:25:55 +0900260 * Called to go through our list of requests and see if we're
261 * good enough to try connecting, or if we have gotten worse and
262 * need to disconnect.
Robert Greenwalt7b816022014-04-18 15:25:25 -0700263 *
Lorenzo Colitti9a6a11a2014-05-24 02:25:55 +0900264 * Once we are registered, does nothing: we disconnect when requested via
Robert Greenwalt7b816022014-04-18 15:25:25 -0700265 * CMD_CHANNEL_DISCONNECTED, generated by either a loss of connection
266 * between modules (bearer or ConnectivityService dies) or more commonly
267 * when the NetworkInfo reports to ConnectivityService it is disconnected.
268 */
269 private void evalScores() {
Lorenzo Colitti9a6a11a2014-05-24 02:25:55 +0900270 synchronized(mLockObj) {
271 if (mRegistered) {
272 if (VDBG) log("evalScores - already connected - size=" + mNetworkRequests.size());
273 // already trying
Robert Greenwalt7b816022014-04-18 15:25:25 -0700274 return;
275 }
Lorenzo Colitti9a6a11a2014-05-24 02:25:55 +0900276 if (VDBG) log("evalScores!");
277 for (int i=0; i < mNetworkRequests.size(); i++) {
278 int score = mNetworkRequests.valueAt(i).score;
279 if (VDBG) log(" checking request Min " + score + " vs my score " + mNetworkScore);
280 if (score < mNetworkScore) {
281 // have a request that has a lower scored network servicing it
282 // (or no network) than we could provide, so let's connect!
283 mConnectionRequested = true;
284 connect();
285 return;
286 }
287 }
288 // Our score is not high enough to satisfy any current request.
289 // This can happen if our score goes down after a connection is
290 // requested but before we actually connect. In this case, disconnect
291 // rather than continue trying - there's no point connecting if we know
292 // we'll just be torn down as soon as we do.
293 if (mConnectionRequested) {
294 mConnectionRequested = false;
295 disconnect();
296 }
Robert Greenwalt7b816022014-04-18 15:25:25 -0700297 }
298 }
299
300 public void addNetworkRequest(NetworkRequest networkRequest, int score) {
301 if (DBG) log("adding NetworkRequest " + networkRequest + " with score " + score);
302 sendMessage(obtainMessage(CMD_ADD_REQUEST,
303 new NetworkRequestAndScore(networkRequest, score)));
304 }
305
306 public void removeNetworkRequest(NetworkRequest networkRequest) {
307 if (DBG) log("removing NetworkRequest " + networkRequest);
308 sendMessage(obtainMessage(CMD_REMOVE_REQUEST, networkRequest));
309 }
310
311 /**
312 * Called by the bearer code when it has new LinkProperties data.
313 * If we're a registered NetworkAgent, this new data will get forwarded on,
314 * otherwise we store a copy in anticipation of registering. This call
315 * may also prompt registration if it causes the NetworkAgent to meet
316 * the conditions (fully configured, connected, satisfys a request and
317 * has sufficient score).
318 */
319 public void sendLinkProperties(LinkProperties linkProperties) {
320 linkProperties = new LinkProperties(linkProperties);
321 synchronized(mLockObj) {
322 mLinkProperties = linkProperties;
323 if (mAsyncChannel != null) {
324 mAsyncChannel.sendMessage(EVENT_NETWORK_PROPERTIES_CHANGED, linkProperties);
325 } else {
326 registerSelf();
327 }
328 }
329 }
330
331 /**
332 * Called by the bearer code when it has new NetworkInfo data.
333 * If we're a registered NetworkAgent, this new data will get forwarded on,
334 * otherwise we store a copy in anticipation of registering. This call
335 * may also prompt registration if it causes the NetworkAgent to meet
336 * the conditions (fully configured, connected, satisfys a request and
337 * has sufficient score).
338 */
339 public void sendNetworkInfo(NetworkInfo networkInfo) {
340 networkInfo = new NetworkInfo(networkInfo);
341 synchronized(mLockObj) {
342 mNetworkInfo = networkInfo;
343 if (mAsyncChannel != null) {
344 mAsyncChannel.sendMessage(EVENT_NETWORK_INFO_CHANGED, networkInfo);
345 } else {
346 registerSelf();
347 }
348 }
349 }
350
351 /**
352 * Called by the bearer code when it has new NetworkCapabilities data.
353 * If we're a registered NetworkAgent, this new data will get forwarded on,
354 * otherwise we store a copy in anticipation of registering. This call
355 * may also prompt registration if it causes the NetworkAgent to meet
356 * the conditions (fully configured, connected, satisfys a request and
357 * has sufficient score).
358 * Note that if these capabilities make the network non-useful,
359 * ConnectivityServce will tear this network down.
360 */
361 public void sendNetworkCapabilities(NetworkCapabilities networkCapabilities) {
362 networkCapabilities = new NetworkCapabilities(networkCapabilities);
363 synchronized(mLockObj) {
364 mNetworkCapabilities = networkCapabilities;
365 if (mAsyncChannel != null) {
366 mAsyncChannel.sendMessage(EVENT_NETWORK_CAPABILITIES_CHANGED, networkCapabilities);
367 } else {
368 registerSelf();
369 }
370 }
371 }
372
373 public NetworkCapabilities getNetworkCapabilities() {
374 synchronized(mLockObj) {
375 return new NetworkCapabilities(mNetworkCapabilities);
376 }
377 }
378
379 /**
380 * Called by the bearer code when it has a new score for this network.
381 * If we're a registered NetworkAgent, this new data will get forwarded on,
382 * otherwise we store a copy.
383 */
384 public synchronized void sendNetworkScore(int score) {
385 synchronized(mLockObj) {
386 mNetworkScore = score;
387 evalScores();
388 if (mAsyncChannel != null) {
389 mAsyncChannel.sendMessage(EVENT_NETWORK_SCORE_CHANGED, mNetworkScore);
390 } else {
391 registerSelf();
392 }
393 }
394 }
395
396 public boolean hasRequests() {
397 return mHasRequests.get();
398 }
399
400 public boolean isConnectionRequested() {
401 synchronized(mLockObj) {
402 return mConnectionRequested;
403 }
404 }
405
406
407 abstract protected void connect();
408 abstract protected void disconnect();
409
410 protected void log(String s) {
411 Log.d(LOG_TAG, "NetworkAgent: " + s);
412 }
413}