Tethering.java revision 94260caf2fb3f5dbf6e17b29a269b46ea05f8680
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 com.android.server.connectivity;
18
19import android.app.Notification;
20import android.app.NotificationManager;
21import android.app.PendingIntent;
22import android.content.BroadcastReceiver;
23import android.content.ContentResolver;
24import android.content.Context;
25import android.content.Intent;
26import android.content.IntentFilter;
27import android.content.pm.PackageManager;
28import android.content.res.Resources;
29import android.hardware.usb.UsbManager;
30import android.net.ConnectivityManager;
31import android.net.InterfaceConfiguration;
32import android.net.IConnectivityManager;
33import android.net.INetworkManagementEventObserver;
34import android.net.NetworkInfo;
35import android.net.NetworkUtils;
36import android.os.Binder;
37import android.os.Environment;
38import android.os.Handler;
39import android.os.HandlerThread;
40import android.os.IBinder;
41import android.os.INetworkManagementService;
42import android.os.Looper;
43import android.os.Message;
44import android.os.RemoteException;
45import android.os.ServiceManager;
46import android.provider.Settings;
47import android.util.Log;
48
49import com.android.internal.telephony.Phone;
50import com.android.internal.util.HierarchicalState;
51import com.android.internal.util.HierarchicalStateMachine;
52
53import java.io.FileDescriptor;
54import java.io.PrintWriter;
55import java.util.ArrayList;
56import java.util.HashMap;
57import java.util.Set;
58/**
59 * @hide
60 *
61 * Timeout
62 *
63 * TODO - look for parent classes and code sharing
64 */
65
66public class Tethering extends INetworkManagementEventObserver.Stub {
67
68    private Context mContext;
69    private final String TAG = "Tethering";
70
71    private boolean mBooted = false;
72    //used to remember if we got connected before boot finished
73    private boolean mDeferedUsbConnection = false;
74
75    // TODO - remove both of these - should be part of interface inspection/selection stuff
76    private String[] mTetherableUsbRegexs;
77    private String[] mTetherableWifiRegexs;
78    private String[] mUpstreamIfaceRegexs;
79
80    private Looper mLooper;
81    private HandlerThread mThread;
82
83    private HashMap<String, TetherInterfaceSM> mIfaces; // all tethered/tetherable ifaces
84
85    private BroadcastReceiver mStateReceiver;
86
87    private static final String USB_NEAR_IFACE_ADDR      = "192.168.42.129";
88    private static final String USB_NETMASK              = "255.255.255.0";
89
90    // FYI - the default wifi is 192.168.43.1 and 255.255.255.0
91
92    private String[] mDhcpRange;
93    private static final String DHCP_DEFAULT_RANGE1_START = "192.168.42.2";
94    private static final String DHCP_DEFAULT_RANGE1_STOP  = "192.168.42.254";
95    private static final String DHCP_DEFAULT_RANGE2_START = "192.168.43.2";
96    private static final String DHCP_DEFAULT_RANGE2_STOP  = "192.168.43.254";
97
98    private String[] mDnsServers;
99    private static final String DNS_DEFAULT_SERVER1 = "8.8.8.8";
100    private static final String DNS_DEFAULT_SERVER2 = "4.2.2.2";
101
102    // resampled each time we turn on tethering - used as cache for settings/config-val
103    private boolean mDunRequired;  // configuration info - must use DUN apn on 3g
104
105    private HierarchicalStateMachine mTetherMasterSM;
106
107    private Notification mTetheredNotification;
108
109    // whether we can tether is the && of these two - they come in as separate
110    // broadcasts so track them so we can decide what to do when either changes
111    private boolean mUsbMassStorageOff;  // track the status of USB Mass Storage
112    private boolean mUsbConnected;       // track the status of USB connection
113
114    public Tethering(Context context, Looper looper) {
115        mContext = context;
116        mLooper = looper;
117
118        // register for notifications from NetworkManagement Service
119        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
120        INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
121        try {
122            service.registerObserver(this);
123        } catch (RemoteException e) {
124            Log.e(TAG, "Error registering observer :" + e);
125        }
126
127        mIfaces = new HashMap<String, TetherInterfaceSM>();
128
129        // make our own thread so we don't anr the system
130        mThread = new HandlerThread("Tethering");
131        mThread.start();
132        mLooper = mThread.getLooper();
133        mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper);
134        mTetherMasterSM.start();
135
136        mStateReceiver = new StateReceiver();
137        IntentFilter filter = new IntentFilter();
138        filter.addAction(UsbManager.ACTION_USB_STATE);
139        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
140        filter.addAction(Intent.ACTION_BOOT_COMPLETED);
141        mContext.registerReceiver(mStateReceiver, filter);
142
143        filter = new IntentFilter();
144        filter.addAction(Intent.ACTION_MEDIA_SHARED);
145        filter.addAction(Intent.ACTION_MEDIA_UNSHARED);
146        filter.addDataScheme("file");
147        mContext.registerReceiver(mStateReceiver, filter);
148
149        mUsbMassStorageOff = !Environment.MEDIA_SHARED.equals(
150                Environment.getExternalStorageState());
151
152        mDhcpRange = context.getResources().getStringArray(
153                com.android.internal.R.array.config_tether_dhcp_range);
154        if ((mDhcpRange.length == 0) || (mDhcpRange.length % 2 ==1)) {
155            mDhcpRange = new String[4];
156            mDhcpRange[0] = DHCP_DEFAULT_RANGE1_START;
157            mDhcpRange[1] = DHCP_DEFAULT_RANGE1_STOP;
158            mDhcpRange[2] = DHCP_DEFAULT_RANGE2_START;
159            mDhcpRange[3] = DHCP_DEFAULT_RANGE2_STOP;
160        }
161        mDunRequired = false; // resample when we turn on
162
163        mTetherableUsbRegexs = context.getResources().getStringArray(
164                com.android.internal.R.array.config_tether_usb_regexs);
165        mTetherableWifiRegexs = context.getResources().getStringArray(
166                com.android.internal.R.array.config_tether_wifi_regexs);
167        mUpstreamIfaceRegexs = context.getResources().getStringArray(
168                com.android.internal.R.array.config_tether_upstream_regexs);
169
170        // TODO - remove and rely on real notifications of the current iface
171        mDnsServers = new String[2];
172        mDnsServers[0] = DNS_DEFAULT_SERVER1;
173        mDnsServers[1] = DNS_DEFAULT_SERVER2;
174    }
175
176    public void interfaceLinkStatusChanged(String iface, boolean link) {
177        Log.d(TAG, "interfaceLinkStatusChanged " + iface + ", " + link);
178        boolean found = false;
179        boolean usb = false;
180        if (isWifi(iface)) {
181            found = true;
182        } else if (isUsb(iface)) {
183            found = true;
184            usb = true;
185        }
186        if (found == false) return;
187
188        synchronized (mIfaces) {
189            TetherInterfaceSM sm = mIfaces.get(iface);
190            if (link) {
191                if (sm == null) {
192                    sm = new TetherInterfaceSM(iface, mLooper, usb);
193                    mIfaces.put(iface, sm);
194                    sm.start();
195                }
196            } else {
197                if (sm != null) {
198                    sm.sendMessage(TetherInterfaceSM.CMD_INTERFACE_DOWN);
199                    mIfaces.remove(iface);
200                }
201            }
202        }
203    }
204
205    private boolean isUsb(String iface) {
206        for (String regex : mTetherableUsbRegexs) {
207            if (iface.matches(regex)) return true;
208        }
209        return false;
210    }
211
212    public boolean isWifi(String iface) {
213        for (String regex : mTetherableWifiRegexs) {
214            if (iface.matches(regex)) return true;
215        }
216        return false;
217    }
218
219    public void interfaceAdded(String iface) {
220        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
221        INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
222        boolean found = false;
223        boolean usb = false;
224        if (isWifi(iface)) {
225            found = true;
226        }
227        if (isUsb(iface)) {
228            found = true;
229            usb = true;
230        }
231        if (found == false) {
232            Log.d(TAG, iface + " is not a tetherable iface, ignoring");
233            return;
234        }
235
236        synchronized (mIfaces) {
237            TetherInterfaceSM sm = mIfaces.get(iface);
238            if (sm != null) {
239                Log.e(TAG, "active iface (" + iface + ") reported as added, ignoring");
240                return;
241            }
242            sm = new TetherInterfaceSM(iface, mLooper, usb);
243            mIfaces.put(iface, sm);
244            sm.start();
245        }
246        Log.d(TAG, "interfaceAdded :" + iface);
247    }
248
249    public void interfaceRemoved(String iface) {
250        synchronized (mIfaces) {
251            TetherInterfaceSM sm = mIfaces.get(iface);
252            if (sm == null) {
253                Log.e(TAG, "attempting to remove unknown iface (" + iface + "), ignoring");
254                return;
255            }
256            sm.sendMessage(TetherInterfaceSM.CMD_INTERFACE_DOWN);
257            mIfaces.remove(iface);
258        }
259    }
260
261    public int tether(String iface) {
262        Log.d(TAG, "Tethering " + iface);
263        TetherInterfaceSM sm = null;
264        synchronized (mIfaces) {
265            sm = mIfaces.get(iface);
266        }
267        if (sm == null) {
268            Log.e(TAG, "Tried to Tether an unknown iface :" + iface + ", ignoring");
269            return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
270        }
271        if (!sm.isAvailable() && !sm.isErrored()) {
272            Log.e(TAG, "Tried to Tether an unavailable iface :" + iface + ", ignoring");
273            return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
274        }
275        sm.sendMessage(TetherInterfaceSM.CMD_TETHER_REQUESTED);
276        return ConnectivityManager.TETHER_ERROR_NO_ERROR;
277    }
278
279    public int untether(String iface) {
280        Log.d(TAG, "Untethering " + iface);
281        TetherInterfaceSM sm = null;
282        synchronized (mIfaces) {
283            sm = mIfaces.get(iface);
284        }
285        if (sm == null) {
286            Log.e(TAG, "Tried to Untether an unknown iface :" + iface + ", ignoring");
287            return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
288        }
289        if (sm.isErrored()) {
290            Log.e(TAG, "Tried to Untethered an errored iface :" + iface + ", ignoring");
291            return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
292        }
293        sm.sendMessage(TetherInterfaceSM.CMD_TETHER_UNREQUESTED);
294        return ConnectivityManager.TETHER_ERROR_NO_ERROR;
295    }
296
297    public int getLastTetherError(String iface) {
298        TetherInterfaceSM sm = null;
299        synchronized (mIfaces) {
300            sm = mIfaces.get(iface);
301        }
302        if (sm == null) {
303            Log.e(TAG, "Tried to getLastTetherError on an unknown iface :" + iface + ", ignoring");
304            return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
305        }
306        return sm.getLastError();
307    }
308
309    private void sendTetherStateChangedBroadcast() {
310        IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
311        IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
312        try {
313            if (!service.isTetheringSupported()) return;
314        } catch (RemoteException e) {
315            return;
316        }
317
318        ArrayList<String> availableList = new ArrayList<String>();
319        ArrayList<String> activeList = new ArrayList<String>();
320        ArrayList<String> erroredList = new ArrayList<String>();
321
322        boolean wifiTethered = false;
323        boolean usbTethered = false;
324
325        synchronized (mIfaces) {
326            Set ifaces = mIfaces.keySet();
327            for (Object iface : ifaces) {
328                TetherInterfaceSM sm = mIfaces.get(iface);
329                if (sm != null) {
330                    if(sm.isErrored()) {
331                        erroredList.add((String)iface);
332                    } else if (sm.isAvailable()) {
333                        availableList.add((String)iface);
334                    } else if (sm.isTethered()) {
335                        if (isUsb((String)iface)) {
336                            usbTethered = true;
337                        } else if (isWifi((String)iface)) {
338                            wifiTethered = true;
339                        }
340                        activeList.add((String)iface);
341                    }
342                }
343            }
344        }
345        Intent broadcast = new Intent(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
346        broadcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
347        broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_AVAILABLE_TETHER,
348                availableList);
349        broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_TETHER, activeList);
350        broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ERRORED_TETHER,
351                erroredList);
352        mContext.sendStickyBroadcast(broadcast);
353        Log.d(TAG, "sendTetherStateChangedBroadcast " + availableList.size() + ", " +
354                activeList.size() + ", " + erroredList.size());
355
356        if (usbTethered) {
357            if (wifiTethered) {
358                showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_general);
359            } else {
360                showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_usb);
361            }
362        } else if (wifiTethered) {
363            showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_wifi);
364        } else {
365            clearTetheredNotification();
366        }
367    }
368
369    private void showTetheredNotification(int icon) {
370        NotificationManager notificationManager =
371                (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE);
372        if (notificationManager == null) {
373            return;
374        }
375
376        if (mTetheredNotification != null) {
377            if (mTetheredNotification.icon == icon) {
378                return;
379            }
380            notificationManager.cancel(mTetheredNotification.icon);
381        }
382
383        Intent intent = new Intent();
384        intent.setClassName("com.android.settings", "com.android.settings.TetherSettings");
385        intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
386
387        PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
388
389        Resources r = Resources.getSystem();
390        CharSequence title = r.getText(com.android.internal.R.string.tethered_notification_title);
391        CharSequence message = r.getText(com.android.internal.R.string.
392                tethered_notification_message);
393
394        if(mTetheredNotification == null) {
395            mTetheredNotification = new Notification();
396            mTetheredNotification.when = 0;
397        }
398        mTetheredNotification.icon = icon;
399        mTetheredNotification.defaults &= ~Notification.DEFAULT_SOUND;
400        mTetheredNotification.flags = Notification.FLAG_ONGOING_EVENT;
401        mTetheredNotification.tickerText = title;
402        mTetheredNotification.setLatestEventInfo(mContext, title, message, pi);
403
404        notificationManager.notify(mTetheredNotification.icon, mTetheredNotification);
405    }
406
407    private void clearTetheredNotification() {
408        NotificationManager notificationManager =
409            (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE);
410        if (notificationManager != null && mTetheredNotification != null) {
411            notificationManager.cancel(mTetheredNotification.icon);
412            mTetheredNotification = null;
413        }
414    }
415
416    private void updateUsbStatus() {
417        boolean enable = mUsbConnected && mUsbMassStorageOff;
418
419        if (mBooted) {
420            enableUsbIfaces(enable);
421        }
422    }
423
424    private class StateReceiver extends BroadcastReceiver {
425        public void onReceive(Context content, Intent intent) {
426            String action = intent.getAction();
427            if (action.equals(UsbManager.ACTION_USB_STATE)) {
428                mUsbConnected = intent.getExtras().getBoolean(UsbManager.USB_CONNECTED);
429                updateUsbStatus();
430            } else if (action.equals(Intent.ACTION_MEDIA_SHARED)) {
431                mUsbMassStorageOff = false;
432                updateUsbStatus();
433            }
434            else if (action.equals(Intent.ACTION_MEDIA_UNSHARED)) {
435                mUsbMassStorageOff = true;
436                updateUsbStatus();
437            } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
438                mTetherMasterSM.sendMessage(TetherMasterSM.CMD_UPSTREAM_CHANGED);
439            } else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
440                mBooted = true;
441                updateUsbStatus();
442            }
443        }
444    }
445
446    // used on cable insert/remove
447    private void enableUsbIfaces(boolean enable) {
448        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
449        INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
450        String[] ifaces = new String[0];
451        try {
452            ifaces = service.listInterfaces();
453        } catch (Exception e) {
454            Log.e(TAG, "Error listing Interfaces :" + e);
455            return;
456        }
457        for (String iface : ifaces) {
458            if (isUsb(iface)) {
459                if (enable) {
460                    interfaceAdded(iface);
461                } else {
462                    interfaceRemoved(iface);
463                }
464            }
465        }
466    }
467
468    // toggled when we enter/leave the fully teathered state
469    private boolean enableUsbRndis(boolean enabled) {
470        Log.d(TAG, "enableUsbRndis(" + enabled + ")");
471        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
472                INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
473
474        try {
475            if (enabled) {
476                synchronized (this) {
477                    if (!service.isUsbRNDISStarted()) {
478                        service.startUsbRNDIS();
479                    }
480                }
481            } else {
482                if (service.isUsbRNDISStarted()) {
483                    service.stopUsbRNDIS();
484                }
485            }
486        } catch (Exception e) {
487            Log.e(TAG, "Error toggling usb RNDIS :" + e);
488            return false;
489        }
490        return true;
491    }
492
493    // configured when we start tethering and unconfig'd on error or conclusion
494    private boolean configureUsbIface(boolean enabled) {
495        Log.d(TAG, "configureUsbIface(" + enabled + ")");
496
497        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
498        INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
499
500        // bring toggle the interfaces
501        String[] ifaces = new String[0];
502        try {
503            ifaces = service.listInterfaces();
504        } catch (Exception e) {
505            Log.e(TAG, "Error listing Interfaces :" + e);
506            return false;
507        }
508        for (String iface : ifaces) {
509            if (isUsb(iface)) {
510                InterfaceConfiguration ifcg = null;
511                try {
512                    ifcg = service.getInterfaceConfig(iface);
513                    if (ifcg != null) {
514                        String[] addr = USB_NEAR_IFACE_ADDR.split("\\.");
515                        ifcg.ipAddr = (Integer.parseInt(addr[0]) << 24) +
516                                (Integer.parseInt(addr[1]) << 16) +
517                                (Integer.parseInt(addr[2]) << 8) +
518                                (Integer.parseInt(addr[3]));
519                        addr = USB_NETMASK.split("\\.");
520                        ifcg.netmask = (Integer.parseInt(addr[0]) << 24) +
521                                (Integer.parseInt(addr[1]) << 16) +
522                                (Integer.parseInt(addr[2]) << 8) +
523                                (Integer.parseInt(addr[3]));
524                        if (enabled) {
525                            ifcg.interfaceFlags = ifcg.interfaceFlags.replace("down", "up");
526                        } else {
527                            ifcg.interfaceFlags = ifcg.interfaceFlags.replace("up", "down");
528                        }
529                        ifcg.interfaceFlags = ifcg.interfaceFlags.replace("running", "");
530                        ifcg.interfaceFlags = ifcg.interfaceFlags.replace("  "," ");
531                        service.setInterfaceConfig(iface, ifcg);
532                    }
533                } catch (Exception e) {
534                    Log.e(TAG, "Error configuring interface " + iface + ", :" + e);
535                    return false;
536                }
537            }
538        }
539
540        return true;
541    }
542
543    public String[] getTetherableUsbRegexs() {
544        return mTetherableUsbRegexs;
545    }
546
547    public String[] getTetherableWifiRegexs() {
548        return mTetherableWifiRegexs;
549    }
550
551    public String[] getUpstreamIfaceRegexs() {
552        return mUpstreamIfaceRegexs;
553    }
554
555    public boolean isDunRequired() {
556        boolean defaultVal = mContext.getResources().getBoolean(
557                com.android.internal.R.bool.config_tether_dun_required);
558        boolean result = (Settings.Secure.getInt(mContext.getContentResolver(),
559                Settings.Secure.TETHER_DUN_REQUIRED, (defaultVal ? 1 : 0)) == 1);
560        return result;
561    }
562
563    public String[] getTetheredIfaces() {
564        ArrayList<String> list = new ArrayList<String>();
565        synchronized (mIfaces) {
566            Set keys = mIfaces.keySet();
567            for (Object key : keys) {
568                TetherInterfaceSM sm = mIfaces.get(key);
569                if (sm.isTethered()) {
570                    list.add((String)key);
571                }
572            }
573        }
574        String[] retVal = new String[list.size()];
575        for (int i=0; i < list.size(); i++) {
576            retVal[i] = list.get(i);
577        }
578        return retVal;
579    }
580
581    public String[] getTetherableIfaces() {
582        ArrayList<String> list = new ArrayList<String>();
583        synchronized (mIfaces) {
584            Set keys = mIfaces.keySet();
585            for (Object key : keys) {
586                TetherInterfaceSM sm = mIfaces.get(key);
587                if (sm.isAvailable()) {
588                    list.add((String)key);
589                }
590            }
591        }
592        String[] retVal = new String[list.size()];
593        for (int i=0; i < list.size(); i++) {
594            retVal[i] = list.get(i);
595        }
596        return retVal;
597    }
598
599    public String[] getErroredIfaces() {
600        ArrayList<String> list = new ArrayList<String>();
601        synchronized (mIfaces) {
602            Set keys = mIfaces.keySet();
603            for (Object key : keys) {
604                TetherInterfaceSM sm = mIfaces.get(key);
605                if (sm.isErrored()) {
606                    list.add((String)key);
607                }
608            }
609        }
610        String[] retVal = new String[list.size()];
611        for (int i= 0; i< list.size(); i++) {
612            retVal[i] = list.get(i);
613        }
614        return retVal;
615    }
616
617
618    class TetherInterfaceSM extends HierarchicalStateMachine {
619        // notification from the master SM that it's not in tether mode
620        static final int CMD_TETHER_MODE_DEAD            =  1;
621        // request from the user that it wants to tether
622        static final int CMD_TETHER_REQUESTED            =  2;
623        // request from the user that it wants to untether
624        static final int CMD_TETHER_UNREQUESTED          =  3;
625        // notification that this interface is down
626        static final int CMD_INTERFACE_DOWN              =  4;
627        // notification that this interface is up
628        static final int CMD_INTERFACE_UP                =  5;
629        // notification from the master SM that it had an error turning on cellular dun
630        static final int CMD_CELL_DUN_ERROR              =  6;
631        // notification from the master SM that it had trouble enabling IP Forwarding
632        static final int CMD_IP_FORWARDING_ENABLE_ERROR  =  7;
633        // notification from the master SM that it had trouble disabling IP Forwarding
634        static final int CMD_IP_FORWARDING_DISABLE_ERROR =  8;
635        // notification from the master SM that it had trouble staring tethering
636        static final int CMD_START_TETHERING_ERROR       =  9;
637        // notification from the master SM that it had trouble stopping tethering
638        static final int CMD_STOP_TETHERING_ERROR        = 10;
639        // notification from the master SM that it had trouble setting the DNS forwarders
640        static final int CMD_SET_DNS_FORWARDERS_ERROR    = 11;
641        // the upstream connection has changed
642        static final int CMD_TETHER_CONNECTION_CHANGED   = 12;
643
644        private HierarchicalState mDefaultState;
645
646        private HierarchicalState mInitialState;
647        private HierarchicalState mStartingState;
648        private HierarchicalState mTetheredState;
649
650        private HierarchicalState mUnavailableState;
651
652        private boolean mAvailable;
653        private boolean mTethered;
654        int mLastError;
655
656        String mIfaceName;
657        String mMyUpstreamIfaceName;  // may change over time
658
659        boolean mUsb;
660
661        TetherInterfaceSM(String name, Looper looper, boolean usb) {
662            super(name, looper);
663            mIfaceName = name;
664            mUsb = usb;
665            setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR);
666
667            mInitialState = new InitialState();
668            addState(mInitialState);
669            mStartingState = new StartingState();
670            addState(mStartingState);
671            mTetheredState = new TetheredState();
672            addState(mTetheredState);
673            mUnavailableState = new UnavailableState();
674            addState(mUnavailableState);
675
676            setInitialState(mInitialState);
677        }
678
679        public String toString() {
680            String res = new String();
681            res += mIfaceName + " - ";
682            HierarchicalState current = getCurrentState();
683            if (current == mInitialState) res += "InitialState";
684            if (current == mStartingState) res += "StartingState";
685            if (current == mTetheredState) res += "TetheredState";
686            if (current == mUnavailableState) res += "UnavailableState";
687            if (mAvailable) res += " - Available";
688            if (mTethered) res += " - Tethered";
689            res += " - lastError =" + mLastError;
690            return res;
691        }
692
693        public synchronized int getLastError() {
694            return mLastError;
695        }
696
697        private synchronized void setLastError(int error) {
698            mLastError = error;
699
700            if (isErrored()) {
701                if (mUsb) {
702                    // note everything's been unwound by this point so nothing to do on
703                    // further error..
704                    Tethering.this.configureUsbIface(false);
705                }
706            }
707        }
708
709        // synchronized between this getter and the following setter
710        public synchronized boolean isAvailable() {
711            return mAvailable;
712        }
713
714        private synchronized void setAvailable(boolean available) {
715            mAvailable = available;
716        }
717
718        // synchronized between this getter and the following setter
719        public synchronized boolean isTethered() {
720            return mTethered;
721        }
722
723        private synchronized void setTethered(boolean tethered) {
724            mTethered = tethered;
725        }
726
727        // synchronized between this getter and the following setter
728        public synchronized boolean isErrored() {
729            return (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR);
730        }
731
732        class InitialState extends HierarchicalState {
733            @Override
734            public void enter() {
735                setAvailable(true);
736                setTethered(false);
737                sendTetherStateChangedBroadcast();
738            }
739
740            @Override
741            public boolean processMessage(Message message) {
742                Log.d(TAG, "InitialState.processMessage what=" + message.what);
743                boolean retValue = true;
744                switch (message.what) {
745                    case CMD_TETHER_REQUESTED:
746                        setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR);
747                        mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_REQUESTED,
748                                TetherInterfaceSM.this);
749                        transitionTo(mStartingState);
750                        break;
751                    case CMD_INTERFACE_DOWN:
752                        transitionTo(mUnavailableState);
753                        break;
754                    default:
755                        retValue = false;
756                        break;
757                }
758                return retValue;
759            }
760        }
761
762        class StartingState extends HierarchicalState {
763            @Override
764            public void enter() {
765                setAvailable(false);
766                if (mUsb) {
767                    if (!Tethering.this.configureUsbIface(true)) {
768                        mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED,
769                                TetherInterfaceSM.this);
770                        setLastError(ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
771
772                        transitionTo(mInitialState);
773                        return;
774                    }
775                }
776                sendTetherStateChangedBroadcast();
777
778                // Skipping StartingState
779                transitionTo(mTetheredState);
780            }
781            @Override
782            public boolean processMessage(Message message) {
783                Log.d(TAG, "StartingState.processMessage what=" + message.what);
784                boolean retValue = true;
785                switch (message.what) {
786                    // maybe a parent class?
787                    case CMD_TETHER_UNREQUESTED:
788                        mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED,
789                                TetherInterfaceSM.this);
790                        if (mUsb) {
791                            if (!Tethering.this.configureUsbIface(false)) {
792                                setLastErrorAndTransitionToInitialState(
793                                    ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
794                                break;
795                            }
796                        }
797                        transitionTo(mInitialState);
798                        break;
799                    case CMD_CELL_DUN_ERROR:
800                    case CMD_IP_FORWARDING_ENABLE_ERROR:
801                    case CMD_IP_FORWARDING_DISABLE_ERROR:
802                    case CMD_START_TETHERING_ERROR:
803                    case CMD_STOP_TETHERING_ERROR:
804                    case CMD_SET_DNS_FORWARDERS_ERROR:
805                        setLastErrorAndTransitionToInitialState(
806                                ConnectivityManager.TETHER_ERROR_MASTER_ERROR);
807                        break;
808                    case CMD_INTERFACE_DOWN:
809                        mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED,
810                                TetherInterfaceSM.this);
811                        transitionTo(mUnavailableState);
812                        break;
813                    default:
814                        retValue = false;
815                }
816                return retValue;
817            }
818        }
819
820        class TetheredState extends HierarchicalState {
821            @Override
822            public void enter() {
823                IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
824                INetworkManagementService service =
825                        INetworkManagementService.Stub.asInterface(b);
826                try {
827                    service.tetherInterface(mIfaceName);
828                } catch (Exception e) {
829                    setLastError(ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR);
830
831                    transitionTo(mInitialState);
832                    return;
833                }
834                if (mUsb) Tethering.this.enableUsbRndis(true);
835                Log.d(TAG, "Tethered " + mIfaceName);
836                setAvailable(false);
837                setTethered(true);
838                sendTetherStateChangedBroadcast();
839            }
840            @Override
841            public void exit() {
842                if (mUsb) Tethering.this.enableUsbRndis(false);
843            }
844            @Override
845            public boolean processMessage(Message message) {
846                Log.d(TAG, "TetheredState.processMessage what=" + message.what);
847                boolean retValue = true;
848                boolean error = false;
849                switch (message.what) {
850                    case CMD_TETHER_UNREQUESTED:
851                    case CMD_INTERFACE_DOWN:
852                        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
853                        INetworkManagementService service =
854                                INetworkManagementService.Stub.asInterface(b);
855                        if (mMyUpstreamIfaceName != null) {
856                            try {
857                                service.disableNat(mIfaceName, mMyUpstreamIfaceName);
858                                mMyUpstreamIfaceName = null;
859                            } catch (Exception e) {
860                                try {
861                                    service.untetherInterface(mIfaceName);
862                                } catch (Exception ee) {}
863
864                                setLastErrorAndTransitionToInitialState(
865                                        ConnectivityManager.TETHER_ERROR_DISABLE_NAT_ERROR);
866                                break;
867                            }
868                        }
869                        try {
870                            service.untetherInterface(mIfaceName);
871                        } catch (Exception e) {
872                            setLastErrorAndTransitionToInitialState(
873                                    ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR);
874                            break;
875                        }
876                        mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED,
877                                TetherInterfaceSM.this);
878                        if (message.what == CMD_TETHER_UNREQUESTED) {
879                            if (mUsb) {
880                                if (!Tethering.this.configureUsbIface(false)) {
881                                    setLastError(
882                                            ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
883                                }
884                            }
885                            transitionTo(mInitialState);
886                        } else if (message.what == CMD_INTERFACE_DOWN) {
887                            transitionTo(mUnavailableState);
888                        }
889                        Log.d(TAG, "Untethered " + mIfaceName);
890                        break;
891                    case CMD_TETHER_CONNECTION_CHANGED:
892                        String newUpstreamIfaceName = (String)(message.obj);
893                        b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
894                        service = INetworkManagementService.Stub.asInterface(b);
895
896                        if (mMyUpstreamIfaceName != null) {
897                            try {
898                                service.disableNat(mIfaceName, mMyUpstreamIfaceName);
899                                mMyUpstreamIfaceName = null;
900                            } catch (Exception e) {
901                                try {
902                                    service.untetherInterface(mIfaceName);
903                                } catch (Exception ee) {}
904
905                                setLastErrorAndTransitionToInitialState(
906                                        ConnectivityManager.TETHER_ERROR_DISABLE_NAT_ERROR);
907                                break;
908                            }
909                        }
910                        if (newUpstreamIfaceName != null) {
911                            try {
912                                service.enableNat(mIfaceName, newUpstreamIfaceName);
913                            } catch (Exception e) {
914                                try {
915                                    service.untetherInterface(mIfaceName);
916                                } catch (Exception ee) {}
917
918                                setLastError(ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR);
919                                transitionTo(mInitialState);
920                                return true;
921                            }
922                        }
923                        mMyUpstreamIfaceName = newUpstreamIfaceName;
924                        break;
925                    case CMD_CELL_DUN_ERROR:
926                    case CMD_IP_FORWARDING_ENABLE_ERROR:
927                    case CMD_IP_FORWARDING_DISABLE_ERROR:
928                    case CMD_START_TETHERING_ERROR:
929                    case CMD_STOP_TETHERING_ERROR:
930                    case CMD_SET_DNS_FORWARDERS_ERROR:
931                        error = true;
932                        // fall through
933                    case CMD_TETHER_MODE_DEAD:
934                        b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
935                        service = INetworkManagementService.Stub.asInterface(b);
936                        if (mMyUpstreamIfaceName != null) {
937                            try {
938                                service.disableNat(mIfaceName, mMyUpstreamIfaceName);
939                                mMyUpstreamIfaceName = null;
940                            } catch (Exception e) {
941                                try {
942                                    service.untetherInterface(mIfaceName);
943                                } catch (Exception ee) {}
944
945                                setLastErrorAndTransitionToInitialState(
946                                        ConnectivityManager.TETHER_ERROR_DISABLE_NAT_ERROR);
947                                break;
948                            }
949                        }
950                        try {
951                            service.untetherInterface(mIfaceName);
952                        } catch (Exception e) {
953                            setLastErrorAndTransitionToInitialState(
954                                    ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR);
955                            break;
956                        }
957                        if (error) {
958                            setLastErrorAndTransitionToInitialState(
959                                    ConnectivityManager.TETHER_ERROR_MASTER_ERROR);
960                            break;
961                        }
962                        Log.d(TAG, "Tether lost upstream connection " + mIfaceName);
963                        sendTetherStateChangedBroadcast();
964                        if (mUsb) {
965                            if (!Tethering.this.configureUsbIface(false)) {
966                                setLastError(ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
967                            }
968                        }
969                        transitionTo(mInitialState);
970                        break;
971                    default:
972                        retValue = false;
973                        break;
974                }
975                return retValue;
976            }
977        }
978
979        class UnavailableState extends HierarchicalState {
980            @Override
981            public void enter() {
982                setAvailable(false);
983                setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR);
984                setTethered(false);
985                sendTetherStateChangedBroadcast();
986            }
987            @Override
988            public boolean processMessage(Message message) {
989                boolean retValue = true;
990                switch (message.what) {
991                    case CMD_INTERFACE_UP:
992                        transitionTo(mInitialState);
993                        break;
994                    default:
995                        retValue = false;
996                        break;
997                }
998                return retValue;
999            }
1000        }
1001
1002        void setLastErrorAndTransitionToInitialState(int error) {
1003            setLastError(error);
1004            transitionTo(mInitialState);
1005        }
1006
1007    }
1008
1009    class TetherMasterSM extends HierarchicalStateMachine {
1010        // an interface SM has requested Tethering
1011        static final int CMD_TETHER_MODE_REQUESTED   = 1;
1012        // an interface SM has unrequested Tethering
1013        static final int CMD_TETHER_MODE_UNREQUESTED = 2;
1014        // upstream connection change - do the right thing
1015        static final int CMD_UPSTREAM_CHANGED        = 3;
1016        // we received notice that the cellular DUN connection is up
1017        static final int CMD_CELL_CONNECTION_RENEW   = 4;
1018        // we don't have a valid upstream conn, check again after a delay
1019        static final int CMD_RETRY_UPSTREAM          = 5;
1020
1021        // This indicates what a timeout event relates to.  A state that
1022        // sends itself a delayed timeout event and handles incoming timeout events
1023        // should inc this when it is entered and whenever it sends a new timeout event.
1024        // We do not flush the old ones.
1025        private int mSequenceNumber;
1026
1027        private HierarchicalState mInitialState;
1028        private HierarchicalState mTetherModeAliveState;
1029
1030        private HierarchicalState mSetIpForwardingEnabledErrorState;
1031        private HierarchicalState mSetIpForwardingDisabledErrorState;
1032        private HierarchicalState mStartTetheringErrorState;
1033        private HierarchicalState mStopTetheringErrorState;
1034        private HierarchicalState mSetDnsForwardersErrorState;
1035
1036        private ArrayList mNotifyList;
1037
1038        private boolean mConnectionRequested = false;
1039
1040        private String mUpstreamIfaceName = null;
1041
1042        private static final int UPSTREAM_SETTLE_TIME_MS     = 10000;
1043        private static final int CELL_CONNECTION_RENEW_MS    = 40000;
1044
1045        TetherMasterSM(String name, Looper looper) {
1046            super(name, looper);
1047
1048            //Add states
1049            mInitialState = new InitialState();
1050            addState(mInitialState);
1051            mTetherModeAliveState = new TetherModeAliveState();
1052            addState(mTetherModeAliveState);
1053
1054            mSetIpForwardingEnabledErrorState = new SetIpForwardingEnabledErrorState();
1055            addState(mSetIpForwardingEnabledErrorState);
1056            mSetIpForwardingDisabledErrorState = new SetIpForwardingDisabledErrorState();
1057            addState(mSetIpForwardingDisabledErrorState);
1058            mStartTetheringErrorState = new StartTetheringErrorState();
1059            addState(mStartTetheringErrorState);
1060            mStopTetheringErrorState = new StopTetheringErrorState();
1061            addState(mStopTetheringErrorState);
1062            mSetDnsForwardersErrorState = new SetDnsForwardersErrorState();
1063            addState(mSetDnsForwardersErrorState);
1064
1065            mNotifyList = new ArrayList();
1066            setInitialState(mInitialState);
1067        }
1068
1069        class TetherMasterUtilState extends HierarchicalState {
1070            protected final static boolean TRY_TO_SETUP_MOBILE_CONNECTION = true;
1071            protected final static boolean WAIT_FOR_NETWORK_TO_SETTLE     = false;
1072
1073            @Override
1074            public boolean processMessage(Message m) {
1075                return false;
1076            }
1077            protected int turnOnMobileConnection() {
1078                IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
1079                IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
1080                int retValue = Phone.APN_REQUEST_FAILED;
1081                try {
1082                    retValue = service.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
1083                            (mDunRequired ? Phone.FEATURE_ENABLE_DUN : Phone.FEATURE_ENABLE_HIPRI),
1084                            new Binder());
1085                } catch (Exception e) {
1086                }
1087                switch (retValue) {
1088                case Phone.APN_ALREADY_ACTIVE:
1089                case Phone.APN_REQUEST_STARTED:
1090                    sendMessageDelayed(CMD_CELL_CONNECTION_RENEW, CELL_CONNECTION_RENEW_MS);
1091                    mConnectionRequested = true;
1092                    break;
1093                case Phone.APN_REQUEST_FAILED:
1094                default:
1095                    mConnectionRequested = false;
1096                    break;
1097                }
1098
1099                return retValue;
1100            }
1101            protected boolean turnOffMobileConnection() {
1102                if (mConnectionRequested) {
1103                    IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
1104                    IConnectivityManager service =
1105                            IConnectivityManager.Stub.asInterface(b);
1106                    try {
1107                        service.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
1108                                (mDunRequired? Phone.FEATURE_ENABLE_DUN :
1109                                             Phone.FEATURE_ENABLE_HIPRI));
1110                    } catch (Exception e) {
1111                        return false;
1112                    }
1113                    mConnectionRequested = false;
1114                }
1115                return true;
1116            }
1117            protected boolean turnOnMasterTetherSettings() {
1118                IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
1119                INetworkManagementService service =
1120                        INetworkManagementService.Stub.asInterface(b);
1121                try {
1122                    service.setIpForwardingEnabled(true);
1123                } catch (Exception e) {
1124                    transitionTo(mSetIpForwardingEnabledErrorState);
1125                    return false;
1126                }
1127                try {
1128                    service.startTethering(mDhcpRange);
1129                } catch (Exception e) {
1130                    transitionTo(mStartTetheringErrorState);
1131                    return false;
1132                }
1133                try {
1134                    service.setDnsForwarders(mDnsServers);
1135                } catch (Exception e) {
1136                    transitionTo(mSetDnsForwardersErrorState);
1137                    return false;
1138                }
1139                return true;
1140            }
1141            protected boolean turnOffMasterTetherSettings() {
1142                IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
1143                INetworkManagementService service =
1144                        INetworkManagementService.Stub.asInterface(b);
1145                try {
1146                    service.stopTethering();
1147                } catch (Exception e) {
1148                    transitionTo(mStopTetheringErrorState);
1149                    return false;
1150                }
1151                try {
1152                    service.setIpForwardingEnabled(false);
1153                } catch (Exception e) {
1154                    transitionTo(mSetIpForwardingDisabledErrorState);
1155                    return false;
1156                }
1157                transitionTo(mInitialState);
1158                return true;
1159            }
1160            protected String findActiveUpstreamIface() {
1161                // check for what iface we can use - if none found switch to error.
1162                IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
1163                INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
1164
1165                String[] ifaces = new String[0];
1166                try {
1167                    ifaces = service.listInterfaces();
1168                } catch (Exception e) {
1169                    Log.e(TAG, "Error listing Interfaces :" + e);
1170                    return null;
1171                }
1172
1173                for (String regex : mUpstreamIfaceRegexs) {
1174                    for (String iface : ifaces) {
1175                        if (iface.matches(regex)) {
1176                            // verify it is active
1177                            InterfaceConfiguration ifcg = null;
1178                            try {
1179                                ifcg = service.getInterfaceConfig(iface);
1180                                if (ifcg.isActive()) {
1181                                    return iface;
1182                                }
1183                            } catch (Exception e) {
1184                                Log.e(TAG, "Error getting iface config :" + e);
1185                                // ignore - try next
1186                                continue;
1187                            }
1188                        }
1189                    }
1190                }
1191                return null;
1192            }
1193            protected void chooseUpstreamType(boolean tryCell) {
1194                // decide if the current upstream is good or not and if not
1195                // do something about it (start up DUN if required or HiPri if not)
1196                String iface = findActiveUpstreamIface();
1197                IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
1198                IConnectivityManager cm = IConnectivityManager.Stub.asInterface(b);
1199                mConnectionRequested = false;
1200                Log.d(TAG, "chooseUpstreamType(" + tryCell + "),  dunRequired ="
1201                        + mDunRequired + ", iface=" + iface);
1202                if (iface != null) {
1203                    try {
1204                        if (mDunRequired) {
1205                            // check if Dun is on - we can use that
1206                            NetworkInfo info = cm.getNetworkInfo(
1207                                    ConnectivityManager.TYPE_MOBILE_DUN);
1208                            if (info.isConnected()) {
1209                                Log.d(TAG, "setting dun ifacename =" + iface);
1210                                // even if we're already connected - it may be somebody else's
1211                                // refcount, so add our own
1212                                turnOnMobileConnection();
1213                            } else {
1214                                // verify the iface is not the default mobile - can't use that!
1215                                info = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
1216                                if (info.isConnected()) {
1217                                    iface = null; // can't accept this one
1218                                }
1219                            }
1220                        } else {
1221                            Log.d(TAG, "checking if hipri brought us this connection");
1222                            NetworkInfo info = cm.getNetworkInfo(
1223                                    ConnectivityManager.TYPE_MOBILE_HIPRI);
1224                            if (info.isConnected()) {
1225                                Log.d(TAG, "yes - hipri in use");
1226                                // even if we're already connected - it may be sombody else's
1227                                // refcount, so add our own
1228                                turnOnMobileConnection();
1229                            }
1230                        }
1231                    } catch (RemoteException e) {
1232                        Log.e(TAG, "RemoteException calling ConnectivityManager " + e);
1233                        iface = null;
1234                    }
1235                }
1236                // may have been set to null in the if above
1237                if (iface == null ) {
1238                    if (tryCell == TRY_TO_SETUP_MOBILE_CONNECTION) {
1239                        turnOnMobileConnection();
1240                    }
1241                    // wait for things to settle and retry
1242                    sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS);
1243                }
1244                notifyTetheredOfNewUpstreamIface(iface);
1245            }
1246            protected void notifyTetheredOfNewUpstreamIface(String ifaceName) {
1247                Log.d(TAG, "notifying tethered with iface =" + ifaceName);
1248                mUpstreamIfaceName = ifaceName;
1249                for (Object o : mNotifyList) {
1250                    TetherInterfaceSM sm = (TetherInterfaceSM)o;
1251                    sm.sendMessage(TetherInterfaceSM.CMD_TETHER_CONNECTION_CHANGED,
1252                            ifaceName);
1253                }
1254            }
1255        }
1256
1257        class InitialState extends TetherMasterUtilState {
1258            @Override
1259            public void enter() {
1260                mConnectionRequested = false;
1261            }
1262            @Override
1263            public boolean processMessage(Message message) {
1264                Log.d(TAG, "MasterInitialState.processMessage what=" + message.what);
1265                boolean retValue = true;
1266                switch (message.what) {
1267                    case CMD_TETHER_MODE_REQUESTED:
1268                        mDunRequired = isDunRequired();
1269                        TetherInterfaceSM who = (TetherInterfaceSM)message.obj;
1270                        Log.d(TAG, "Tether Mode requested by " + who.toString());
1271                        mNotifyList.add(who);
1272                        transitionTo(mTetherModeAliveState);
1273                        break;
1274                    case CMD_TETHER_MODE_UNREQUESTED:
1275                        who = (TetherInterfaceSM)message.obj;
1276                        Log.d(TAG, "Tether Mode unrequested by " + who.toString());
1277                        int index = mNotifyList.indexOf(who);
1278                        if (index != -1) {
1279                            mNotifyList.remove(who);
1280                        }
1281                        break;
1282                    default:
1283                        retValue = false;
1284                        break;
1285                }
1286                return retValue;
1287            }
1288        }
1289
1290        class TetherModeAliveState extends TetherMasterUtilState {
1291            boolean mTryCell = WAIT_FOR_NETWORK_TO_SETTLE;
1292            @Override
1293            public void enter() {
1294                mTryCell = WAIT_FOR_NETWORK_TO_SETTLE;  // first pass lets just see what we have.
1295                chooseUpstreamType(mTryCell);
1296                mTryCell = !mTryCell;
1297                turnOnMasterTetherSettings(); // may transition us out
1298            }
1299            @Override
1300            public void exit() {
1301                turnOffMobileConnection();
1302                notifyTetheredOfNewUpstreamIface(null);
1303            }
1304            @Override
1305            public boolean processMessage(Message message) {
1306                Log.d(TAG, "TetherModeAliveState.processMessage what=" + message.what);
1307                boolean retValue = true;
1308                switch (message.what) {
1309                    case CMD_TETHER_MODE_REQUESTED:
1310                        TetherInterfaceSM who = (TetherInterfaceSM)message.obj;
1311                        mNotifyList.add(who);
1312                        who.sendMessage(TetherInterfaceSM.CMD_TETHER_CONNECTION_CHANGED,
1313                                mUpstreamIfaceName);
1314                        break;
1315                    case CMD_TETHER_MODE_UNREQUESTED:
1316                        who = (TetherInterfaceSM)message.obj;
1317                        int index = mNotifyList.indexOf(who);
1318                        if (index != -1) {
1319                            mNotifyList.remove(index);
1320                            if (mNotifyList.isEmpty()) {
1321                                turnOffMasterTetherSettings(); // transitions appropriately
1322                            }
1323                        }
1324                        break;
1325                    case CMD_UPSTREAM_CHANGED:
1326                        mTryCell = WAIT_FOR_NETWORK_TO_SETTLE;
1327                        chooseUpstreamType(mTryCell);
1328                        mTryCell = !mTryCell;
1329                        break;
1330                    case CMD_CELL_CONNECTION_RENEW:
1331                        // make sure we're still using a requested connection - may have found
1332                        // wifi or something since then.
1333                        if (mConnectionRequested) {
1334                            Log.d(TAG, "renewing mobile connection - requeuing for another " +
1335                                    CELL_CONNECTION_RENEW_MS + "ms");
1336                            turnOnMobileConnection();
1337                        }
1338                        break;
1339                   case CMD_RETRY_UPSTREAM:
1340                       chooseUpstreamType(mTryCell);
1341                       mTryCell = !mTryCell;
1342                       break;
1343                   default:
1344                       retValue = false;
1345                       break;
1346                }
1347                return retValue;
1348            }
1349        }
1350
1351        class ErrorState extends HierarchicalState {
1352            int mErrorNotification;
1353            @Override
1354            public boolean processMessage(Message message) {
1355                boolean retValue = true;
1356                switch (message.what) {
1357                    case CMD_TETHER_MODE_REQUESTED:
1358                        TetherInterfaceSM who = (TetherInterfaceSM)message.obj;
1359                        who.sendMessage(mErrorNotification);
1360                        break;
1361                    default:
1362                       retValue = false;
1363                }
1364                return retValue;
1365            }
1366            void notify(int msgType) {
1367                mErrorNotification = msgType;
1368                for (Object o : mNotifyList) {
1369                    TetherInterfaceSM sm = (TetherInterfaceSM)o;
1370                    sm.sendMessage(msgType);
1371                }
1372            }
1373
1374        }
1375        class SetIpForwardingEnabledErrorState extends ErrorState {
1376            @Override
1377            public void enter() {
1378                Log.e(TAG, "Error in setIpForwardingEnabled");
1379                notify(TetherInterfaceSM.CMD_IP_FORWARDING_ENABLE_ERROR);
1380            }
1381        }
1382
1383        class SetIpForwardingDisabledErrorState extends ErrorState {
1384            @Override
1385            public void enter() {
1386                Log.e(TAG, "Error in setIpForwardingDisabled");
1387                notify(TetherInterfaceSM.CMD_IP_FORWARDING_DISABLE_ERROR);
1388            }
1389        }
1390
1391        class StartTetheringErrorState extends ErrorState {
1392            @Override
1393            public void enter() {
1394                Log.e(TAG, "Error in startTethering");
1395                notify(TetherInterfaceSM.CMD_START_TETHERING_ERROR);
1396                IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
1397                INetworkManagementService service =
1398                        INetworkManagementService.Stub.asInterface(b);
1399                try {
1400                    service.setIpForwardingEnabled(false);
1401                } catch (Exception e) {}
1402            }
1403        }
1404
1405        class StopTetheringErrorState extends ErrorState {
1406            @Override
1407            public void enter() {
1408                Log.e(TAG, "Error in stopTethering");
1409                notify(TetherInterfaceSM.CMD_STOP_TETHERING_ERROR);
1410                IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
1411                INetworkManagementService service =
1412                         INetworkManagementService.Stub.asInterface(b);
1413                try {
1414                    service.setIpForwardingEnabled(false);
1415                } catch (Exception e) {}
1416            }
1417        }
1418
1419        class SetDnsForwardersErrorState extends ErrorState {
1420            @Override
1421            public void enter() {
1422                Log.e(TAG, "Error in setDnsForwarders");
1423                notify(TetherInterfaceSM.CMD_SET_DNS_FORWARDERS_ERROR);
1424                IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
1425                INetworkManagementService service =
1426                        INetworkManagementService.Stub.asInterface(b);
1427                try {
1428                    service.stopTethering();
1429                } catch (Exception e) {}
1430                try {
1431                    service.setIpForwardingEnabled(false);
1432                } catch (Exception e) {}
1433            }
1434        }
1435    }
1436
1437    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1438        if (mContext.checkCallingOrSelfPermission(
1439                android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) {
1440            pw.println("Permission Denial: can't dump ConnectivityService.Tether " +
1441                    "from from pid=" + Binder.getCallingPid() + ", uid=" +
1442                    Binder.getCallingUid());
1443                    return;
1444        }
1445
1446        pw.println();
1447        pw.println("Tether state:");
1448        synchronized (mIfaces) {
1449            for (Object o : mIfaces.values()) {
1450                pw.println(" "+o.toString());
1451            }
1452        }
1453        pw.println();
1454        return;
1455    }
1456}
1457