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