OSDN Git Service

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