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