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;
27
28import com.android.internal.util.AsyncChannel;
29import com.android.internal.util.Protocol;
30
31import java.util.ArrayList;
32import 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 */
44public 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
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
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
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
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
293    protected void networkStatus(int status) {
294    }
295
296    protected void log(String s) {
297        Log.d(LOG_TAG, "NetworkAgent: " + s);
298    }
299}
300