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