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