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