2 * Copyright (C) 2010 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.server.connectivity;
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;
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;
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;
71 * TODO - look for parent classes and code sharing
73 public class Tethering extends INetworkManagementEventObserver.Stub {
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;
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;
86 // used to synchronize public access to members
87 private Object mPublicSync;
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);
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;
97 private final INetworkManagementService mNMService;
98 private final INetworkStatsService mStatsService;
99 private final IConnectivityManager mConnService;
100 private Looper mLooper;
102 private HashMap<String, TetherInterfaceSM> mIfaces; // all tethered/tetherable ifaces
104 private BroadcastReceiver mStateReceiver;
106 private static final String USB_NEAR_IFACE_ADDR = "192.168.42.129";
107 private static final int USB_PREFIX_LENGTH = 24;
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
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",
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";
126 private StateMachine mTetherMasterSM;
128 private Notification mTetheredNotification;
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
134 public Tethering(Context context, INetworkManagementService nmService,
135 INetworkStatsService statsService, IConnectivityManager connService, Looper looper) {
137 mNMService = nmService;
138 mStatsService = statsService;
139 mConnService = connService;
142 mPublicSync = new Object();
144 mIfaces = new HashMap<String, TetherInterfaceSM>();
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();
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);
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);
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;
170 // load device config info
171 updateConfiguration();
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;
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);
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));
194 synchronized (mPublicSync) {
195 mTetherableUsbRegexs = tetherableUsbRegexs;
196 mTetherableWifiRegexs = tetherableWifiRegexs;
197 mTetherableBluetoothRegexs = tetherableBluetoothRegexs;
198 mUpstreamIfaceTypes = upstreamIfaceTypes;
201 // check if the upstream type list needs to be modified due to secure-settings
205 public void interfaceStatusChanged(String iface, boolean up) {
206 if (VDBG) Log.d(TAG, "interfaceStatusChanged " + iface + ", " + up);
207 boolean found = false;
209 synchronized (mPublicSync) {
212 } else if (isUsb(iface)) {
215 } else if (isBluetooth(iface)) {
218 if (found == false) return;
220 TetherInterfaceSM sm = mIfaces.get(iface);
223 sm = new TetherInterfaceSM(iface, mLooper, usb);
224 mIfaces.put(iface, sm);
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 (isBluetooth(iface)) {
233 // ignore interface down for bt liskstate change
234 // disconnect will only be handled in interfaceRemoved
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);
244 public void interfaceLinkStateChanged(String iface, boolean up) {
245 if (VDBG) Log.d(TAG, "interfaceLinkStateChanged " + iface + ", " + up);
246 interfaceStatusChanged(iface, up);
249 private boolean isUsb(String iface) {
250 synchronized (mPublicSync) {
251 for (String regex : mTetherableUsbRegexs) {
252 if (iface.matches(regex)) return true;
258 public boolean isWifi(String iface) {
259 synchronized (mPublicSync) {
260 for (String regex : mTetherableWifiRegexs) {
261 if (iface.matches(regex)) return true;
267 public boolean isBluetooth(String iface) {
268 synchronized (mPublicSync) {
269 for (String regex : mTetherableBluetoothRegexs) {
270 if (iface.matches(regex)) return true;
276 public void interfaceAdded(String iface) {
277 if (VDBG) Log.d(TAG, "interfaceAdded " + iface);
278 boolean found = false;
280 synchronized (mPublicSync) {
288 if (isBluetooth(iface)) {
291 if (found == false) {
292 if (VDBG) Log.d(TAG, iface + " is not a tetherable iface, ignoring");
296 TetherInterfaceSM sm = mIfaces.get(iface);
298 if (VDBG) Log.d(TAG, "active iface (" + iface + ") reported as added, ignoring");
301 sm = new TetherInterfaceSM(iface, mLooper, usb);
302 mIfaces.put(iface, sm);
307 public void interfaceRemoved(String iface) {
308 if (VDBG) Log.d(TAG, "interfaceRemoved " + iface);
309 synchronized (mPublicSync) {
310 TetherInterfaceSM sm = mIfaces.get(iface);
313 Log.e(TAG, "attempting to remove unknown iface (" + iface + "), ignoring");
317 sm.sendMessage(TetherInterfaceSM.CMD_INTERFACE_DOWN);
318 mIfaces.remove(iface);
322 public void addressUpdated(String address, String iface, int flags, int scope) {}
324 public void addressRemoved(String address, String iface, int flags, int scope) {}
326 public void limitReached(String limitName, String iface) {}
328 public void interfaceClassDataActivityChanged(String label, boolean active) {}
330 public int tether(String iface) {
331 if (DBG) Log.d(TAG, "Tethering " + iface);
332 TetherInterfaceSM sm = null;
333 synchronized (mPublicSync) {
334 sm = mIfaces.get(iface);
337 Log.e(TAG, "Tried to Tether an unknown iface :" + iface + ", ignoring");
338 return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
340 if (!sm.isAvailable() && !sm.isErrored()) {
341 Log.e(TAG, "Tried to Tether an unavailable iface :" + iface + ", ignoring");
342 return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
344 sm.sendMessage(TetherInterfaceSM.CMD_TETHER_REQUESTED);
345 return ConnectivityManager.TETHER_ERROR_NO_ERROR;
348 public int untether(String iface) {
349 if (DBG) Log.d(TAG, "Untethering " + iface);
350 TetherInterfaceSM sm = null;
351 synchronized (mPublicSync) {
352 sm = mIfaces.get(iface);
355 Log.e(TAG, "Tried to Untether an unknown iface :" + iface + ", ignoring");
356 return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
358 if (sm.isErrored()) {
359 Log.e(TAG, "Tried to Untethered an errored iface :" + iface + ", ignoring");
360 return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
362 sm.sendMessage(TetherInterfaceSM.CMD_TETHER_UNREQUESTED);
363 return ConnectivityManager.TETHER_ERROR_NO_ERROR;
366 public int getLastTetherError(String iface) {
367 TetherInterfaceSM sm = null;
368 synchronized (mPublicSync) {
369 sm = mIfaces.get(iface);
371 Log.e(TAG, "Tried to getLastTetherError on an unknown iface :" + iface +
373 return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
375 return sm.getLastError();
379 // TODO - move all private methods used only by the state machine into the state machine
380 // to clarify what needs synchronized protection.
381 private void sendTetherStateChangedBroadcast() {
383 if (!mConnService.isTetheringSupported()) return;
384 } catch (RemoteException e) {
388 ArrayList<String> availableList = new ArrayList<String>();
389 ArrayList<String> activeList = new ArrayList<String>();
390 ArrayList<String> erroredList = new ArrayList<String>();
392 boolean wifiTethered = false;
393 boolean usbTethered = false;
394 boolean bluetoothTethered = false;
396 synchronized (mPublicSync) {
397 Set ifaces = mIfaces.keySet();
398 for (Object iface : ifaces) {
399 TetherInterfaceSM sm = mIfaces.get(iface);
401 if (sm.isErrored()) {
402 erroredList.add((String)iface);
403 } else if (sm.isAvailable()) {
404 availableList.add((String)iface);
405 } else if (sm.isTethered()) {
406 if (isUsb((String)iface)) {
408 } else if (isWifi((String)iface)) {
410 } else if (isBluetooth((String)iface)) {
411 bluetoothTethered = true;
413 activeList.add((String)iface);
418 Intent broadcast = new Intent(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
419 broadcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
420 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
421 broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_AVAILABLE_TETHER,
423 broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_TETHER, activeList);
424 broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ERRORED_TETHER,
426 mContext.sendStickyBroadcastAsUser(broadcast, UserHandle.ALL);
428 Log.d(TAG, "sendTetherStateChangedBroadcast " + availableList.size() + ", " +
429 activeList.size() + ", " + erroredList.size());
433 if (wifiTethered || bluetoothTethered) {
434 showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_general);
436 showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_usb);
438 } else if (wifiTethered) {
439 if (bluetoothTethered) {
440 showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_general);
442 showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_wifi);
444 } else if (bluetoothTethered) {
445 showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_bluetooth);
447 clearTetheredNotification();
451 private void showTetheredNotification(int icon) {
452 NotificationManager notificationManager =
453 (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE);
454 if (notificationManager == null) {
458 if (mTetheredNotification != null) {
459 if (mTetheredNotification.icon == icon) {
462 notificationManager.cancelAsUser(null, mTetheredNotification.icon,
466 Intent intent = new Intent();
467 intent.setClassName("com.android.settings", "com.android.settings.TetherSettings");
468 intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
470 PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0, intent, 0,
471 null, UserHandle.CURRENT);
473 Resources r = Resources.getSystem();
474 CharSequence title = r.getText(com.android.internal.R.string.tethered_notification_title);
475 CharSequence message = r.getText(com.android.internal.R.string.
476 tethered_notification_message);
478 if (mTetheredNotification == null) {
479 mTetheredNotification = new Notification();
480 mTetheredNotification.when = 0;
482 mTetheredNotification.icon = icon;
483 mTetheredNotification.defaults &= ~Notification.DEFAULT_SOUND;
484 mTetheredNotification.flags = Notification.FLAG_ONGOING_EVENT;
485 mTetheredNotification.tickerText = title;
486 mTetheredNotification.setLatestEventInfo(mContext, title, message, pi);
488 notificationManager.notifyAsUser(null, mTetheredNotification.icon,
489 mTetheredNotification, UserHandle.ALL);
492 private void clearTetheredNotification() {
493 NotificationManager notificationManager =
494 (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE);
495 if (notificationManager != null && mTetheredNotification != null) {
496 notificationManager.cancelAsUser(null, mTetheredNotification.icon,
498 mTetheredNotification = null;
502 private class StateReceiver extends BroadcastReceiver {
503 public void onReceive(Context content, Intent intent) {
504 String action = intent.getAction();
505 if (action.equals(UsbManager.ACTION_USB_STATE)) {
506 synchronized (Tethering.this.mPublicSync) {
507 boolean usbConnected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false);
508 mRndisEnabled = intent.getBooleanExtra(UsbManager.USB_FUNCTION_RNDIS, false);
509 // start tethering if we have a request pending
510 if (usbConnected && mRndisEnabled && mUsbTetherRequested) {
513 mUsbTetherRequested = false;
515 } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
516 NetworkInfo networkInfo = (NetworkInfo)intent.getParcelableExtra(
517 ConnectivityManager.EXTRA_NETWORK_INFO);
518 if (networkInfo != null &&
519 networkInfo.getDetailedState() != NetworkInfo.DetailedState.FAILED) {
520 if (VDBG) Log.d(TAG, "Tethering got CONNECTIVITY_ACTION");
521 mTetherMasterSM.sendMessage(TetherMasterSM.CMD_UPSTREAM_CHANGED);
523 } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
524 updateConfiguration();
529 private void tetherUsb(boolean enable) {
530 if (VDBG) Log.d(TAG, "tetherUsb " + enable);
532 String[] ifaces = new String[0];
534 ifaces = mNMService.listInterfaces();
535 } catch (Exception e) {
536 Log.e(TAG, "Error listing Interfaces", e);
539 for (String iface : ifaces) {
541 int result = (enable ? tether(iface) : untether(iface));
542 if (result == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
547 Log.e(TAG, "unable start or stop USB tethering");
550 // configured when we start tethering and unconfig'd on error or conclusion
551 private boolean configureUsbIface(boolean enabled) {
552 if (VDBG) Log.d(TAG, "configureUsbIface(" + enabled + ")");
554 // toggle the USB interfaces
555 String[] ifaces = new String[0];
557 ifaces = mNMService.listInterfaces();
558 } catch (Exception e) {
559 Log.e(TAG, "Error listing Interfaces", e);
562 for (String iface : ifaces) {
564 InterfaceConfiguration ifcg = null;
566 ifcg = mNMService.getInterfaceConfig(iface);
568 InetAddress addr = NetworkUtils.numericToInetAddress(USB_NEAR_IFACE_ADDR);
569 ifcg.setLinkAddress(new LinkAddress(addr, USB_PREFIX_LENGTH));
571 ifcg.setInterfaceUp();
573 ifcg.setInterfaceDown();
575 ifcg.clearFlag("running");
576 mNMService.setInterfaceConfig(iface, ifcg);
578 } catch (Exception e) {
579 Log.e(TAG, "Error configuring interface " + iface, e);
588 // TODO - return copies so people can't tamper
589 public String[] getTetherableUsbRegexs() {
590 return mTetherableUsbRegexs;
593 public String[] getTetherableWifiRegexs() {
594 return mTetherableWifiRegexs;
597 public String[] getTetherableBluetoothRegexs() {
598 return mTetherableBluetoothRegexs;
601 public int setUsbTethering(boolean enable) {
602 if (VDBG) Log.d(TAG, "setUsbTethering(" + enable + ")");
603 UsbManager usbManager = (UsbManager)mContext.getSystemService(Context.USB_SERVICE);
605 synchronized (mPublicSync) {
610 mUsbTetherRequested = true;
611 usbManager.setCurrentFunction(UsbManager.USB_FUNCTION_RNDIS, false);
616 usbManager.setCurrentFunction(null, false);
618 mUsbTetherRequested = false;
621 return ConnectivityManager.TETHER_ERROR_NO_ERROR;
624 public int[] getUpstreamIfaceTypes() {
626 synchronized (mPublicSync) {
627 updateConfiguration(); // TODO - remove?
628 values = new int[mUpstreamIfaceTypes.size()];
629 Iterator<Integer> iterator = mUpstreamIfaceTypes.iterator();
630 for (int i=0; i < mUpstreamIfaceTypes.size(); i++) {
631 values[i] = iterator.next();
637 public void checkDunRequired() {
638 int secureSetting = Settings.Global.getInt(mContext.getContentResolver(),
639 Settings.Global.TETHER_DUN_REQUIRED, 2);
640 synchronized (mPublicSync) {
641 // 2 = not set, 0 = DUN not required, 1 = DUN required
642 if (secureSetting != 2) {
643 int requiredApn = (secureSetting == 1 ?
644 ConnectivityManager.TYPE_MOBILE_DUN :
645 ConnectivityManager.TYPE_MOBILE_HIPRI);
646 if (requiredApn == ConnectivityManager.TYPE_MOBILE_DUN) {
647 while (mUpstreamIfaceTypes.contains(MOBILE_TYPE)) {
648 mUpstreamIfaceTypes.remove(MOBILE_TYPE);
650 while (mUpstreamIfaceTypes.contains(HIPRI_TYPE)) {
651 mUpstreamIfaceTypes.remove(HIPRI_TYPE);
653 if (mUpstreamIfaceTypes.contains(DUN_TYPE) == false) {
654 mUpstreamIfaceTypes.add(DUN_TYPE);
657 while (mUpstreamIfaceTypes.contains(DUN_TYPE)) {
658 mUpstreamIfaceTypes.remove(DUN_TYPE);
660 if (mUpstreamIfaceTypes.contains(MOBILE_TYPE) == false) {
661 mUpstreamIfaceTypes.add(MOBILE_TYPE);
663 if (mUpstreamIfaceTypes.contains(HIPRI_TYPE) == false) {
664 mUpstreamIfaceTypes.add(HIPRI_TYPE);
668 if (mUpstreamIfaceTypes.contains(DUN_TYPE)) {
669 mPreferredUpstreamMobileApn = ConnectivityManager.TYPE_MOBILE_DUN;
671 mPreferredUpstreamMobileApn = ConnectivityManager.TYPE_MOBILE_HIPRI;
676 // TODO review API - maybe return ArrayList<String> here and below?
677 public String[] getTetheredIfaces() {
678 ArrayList<String> list = new ArrayList<String>();
679 synchronized (mPublicSync) {
680 Set keys = mIfaces.keySet();
681 for (Object key : keys) {
682 TetherInterfaceSM sm = mIfaces.get(key);
683 if (sm.isTethered()) {
684 list.add((String)key);
688 String[] retVal = new String[list.size()];
689 for (int i=0; i < list.size(); i++) {
690 retVal[i] = list.get(i);
695 public String[] getTetherableIfaces() {
696 ArrayList<String> list = new ArrayList<String>();
697 synchronized (mPublicSync) {
698 Set keys = mIfaces.keySet();
699 for (Object key : keys) {
700 TetherInterfaceSM sm = mIfaces.get(key);
701 if (sm.isAvailable()) {
702 list.add((String)key);
706 String[] retVal = new String[list.size()];
707 for (int i=0; i < list.size(); i++) {
708 retVal[i] = list.get(i);
713 public String[] getErroredIfaces() {
714 ArrayList<String> list = new ArrayList<String>();
715 synchronized (mPublicSync) {
716 Set keys = mIfaces.keySet();
717 for (Object key : keys) {
718 TetherInterfaceSM sm = mIfaces.get(key);
719 if (sm.isErrored()) {
720 list.add((String)key);
724 String[] retVal = new String[list.size()];
725 for (int i= 0; i< list.size(); i++) {
726 retVal[i] = list.get(i);
731 //TODO: Temporary handling upstream change triggered without
732 // CONNECTIVITY_ACTION. Only to accomodate interface
735 public void handleTetherIfaceChange() {
736 mTetherMasterSM.sendMessage(TetherMasterSM.CMD_UPSTREAM_CHANGED);
739 class TetherInterfaceSM extends StateMachine {
740 // notification from the master SM that it's not in tether mode
741 static final int CMD_TETHER_MODE_DEAD = 1;
742 // request from the user that it wants to tether
743 static final int CMD_TETHER_REQUESTED = 2;
744 // request from the user that it wants to untether
745 static final int CMD_TETHER_UNREQUESTED = 3;
746 // notification that this interface is down
747 static final int CMD_INTERFACE_DOWN = 4;
748 // notification that this interface is up
749 static final int CMD_INTERFACE_UP = 5;
750 // notification from the master SM that it had an error turning on cellular dun
751 static final int CMD_CELL_DUN_ERROR = 6;
752 // notification from the master SM that it had trouble enabling IP Forwarding
753 static final int CMD_IP_FORWARDING_ENABLE_ERROR = 7;
754 // notification from the master SM that it had trouble disabling IP Forwarding
755 static final int CMD_IP_FORWARDING_DISABLE_ERROR = 8;
756 // notification from the master SM that it had trouble staring tethering
757 static final int CMD_START_TETHERING_ERROR = 9;
758 // notification from the master SM that it had trouble stopping tethering
759 static final int CMD_STOP_TETHERING_ERROR = 10;
760 // notification from the master SM that it had trouble setting the DNS forwarders
761 static final int CMD_SET_DNS_FORWARDERS_ERROR = 11;
762 // the upstream connection has changed
763 static final int CMD_TETHER_CONNECTION_CHANGED = 12;
765 private State mDefaultState;
767 private State mInitialState;
768 private State mStartingState;
769 private State mTetheredState;
771 private State mUnavailableState;
773 private boolean mAvailable;
774 private boolean mTethered;
778 String mMyUpstreamIfaceName; // may change over time
782 TetherInterfaceSM(String name, Looper looper, boolean usb) {
786 setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR);
788 mInitialState = new InitialState();
789 addState(mInitialState);
790 mStartingState = new StartingState();
791 addState(mStartingState);
792 mTetheredState = new TetheredState();
793 addState(mTetheredState);
794 mUnavailableState = new UnavailableState();
795 addState(mUnavailableState);
797 setInitialState(mInitialState);
800 public String toString() {
801 String res = new String();
802 res += mIfaceName + " - ";
803 IState current = getCurrentState();
804 if (current == mInitialState) res += "InitialState";
805 if (current == mStartingState) res += "StartingState";
806 if (current == mTetheredState) res += "TetheredState";
807 if (current == mUnavailableState) res += "UnavailableState";
808 if (mAvailable) res += " - Available";
809 if (mTethered) res += " - Tethered";
810 res += " - lastError =" + mLastError;
814 public int getLastError() {
815 synchronized (Tethering.this.mPublicSync) {
820 private void setLastError(int error) {
821 synchronized (Tethering.this.mPublicSync) {
826 // note everything's been unwound by this point so nothing to do on
828 Tethering.this.configureUsbIface(false);
834 public boolean isAvailable() {
835 synchronized (Tethering.this.mPublicSync) {
840 private void setAvailable(boolean available) {
841 synchronized (Tethering.this.mPublicSync) {
842 mAvailable = available;
846 public boolean isTethered() {
847 synchronized (Tethering.this.mPublicSync) {
852 private void setTethered(boolean tethered) {
853 synchronized (Tethering.this.mPublicSync) {
854 mTethered = tethered;
858 public boolean isErrored() {
859 synchronized (Tethering.this.mPublicSync) {
860 return (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR);
864 class InitialState extends State {
866 public void enter() {
869 sendTetherStateChangedBroadcast();
873 public boolean processMessage(Message message) {
874 if (DBG) Log.d(TAG, "InitialState.processMessage what=" + message.what);
875 boolean retValue = true;
876 switch (message.what) {
877 case CMD_TETHER_REQUESTED:
878 setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR);
879 mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_REQUESTED,
880 TetherInterfaceSM.this);
881 transitionTo(mStartingState);
883 case CMD_INTERFACE_DOWN:
884 transitionTo(mUnavailableState);
894 class StartingState extends State {
896 public void enter() {
899 if (!Tethering.this.configureUsbIface(true)) {
900 mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED,
901 TetherInterfaceSM.this);
902 setLastError(ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
904 transitionTo(mInitialState);
908 sendTetherStateChangedBroadcast();
910 // Skipping StartingState
911 transitionTo(mTetheredState);
914 public boolean processMessage(Message message) {
915 if (DBG) Log.d(TAG, "StartingState.processMessage what=" + message.what);
916 boolean retValue = true;
917 switch (message.what) {
918 // maybe a parent class?
919 case CMD_TETHER_UNREQUESTED:
920 mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED,
921 TetherInterfaceSM.this);
923 if (!Tethering.this.configureUsbIface(false)) {
924 setLastErrorAndTransitionToInitialState(
925 ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
929 transitionTo(mInitialState);
931 case CMD_CELL_DUN_ERROR:
932 case CMD_IP_FORWARDING_ENABLE_ERROR:
933 case CMD_IP_FORWARDING_DISABLE_ERROR:
934 case CMD_START_TETHERING_ERROR:
935 case CMD_STOP_TETHERING_ERROR:
936 case CMD_SET_DNS_FORWARDERS_ERROR:
937 setLastErrorAndTransitionToInitialState(
938 ConnectivityManager.TETHER_ERROR_MASTER_ERROR);
940 case CMD_INTERFACE_DOWN:
941 mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED,
942 TetherInterfaceSM.this);
943 transitionTo(mUnavailableState);
952 class TetheredState extends State {
954 public void enter() {
956 mNMService.tetherInterface(mIfaceName);
957 } catch (Exception e) {
958 Log.e(TAG, "Error Tethering: " + e.toString());
959 setLastError(ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR);
961 transitionTo(mInitialState);
964 if (DBG) Log.d(TAG, "Tethered " + mIfaceName);
967 sendTetherStateChangedBroadcast();
970 private void cleanupUpstream() {
971 if (mMyUpstreamIfaceName != null) {
972 // note that we don't care about errors here.
973 // sometimes interfaces are gone before we get
974 // to remove their rules, which generates errors.
975 // just do the best we can.
977 // about to tear down NAT; gather remaining statistics
978 mStatsService.forceUpdate();
979 } catch (Exception e) {
980 if (VDBG) Log.e(TAG, "Exception in forceUpdate: " + e.toString());
983 mNMService.disableNat(mIfaceName, mMyUpstreamIfaceName);
984 } catch (Exception e) {
985 if (VDBG) Log.e(TAG, "Exception in disableNat: " + e.toString());
987 mMyUpstreamIfaceName = null;
993 public boolean processMessage(Message message) {
994 if (DBG) Log.d(TAG, "TetheredState.processMessage what=" + message.what);
995 boolean retValue = true;
996 boolean error = false;
997 switch (message.what) {
998 case CMD_TETHER_UNREQUESTED:
999 case CMD_INTERFACE_DOWN:
1002 mNMService.untetherInterface(mIfaceName);
1003 } catch (Exception e) {
1004 setLastErrorAndTransitionToInitialState(
1005 ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR);
1008 mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED,
1009 TetherInterfaceSM.this);
1010 if (message.what == CMD_TETHER_UNREQUESTED) {
1012 if (!Tethering.this.configureUsbIface(false)) {
1014 ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
1017 transitionTo(mInitialState);
1018 } else if (message.what == CMD_INTERFACE_DOWN) {
1019 transitionTo(mUnavailableState);
1021 if (DBG) Log.d(TAG, "Untethered " + mIfaceName);
1023 case CMD_TETHER_CONNECTION_CHANGED:
1024 String newUpstreamIfaceName = (String)(message.obj);
1025 if ((mMyUpstreamIfaceName == null && newUpstreamIfaceName == null) ||
1026 (mMyUpstreamIfaceName != null &&
1027 mMyUpstreamIfaceName.equals(newUpstreamIfaceName))) {
1028 if (VDBG) Log.d(TAG, "Connection changed noop - dropping");
1032 if (newUpstreamIfaceName != null) {
1034 mNMService.enableNat(mIfaceName, newUpstreamIfaceName);
1035 } catch (Exception e) {
1036 Log.e(TAG, "Exception enabling Nat: " + e.toString());
1038 mNMService.untetherInterface(mIfaceName);
1039 } catch (Exception ee) {}
1041 setLastError(ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR);
1042 transitionTo(mInitialState);
1046 mMyUpstreamIfaceName = newUpstreamIfaceName;
1048 case CMD_CELL_DUN_ERROR:
1049 case CMD_IP_FORWARDING_ENABLE_ERROR:
1050 case CMD_IP_FORWARDING_DISABLE_ERROR:
1051 case CMD_START_TETHERING_ERROR:
1052 case CMD_STOP_TETHERING_ERROR:
1053 case CMD_SET_DNS_FORWARDERS_ERROR:
1056 case CMD_TETHER_MODE_DEAD:
1059 mNMService.untetherInterface(mIfaceName);
1060 } catch (Exception e) {
1061 setLastErrorAndTransitionToInitialState(
1062 ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR);
1066 setLastErrorAndTransitionToInitialState(
1067 ConnectivityManager.TETHER_ERROR_MASTER_ERROR);
1070 if (DBG) Log.d(TAG, "Tether lost upstream connection " + mIfaceName);
1071 sendTetherStateChangedBroadcast();
1073 if (!Tethering.this.configureUsbIface(false)) {
1074 setLastError(ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
1077 transitionTo(mInitialState);
1087 class UnavailableState extends State {
1089 public void enter() {
1090 setAvailable(false);
1091 setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR);
1093 sendTetherStateChangedBroadcast();
1096 public boolean processMessage(Message message) {
1097 boolean retValue = true;
1098 switch (message.what) {
1099 case CMD_INTERFACE_UP:
1100 transitionTo(mInitialState);
1110 void setLastErrorAndTransitionToInitialState(int error) {
1111 setLastError(error);
1112 transitionTo(mInitialState);
1117 class TetherMasterSM extends StateMachine {
1118 // an interface SM has requested Tethering
1119 static final int CMD_TETHER_MODE_REQUESTED = 1;
1120 // an interface SM has unrequested Tethering
1121 static final int CMD_TETHER_MODE_UNREQUESTED = 2;
1122 // upstream connection change - do the right thing
1123 static final int CMD_UPSTREAM_CHANGED = 3;
1124 // we received notice that the cellular DUN connection is up
1125 static final int CMD_CELL_CONNECTION_RENEW = 4;
1126 // we don't have a valid upstream conn, check again after a delay
1127 static final int CMD_RETRY_UPSTREAM = 5;
1129 // This indicates what a timeout event relates to. A state that
1130 // sends itself a delayed timeout event and handles incoming timeout events
1131 // should inc this when it is entered and whenever it sends a new timeout event.
1132 // We do not flush the old ones.
1133 private int mSequenceNumber;
1135 private State mInitialState;
1136 private State mTetherModeAliveState;
1138 private State mSetIpForwardingEnabledErrorState;
1139 private State mSetIpForwardingDisabledErrorState;
1140 private State mStartTetheringErrorState;
1141 private State mStopTetheringErrorState;
1142 private State mSetDnsForwardersErrorState;
1144 private ArrayList<TetherInterfaceSM> mNotifyList;
1146 private int mCurrentConnectionSequence;
1147 private int mMobileApnReserved = ConnectivityManager.TYPE_NONE;
1149 private String mUpstreamIfaceName = null;
1151 private static final int UPSTREAM_SETTLE_TIME_MS = 10000;
1152 private static final int CELL_CONNECTION_RENEW_MS = 40000;
1154 TetherMasterSM(String name, Looper looper) {
1155 super(name, looper);
1158 mInitialState = new InitialState();
1159 addState(mInitialState);
1160 mTetherModeAliveState = new TetherModeAliveState();
1161 addState(mTetherModeAliveState);
1163 mSetIpForwardingEnabledErrorState = new SetIpForwardingEnabledErrorState();
1164 addState(mSetIpForwardingEnabledErrorState);
1165 mSetIpForwardingDisabledErrorState = new SetIpForwardingDisabledErrorState();
1166 addState(mSetIpForwardingDisabledErrorState);
1167 mStartTetheringErrorState = new StartTetheringErrorState();
1168 addState(mStartTetheringErrorState);
1169 mStopTetheringErrorState = new StopTetheringErrorState();
1170 addState(mStopTetheringErrorState);
1171 mSetDnsForwardersErrorState = new SetDnsForwardersErrorState();
1172 addState(mSetDnsForwardersErrorState);
1174 mNotifyList = new ArrayList<TetherInterfaceSM>();
1175 setInitialState(mInitialState);
1178 class TetherMasterUtilState extends State {
1179 protected final static boolean TRY_TO_SETUP_MOBILE_CONNECTION = true;
1180 protected final static boolean WAIT_FOR_NETWORK_TO_SETTLE = false;
1183 public boolean processMessage(Message m) {
1186 protected String enableString(int apnType) {
1188 case ConnectivityManager.TYPE_MOBILE_DUN:
1189 return Phone.FEATURE_ENABLE_DUN_ALWAYS;
1190 case ConnectivityManager.TYPE_MOBILE:
1191 case ConnectivityManager.TYPE_MOBILE_HIPRI:
1192 return Phone.FEATURE_ENABLE_HIPRI;
1196 protected boolean turnOnUpstreamMobileConnection(int apnType) {
1197 boolean retValue = true;
1198 if (apnType == ConnectivityManager.TYPE_NONE) return false;
1199 if (apnType != mMobileApnReserved) turnOffUpstreamMobileConnection();
1200 int result = PhoneConstants.APN_REQUEST_FAILED;
1201 String enableString = enableString(apnType);
1202 if (enableString == null) return false;
1204 result = mConnService.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
1205 enableString, new Binder());
1206 } catch (Exception e) {
1209 case PhoneConstants.APN_ALREADY_ACTIVE:
1210 case PhoneConstants.APN_REQUEST_STARTED:
1211 mMobileApnReserved = apnType;
1212 Message m = obtainMessage(CMD_CELL_CONNECTION_RENEW);
1213 m.arg1 = ++mCurrentConnectionSequence;
1214 sendMessageDelayed(m, CELL_CONNECTION_RENEW_MS);
1216 case PhoneConstants.APN_REQUEST_FAILED:
1224 protected boolean turnOffUpstreamMobileConnection() {
1225 // ignore pending renewal requests
1226 ++mCurrentConnectionSequence;
1227 if (mMobileApnReserved != ConnectivityManager.TYPE_NONE) {
1229 mConnService.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
1230 enableString(mMobileApnReserved));
1231 } catch (Exception e) {
1234 mMobileApnReserved = ConnectivityManager.TYPE_NONE;
1238 protected boolean turnOnMasterTetherSettings() {
1240 mNMService.setIpForwardingEnabled(true);
1241 } catch (Exception e) {
1242 transitionTo(mSetIpForwardingEnabledErrorState);
1246 mNMService.startTethering(mDhcpRange);
1247 } catch (Exception e) {
1249 mNMService.stopTethering();
1250 mNMService.startTethering(mDhcpRange);
1251 } catch (Exception ee) {
1252 transitionTo(mStartTetheringErrorState);
1257 mNMService.setDnsForwarders(mDefaultDnsServers);
1258 } catch (Exception e) {
1259 transitionTo(mSetDnsForwardersErrorState);
1264 protected boolean turnOffMasterTetherSettings() {
1266 mNMService.stopTethering();
1267 } catch (Exception e) {
1268 transitionTo(mStopTetheringErrorState);
1272 mNMService.setIpForwardingEnabled(false);
1273 } catch (Exception e) {
1274 transitionTo(mSetIpForwardingDisabledErrorState);
1277 transitionTo(mInitialState);
1281 protected void chooseUpstreamType(boolean tryCell) {
1282 int upType = ConnectivityManager.TYPE_NONE;
1283 String iface = null;
1285 updateConfiguration(); // TODO - remove?
1287 synchronized (mPublicSync) {
1289 Log.d(TAG, "chooseUpstreamType has upstream iface types:");
1290 for (Integer netType : mUpstreamIfaceTypes) {
1291 Log.d(TAG, " " + netType);
1295 for (Integer netType : mUpstreamIfaceTypes) {
1296 NetworkInfo info = null;
1298 info = mConnService.getNetworkInfo(netType.intValue());
1299 } catch (RemoteException e) { }
1300 if ((info != null) && info.isConnected()) {
1301 upType = netType.intValue();
1308 Log.d(TAG, "chooseUpstreamType(" + tryCell + "), preferredApn ="
1309 + mPreferredUpstreamMobileApn + ", got type=" + upType);
1312 // if we're on DUN, put our own grab on it
1313 if (upType == ConnectivityManager.TYPE_MOBILE_DUN ||
1314 upType == ConnectivityManager.TYPE_MOBILE_HIPRI) {
1315 turnOnUpstreamMobileConnection(upType);
1316 } else if (upType != ConnectivityManager.TYPE_NONE) {
1317 /* If we've found an active upstream connection that's not DUN/HIPRI
1318 * we should stop any outstanding DUN/HIPRI start requests.
1320 * If we found NONE we don't want to do this as we want any previous
1321 * requests to keep trying to bring up something we can use.
1323 turnOffUpstreamMobileConnection();
1326 if (upType == ConnectivityManager.TYPE_NONE) {
1327 boolean tryAgainLater = true;
1328 if ((tryCell == TRY_TO_SETUP_MOBILE_CONNECTION) &&
1329 (turnOnUpstreamMobileConnection(mPreferredUpstreamMobileApn) == true)) {
1330 // we think mobile should be coming up - don't set a retry
1331 tryAgainLater = false;
1333 if (tryAgainLater) {
1334 sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS);
1337 LinkProperties linkProperties = null;
1339 linkProperties = mConnService.getLinkProperties(upType);
1340 } catch (RemoteException e) { }
1341 if (linkProperties != null) {
1342 // Find the interface with the default IPv4 route. It may be the
1343 // interface described by linkProperties, or one of the interfaces
1344 // stacked on top of it.
1345 Log.i(TAG, "Finding IPv4 upstream interface on: " + linkProperties);
1346 RouteInfo ipv4Default = RouteInfo.selectBestRoute(
1347 linkProperties.getAllRoutes(), Inet4Address.ANY);
1348 if (ipv4Default != null) {
1349 iface = ipv4Default.getInterface();
1350 Log.i(TAG, "Found interface " + ipv4Default.getInterface());
1352 Log.i(TAG, "No IPv4 upstream interface, giving up.");
1356 if (iface != null) {
1357 String[] dnsServers = mDefaultDnsServers;
1358 Collection<InetAddress> dnses = linkProperties.getDnses();
1359 if (dnses != null) {
1360 // we currently only handle IPv4
1361 ArrayList<InetAddress> v4Dnses =
1362 new ArrayList<InetAddress>(dnses.size());
1363 for (InetAddress dnsAddress : dnses) {
1364 if (dnsAddress instanceof Inet4Address) {
1365 v4Dnses.add(dnsAddress);
1368 if (v4Dnses.size() > 0) {
1369 dnsServers = NetworkUtils.makeStrings(v4Dnses);
1373 mNMService.setDnsForwarders(dnsServers);
1374 } catch (Exception e) {
1375 transitionTo(mSetDnsForwardersErrorState);
1379 notifyTetheredOfNewUpstreamIface(iface);
1382 protected void notifyTetheredOfNewUpstreamIface(String ifaceName) {
1383 if (DBG) Log.d(TAG, "notifying tethered with iface =" + ifaceName);
1384 mUpstreamIfaceName = ifaceName;
1385 for (TetherInterfaceSM sm : mNotifyList) {
1386 sm.sendMessage(TetherInterfaceSM.CMD_TETHER_CONNECTION_CHANGED,
1392 class InitialState extends TetherMasterUtilState {
1394 public void enter() {
1397 public boolean processMessage(Message message) {
1398 if (DBG) Log.d(TAG, "MasterInitialState.processMessage what=" + message.what);
1399 boolean retValue = true;
1400 switch (message.what) {
1401 case CMD_TETHER_MODE_REQUESTED:
1402 TetherInterfaceSM who = (TetherInterfaceSM)message.obj;
1403 if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
1404 mNotifyList.add(who);
1405 transitionTo(mTetherModeAliveState);
1407 case CMD_TETHER_MODE_UNREQUESTED:
1408 who = (TetherInterfaceSM)message.obj;
1409 if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
1410 int index = mNotifyList.indexOf(who);
1412 mNotifyList.remove(who);
1423 class TetherModeAliveState extends TetherMasterUtilState {
1424 boolean mTryCell = !WAIT_FOR_NETWORK_TO_SETTLE;
1426 public void enter() {
1427 turnOnMasterTetherSettings(); // may transition us out
1429 mTryCell = !WAIT_FOR_NETWORK_TO_SETTLE; // better try something first pass
1430 // or crazy tests cases will fail
1431 chooseUpstreamType(mTryCell);
1432 mTryCell = !mTryCell;
1435 public void exit() {
1436 turnOffUpstreamMobileConnection();
1437 notifyTetheredOfNewUpstreamIface(null);
1440 public boolean processMessage(Message message) {
1441 if (DBG) Log.d(TAG, "TetherModeAliveState.processMessage what=" + message.what);
1442 boolean retValue = true;
1443 switch (message.what) {
1444 case CMD_TETHER_MODE_REQUESTED:
1445 TetherInterfaceSM who = (TetherInterfaceSM)message.obj;
1446 if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
1447 mNotifyList.add(who);
1448 who.sendMessage(TetherInterfaceSM.CMD_TETHER_CONNECTION_CHANGED,
1449 mUpstreamIfaceName);
1451 case CMD_TETHER_MODE_UNREQUESTED:
1452 who = (TetherInterfaceSM)message.obj;
1453 if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
1454 int index = mNotifyList.indexOf(who);
1456 if (DBG) Log.d(TAG, "TetherModeAlive removing notifyee " + who);
1457 mNotifyList.remove(index);
1458 if (mNotifyList.isEmpty()) {
1459 turnOffMasterTetherSettings(); // transitions appropriately
1462 Log.d(TAG, "TetherModeAlive still has " + mNotifyList.size() +
1464 for (Object o : mNotifyList) Log.d(TAG, " " + o);
1468 Log.e(TAG, "TetherModeAliveState UNREQUESTED has unknown who: " + who);
1471 case CMD_UPSTREAM_CHANGED:
1472 // need to try DUN immediately if Wifi goes down
1473 mTryCell = !WAIT_FOR_NETWORK_TO_SETTLE;
1474 chooseUpstreamType(mTryCell);
1475 mTryCell = !mTryCell;
1477 case CMD_CELL_CONNECTION_RENEW:
1478 // make sure we're still using a requested connection - may have found
1479 // wifi or something since then.
1480 if (mCurrentConnectionSequence == message.arg1) {
1482 Log.d(TAG, "renewing mobile connection - requeuing for another " +
1483 CELL_CONNECTION_RENEW_MS + "ms");
1485 turnOnUpstreamMobileConnection(mMobileApnReserved);
1488 case CMD_RETRY_UPSTREAM:
1489 chooseUpstreamType(mTryCell);
1490 mTryCell = !mTryCell;
1500 class ErrorState extends State {
1501 int mErrorNotification;
1503 public boolean processMessage(Message message) {
1504 boolean retValue = true;
1505 switch (message.what) {
1506 case CMD_TETHER_MODE_REQUESTED:
1507 TetherInterfaceSM who = (TetherInterfaceSM)message.obj;
1508 who.sendMessage(mErrorNotification);
1515 void notify(int msgType) {
1516 mErrorNotification = msgType;
1517 for (Object o : mNotifyList) {
1518 TetherInterfaceSM sm = (TetherInterfaceSM)o;
1519 sm.sendMessage(msgType);
1524 class SetIpForwardingEnabledErrorState extends ErrorState {
1526 public void enter() {
1527 Log.e(TAG, "Error in setIpForwardingEnabled");
1528 notify(TetherInterfaceSM.CMD_IP_FORWARDING_ENABLE_ERROR);
1532 class SetIpForwardingDisabledErrorState extends ErrorState {
1534 public void enter() {
1535 Log.e(TAG, "Error in setIpForwardingDisabled");
1536 notify(TetherInterfaceSM.CMD_IP_FORWARDING_DISABLE_ERROR);
1540 class StartTetheringErrorState extends ErrorState {
1542 public void enter() {
1543 Log.e(TAG, "Error in startTethering");
1544 notify(TetherInterfaceSM.CMD_START_TETHERING_ERROR);
1546 mNMService.setIpForwardingEnabled(false);
1547 } catch (Exception e) {}
1551 class StopTetheringErrorState extends ErrorState {
1553 public void enter() {
1554 Log.e(TAG, "Error in stopTethering");
1555 notify(TetherInterfaceSM.CMD_STOP_TETHERING_ERROR);
1557 mNMService.setIpForwardingEnabled(false);
1558 } catch (Exception e) {}
1562 class SetDnsForwardersErrorState extends ErrorState {
1564 public void enter() {
1565 Log.e(TAG, "Error in setDnsForwarders");
1566 notify(TetherInterfaceSM.CMD_SET_DNS_FORWARDERS_ERROR);
1568 mNMService.stopTethering();
1569 } catch (Exception e) {}
1571 mNMService.setIpForwardingEnabled(false);
1572 } catch (Exception e) {}
1577 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1578 if (mContext.checkCallingOrSelfPermission(
1579 android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) {
1580 pw.println("Permission Denial: can't dump ConnectivityService.Tether " +
1581 "from from pid=" + Binder.getCallingPid() + ", uid=" +
1582 Binder.getCallingUid());
1586 synchronized (mPublicSync) {
1587 pw.println("mUpstreamIfaceTypes: ");
1588 for (Integer netType : mUpstreamIfaceTypes) {
1589 pw.println(" " + netType);
1593 pw.println("Tether state:");
1594 for (Object o : mIfaces.values()) {
1595 pw.println(" " + o);