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