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