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