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