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.os.Parcel;
25 import android.os.Parcelable;
26 import android.util.Log;
27 
28 import com.android.internal.util.AsyncChannel;
29 import com.android.internal.util.Protocol;
30 
31 import java.util.ArrayList;
32 import java.util.concurrent.atomic.AtomicBoolean;
33 
34 /**
35  * A Utility class for handling for communicating between bearer-specific
36  * code and ConnectivityService.
37  *
38  * A bearer may have more than one NetworkAgent if it can simultaneously
39  * support separate networks (IMS / Internet / MMS Apns on cellular, or
40  * perhaps connections with different SSID or P2P for Wi-Fi).
41  *
42  * @hide
43  */
44 public abstract class NetworkAgent extends Handler {
45     private volatile AsyncChannel mAsyncChannel;
46     private final String LOG_TAG;
47     private static final boolean DBG = true;
48     private static final boolean VDBG = false;
49     private final Context mContext;
50     private final ArrayList<Message>mPreConnectedQueue = new ArrayList<Message>();
51 
52     private static final int BASE = Protocol.BASE_NETWORK_AGENT;
53 
54     /**
55      * Sent by ConnectivityService to the NetworkAgent to inform it of
56      * suspected connectivity problems on its network.  The NetworkAgent
57      * should take steps to verify and correct connectivity.
58      */
59     public static final int CMD_SUSPECT_BAD = BASE;
60 
61     /**
62      * Sent by the NetworkAgent (note the EVENT vs CMD prefix) to
63      * ConnectivityService to pass the current NetworkInfo (connection state).
64      * Sent when the NetworkInfo changes, mainly due to change of state.
65      * obj = NetworkInfo
66      */
67     public static final int EVENT_NETWORK_INFO_CHANGED = BASE + 1;
68 
69     /**
70      * Sent by the NetworkAgent to ConnectivityService to pass the current
71      * NetworkCapabilties.
72      * obj = NetworkCapabilities
73      */
74     public static final int EVENT_NETWORK_CAPABILITIES_CHANGED = BASE + 2;
75 
76     /**
77      * Sent by the NetworkAgent to ConnectivityService to pass the current
78      * NetworkProperties.
79      * obj = NetworkProperties
80      */
81     public static final int EVENT_NETWORK_PROPERTIES_CHANGED = BASE + 3;
82 
83     /* centralize place where base network score, and network score scaling, will be
84      * stored, so as we can consistently compare apple and oranges, or wifi, ethernet and LTE
85      */
86     public static final int WIFI_BASE_SCORE = 60;
87 
88     /**
89      * Sent by the NetworkAgent to ConnectivityService to pass the current
90      * network score.
91      * obj = network score Integer
92      */
93     public static final int EVENT_NETWORK_SCORE_CHANGED = BASE + 4;
94 
95     /**
96      * Sent by the NetworkAgent to ConnectivityService to add new UID ranges
97      * to be forced into this Network.  For VPNs only.
98      * obj = UidRange[] to forward
99      */
100     public static final int EVENT_UID_RANGES_ADDED = BASE + 5;
101 
102     /**
103      * Sent by the NetworkAgent to ConnectivityService to remove UID ranges
104      * from being forced into this Network.  For VPNs only.
105      * obj = UidRange[] to stop forwarding
106      */
107     public static final int EVENT_UID_RANGES_REMOVED = BASE + 6;
108 
109     /**
110      * Sent by ConnectivitySerice to the NetworkAgent to inform the agent of the
111      * networks status - whether we could use the network or could not, due to
112      * either a bad network configuration (no internet link) or captive portal.
113      *
114      * arg1 = either {@code VALID_NETWORK} or {@code INVALID_NETWORK}
115      */
116     public static final int CMD_REPORT_NETWORK_STATUS = BASE + 7;
117 
118     public static final int VALID_NETWORK = 1;
119     public static final int INVALID_NETWORK = 2;
120 
121      /**
122      * Sent by the NetworkAgent to ConnectivityService to indicate this network was
123      * explicitly selected.  This should be sent before the NetworkInfo is marked
124      * CONNECTED so it can be given special treatment at that time.
125      */
126     public static final int EVENT_SET_EXPLICITLY_SELECTED = BASE + 8;
127 
NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, NetworkCapabilities nc, LinkProperties lp, int score)128     public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
129             NetworkCapabilities nc, LinkProperties lp, int score) {
130         this(looper, context, logTag, ni, nc, lp, score, null);
131     }
132 
NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc)133     public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
134             NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {
135         super(looper);
136         LOG_TAG = logTag;
137         mContext = context;
138         if (ni == null || nc == null || lp == null) {
139             throw new IllegalArgumentException();
140         }
141 
142         if (VDBG) log("Registering NetworkAgent");
143         ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
144                 Context.CONNECTIVITY_SERVICE);
145         cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni),
146                 new LinkProperties(lp), new NetworkCapabilities(nc), score, misc);
147     }
148 
149     @Override
handleMessage(Message msg)150     public void handleMessage(Message msg) {
151         switch (msg.what) {
152             case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
153                 if (mAsyncChannel != null) {
154                     log("Received new connection while already connected!");
155                 } else {
156                     if (VDBG) log("NetworkAgent fully connected");
157                     AsyncChannel ac = new AsyncChannel();
158                     ac.connected(null, this, msg.replyTo);
159                     ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
160                             AsyncChannel.STATUS_SUCCESSFUL);
161                     synchronized (mPreConnectedQueue) {
162                         mAsyncChannel = ac;
163                         for (Message m : mPreConnectedQueue) {
164                             ac.sendMessage(m);
165                         }
166                         mPreConnectedQueue.clear();
167                     }
168                 }
169                 break;
170             }
171             case AsyncChannel.CMD_CHANNEL_DISCONNECT: {
172                 if (VDBG) log("CMD_CHANNEL_DISCONNECT");
173                 if (mAsyncChannel != null) mAsyncChannel.disconnect();
174                 break;
175             }
176             case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
177                 if (DBG) log("NetworkAgent channel lost");
178                 // let the client know CS is done with us.
179                 unwanted();
180                 synchronized (mPreConnectedQueue) {
181                     mAsyncChannel = null;
182                 }
183                 break;
184             }
185             case CMD_SUSPECT_BAD: {
186                 log("Unhandled Message " + msg);
187                 break;
188             }
189             case CMD_REPORT_NETWORK_STATUS: {
190                 if (VDBG) {
191                     log("CMD_REPORT_NETWORK_STATUS(" +
192                             (msg.arg1 == VALID_NETWORK ? "VALID)" : "INVALID)"));
193                 }
194                 networkStatus(msg.arg1);
195                 break;
196             }
197         }
198     }
199 
queueOrSendMessage(int what, Object obj)200     private void queueOrSendMessage(int what, Object obj) {
201         synchronized (mPreConnectedQueue) {
202             if (mAsyncChannel != null) {
203                 mAsyncChannel.sendMessage(what, obj);
204             } else {
205                 Message msg = Message.obtain();
206                 msg.what = what;
207                 msg.obj = obj;
208                 mPreConnectedQueue.add(msg);
209             }
210         }
211     }
212 
213     /**
214      * Called by the bearer code when it has new LinkProperties data.
215      */
sendLinkProperties(LinkProperties linkProperties)216     public void sendLinkProperties(LinkProperties linkProperties) {
217         queueOrSendMessage(EVENT_NETWORK_PROPERTIES_CHANGED, new LinkProperties(linkProperties));
218     }
219 
220     /**
221      * Called by the bearer code when it has new NetworkInfo data.
222      */
sendNetworkInfo(NetworkInfo networkInfo)223     public void sendNetworkInfo(NetworkInfo networkInfo) {
224         queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, new NetworkInfo(networkInfo));
225     }
226 
227     /**
228      * Called by the bearer code when it has new NetworkCapabilities data.
229      */
sendNetworkCapabilities(NetworkCapabilities networkCapabilities)230     public void sendNetworkCapabilities(NetworkCapabilities networkCapabilities) {
231         queueOrSendMessage(EVENT_NETWORK_CAPABILITIES_CHANGED,
232                 new NetworkCapabilities(networkCapabilities));
233     }
234 
235     /**
236      * Called by the bearer code when it has a new score for this network.
237      */
sendNetworkScore(int score)238     public void sendNetworkScore(int score) {
239         if (score < 0) {
240             throw new IllegalArgumentException("Score must be >= 0");
241         }
242         queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, new Integer(score));
243     }
244 
245     /**
246      * Called by the VPN code when it wants to add ranges of UIDs to be routed
247      * through the VPN network.
248      */
addUidRanges(UidRange[] ranges)249     public void addUidRanges(UidRange[] ranges) {
250         queueOrSendMessage(EVENT_UID_RANGES_ADDED, ranges);
251     }
252 
253     /**
254      * Called by the VPN code when it wants to remove ranges of UIDs from being routed
255      * through the VPN network.
256      */
removeUidRanges(UidRange[] ranges)257     public void removeUidRanges(UidRange[] ranges) {
258         queueOrSendMessage(EVENT_UID_RANGES_REMOVED, ranges);
259     }
260 
261     /**
262      * Called by the bearer to indicate this network was manually selected by the user.
263      * This should be called before the NetworkInfo is marked CONNECTED so that this
264      * Network can be given special treatment at that time.
265      */
explicitlySelected()266     public void explicitlySelected() {
267         queueOrSendMessage(EVENT_SET_EXPLICITLY_SELECTED, 0);
268     }
269 
270     /**
271      * Called when ConnectivityService has indicated they no longer want this network.
272      * The parent factory should (previously) have received indication of the change
273      * as well, either canceling NetworkRequests or altering their score such that this
274      * network won't be immediately requested again.
275      */
unwanted()276     abstract protected void unwanted();
277 
278     /**
279      * Called when the system determines the usefulness of this network.
280      *
281      * Networks claiming internet connectivity will have their internet
282      * connectivity verified.
283      *
284      * Currently there are two possible values:
285      * {@code VALID_NETWORK} if the system is happy with the connection,
286      * {@code INVALID_NETWORK} if the system is not happy.
287      * TODO - add indications of captive portal-ness and related success/failure,
288      * ie, CAPTIVE_SUCCESS_NETWORK, CAPTIVE_NETWORK for successful login and detection
289      *
290      * This may be called multiple times as the network status changes and may
291      * generate false negatives if we lose ip connectivity before the link is torn down.
292      */
networkStatus(int status)293     protected void networkStatus(int status) {
294     }
295 
log(String s)296     protected void log(String s) {
297         Log.d(LOG_TAG, "NetworkAgent: " + s);
298     }
299 }
300