• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 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 java.io.FileWriter;
20 import java.io.IOException;
21 
22 import android.os.Handler;
23 import android.os.Message;
24 import android.os.SystemProperties;
25 import android.content.Context;
26 import android.text.TextUtils;
27 import android.util.Config;
28 import android.util.Log;
29 
30 
31 /**
32  * Each subclass of this class keeps track of the state of connectivity
33  * of a network interface. All state information for a network should
34  * be kept in a Tracker class. This superclass manages the
35  * network-type-independent aspects of network state.
36  *
37  * {@hide}
38  */
39 public abstract class NetworkStateTracker extends Handler {
40 
41     protected NetworkInfo mNetworkInfo;
42     protected Context mContext;
43     protected Handler mTarget;
44     protected String mInterfaceName;
45     protected String[] mDnsPropNames;
46     private boolean mPrivateDnsRouteSet;
47     protected int mDefaultGatewayAddr;
48     private boolean mDefaultRouteSet;
49     private boolean mTeardownRequested;
50 
51     private static boolean DBG = true;
52     private static final String TAG = "NetworkStateTracker";
53 
54     public static final int EVENT_STATE_CHANGED = 1;
55     public static final int EVENT_SCAN_RESULTS_AVAILABLE = 2;
56     /**
57      * arg1: 1 to show, 0 to hide
58      * arg2: ID of the notification
59      * obj: Notification (if showing)
60      */
61     public static final int EVENT_NOTIFICATION_CHANGED = 3;
62     public static final int EVENT_CONFIGURATION_CHANGED = 4;
63     public static final int EVENT_ROAMING_CHANGED = 5;
64     public static final int EVENT_NETWORK_SUBTYPE_CHANGED = 6;
65     public static final int EVENT_RESTORE_DEFAULT_NETWORK = 7;
66 
NetworkStateTracker(Context context, Handler target, int networkType, int subType, String typeName, String subtypeName)67     public NetworkStateTracker(Context context,
68             Handler target,
69             int networkType,
70             int subType,
71             String typeName,
72             String subtypeName) {
73         super();
74         mContext = context;
75         mTarget = target;
76         mTeardownRequested = false;
77 
78         this.mNetworkInfo = new NetworkInfo(networkType, subType, typeName, subtypeName);
79     }
80 
getNetworkInfo()81     public NetworkInfo getNetworkInfo() {
82         return mNetworkInfo;
83     }
84 
85     /**
86      * Return the system properties name associated with the tcp buffer sizes
87      * for this network.
88      */
getTcpBufferSizesPropName()89     public abstract String getTcpBufferSizesPropName();
90 
91     /**
92      * Return the IP addresses of the DNS servers available for the mobile data
93      * network interface.
94      * @return a list of DNS addresses, with no holes.
95      */
getNameServers()96     public String[] getNameServers() {
97         return getNameServerList(mDnsPropNames);
98     }
99 
100     /**
101      * Return the IP addresses of the DNS servers available for this
102      * network interface.
103      * @param propertyNames the names of the system properties whose values
104      * give the IP addresses. Properties with no values are skipped.
105      * @return an array of {@code String}s containing the IP addresses
106      * of the DNS servers, in dot-notation. This may have fewer
107      * non-null entries than the list of names passed in, since
108      * some of the passed-in names may have empty values.
109      */
getNameServerList(String[] propertyNames)110     static protected String[] getNameServerList(String[] propertyNames) {
111         String[] dnsAddresses = new String[propertyNames.length];
112         int i, j;
113 
114         for (i = 0, j = 0; i < propertyNames.length; i++) {
115             String value = SystemProperties.get(propertyNames[i]);
116             // The GSM layer sometimes sets a bogus DNS server address of
117             // 0.0.0.0
118             if (!TextUtils.isEmpty(value) && !TextUtils.equals(value, "0.0.0.0")) {
119                 dnsAddresses[j++] = value;
120             }
121         }
122         return dnsAddresses;
123     }
124 
addPrivateDnsRoutes()125     public void addPrivateDnsRoutes() {
126         if (DBG) {
127             Log.d(TAG, "addPrivateDnsRoutes for " + this +
128                     "(" + mInterfaceName + ") - mPrivateDnsRouteSet = "+mPrivateDnsRouteSet);
129         }
130         if (mInterfaceName != null && !mPrivateDnsRouteSet) {
131             for (String addrString : getNameServers()) {
132                 int addr = NetworkUtils.lookupHost(addrString);
133                 if (addr != -1 && addr != 0) {
134                     if (DBG) Log.d(TAG, "  adding "+addrString+" ("+addr+")");
135                     NetworkUtils.addHostRoute(mInterfaceName, addr);
136                 }
137             }
138             mPrivateDnsRouteSet = true;
139         }
140     }
141 
removePrivateDnsRoutes()142     public void removePrivateDnsRoutes() {
143         // TODO - we should do this explicitly but the NetUtils api doesnt
144         // support this yet - must remove all.  No worse than before
145         if (mInterfaceName != null && mPrivateDnsRouteSet) {
146             if (DBG) {
147                 Log.d(TAG, "removePrivateDnsRoutes for " + mNetworkInfo.getTypeName() +
148                         " (" + mInterfaceName + ")");
149             }
150             NetworkUtils.removeHostRoutes(mInterfaceName);
151             mPrivateDnsRouteSet = false;
152         }
153     }
154 
addDefaultRoute()155     public void addDefaultRoute() {
156         if ((mInterfaceName != null) && (mDefaultGatewayAddr != 0) &&
157                 mDefaultRouteSet == false) {
158             if (DBG) {
159                 Log.d(TAG, "addDefaultRoute for " + mNetworkInfo.getTypeName() +
160                         " (" + mInterfaceName + "), GatewayAddr=" + mDefaultGatewayAddr);
161             }
162             NetworkUtils.setDefaultRoute(mInterfaceName, mDefaultGatewayAddr);
163             mDefaultRouteSet = true;
164         }
165     }
166 
removeDefaultRoute()167     public void removeDefaultRoute() {
168         if (mInterfaceName != null && mDefaultRouteSet == true) {
169             if (DBG) {
170                 Log.d(TAG, "removeDefaultRoute for " + mNetworkInfo.getTypeName() + " (" +
171                         mInterfaceName + ")");
172             }
173             NetworkUtils.removeDefaultRoute(mInterfaceName);
174             mDefaultRouteSet = false;
175         }
176     }
177 
178     /**
179      * Reads the network specific TCP buffer sizes from SystemProperties
180      * net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system
181      * wide use
182      */
updateNetworkSettings()183    public void updateNetworkSettings() {
184         String key = getTcpBufferSizesPropName();
185         String bufferSizes = SystemProperties.get(key);
186 
187         if (bufferSizes.length() == 0) {
188             Log.e(TAG, key + " not found in system properties. Using defaults");
189 
190             // Setting to default values so we won't be stuck to previous values
191             key = "net.tcp.buffersize.default";
192             bufferSizes = SystemProperties.get(key);
193         }
194 
195         // Set values in kernel
196         if (bufferSizes.length() != 0) {
197             if (DBG) {
198                 Log.v(TAG, "Setting TCP values: [" + bufferSizes
199                         + "] which comes from [" + key + "]");
200             }
201             setBufferSize(bufferSizes);
202         }
203     }
204 
205     /**
206      * Release the wakelock, if any, that may be held while handling a
207      * disconnect operation.
208      */
releaseWakeLock()209     public void releaseWakeLock() {
210     }
211 
212     /**
213      * Writes TCP buffer sizes to /sys/kernel/ipv4/tcp_[r/w]mem_[min/def/max]
214      * which maps to /proc/sys/net/ipv4/tcp_rmem and tcpwmem
215      *
216      * @param bufferSizes in the format of "readMin, readInitial, readMax,
217      *        writeMin, writeInitial, writeMax"
218      */
setBufferSize(String bufferSizes)219     private void setBufferSize(String bufferSizes) {
220         try {
221             String[] values = bufferSizes.split(",");
222 
223             if (values.length == 6) {
224               final String prefix = "/sys/kernel/ipv4/tcp_";
225                 stringToFile(prefix + "rmem_min", values[0]);
226                 stringToFile(prefix + "rmem_def", values[1]);
227                 stringToFile(prefix + "rmem_max", values[2]);
228                 stringToFile(prefix + "wmem_min", values[3]);
229                 stringToFile(prefix + "wmem_def", values[4]);
230                 stringToFile(prefix + "wmem_max", values[5]);
231             } else {
232                 Log.e(TAG, "Invalid buffersize string: " + bufferSizes);
233             }
234         } catch (IOException e) {
235             Log.e(TAG, "Can't set tcp buffer sizes:" + e);
236         }
237     }
238 
239     /**
240      * Writes string to file. Basically same as "echo -n $string > $filename"
241      *
242      * @param filename
243      * @param string
244      * @throws IOException
245      */
stringToFile(String filename, String string)246     private void stringToFile(String filename, String string) throws IOException {
247         FileWriter out = new FileWriter(filename);
248         try {
249             out.write(string);
250         } finally {
251             out.close();
252         }
253     }
254 
255     /**
256      * Record the detailed state of a network, and if it is a
257      * change from the previous state, send a notification to
258      * any listeners.
259      * @param state the new @{code DetailedState}
260      */
setDetailedState(NetworkInfo.DetailedState state)261     public void setDetailedState(NetworkInfo.DetailedState state) {
262         setDetailedState(state, null, null);
263     }
264 
265     /**
266      * Record the detailed state of a network, and if it is a
267      * change from the previous state, send a notification to
268      * any listeners.
269      * @param state the new @{code DetailedState}
270      * @param reason a {@code String} indicating a reason for the state change,
271      * if one was supplied. May be {@code null}.
272      * @param extraInfo optional {@code String} providing extra information about the state change
273      */
setDetailedState(NetworkInfo.DetailedState state, String reason, String extraInfo)274     public void setDetailedState(NetworkInfo.DetailedState state, String reason, String extraInfo) {
275         if (DBG) Log.d(TAG, "setDetailed state, old ="+mNetworkInfo.getDetailedState()+" and new state="+state);
276         if (state != mNetworkInfo.getDetailedState()) {
277             boolean wasConnecting = (mNetworkInfo.getState() == NetworkInfo.State.CONNECTING);
278             String lastReason = mNetworkInfo.getReason();
279             /*
280              * If a reason was supplied when the CONNECTING state was entered, and no
281              * reason was supplied for entering the CONNECTED state, then retain the
282              * reason that was supplied when going to CONNECTING.
283              */
284             if (wasConnecting && state == NetworkInfo.DetailedState.CONNECTED && reason == null
285                     && lastReason != null)
286                 reason = lastReason;
287             mNetworkInfo.setDetailedState(state, reason, extraInfo);
288             Message msg = mTarget.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
289             msg.sendToTarget();
290         }
291     }
292 
setDetailedStateInternal(NetworkInfo.DetailedState state)293     protected void setDetailedStateInternal(NetworkInfo.DetailedState state) {
294         mNetworkInfo.setDetailedState(state, null, null);
295     }
296 
setTeardownRequested(boolean isRequested)297     public void setTeardownRequested(boolean isRequested) {
298         mTeardownRequested = isRequested;
299     }
300 
isTeardownRequested()301     public boolean isTeardownRequested() {
302         return mTeardownRequested;
303     }
304 
305     /**
306      * Send a  notification that the results of a scan for network access
307      * points has completed, and results are available.
308      */
sendScanResultsAvailable()309     protected void sendScanResultsAvailable() {
310         Message msg = mTarget.obtainMessage(EVENT_SCAN_RESULTS_AVAILABLE, mNetworkInfo);
311         msg.sendToTarget();
312     }
313 
314     /**
315      * Record the roaming status of the device, and if it is a change from the previous
316      * status, send a notification to any listeners.
317      * @param isRoaming {@code true} if the device is now roaming, {@code false}
318      * if it is no longer roaming.
319      */
setRoamingStatus(boolean isRoaming)320     protected void setRoamingStatus(boolean isRoaming) {
321         if (isRoaming != mNetworkInfo.isRoaming()) {
322             mNetworkInfo.setRoaming(isRoaming);
323             Message msg = mTarget.obtainMessage(EVENT_ROAMING_CHANGED, mNetworkInfo);
324             msg.sendToTarget();
325         }
326     }
327 
setSubtype(int subtype, String subtypeName)328     protected void setSubtype(int subtype, String subtypeName) {
329         if (mNetworkInfo.isConnected()) {
330             int oldSubtype = mNetworkInfo.getSubtype();
331             if (subtype != oldSubtype) {
332                 mNetworkInfo.setSubtype(subtype, subtypeName);
333                 Message msg = mTarget.obtainMessage(
334                         EVENT_NETWORK_SUBTYPE_CHANGED, oldSubtype, 0, mNetworkInfo);
335                 msg.sendToTarget();
336             }
337         }
338     }
339 
startMonitoring()340     public abstract void startMonitoring();
341 
342     /**
343      * Disable connectivity to a network
344      * @return {@code true} if a teardown occurred, {@code false} if the
345      * teardown did not occur.
346      */
teardown()347     public abstract boolean teardown();
348 
349     /**
350      * Reenable connectivity to a network after a {@link #teardown()}.
351      */
reconnect()352     public abstract boolean reconnect();
353 
354     /**
355      * Turn the wireless radio off for a network.
356      * @param turnOn {@code true} to turn the radio on, {@code false}
357      */
setRadio(boolean turnOn)358     public abstract boolean setRadio(boolean turnOn);
359 
360     /**
361      * Returns an indication of whether this network is available for
362      * connections. A value of {@code false} means that some quasi-permanent
363      * condition prevents connectivity to this network.
364      */
isAvailable()365     public abstract boolean isAvailable();
366 
367     /**
368      * Tells the underlying networking system that the caller wants to
369      * begin using the named feature. The interpretation of {@code feature}
370      * is completely up to each networking implementation.
371      * @param feature the name of the feature to be used
372      * @param callingPid the process ID of the process that is issuing this request
373      * @param callingUid the user ID of the process that is issuing this request
374      * @return an integer value representing the outcome of the request.
375      * The interpretation of this value is specific to each networking
376      * implementation+feature combination, except that the value {@code -1}
377      * always indicates failure.
378      */
startUsingNetworkFeature(String feature, int callingPid, int callingUid)379     public abstract int startUsingNetworkFeature(String feature, int callingPid, int callingUid);
380 
381     /**
382      * Tells the underlying networking system that the caller is finished
383      * using the named feature. The interpretation of {@code feature}
384      * is completely up to each networking implementation.
385      * @param feature the name of the feature that is no longer needed.
386      * @param callingPid the process ID of the process that is issuing this request
387      * @param callingUid the user ID of the process that is issuing this request
388      * @return an integer value representing the outcome of the request.
389      * The interpretation of this value is specific to each networking
390      * implementation+feature combination, except that the value {@code -1}
391      * always indicates failure.
392      */
stopUsingNetworkFeature(String feature, int callingPid, int callingUid)393     public abstract int stopUsingNetworkFeature(String feature, int callingPid, int callingUid);
394 
395     /**
396      * Ensure that a network route exists to deliver traffic to the specified
397      * host via this network interface.
398      * @param hostAddress the IP address of the host to which the route is desired
399      * @return {@code true} on success, {@code false} on failure
400      */
requestRouteToHost(int hostAddress)401     public boolean requestRouteToHost(int hostAddress) {
402         return false;
403     }
404 
405     /**
406      * Interprets scan results. This will be called at a safe time for
407      * processing, and from a safe thread.
408      */
interpretScanResultsAvailable()409     public void interpretScanResultsAvailable() {
410     }
411 
412 }
413