EthernetDataTracker.java revision 1997069436f0d47583a0b700c12ed63132cf3312
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 mIface = "";
67
68    private static class InterfaceObserver extends INetworkManagementEventObserver.Stub {
69        private EthernetDataTracker mTracker;
70
71        InterfaceObserver(EthernetDataTracker tracker) {
72            super();
73            mTracker = tracker;
74        }
75
76        public void interfaceLinkStatusChanged(String iface, boolean up) {
77            Log.d(TAG, "Interface " + iface + " link " + (up ? "up" : "down"));
78        }
79
80        public void interfaceAdded(String iface) {
81            mTracker.interfaceAdded(iface);
82        }
83
84        public void interfaceRemoved(String iface) {
85            mTracker.interfaceRemoved(iface);
86        }
87    }
88
89    private EthernetDataTracker() {
90        mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORKTYPE, "");
91        mLinkProperties = new LinkProperties();
92        mLinkCapabilities = new LinkCapabilities();
93
94        mNetworkInfo.setIsAvailable(false);
95        setTeardownRequested(false);
96    }
97
98    private void interfaceAdded(String iface) {
99        if (!iface.matches("eth\\d"))
100            return;
101
102        Log.d(TAG, "Adding " + iface);
103
104        synchronized(mIface) {
105            if(!mIface.isEmpty())
106                return;
107            mIface = iface;
108        }
109
110        mNetworkInfo.setIsAvailable(true);
111        Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
112        msg.sendToTarget();
113
114        runDhcp();
115    }
116
117    private void interfaceRemoved(String iface) {
118        if (!iface.equals(mIface))
119            return;
120
121        Log.d(TAG, "Removing " + iface);
122
123        NetworkUtils.stopDhcp(mIface);
124
125        mLinkProperties.clear();
126        mNetworkInfo.setIsAvailable(false);
127        mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
128
129        Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
130        msg.sendToTarget();
131
132        msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
133        msg.sendToTarget();
134
135        mIface = "";
136    }
137
138    private void runDhcp() {
139        Thread dhcpThread = new Thread(new Runnable() {
140            public void run() {
141                DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal();
142                if (!NetworkUtils.runDhcp(mIface, dhcpInfoInternal)) {
143                    Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError());
144                    return;
145                }
146                mLinkProperties = dhcpInfoInternal.makeLinkProperties();
147                mLinkProperties.setInterfaceName(mIface);
148
149                mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
150                Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
151                msg.sendToTarget();
152            }
153        });
154        dhcpThread.start();
155    }
156
157    public static synchronized EthernetDataTracker getInstance() {
158        if (sInstance == null) sInstance = new EthernetDataTracker();
159        return sInstance;
160    }
161
162    public Object Clone() throws CloneNotSupportedException {
163        throw new CloneNotSupportedException();
164    }
165
166    public void setTeardownRequested(boolean isRequested) {
167        mTeardownRequested.set(isRequested);
168    }
169
170    public boolean isTeardownRequested() {
171        return mTeardownRequested.get();
172    }
173
174    /**
175     * Begin monitoring connectivity
176     */
177    public void startMonitoring(Context context, Handler target) {
178        mContext = context;
179        mCsHandler = target;
180
181        // register for notifications from NetworkManagement Service
182        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
183        INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
184        mInterfaceObserver = new InterfaceObserver(this);
185        try {
186            service.registerObserver(mInterfaceObserver);
187        } catch (RemoteException e) {
188            Log.e(TAG, "Could not register InterfaceObserver " + e);
189        }
190    }
191
192    /**
193     * Disable connectivity to a network
194     * TODO: do away with return value after making MobileDataStateTracker async
195     */
196    public boolean teardown() {
197        mTeardownRequested.set(true);
198        NetworkUtils.stopDhcp(mIface);
199        return true;
200    }
201
202    /**
203     * Re-enable connectivity to a network after a {@link #teardown()}.
204     */
205    public boolean reconnect() {
206        mTeardownRequested.set(false);
207        runDhcp();
208        return true;
209    }
210
211    /**
212     * Turn the wireless radio off for a network.
213     * @param turnOn {@code true} to turn the radio on, {@code false}
214     */
215    public boolean setRadio(boolean turnOn) {
216        return true;
217    }
218
219    /**
220     * @return true - If are we currently tethered with another device.
221     */
222    public synchronized boolean isAvailable() {
223        return mNetworkInfo.isAvailable();
224    }
225
226    /**
227     * Tells the underlying networking system that the caller wants to
228     * begin using the named feature. The interpretation of {@code feature}
229     * is completely up to each networking implementation.
230     * @param feature the name of the feature to be used
231     * @param callingPid the process ID of the process that is issuing this request
232     * @param callingUid the user ID of the process that is issuing this request
233     * @return an integer value representing the outcome of the request.
234     * The interpretation of this value is specific to each networking
235     * implementation+feature combination, except that the value {@code -1}
236     * always indicates failure.
237     * TODO: needs to go away
238     */
239    public int startUsingNetworkFeature(String feature, int callingPid, int callingUid) {
240        return -1;
241    }
242
243    /**
244     * Tells the underlying networking system that the caller is finished
245     * 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 that is no longer needed.
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 stopUsingNetworkFeature(String feature, int callingPid, int callingUid) {
257        return -1;
258    }
259
260    /**
261     * @param enabled
262     */
263    public void setDataEnable(boolean enabled) {
264        Log.d(TAG, "setDataEnabled: IGNORING enabled=" + enabled);
265    }
266
267    /**
268     * Check if private DNS route is set for the network
269     */
270    public boolean isPrivateDnsRouteSet() {
271        return mPrivateDnsRouteSet.get();
272    }
273
274    /**
275     * Set a flag indicating private DNS route is set
276     */
277    public void privateDnsRouteSet(boolean enabled) {
278        mPrivateDnsRouteSet.set(enabled);
279    }
280
281    /**
282     * Fetch NetworkInfo for the network
283     */
284    public synchronized NetworkInfo getNetworkInfo() {
285        return mNetworkInfo;
286    }
287
288    /**
289     * Fetch LinkProperties for the network
290     */
291    public synchronized LinkProperties getLinkProperties() {
292        return new LinkProperties(mLinkProperties);
293    }
294
295   /**
296     * A capability is an Integer/String pair, the capabilities
297     * are defined in the class LinkSocket#Key.
298     *
299     * @return a copy of this connections capabilities, may be empty but never null.
300     */
301    public LinkCapabilities getLinkCapabilities() {
302        return new LinkCapabilities(mLinkCapabilities);
303    }
304
305    /**
306     * Fetch default gateway address for the network
307     */
308    public int getDefaultGatewayAddr() {
309        return mDefaultGatewayAddr.get();
310    }
311
312    /**
313     * Check if default route is set
314     */
315    public boolean isDefaultRouteSet() {
316        return mDefaultRouteSet.get();
317    }
318
319    /**
320     * Set a flag indicating default route is set for the network
321     */
322    public void defaultRouteSet(boolean enabled) {
323        mDefaultRouteSet.set(enabled);
324    }
325
326    /**
327     * Return the system properties name associated with the tcp buffer sizes
328     * for this network.
329     */
330    public String getTcpBufferSizesPropName() {
331        return "net.tcp.buffersize.wifi";
332    }
333}
334