Tethering.java revision db3c8678e5cbdfec011afaf25bde2091152c30ad
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.Context;
24import android.content.Intent;
25import android.content.IntentFilter;
26import android.content.pm.PackageManager;
27import android.content.res.Resources;
28import android.hardware.usb.UsbManager;
29import android.net.ConnectivityManager;
30import android.net.IConnectivityManager;
31import android.net.INetworkManagementEventObserver;
32import android.net.INetworkStatsService;
33import android.net.InterfaceConfiguration;
34import android.net.LinkAddress;
35import android.net.LinkProperties;
36import android.net.NetworkInfo;
37import android.net.NetworkUtils;
38import android.os.Binder;
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.telephony.PhoneConstants;
51import com.android.internal.util.IState;
52import com.android.internal.util.State;
53import com.android.internal.util.StateMachine;
54import com.google.android.collect.Lists;
55
56import java.io.FileDescriptor;
57import java.io.PrintWriter;
58import java.net.InetAddress;
59import java.net.Inet4Address;
60import java.util.ArrayList;
61import java.util.Collection;
62import java.util.HashMap;
63import java.util.Iterator;
64import java.util.Set;
65
66/**
67 * @hide
68 *
69 * Timeout
70 *
71 * TODO - look for parent classes and code sharing
72 */
73public class Tethering extends INetworkManagementEventObserver.Stub {
74
75    private Context mContext;
76    private final static String TAG = "Tethering";
77    private final static boolean DBG = true;
78    private final static boolean VDBG = false;
79
80    // TODO - remove both of these - should be part of interface inspection/selection stuff
81    private String[] mTetherableUsbRegexs;
82    private String[] mTetherableWifiRegexs;
83    private String[] mTetherableBluetoothRegexs;
84    private Collection<Integer> mUpstreamIfaceTypes;
85
86    // used to synchronize public access to members
87    private Object mPublicSync;
88
89    private static final Integer MOBILE_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE);
90    private static final Integer HIPRI_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE_HIPRI);
91    private static final Integer DUN_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE_DUN);
92
93    // if we have to connect to mobile, what APN type should we use?  Calculated by examining the
94    // upstream type list and the DUN_REQUIRED secure-setting
95    private int mPreferredUpstreamMobileApn = ConnectivityManager.TYPE_NONE;
96
97    private final INetworkManagementService mNMService;
98    private final INetworkStatsService mStatsService;
99    private final IConnectivityManager mConnService;
100    private Looper mLooper;
101    private HandlerThread mThread;
102
103    private HashMap<String, TetherInterfaceSM> mIfaces; // all tethered/tetherable ifaces
104
105    private BroadcastReceiver mStateReceiver;
106
107    private static final String USB_NEAR_IFACE_ADDR      = "192.168.42.129";
108    private static final int USB_PREFIX_LENGTH        = 24;
109
110    // USB is  192.168.42.1 and 255.255.255.0
111    // Wifi is 192.168.43.1 and 255.255.255.0
112    // BT is limited to max default of 5 connections. 192.168.44.1 to 192.168.48.1
113    // with 255.255.255.0
114
115    private String[] mDhcpRange;
116    private static final String[] DHCP_DEFAULT_RANGE = {
117        "192.168.42.2", "192.168.42.254", "192.168.43.2", "192.168.43.254",
118        "192.168.44.2", "192.168.44.254", "192.168.45.2", "192.168.45.254",
119        "192.168.46.2", "192.168.46.254", "192.168.47.2", "192.168.47.254",
120        "192.168.48.2", "192.168.48.254",
121    };
122
123    private String[] mDefaultDnsServers;
124    private static final String DNS_DEFAULT_SERVER1 = "8.8.8.8";
125    private static final String DNS_DEFAULT_SERVER2 = "8.8.4.4";
126
127    private StateMachine mTetherMasterSM;
128
129    private Notification mTetheredNotification;
130
131    private boolean mRndisEnabled;       // track the RNDIS function enabled state
132    private boolean mUsbTetherRequested; // true if USB tethering should be started
133                                         // when RNDIS is enabled
134
135    public Tethering(Context context, INetworkManagementService nmService,
136            INetworkStatsService statsService, IConnectivityManager connService, Looper looper) {
137        mContext = context;
138        mNMService = nmService;
139        mStatsService = statsService;
140        mConnService = connService;
141        mLooper = looper;
142
143        mPublicSync = new Object();
144
145        mIfaces = new HashMap<String, TetherInterfaceSM>();
146
147        // make our own thread so we don't anr the system
148        mThread = new HandlerThread("Tethering");
149        mThread.start();
150        mLooper = mThread.getLooper();
151        mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper);
152        mTetherMasterSM.start();
153
154        mStateReceiver = new StateReceiver();
155        IntentFilter filter = new IntentFilter();
156        filter.addAction(UsbManager.ACTION_USB_STATE);
157        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
158        mContext.registerReceiver(mStateReceiver, filter);
159
160        filter = new IntentFilter();
161        filter.addAction(Intent.ACTION_MEDIA_SHARED);
162        filter.addAction(Intent.ACTION_MEDIA_UNSHARED);
163        filter.addDataScheme("file");
164        mContext.registerReceiver(mStateReceiver, filter);
165
166        mDhcpRange = context.getResources().getStringArray(
167                com.android.internal.R.array.config_tether_dhcp_range);
168        if ((mDhcpRange.length == 0) || (mDhcpRange.length % 2 ==1)) {
169            mDhcpRange = DHCP_DEFAULT_RANGE;
170        }
171
172        // load device config info
173        updateConfiguration();
174
175        // TODO - remove and rely on real notifications of the current iface
176        mDefaultDnsServers = new String[2];
177        mDefaultDnsServers[0] = DNS_DEFAULT_SERVER1;
178        mDefaultDnsServers[1] = DNS_DEFAULT_SERVER2;
179    }
180
181    void updateConfiguration() {
182        String[] tetherableUsbRegexs = mContext.getResources().getStringArray(
183                com.android.internal.R.array.config_tether_usb_regexs);
184        String[] tetherableWifiRegexs = mContext.getResources().getStringArray(
185                com.android.internal.R.array.config_tether_wifi_regexs);
186        String[] tetherableBluetoothRegexs = mContext.getResources().getStringArray(
187                com.android.internal.R.array.config_tether_bluetooth_regexs);
188
189        int ifaceTypes[] = mContext.getResources().getIntArray(
190                com.android.internal.R.array.config_tether_upstream_types);
191        Collection<Integer> upstreamIfaceTypes = new ArrayList();
192        for (int i : ifaceTypes) {
193            upstreamIfaceTypes.add(new Integer(i));
194        }
195
196        synchronized (mPublicSync) {
197            mTetherableUsbRegexs = tetherableUsbRegexs;
198            mTetherableWifiRegexs = tetherableWifiRegexs;
199            mTetherableBluetoothRegexs = tetherableBluetoothRegexs;
200            mUpstreamIfaceTypes = upstreamIfaceTypes;
201        }
202
203        // check if the upstream type list needs to be modified due to secure-settings
204        checkDunRequired();
205    }
206
207    public void interfaceStatusChanged(String iface, boolean up) {
208        if (VDBG) Log.d(TAG, "interfaceStatusChanged " + iface + ", " + up);
209        boolean found = false;
210        boolean usb = false;
211        synchronized (mPublicSync) {
212            if (isWifi(iface)) {
213                found = true;
214            } else if (isUsb(iface)) {
215                found = true;
216                usb = true;
217            } else if (isBluetooth(iface)) {
218                found = true;
219            }
220            if (found == false) return;
221
222            TetherInterfaceSM sm = mIfaces.get(iface);
223            if (up) {
224                if (sm == null) {
225                    sm = new TetherInterfaceSM(iface, mLooper, usb);
226                    mIfaces.put(iface, sm);
227                    sm.start();
228                }
229            } else {
230                if (isUsb(iface)) {
231                    // ignore usb0 down after enabling RNDIS
232                    // we will handle disconnect in interfaceRemoved instead
233                    if (VDBG) Log.d(TAG, "ignore interface down for " + iface);
234                } else if (sm != null) {
235                    sm.sendMessage(TetherInterfaceSM.CMD_INTERFACE_DOWN);
236                    mIfaces.remove(iface);
237                }
238            }
239        }
240    }
241
242    public void interfaceLinkStateChanged(String iface, boolean up) {
243        if (VDBG) Log.d(TAG, "interfaceLinkStateChanged " + iface + ", " + up);
244        interfaceStatusChanged(iface, up);
245    }
246
247    private boolean isUsb(String iface) {
248        synchronized (mPublicSync) {
249            for (String regex : mTetherableUsbRegexs) {
250                if (iface.matches(regex)) return true;
251            }
252            return false;
253        }
254    }
255
256    public boolean isWifi(String iface) {
257        synchronized (mPublicSync) {
258            for (String regex : mTetherableWifiRegexs) {
259                if (iface.matches(regex)) return true;
260            }
261            return false;
262        }
263    }
264
265    public boolean isBluetooth(String iface) {
266        synchronized (mPublicSync) {
267            for (String regex : mTetherableBluetoothRegexs) {
268                if (iface.matches(regex)) return true;
269            }
270            return false;
271        }
272    }
273
274    public void interfaceAdded(String iface) {
275        if (VDBG) Log.d(TAG, "interfaceAdded " + iface);
276        boolean found = false;
277        boolean usb = false;
278        synchronized (mPublicSync) {
279            if (isWifi(iface)) {
280                found = true;
281            }
282            if (isUsb(iface)) {
283                found = true;
284                usb = true;
285            }
286            if (isBluetooth(iface)) {
287                found = true;
288            }
289            if (found == false) {
290                if (VDBG) Log.d(TAG, iface + " is not a tetherable iface, ignoring");
291                return;
292            }
293
294            TetherInterfaceSM sm = mIfaces.get(iface);
295            if (sm != null) {
296                if (VDBG) Log.d(TAG, "active iface (" + iface + ") reported as added, ignoring");
297                return;
298            }
299            sm = new TetherInterfaceSM(iface, mLooper, usb);
300            mIfaces.put(iface, sm);
301            sm.start();
302        }
303    }
304
305    public void interfaceRemoved(String iface) {
306        if (VDBG) Log.d(TAG, "interfaceRemoved " + iface);
307        synchronized (mPublicSync) {
308            TetherInterfaceSM sm = mIfaces.get(iface);
309            if (sm == null) {
310                if (VDBG) {
311                    Log.e(TAG, "attempting to remove unknown iface (" + iface + "), ignoring");
312                }
313                return;
314            }
315            sm.sendMessage(TetherInterfaceSM.CMD_INTERFACE_DOWN);
316            mIfaces.remove(iface);
317        }
318    }
319
320    public void limitReached(String limitName, String iface) {}
321
322    public void interfaceClassDataActivityChanged(String label, boolean active) {}
323
324    public int tether(String iface) {
325        if (DBG) Log.d(TAG, "Tethering " + iface);
326        TetherInterfaceSM sm = null;
327        synchronized (mPublicSync) {
328            sm = mIfaces.get(iface);
329        }
330        if (sm == null) {
331            Log.e(TAG, "Tried to Tether an unknown iface :" + iface + ", ignoring");
332            return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
333        }
334        if (!sm.isAvailable() && !sm.isErrored()) {
335            Log.e(TAG, "Tried to Tether an unavailable iface :" + iface + ", ignoring");
336            return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
337        }
338        sm.sendMessage(TetherInterfaceSM.CMD_TETHER_REQUESTED);
339        return ConnectivityManager.TETHER_ERROR_NO_ERROR;
340    }
341
342    public int untether(String iface) {
343        if (DBG) Log.d(TAG, "Untethering " + iface);
344        TetherInterfaceSM sm = null;
345        synchronized (mPublicSync) {
346            sm = mIfaces.get(iface);
347        }
348        if (sm == null) {
349            Log.e(TAG, "Tried to Untether an unknown iface :" + iface + ", ignoring");
350            return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
351        }
352        if (sm.isErrored()) {
353            Log.e(TAG, "Tried to Untethered an errored iface :" + iface + ", ignoring");
354            return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
355        }
356        sm.sendMessage(TetherInterfaceSM.CMD_TETHER_UNREQUESTED);
357        return ConnectivityManager.TETHER_ERROR_NO_ERROR;
358    }
359
360    public int getLastTetherError(String iface) {
361        TetherInterfaceSM sm = null;
362        synchronized (mPublicSync) {
363            sm = mIfaces.get(iface);
364            if (sm == null) {
365                Log.e(TAG, "Tried to getLastTetherError on an unknown iface :" + iface +
366                        ", ignoring");
367                return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
368            }
369            return sm.getLastError();
370        }
371    }
372
373    // TODO - move all private methods used only by the state machine into the state machine
374    // to clarify what needs synchronized protection.
375    private void sendTetherStateChangedBroadcast() {
376        try {
377            if (!mConnService.isTetheringSupported()) return;
378        } catch (RemoteException e) {
379            return;
380        }
381
382        ArrayList<String> availableList = new ArrayList<String>();
383        ArrayList<String> activeList = new ArrayList<String>();
384        ArrayList<String> erroredList = new ArrayList<String>();
385
386        boolean wifiTethered = false;
387        boolean usbTethered = false;
388        boolean bluetoothTethered = false;
389
390        synchronized (mPublicSync) {
391            Set ifaces = mIfaces.keySet();
392            for (Object iface : ifaces) {
393                TetherInterfaceSM sm = mIfaces.get(iface);
394                if (sm != null) {
395                    if (sm.isErrored()) {
396                        erroredList.add((String)iface);
397                    } else if (sm.isAvailable()) {
398                        availableList.add((String)iface);
399                    } else if (sm.isTethered()) {
400                        if (isUsb((String)iface)) {
401                            usbTethered = true;
402                        } else if (isWifi((String)iface)) {
403                            wifiTethered = true;
404                      } else if (isBluetooth((String)iface)) {
405                            bluetoothTethered = true;
406                        }
407                        activeList.add((String)iface);
408                    }
409                }
410            }
411        }
412        Intent broadcast = new Intent(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
413        broadcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
414                Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
415        broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_AVAILABLE_TETHER,
416                availableList);
417        broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_TETHER, activeList);
418        broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ERRORED_TETHER,
419                erroredList);
420        mContext.sendStickyBroadcast(broadcast);
421        if (DBG) {
422            Log.d(TAG, "sendTetherStateChangedBroadcast " + availableList.size() + ", " +
423                    activeList.size() + ", " + erroredList.size());
424        }
425
426        if (usbTethered) {
427            if (wifiTethered || bluetoothTethered) {
428                showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_general);
429            } else {
430                showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_usb);
431            }
432        } else if (wifiTethered) {
433            if (bluetoothTethered) {
434                showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_general);
435            } else {
436                showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_wifi);
437            }
438        } else if (bluetoothTethered) {
439            showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_bluetooth);
440        } else {
441            clearTetheredNotification();
442        }
443    }
444
445    private void showTetheredNotification(int icon) {
446        NotificationManager notificationManager =
447                (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE);
448        if (notificationManager == null) {
449            return;
450        }
451
452        if (mTetheredNotification != null) {
453            if (mTetheredNotification.icon == icon) {
454                return;
455            }
456            notificationManager.cancel(mTetheredNotification.icon);
457        }
458
459        Intent intent = new Intent();
460        intent.setClassName("com.android.settings", "com.android.settings.TetherSettings");
461        intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
462
463        PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
464
465        Resources r = Resources.getSystem();
466        CharSequence title = r.getText(com.android.internal.R.string.tethered_notification_title);
467        CharSequence message = r.getText(com.android.internal.R.string.
468                tethered_notification_message);
469
470        if (mTetheredNotification == null) {
471            mTetheredNotification = new Notification();
472            mTetheredNotification.when = 0;
473        }
474        mTetheredNotification.icon = icon;
475        mTetheredNotification.defaults &= ~Notification.DEFAULT_SOUND;
476        mTetheredNotification.flags = Notification.FLAG_ONGOING_EVENT;
477        mTetheredNotification.tickerText = title;
478        mTetheredNotification.setLatestEventInfo(mContext, title, message, pi);
479
480        notificationManager.notify(mTetheredNotification.icon, mTetheredNotification);
481    }
482
483    private void clearTetheredNotification() {
484        NotificationManager notificationManager =
485            (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE);
486        if (notificationManager != null && mTetheredNotification != null) {
487            notificationManager.cancel(mTetheredNotification.icon);
488            mTetheredNotification = null;
489        }
490    }
491
492    private class StateReceiver extends BroadcastReceiver {
493        public void onReceive(Context content, Intent intent) {
494            String action = intent.getAction();
495            if (action.equals(UsbManager.ACTION_USB_STATE)) {
496                synchronized (Tethering.this.mPublicSync) {
497                    boolean usbConnected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false);
498                    mRndisEnabled = intent.getBooleanExtra(UsbManager.USB_FUNCTION_RNDIS, false);
499                    // start tethering if we have a request pending
500                    if (usbConnected && mRndisEnabled && mUsbTetherRequested) {
501                        tetherUsb(true);
502                    }
503                    mUsbTetherRequested = false;
504                }
505            } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
506                NetworkInfo networkInfo = (NetworkInfo)intent.getParcelableExtra(
507                        ConnectivityManager.EXTRA_NETWORK_INFO);
508                if (networkInfo != null &&
509                        networkInfo.getDetailedState() != NetworkInfo.DetailedState.FAILED) {
510                    if (VDBG) Log.d(TAG, "Tethering got CONNECTIVITY_ACTION");
511                    mTetherMasterSM.sendMessage(TetherMasterSM.CMD_UPSTREAM_CHANGED);
512                }
513            }
514        }
515    }
516
517    private void tetherUsb(boolean enable) {
518        if (VDBG) Log.d(TAG, "tetherUsb " + enable);
519
520        String[] ifaces = new String[0];
521        try {
522            ifaces = mNMService.listInterfaces();
523        } catch (Exception e) {
524            Log.e(TAG, "Error listing Interfaces", e);
525            return;
526        }
527        for (String iface : ifaces) {
528            if (isUsb(iface)) {
529                int result = (enable ? tether(iface) : untether(iface));
530                if (result == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
531                    return;
532                }
533            }
534        }
535        Log.e(TAG, "unable start or stop USB tethering");
536    }
537
538    // configured when we start tethering and unconfig'd on error or conclusion
539    private boolean configureUsbIface(boolean enabled) {
540        if (VDBG) Log.d(TAG, "configureUsbIface(" + enabled + ")");
541
542        // toggle the USB interfaces
543        String[] ifaces = new String[0];
544        try {
545            ifaces = mNMService.listInterfaces();
546        } catch (Exception e) {
547            Log.e(TAG, "Error listing Interfaces", e);
548            return false;
549        }
550        for (String iface : ifaces) {
551            if (isUsb(iface)) {
552                InterfaceConfiguration ifcg = null;
553                try {
554                    ifcg = mNMService.getInterfaceConfig(iface);
555                    if (ifcg != null) {
556                        InetAddress addr = NetworkUtils.numericToInetAddress(USB_NEAR_IFACE_ADDR);
557                        ifcg.setLinkAddress(new LinkAddress(addr, USB_PREFIX_LENGTH));
558                        if (enabled) {
559                            ifcg.setInterfaceUp();
560                        } else {
561                            ifcg.setInterfaceDown();
562                        }
563                        ifcg.clearFlag("running");
564                        mNMService.setInterfaceConfig(iface, ifcg);
565                    }
566                } catch (Exception e) {
567                    Log.e(TAG, "Error configuring interface " + iface, e);
568                    return false;
569                }
570            }
571         }
572
573        return true;
574    }
575
576    // TODO - return copies so people can't tamper
577    public String[] getTetherableUsbRegexs() {
578        return mTetherableUsbRegexs;
579    }
580
581    public String[] getTetherableWifiRegexs() {
582        return mTetherableWifiRegexs;
583    }
584
585    public String[] getTetherableBluetoothRegexs() {
586        return mTetherableBluetoothRegexs;
587    }
588
589    public int setUsbTethering(boolean enable) {
590        if (VDBG) Log.d(TAG, "setUsbTethering(" + enable + ")");
591        UsbManager usbManager = (UsbManager)mContext.getSystemService(Context.USB_SERVICE);
592
593        synchronized (mPublicSync) {
594            if (enable) {
595                if (mRndisEnabled) {
596                    tetherUsb(true);
597                } else {
598                    mUsbTetherRequested = true;
599                    usbManager.setCurrentFunction(UsbManager.USB_FUNCTION_RNDIS, false);
600                }
601            } else {
602                tetherUsb(false);
603                if (mRndisEnabled) {
604                    usbManager.setCurrentFunction(null, false);
605                }
606                mUsbTetherRequested = false;
607            }
608        }
609        return ConnectivityManager.TETHER_ERROR_NO_ERROR;
610    }
611
612    public int[] getUpstreamIfaceTypes() {
613        int values[];
614        synchronized (mPublicSync) {
615            updateConfiguration();
616            values = new int[mUpstreamIfaceTypes.size()];
617            Iterator<Integer> iterator = mUpstreamIfaceTypes.iterator();
618            for (int i=0; i < mUpstreamIfaceTypes.size(); i++) {
619                values[i] = iterator.next();
620            }
621        }
622        return values;
623    }
624
625    public void checkDunRequired() {
626        int secureSetting = Settings.Secure.getInt(mContext.getContentResolver(),
627                Settings.Secure.TETHER_DUN_REQUIRED, 2);
628        synchronized (mPublicSync) {
629            // 2 = not set, 0 = DUN not required, 1 = DUN required
630            if (secureSetting != 2) {
631                int requiredApn = (secureSetting == 1 ?
632                        ConnectivityManager.TYPE_MOBILE_DUN :
633                        ConnectivityManager.TYPE_MOBILE_HIPRI);
634                if (requiredApn == ConnectivityManager.TYPE_MOBILE_DUN) {
635                    while (mUpstreamIfaceTypes.contains(MOBILE_TYPE)) {
636                        mUpstreamIfaceTypes.remove(MOBILE_TYPE);
637                    }
638                    while (mUpstreamIfaceTypes.contains(HIPRI_TYPE)) {
639                        mUpstreamIfaceTypes.remove(HIPRI_TYPE);
640                    }
641                    if (mUpstreamIfaceTypes.contains(DUN_TYPE) == false) {
642                        mUpstreamIfaceTypes.add(DUN_TYPE);
643                    }
644                } else {
645                    while (mUpstreamIfaceTypes.contains(DUN_TYPE)) {
646                        mUpstreamIfaceTypes.remove(DUN_TYPE);
647                    }
648                    if (mUpstreamIfaceTypes.contains(MOBILE_TYPE) == false) {
649                        mUpstreamIfaceTypes.add(MOBILE_TYPE);
650                    }
651                    if (mUpstreamIfaceTypes.contains(HIPRI_TYPE) == false) {
652                        mUpstreamIfaceTypes.add(HIPRI_TYPE);
653                    }
654                }
655            }
656            if (mUpstreamIfaceTypes.contains(DUN_TYPE)) {
657                mPreferredUpstreamMobileApn = ConnectivityManager.TYPE_MOBILE_DUN;
658            } else {
659                mPreferredUpstreamMobileApn = ConnectivityManager.TYPE_MOBILE_HIPRI;
660            }
661        }
662    }
663
664    // TODO review API - maybe return ArrayList<String> here and below?
665    public String[] getTetheredIfaces() {
666        ArrayList<String> list = new ArrayList<String>();
667        synchronized (mPublicSync) {
668            Set keys = mIfaces.keySet();
669            for (Object key : keys) {
670                TetherInterfaceSM sm = mIfaces.get(key);
671                if (sm.isTethered()) {
672                    list.add((String)key);
673                }
674            }
675        }
676        String[] retVal = new String[list.size()];
677        for (int i=0; i < list.size(); i++) {
678            retVal[i] = list.get(i);
679        }
680        return retVal;
681    }
682
683    public String[] getTetheredIfacePairs() {
684        final ArrayList<String> list = Lists.newArrayList();
685        synchronized (mPublicSync) {
686            for (TetherInterfaceSM sm : mIfaces.values()) {
687                if (sm.isTethered()) {
688                    list.add(sm.mMyUpstreamIfaceName);
689                    list.add(sm.mIfaceName);
690                }
691            }
692        }
693        return list.toArray(new String[list.size()]);
694    }
695
696    public String[] getTetherableIfaces() {
697        ArrayList<String> list = new ArrayList<String>();
698        synchronized (mPublicSync) {
699            Set keys = mIfaces.keySet();
700            for (Object key : keys) {
701                TetherInterfaceSM sm = mIfaces.get(key);
702                if (sm.isAvailable()) {
703                    list.add((String)key);
704                }
705            }
706        }
707        String[] retVal = new String[list.size()];
708        for (int i=0; i < list.size(); i++) {
709            retVal[i] = list.get(i);
710        }
711        return retVal;
712    }
713
714    public String[] getErroredIfaces() {
715        ArrayList<String> list = new ArrayList<String>();
716        synchronized (mPublicSync) {
717            Set keys = mIfaces.keySet();
718            for (Object key : keys) {
719                TetherInterfaceSM sm = mIfaces.get(key);
720                if (sm.isErrored()) {
721                    list.add((String)key);
722                }
723            }
724        }
725        String[] retVal = new String[list.size()];
726        for (int i= 0; i< list.size(); i++) {
727            retVal[i] = list.get(i);
728        }
729        return retVal;
730    }
731
732    //TODO: Temporary handling upstream change triggered without
733    //      CONNECTIVITY_ACTION. Only to accomodate interface
734    //      switch during HO.
735    //      @see bug/4455071
736    public void handleTetherIfaceChange() {
737        mTetherMasterSM.sendMessage(TetherMasterSM.CMD_UPSTREAM_CHANGED);
738    }
739
740    class TetherInterfaceSM extends StateMachine {
741        // notification from the master SM that it's not in tether mode
742        static final int CMD_TETHER_MODE_DEAD            =  1;
743        // request from the user that it wants to tether
744        static final int CMD_TETHER_REQUESTED            =  2;
745        // request from the user that it wants to untether
746        static final int CMD_TETHER_UNREQUESTED          =  3;
747        // notification that this interface is down
748        static final int CMD_INTERFACE_DOWN              =  4;
749        // notification that this interface is up
750        static final int CMD_INTERFACE_UP                =  5;
751        // notification from the master SM that it had an error turning on cellular dun
752        static final int CMD_CELL_DUN_ERROR              =  6;
753        // notification from the master SM that it had trouble enabling IP Forwarding
754        static final int CMD_IP_FORWARDING_ENABLE_ERROR  =  7;
755        // notification from the master SM that it had trouble disabling IP Forwarding
756        static final int CMD_IP_FORWARDING_DISABLE_ERROR =  8;
757        // notification from the master SM that it had trouble staring tethering
758        static final int CMD_START_TETHERING_ERROR       =  9;
759        // notification from the master SM that it had trouble stopping tethering
760        static final int CMD_STOP_TETHERING_ERROR        = 10;
761        // notification from the master SM that it had trouble setting the DNS forwarders
762        static final int CMD_SET_DNS_FORWARDERS_ERROR    = 11;
763        // the upstream connection has changed
764        static final int CMD_TETHER_CONNECTION_CHANGED   = 12;
765
766        private State mDefaultState;
767
768        private State mInitialState;
769        private State mStartingState;
770        private State mTetheredState;
771
772        private State mUnavailableState;
773
774        private boolean mAvailable;
775        private boolean mTethered;
776        int mLastError;
777
778        String mIfaceName;
779        String mMyUpstreamIfaceName;  // may change over time
780
781        boolean mUsb;
782
783        TetherInterfaceSM(String name, Looper looper, boolean usb) {
784            super(name, looper);
785            mIfaceName = name;
786            mUsb = usb;
787            setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR);
788
789            mInitialState = new InitialState();
790            addState(mInitialState);
791            mStartingState = new StartingState();
792            addState(mStartingState);
793            mTetheredState = new TetheredState();
794            addState(mTetheredState);
795            mUnavailableState = new UnavailableState();
796            addState(mUnavailableState);
797
798            setInitialState(mInitialState);
799        }
800
801        public String toString() {
802            String res = new String();
803            res += mIfaceName + " - ";
804            IState current = getCurrentState();
805            if (current == mInitialState) res += "InitialState";
806            if (current == mStartingState) res += "StartingState";
807            if (current == mTetheredState) res += "TetheredState";
808            if (current == mUnavailableState) res += "UnavailableState";
809            if (mAvailable) res += " - Available";
810            if (mTethered) res += " - Tethered";
811            res += " - lastError =" + mLastError;
812            return res;
813        }
814
815        public int getLastError() {
816            synchronized (Tethering.this.mPublicSync) {
817                return mLastError;
818            }
819        }
820
821        private void setLastError(int error) {
822            synchronized (Tethering.this.mPublicSync) {
823                mLastError = error;
824
825                if (isErrored()) {
826                    if (mUsb) {
827                        // note everything's been unwound by this point so nothing to do on
828                        // further error..
829                        Tethering.this.configureUsbIface(false);
830                    }
831                }
832            }
833        }
834
835        public boolean isAvailable() {
836            synchronized (Tethering.this.mPublicSync) {
837                return mAvailable;
838            }
839        }
840
841        private void setAvailable(boolean available) {
842            synchronized (Tethering.this.mPublicSync) {
843                mAvailable = available;
844            }
845        }
846
847        public boolean isTethered() {
848            synchronized (Tethering.this.mPublicSync) {
849                return mTethered;
850            }
851        }
852
853        private void setTethered(boolean tethered) {
854            synchronized (Tethering.this.mPublicSync) {
855                mTethered = tethered;
856            }
857        }
858
859        public boolean isErrored() {
860            synchronized (Tethering.this.mPublicSync) {
861                return (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR);
862            }
863        }
864
865        class InitialState extends State {
866            @Override
867            public void enter() {
868                setAvailable(true);
869                setTethered(false);
870                sendTetherStateChangedBroadcast();
871            }
872
873            @Override
874            public boolean processMessage(Message message) {
875                if (DBG) Log.d(TAG, "InitialState.processMessage what=" + message.what);
876                boolean retValue = true;
877                switch (message.what) {
878                    case CMD_TETHER_REQUESTED:
879                        setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR);
880                        mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_REQUESTED,
881                                TetherInterfaceSM.this);
882                        transitionTo(mStartingState);
883                        break;
884                    case CMD_INTERFACE_DOWN:
885                        transitionTo(mUnavailableState);
886                        break;
887                    default:
888                        retValue = false;
889                        break;
890                }
891                return retValue;
892            }
893        }
894
895        class StartingState extends State {
896            @Override
897            public void enter() {
898                setAvailable(false);
899                if (mUsb) {
900                    if (!Tethering.this.configureUsbIface(true)) {
901                        mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED,
902                                TetherInterfaceSM.this);
903                        setLastError(ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
904
905                        transitionTo(mInitialState);
906                        return;
907                    }
908                }
909                sendTetherStateChangedBroadcast();
910
911                // Skipping StartingState
912                transitionTo(mTetheredState);
913            }
914            @Override
915            public boolean processMessage(Message message) {
916                if (DBG) Log.d(TAG, "StartingState.processMessage what=" + message.what);
917                boolean retValue = true;
918                switch (message.what) {
919                    // maybe a parent class?
920                    case CMD_TETHER_UNREQUESTED:
921                        mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED,
922                                TetherInterfaceSM.this);
923                        if (mUsb) {
924                            if (!Tethering.this.configureUsbIface(false)) {
925                                setLastErrorAndTransitionToInitialState(
926                                    ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
927                                break;
928                            }
929                        }
930                        transitionTo(mInitialState);
931                        break;
932                    case CMD_CELL_DUN_ERROR:
933                    case CMD_IP_FORWARDING_ENABLE_ERROR:
934                    case CMD_IP_FORWARDING_DISABLE_ERROR:
935                    case CMD_START_TETHERING_ERROR:
936                    case CMD_STOP_TETHERING_ERROR:
937                    case CMD_SET_DNS_FORWARDERS_ERROR:
938                        setLastErrorAndTransitionToInitialState(
939                                ConnectivityManager.TETHER_ERROR_MASTER_ERROR);
940                        break;
941                    case CMD_INTERFACE_DOWN:
942                        mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED,
943                                TetherInterfaceSM.this);
944                        transitionTo(mUnavailableState);
945                        break;
946                    default:
947                        retValue = false;
948                }
949                return retValue;
950            }
951        }
952
953        class TetheredState extends State {
954            @Override
955            public void enter() {
956                try {
957                    mNMService.tetherInterface(mIfaceName);
958                } catch (Exception e) {
959                    Log.e(TAG, "Error Tethering: " + e.toString());
960                    setLastError(ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR);
961
962                    transitionTo(mInitialState);
963                    return;
964                }
965                if (DBG) Log.d(TAG, "Tethered " + mIfaceName);
966                setAvailable(false);
967                setTethered(true);
968                sendTetherStateChangedBroadcast();
969            }
970
971            private void cleanupUpstream() {
972                if (mMyUpstreamIfaceName != null) {
973                    // note that we don't care about errors here.
974                    // sometimes interfaces are gone before we get
975                    // to remove their rules, which generates errors.
976                    // just do the best we can.
977                    try {
978                        // about to tear down NAT; gather remaining statistics
979                        mStatsService.forceUpdate();
980                    } catch (Exception e) {
981                        if (VDBG) Log.e(TAG, "Exception in forceUpdate: " + e.toString());
982                    }
983                    try {
984                        mNMService.disableNat(mIfaceName, mMyUpstreamIfaceName);
985                    } catch (Exception e) {
986                        if (VDBG) Log.e(TAG, "Exception in disableNat: " + e.toString());
987                    }
988                    mMyUpstreamIfaceName = null;
989                }
990                return;
991            }
992
993            @Override
994            public boolean processMessage(Message message) {
995                if (DBG) Log.d(TAG, "TetheredState.processMessage what=" + message.what);
996                boolean retValue = true;
997                boolean error = false;
998                switch (message.what) {
999                    case CMD_TETHER_UNREQUESTED:
1000                    case CMD_INTERFACE_DOWN:
1001                        cleanupUpstream();
1002                        try {
1003                            mNMService.untetherInterface(mIfaceName);
1004                        } catch (Exception e) {
1005                            setLastErrorAndTransitionToInitialState(
1006                                    ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR);
1007                            break;
1008                        }
1009                        mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED,
1010                                TetherInterfaceSM.this);
1011                        if (message.what == CMD_TETHER_UNREQUESTED) {
1012                            if (mUsb) {
1013                                if (!Tethering.this.configureUsbIface(false)) {
1014                                    setLastError(
1015                                            ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
1016                                }
1017                            }
1018                            transitionTo(mInitialState);
1019                        } else if (message.what == CMD_INTERFACE_DOWN) {
1020                            transitionTo(mUnavailableState);
1021                        }
1022                        if (DBG) Log.d(TAG, "Untethered " + mIfaceName);
1023                        break;
1024                    case CMD_TETHER_CONNECTION_CHANGED:
1025                        String newUpstreamIfaceName = (String)(message.obj);
1026                        if ((mMyUpstreamIfaceName == null && newUpstreamIfaceName == null) ||
1027                                (mMyUpstreamIfaceName != null &&
1028                                mMyUpstreamIfaceName.equals(newUpstreamIfaceName))) {
1029                            if (VDBG) Log.d(TAG, "Connection changed noop - dropping");
1030                            break;
1031                        }
1032                        cleanupUpstream();
1033                        if (newUpstreamIfaceName != null) {
1034                            try {
1035                                mNMService.enableNat(mIfaceName, newUpstreamIfaceName);
1036                            } catch (Exception e) {
1037                                Log.e(TAG, "Exception enabling Nat: " + e.toString());
1038                                try {
1039                                    mNMService.untetherInterface(mIfaceName);
1040                                } catch (Exception ee) {}
1041
1042                                setLastError(ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR);
1043                                transitionTo(mInitialState);
1044                                return true;
1045                            }
1046                        }
1047                        mMyUpstreamIfaceName = newUpstreamIfaceName;
1048                        break;
1049                    case CMD_CELL_DUN_ERROR:
1050                    case CMD_IP_FORWARDING_ENABLE_ERROR:
1051                    case CMD_IP_FORWARDING_DISABLE_ERROR:
1052                    case CMD_START_TETHERING_ERROR:
1053                    case CMD_STOP_TETHERING_ERROR:
1054                    case CMD_SET_DNS_FORWARDERS_ERROR:
1055                        error = true;
1056                        // fall through
1057                    case CMD_TETHER_MODE_DEAD:
1058                        cleanupUpstream();
1059                        try {
1060                            mNMService.untetherInterface(mIfaceName);
1061                        } catch (Exception e) {
1062                            setLastErrorAndTransitionToInitialState(
1063                                    ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR);
1064                            break;
1065                        }
1066                        if (error) {
1067                            setLastErrorAndTransitionToInitialState(
1068                                    ConnectivityManager.TETHER_ERROR_MASTER_ERROR);
1069                            break;
1070                        }
1071                        if (DBG) Log.d(TAG, "Tether lost upstream connection " + mIfaceName);
1072                        sendTetherStateChangedBroadcast();
1073                        if (mUsb) {
1074                            if (!Tethering.this.configureUsbIface(false)) {
1075                                setLastError(ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
1076                            }
1077                        }
1078                        transitionTo(mInitialState);
1079                        break;
1080                    default:
1081                        retValue = false;
1082                        break;
1083                }
1084                return retValue;
1085            }
1086        }
1087
1088        class UnavailableState extends State {
1089            @Override
1090            public void enter() {
1091                setAvailable(false);
1092                setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR);
1093                setTethered(false);
1094                sendTetherStateChangedBroadcast();
1095            }
1096            @Override
1097            public boolean processMessage(Message message) {
1098                boolean retValue = true;
1099                switch (message.what) {
1100                    case CMD_INTERFACE_UP:
1101                        transitionTo(mInitialState);
1102                        break;
1103                    default:
1104                        retValue = false;
1105                        break;
1106                }
1107                return retValue;
1108            }
1109        }
1110
1111        void setLastErrorAndTransitionToInitialState(int error) {
1112            setLastError(error);
1113            transitionTo(mInitialState);
1114        }
1115
1116    }
1117
1118    class TetherMasterSM extends StateMachine {
1119        // an interface SM has requested Tethering
1120        static final int CMD_TETHER_MODE_REQUESTED   = 1;
1121        // an interface SM has unrequested Tethering
1122        static final int CMD_TETHER_MODE_UNREQUESTED = 2;
1123        // upstream connection change - do the right thing
1124        static final int CMD_UPSTREAM_CHANGED        = 3;
1125        // we received notice that the cellular DUN connection is up
1126        static final int CMD_CELL_CONNECTION_RENEW   = 4;
1127        // we don't have a valid upstream conn, check again after a delay
1128        static final int CMD_RETRY_UPSTREAM          = 5;
1129
1130        // This indicates what a timeout event relates to.  A state that
1131        // sends itself a delayed timeout event and handles incoming timeout events
1132        // should inc this when it is entered and whenever it sends a new timeout event.
1133        // We do not flush the old ones.
1134        private int mSequenceNumber;
1135
1136        private State mInitialState;
1137        private State mTetherModeAliveState;
1138
1139        private State mSetIpForwardingEnabledErrorState;
1140        private State mSetIpForwardingDisabledErrorState;
1141        private State mStartTetheringErrorState;
1142        private State mStopTetheringErrorState;
1143        private State mSetDnsForwardersErrorState;
1144
1145        private ArrayList<TetherInterfaceSM> mNotifyList;
1146
1147        private int mCurrentConnectionSequence;
1148        private int mMobileApnReserved = ConnectivityManager.TYPE_NONE;
1149
1150        private String mUpstreamIfaceName = null;
1151
1152        private static final int UPSTREAM_SETTLE_TIME_MS     = 10000;
1153        private static final int CELL_CONNECTION_RENEW_MS    = 40000;
1154
1155        TetherMasterSM(String name, Looper looper) {
1156            super(name, looper);
1157
1158            //Add states
1159            mInitialState = new InitialState();
1160            addState(mInitialState);
1161            mTetherModeAliveState = new TetherModeAliveState();
1162            addState(mTetherModeAliveState);
1163
1164            mSetIpForwardingEnabledErrorState = new SetIpForwardingEnabledErrorState();
1165            addState(mSetIpForwardingEnabledErrorState);
1166            mSetIpForwardingDisabledErrorState = new SetIpForwardingDisabledErrorState();
1167            addState(mSetIpForwardingDisabledErrorState);
1168            mStartTetheringErrorState = new StartTetheringErrorState();
1169            addState(mStartTetheringErrorState);
1170            mStopTetheringErrorState = new StopTetheringErrorState();
1171            addState(mStopTetheringErrorState);
1172            mSetDnsForwardersErrorState = new SetDnsForwardersErrorState();
1173            addState(mSetDnsForwardersErrorState);
1174
1175            mNotifyList = new ArrayList<TetherInterfaceSM>();
1176            setInitialState(mInitialState);
1177        }
1178
1179        class TetherMasterUtilState extends State {
1180            protected final static boolean TRY_TO_SETUP_MOBILE_CONNECTION = true;
1181            protected final static boolean WAIT_FOR_NETWORK_TO_SETTLE     = false;
1182
1183            @Override
1184            public boolean processMessage(Message m) {
1185                return false;
1186            }
1187            protected String enableString(int apnType) {
1188                switch (apnType) {
1189                case ConnectivityManager.TYPE_MOBILE_DUN:
1190                    return Phone.FEATURE_ENABLE_DUN_ALWAYS;
1191                case ConnectivityManager.TYPE_MOBILE:
1192                case ConnectivityManager.TYPE_MOBILE_HIPRI:
1193                    return Phone.FEATURE_ENABLE_HIPRI;
1194                }
1195                return null;
1196            }
1197            protected boolean turnOnUpstreamMobileConnection(int apnType) {
1198                boolean retValue = true;
1199                if (apnType == ConnectivityManager.TYPE_NONE) return false;
1200                if (apnType != mMobileApnReserved) turnOffUpstreamMobileConnection();
1201                int result = PhoneConstants.APN_REQUEST_FAILED;
1202                String enableString = enableString(apnType);
1203                if (enableString == null) return false;
1204                try {
1205                    result = mConnService.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
1206                            enableString, new Binder());
1207                } catch (Exception e) {
1208                }
1209                switch (result) {
1210                case PhoneConstants.APN_ALREADY_ACTIVE:
1211                case PhoneConstants.APN_REQUEST_STARTED:
1212                    mMobileApnReserved = apnType;
1213                    Message m = obtainMessage(CMD_CELL_CONNECTION_RENEW);
1214                    m.arg1 = ++mCurrentConnectionSequence;
1215                    sendMessageDelayed(m, CELL_CONNECTION_RENEW_MS);
1216                    break;
1217                case PhoneConstants.APN_REQUEST_FAILED:
1218                default:
1219                    retValue = false;
1220                    break;
1221                }
1222
1223                return retValue;
1224            }
1225            protected boolean turnOffUpstreamMobileConnection() {
1226                // ignore pending renewal requests
1227                ++mCurrentConnectionSequence;
1228                if (mMobileApnReserved != ConnectivityManager.TYPE_NONE) {
1229                    try {
1230                        mConnService.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
1231                                enableString(mMobileApnReserved));
1232                    } catch (Exception e) {
1233                        return false;
1234                    }
1235                    mMobileApnReserved = ConnectivityManager.TYPE_NONE;
1236                }
1237                return true;
1238            }
1239            protected boolean turnOnMasterTetherSettings() {
1240                try {
1241                    mNMService.setIpForwardingEnabled(true);
1242                } catch (Exception e) {
1243                    transitionTo(mSetIpForwardingEnabledErrorState);
1244                    return false;
1245                }
1246                try {
1247                    mNMService.startTethering(mDhcpRange);
1248                } catch (Exception e) {
1249                    try {
1250                        mNMService.stopTethering();
1251                        mNMService.startTethering(mDhcpRange);
1252                    } catch (Exception ee) {
1253                        transitionTo(mStartTetheringErrorState);
1254                        return false;
1255                    }
1256                }
1257                try {
1258                    mNMService.setDnsForwarders(mDefaultDnsServers);
1259                } catch (Exception e) {
1260                    transitionTo(mSetDnsForwardersErrorState);
1261                    return false;
1262                }
1263                return true;
1264            }
1265            protected boolean turnOffMasterTetherSettings() {
1266                try {
1267                    mNMService.stopTethering();
1268                } catch (Exception e) {
1269                    transitionTo(mStopTetheringErrorState);
1270                    return false;
1271                }
1272                try {
1273                    mNMService.setIpForwardingEnabled(false);
1274                } catch (Exception e) {
1275                    transitionTo(mSetIpForwardingDisabledErrorState);
1276                    return false;
1277                }
1278                transitionTo(mInitialState);
1279                return true;
1280            }
1281
1282            protected void chooseUpstreamType(boolean tryCell) {
1283                int upType = ConnectivityManager.TYPE_NONE;
1284                String iface = null;
1285
1286                updateConfiguration();
1287
1288                synchronized (mPublicSync) {
1289                    if (VDBG) {
1290                        Log.d(TAG, "chooseUpstreamType has upstream iface types:");
1291                        for (Integer netType : mUpstreamIfaceTypes) {
1292                            Log.d(TAG, " " + netType);
1293                        }
1294                    }
1295
1296                    for (Integer netType : mUpstreamIfaceTypes) {
1297                        NetworkInfo info = null;
1298                        try {
1299                            info = mConnService.getNetworkInfo(netType.intValue());
1300                        } catch (RemoteException e) { }
1301                        if ((info != null) && info.isConnected()) {
1302                            upType = netType.intValue();
1303                            break;
1304                        }
1305                    }
1306                }
1307
1308                if (DBG) {
1309                    Log.d(TAG, "chooseUpstreamType(" + tryCell + "), preferredApn ="
1310                            + mPreferredUpstreamMobileApn + ", got type=" + upType);
1311                }
1312
1313                // if we're on DUN, put our own grab on it
1314                if (upType == ConnectivityManager.TYPE_MOBILE_DUN ||
1315                        upType == ConnectivityManager.TYPE_MOBILE_HIPRI) {
1316                    turnOnUpstreamMobileConnection(upType);
1317                } else if (upType != ConnectivityManager.TYPE_NONE) {
1318                    /* If we've found an active upstream connection that's not DUN/HIPRI
1319                     * we should stop any outstanding DUN/HIPRI start requests.
1320                     *
1321                     * If we found NONE we don't want to do this as we want any previous
1322                     * requests to keep trying to bring up something we can use.
1323                     */
1324                    turnOffUpstreamMobileConnection();
1325                }
1326
1327                if (upType == ConnectivityManager.TYPE_NONE) {
1328                    boolean tryAgainLater = true;
1329                    if ((tryCell == TRY_TO_SETUP_MOBILE_CONNECTION) &&
1330                            (turnOnUpstreamMobileConnection(mPreferredUpstreamMobileApn) == true)) {
1331                        // we think mobile should be coming up - don't set a retry
1332                        tryAgainLater = false;
1333                    }
1334                    if (tryAgainLater) {
1335                        sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS);
1336                    }
1337                } else {
1338                    LinkProperties linkProperties = null;
1339                    try {
1340                        linkProperties = mConnService.getLinkProperties(upType);
1341                    } catch (RemoteException e) { }
1342                    if (linkProperties != null) {
1343                        iface = linkProperties.getInterfaceName();
1344                        String[] dnsServers = mDefaultDnsServers;
1345                        Collection<InetAddress> dnses = linkProperties.getDnses();
1346                        if (dnses != null) {
1347                            // we currently only handle IPv4
1348                            ArrayList<InetAddress> v4Dnses =
1349                                    new ArrayList<InetAddress>(dnses.size());
1350                            for (InetAddress dnsAddress : dnses) {
1351                                if (dnsAddress instanceof Inet4Address) {
1352                                    v4Dnses.add(dnsAddress);
1353                                }
1354                            }
1355                            if (v4Dnses.size() > 0) {
1356                                dnsServers = NetworkUtils.makeStrings(v4Dnses);
1357                            }
1358                        }
1359                        try {
1360                            mNMService.setDnsForwarders(dnsServers);
1361                        } catch (Exception e) {
1362                            transitionTo(mSetDnsForwardersErrorState);
1363                        }
1364                    }
1365                }
1366                notifyTetheredOfNewUpstreamIface(iface);
1367            }
1368
1369            protected void notifyTetheredOfNewUpstreamIface(String ifaceName) {
1370                if (DBG) Log.d(TAG, "notifying tethered with iface =" + ifaceName);
1371                mUpstreamIfaceName = ifaceName;
1372                for (TetherInterfaceSM sm : mNotifyList) {
1373                    sm.sendMessage(TetherInterfaceSM.CMD_TETHER_CONNECTION_CHANGED,
1374                            ifaceName);
1375                }
1376            }
1377        }
1378
1379        class InitialState extends TetherMasterUtilState {
1380            @Override
1381            public void enter() {
1382            }
1383            @Override
1384            public boolean processMessage(Message message) {
1385                if (DBG) Log.d(TAG, "MasterInitialState.processMessage what=" + message.what);
1386                boolean retValue = true;
1387                switch (message.what) {
1388                    case CMD_TETHER_MODE_REQUESTED:
1389                        TetherInterfaceSM who = (TetherInterfaceSM)message.obj;
1390                        if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
1391                        mNotifyList.add(who);
1392                        transitionTo(mTetherModeAliveState);
1393                        break;
1394                    case CMD_TETHER_MODE_UNREQUESTED:
1395                        who = (TetherInterfaceSM)message.obj;
1396                        if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
1397                        int index = mNotifyList.indexOf(who);
1398                        if (index != -1) {
1399                            mNotifyList.remove(who);
1400                        }
1401                        break;
1402                    default:
1403                        retValue = false;
1404                        break;
1405                }
1406                return retValue;
1407            }
1408        }
1409
1410        class TetherModeAliveState extends TetherMasterUtilState {
1411            boolean mTryCell = !WAIT_FOR_NETWORK_TO_SETTLE;
1412            @Override
1413            public void enter() {
1414                turnOnMasterTetherSettings(); // may transition us out
1415
1416                mTryCell = !WAIT_FOR_NETWORK_TO_SETTLE; // better try something first pass
1417                                                        // or crazy tests cases will fail
1418                chooseUpstreamType(mTryCell);
1419                mTryCell = !mTryCell;
1420            }
1421            @Override
1422            public void exit() {
1423                turnOffUpstreamMobileConnection();
1424                notifyTetheredOfNewUpstreamIface(null);
1425            }
1426            @Override
1427            public boolean processMessage(Message message) {
1428                if (DBG) Log.d(TAG, "TetherModeAliveState.processMessage what=" + message.what);
1429                boolean retValue = true;
1430                switch (message.what) {
1431                    case CMD_TETHER_MODE_REQUESTED:
1432                        TetherInterfaceSM who = (TetherInterfaceSM)message.obj;
1433                        if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
1434                        mNotifyList.add(who);
1435                        who.sendMessage(TetherInterfaceSM.CMD_TETHER_CONNECTION_CHANGED,
1436                                mUpstreamIfaceName);
1437                        break;
1438                    case CMD_TETHER_MODE_UNREQUESTED:
1439                        who = (TetherInterfaceSM)message.obj;
1440                        if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
1441                        int index = mNotifyList.indexOf(who);
1442                        if (index != -1) {
1443                            if (DBG) Log.d(TAG, "TetherModeAlive removing notifyee " + who);
1444                            mNotifyList.remove(index);
1445                            if (mNotifyList.isEmpty()) {
1446                                turnOffMasterTetherSettings(); // transitions appropriately
1447                            } else {
1448                                if (DBG) {
1449                                    Log.d(TAG, "TetherModeAlive still has " + mNotifyList.size() +
1450                                            " live requests:");
1451                                    for (Object o : mNotifyList) Log.d(TAG, "  " + o);
1452                                }
1453                            }
1454                        } else {
1455                           Log.e(TAG, "TetherModeAliveState UNREQUESTED has unknown who: " + who);
1456                        }
1457                        break;
1458                    case CMD_UPSTREAM_CHANGED:
1459                        // need to try DUN immediately if Wifi goes down
1460                        mTryCell = !WAIT_FOR_NETWORK_TO_SETTLE;
1461                        chooseUpstreamType(mTryCell);
1462                        mTryCell = !mTryCell;
1463                        break;
1464                    case CMD_CELL_CONNECTION_RENEW:
1465                        // make sure we're still using a requested connection - may have found
1466                        // wifi or something since then.
1467                        if (mCurrentConnectionSequence == message.arg1) {
1468                            if (VDBG) {
1469                                Log.d(TAG, "renewing mobile connection - requeuing for another " +
1470                                        CELL_CONNECTION_RENEW_MS + "ms");
1471                            }
1472                            turnOnUpstreamMobileConnection(mMobileApnReserved);
1473                        }
1474                        break;
1475                    case CMD_RETRY_UPSTREAM:
1476                        chooseUpstreamType(mTryCell);
1477                        mTryCell = !mTryCell;
1478                        break;
1479                    default:
1480                        retValue = false;
1481                        break;
1482                }
1483                return retValue;
1484            }
1485        }
1486
1487        class ErrorState extends State {
1488            int mErrorNotification;
1489            @Override
1490            public boolean processMessage(Message message) {
1491                boolean retValue = true;
1492                switch (message.what) {
1493                    case CMD_TETHER_MODE_REQUESTED:
1494                        TetherInterfaceSM who = (TetherInterfaceSM)message.obj;
1495                        who.sendMessage(mErrorNotification);
1496                        break;
1497                    default:
1498                       retValue = false;
1499                }
1500                return retValue;
1501            }
1502            void notify(int msgType) {
1503                mErrorNotification = msgType;
1504                for (Object o : mNotifyList) {
1505                    TetherInterfaceSM sm = (TetherInterfaceSM)o;
1506                    sm.sendMessage(msgType);
1507                }
1508            }
1509
1510        }
1511        class SetIpForwardingEnabledErrorState extends ErrorState {
1512            @Override
1513            public void enter() {
1514                Log.e(TAG, "Error in setIpForwardingEnabled");
1515                notify(TetherInterfaceSM.CMD_IP_FORWARDING_ENABLE_ERROR);
1516            }
1517        }
1518
1519        class SetIpForwardingDisabledErrorState extends ErrorState {
1520            @Override
1521            public void enter() {
1522                Log.e(TAG, "Error in setIpForwardingDisabled");
1523                notify(TetherInterfaceSM.CMD_IP_FORWARDING_DISABLE_ERROR);
1524            }
1525        }
1526
1527        class StartTetheringErrorState extends ErrorState {
1528            @Override
1529            public void enter() {
1530                Log.e(TAG, "Error in startTethering");
1531                notify(TetherInterfaceSM.CMD_START_TETHERING_ERROR);
1532                try {
1533                    mNMService.setIpForwardingEnabled(false);
1534                } catch (Exception e) {}
1535            }
1536        }
1537
1538        class StopTetheringErrorState extends ErrorState {
1539            @Override
1540            public void enter() {
1541                Log.e(TAG, "Error in stopTethering");
1542                notify(TetherInterfaceSM.CMD_STOP_TETHERING_ERROR);
1543                try {
1544                    mNMService.setIpForwardingEnabled(false);
1545                } catch (Exception e) {}
1546            }
1547        }
1548
1549        class SetDnsForwardersErrorState extends ErrorState {
1550            @Override
1551            public void enter() {
1552                Log.e(TAG, "Error in setDnsForwarders");
1553                notify(TetherInterfaceSM.CMD_SET_DNS_FORWARDERS_ERROR);
1554                try {
1555                    mNMService.stopTethering();
1556                } catch (Exception e) {}
1557                try {
1558                    mNMService.setIpForwardingEnabled(false);
1559                } catch (Exception e) {}
1560            }
1561        }
1562    }
1563
1564    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1565        if (mContext.checkCallingOrSelfPermission(
1566                android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) {
1567            pw.println("Permission Denial: can't dump ConnectivityService.Tether " +
1568                    "from from pid=" + Binder.getCallingPid() + ", uid=" +
1569                    Binder.getCallingUid());
1570                    return;
1571        }
1572
1573        synchronized (mPublicSync) {
1574            pw.println("mUpstreamIfaceTypes: ");
1575            for (Integer netType : mUpstreamIfaceTypes) {
1576                pw.println(" " + netType);
1577            }
1578
1579            pw.println();
1580            pw.println("Tether state:");
1581            for (Object o : mIfaces.values()) {
1582                pw.println(" " + o);
1583            }
1584        }
1585        pw.println();
1586        return;
1587    }
1588}
1589