EthernetDataTracker.java revision c96a667162fab44a250503caccb770109a9cb69a
1/*
2 * Copyright (C) 2010 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.net.ConnectivityManager;
21import android.net.DhcpInfoInternal;
22import android.net.LinkAddress;
23import android.net.LinkCapabilities;
24import android.net.LinkProperties;
25import android.net.NetworkInfo;
26import android.net.NetworkInfo.DetailedState;
27import android.net.NetworkStateTracker;
28import android.net.NetworkUtils;
29import android.os.Handler;
30import android.os.IBinder;
31import android.os.INetworkManagementService;
32import android.os.Message;
33import android.os.RemoteException;
34import android.os.ServiceManager;
35import android.util.Log;
36
37import java.net.InetAddress;
38import java.util.concurrent.atomic.AtomicBoolean;
39import java.util.concurrent.atomic.AtomicInteger;
40
41/**
42 * This class tracks the data connection associated with Ethernet
43 * This is a singleton class and an instance will be created by
44 * ConnectivityService.
45 * @hide
46 */
47public class EthernetDataTracker implements NetworkStateTracker {
48    private static final String NETWORKTYPE = "ETHERNET";
49    private static final String TAG = "Ethernet";
50
51    private AtomicBoolean mTeardownRequested = new AtomicBoolean(false);
52    private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false);
53    private AtomicInteger mDefaultGatewayAddr = new AtomicInteger(0);
54    private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false);
55
56    private LinkProperties mLinkProperties;
57    private LinkCapabilities mLinkCapabilities;
58    private NetworkInfo mNetworkInfo;
59    private InterfaceObserver mInterfaceObserver;
60
61    /* For sending events to connectivity service handler */
62    private Handler mCsHandler;
63    private Context mContext;
64
65    private static EthernetDataTracker sInstance;
66    private static String sIfaceMatch = "";
67    private static String mIface = "";
68
69    private static class InterfaceObserver extends INetworkManagementEventObserver.Stub {
70        private EthernetDataTracker mTracker;
71
72        InterfaceObserver(EthernetDataTracker tracker) {
73            super();
74            mTracker = tracker;
75        }
76
77        public void interfaceLinkStatusChanged(String iface, boolean up) {
78            Log.d(TAG, "Interface " + iface + " link " + (up ? "up" : "down"));
79        }
80
81        public void interfaceAdded(String iface) {
82            mTracker.interfaceAdded(iface);
83        }
84
85        public void interfaceRemoved(String iface) {
86            mTracker.interfaceRemoved(iface);
87        }
88    }
89
90    private EthernetDataTracker() {
91        mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORKTYPE, "");
92        mLinkProperties = new LinkProperties();
93        mLinkCapabilities = new LinkCapabilities();
94
95        mNetworkInfo.setIsAvailable(false);
96        setTeardownRequested(false);
97    }
98
99    private void interfaceAdded(String iface) {
100        if (!iface.matches(sIfaceMatch))
101            return;
102
103        Log.d(TAG, "Adding " + iface);
104
105        synchronized(mIface) {
106            if(!mIface.isEmpty())
107                return;
108            mIface = iface;
109        }
110
111        mNetworkInfo.setIsAvailable(true);
112        Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
113        msg.sendToTarget();
114
115        runDhcp();
116    }
117
118    private void interfaceRemoved(String iface) {
119        if (!iface.equals(mIface))
120            return;
121
122        Log.d(TAG, "Removing " + iface);
123
124        NetworkUtils.stopDhcp(mIface);
125
126        mLinkProperties.clear();
127        mNetworkInfo.setIsAvailable(false);
128        mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
129
130        Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
131        msg.sendToTarget();
132
133        msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
134        msg.sendToTarget();
135
136        mIface = "";
137    }
138
139    private void runDhcp() {
140        Thread dhcpThread = new Thread(new Runnable() {
141            public void run() {
142                DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal();
143                if (!NetworkUtils.runDhcp(mIface, dhcpInfoInternal)) {
144                    Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError());
145                    return;
146                }
147                mLinkProperties = dhcpInfoInternal.makeLinkProperties();
148                mLinkProperties.setInterfaceName(mIface);
149
150                mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
151                Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
152                msg.sendToTarget();
153            }
154        });
155        dhcpThread.start();
156    }
157
158    public static synchronized EthernetDataTracker getInstance() {
159        if (sInstance == null) sInstance = new EthernetDataTracker();
160        return sInstance;
161    }
162
163    public Object Clone() throws CloneNotSupportedException {
164        throw new CloneNotSupportedException();
165    }
166
167    public void setTeardownRequested(boolean isRequested) {
168        mTeardownRequested.set(isRequested);
169    }
170
171    public boolean isTeardownRequested() {
172        return mTeardownRequested.get();
173    }
174
175    /**
176     * Begin monitoring connectivity
177     */
178    public void startMonitoring(Context context, Handler target) {
179        mContext = context;
180        mCsHandler = target;
181
182        // register for notifications from NetworkManagement Service
183        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
184        INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
185        mInterfaceObserver = new InterfaceObserver(this);
186        try {
187            service.registerObserver(mInterfaceObserver);
188        } catch (RemoteException e) {
189            Log.e(TAG, "Could not register InterfaceObserver " + e);
190        }
191
192        // connect to an ethernet interface that already exists
193        sIfaceMatch = context.getResources().getString(
194            com.android.internal.R.string.config_ethernet_iface_regex);
195        try {
196            final String[] ifaces = service.listInterfaces();
197            for (String iface : ifaces) {
198                if (iface.matches(sIfaceMatch)) {
199                    mIface = iface;
200                    reconnect();
201                    break;
202                }
203            }
204        } catch (RemoteException e) {
205            Log.e(TAG, "Could not get list of interfaces " + e);
206        }
207    }
208
209    /**
210     * Disable connectivity to a network
211     * TODO: do away with return value after making MobileDataStateTracker async
212     */
213    public boolean teardown() {
214        mTeardownRequested.set(true);
215        NetworkUtils.stopDhcp(mIface);
216        return true;
217    }
218
219    /**
220     * Re-enable connectivity to a network after a {@link #teardown()}.
221     */
222    public boolean reconnect() {
223        mTeardownRequested.set(false);
224        runDhcp();
225        return true;
226    }
227
228    /**
229     * Turn the wireless radio off for a network.
230     * @param turnOn {@code true} to turn the radio on, {@code false}
231     */
232    public boolean setRadio(boolean turnOn) {
233        return true;
234    }
235
236    /**
237     * @return true - If are we currently tethered with another device.
238     */
239    public synchronized boolean isAvailable() {
240        return mNetworkInfo.isAvailable();
241    }
242
243    /**
244     * Tells the underlying networking system that the caller wants to
245     * begin using the named feature. The interpretation of {@code feature}
246     * is completely up to each networking implementation.
247     * @param feature the name of the feature to be used
248     * @param callingPid the process ID of the process that is issuing this request
249     * @param callingUid the user ID of the process that is issuing this request
250     * @return an integer value representing the outcome of the request.
251     * The interpretation of this value is specific to each networking
252     * implementation+feature combination, except that the value {@code -1}
253     * always indicates failure.
254     * TODO: needs to go away
255     */
256    public int startUsingNetworkFeature(String feature, int callingPid, int callingUid) {
257        return -1;
258    }
259
260    /**
261     * Tells the underlying networking system that the caller is finished
262     * using the named feature. The interpretation of {@code feature}
263     * is completely up to each networking implementation.
264     * @param feature the name of the feature that is no longer needed.
265     * @param callingPid the process ID of the process that is issuing this request
266     * @param callingUid the user ID of the process that is issuing this request
267     * @return an integer value representing the outcome of the request.
268     * The interpretation of this value is specific to each networking
269     * implementation+feature combination, except that the value {@code -1}
270     * always indicates failure.
271     * TODO: needs to go away
272     */
273    public int stopUsingNetworkFeature(String feature, int callingPid, int callingUid) {
274        return -1;
275    }
276
277    /**
278     * @param enabled
279     */
280    public void setDataEnable(boolean enabled) {
281        Log.d(TAG, "setDataEnabled: IGNORING enabled=" + enabled);
282    }
283
284    /**
285     * Check if private DNS route is set for the network
286     */
287    public boolean isPrivateDnsRouteSet() {
288        return mPrivateDnsRouteSet.get();
289    }
290
291    /**
292     * Set a flag indicating private DNS route is set
293     */
294    public void privateDnsRouteSet(boolean enabled) {
295        mPrivateDnsRouteSet.set(enabled);
296    }
297
298    /**
299     * Fetch NetworkInfo for the network
300     */
301    public synchronized NetworkInfo getNetworkInfo() {
302        return mNetworkInfo;
303    }
304
305    /**
306     * Fetch LinkProperties for the network
307     */
308    public synchronized LinkProperties getLinkProperties() {
309        return new LinkProperties(mLinkProperties);
310    }
311
312   /**
313     * A capability is an Integer/String pair, the capabilities
314     * are defined in the class LinkSocket#Key.
315     *
316     * @return a copy of this connections capabilities, may be empty but never null.
317     */
318    public LinkCapabilities getLinkCapabilities() {
319        return new LinkCapabilities(mLinkCapabilities);
320    }
321
322    /**
323     * Fetch default gateway address for the network
324     */
325    public int getDefaultGatewayAddr() {
326        return mDefaultGatewayAddr.get();
327    }
328
329    /**
330     * Check if default route is set
331     */
332    public boolean isDefaultRouteSet() {
333        return mDefaultRouteSet.get();
334    }
335
336    /**
337     * Set a flag indicating default route is set for the network
338     */
339    public void defaultRouteSet(boolean enabled) {
340        mDefaultRouteSet.set(enabled);
341    }
342
343    /**
344     * Return the system properties name associated with the tcp buffer sizes
345     * for this network.
346     */
347    public String getTcpBufferSizesPropName() {
348        return "net.tcp.buffersize.wifi";
349    }
350
351    public void setDependencyMet(boolean met) {
352        // not supported on this network
353    }
354}
355