Tethering.java revision 636c07d9a9a6e48197706bd9724e5d5db4e2fe9d
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
17package com.android.server.connectivity;
18
19import android.app.Notification;
20import android.app.NotificationManager;
21import android.app.PendingIntent;
22import android.bluetooth.BluetoothAdapter;
23import android.bluetooth.BluetoothPan;
24import android.bluetooth.BluetoothProfile;
25import android.bluetooth.BluetoothProfile.ServiceListener;
26import android.content.BroadcastReceiver;
27import android.content.ComponentName;
28import android.content.Context;
29import android.content.Intent;
30import android.content.IntentFilter;
31import android.content.pm.PackageManager;
32import android.content.res.Resources;
33import android.hardware.usb.UsbManager;
34import android.net.ConnectivityManager;
35import android.net.ConnectivityManager.NetworkCallback;
36import android.net.INetworkStatsService;
37import android.net.InterfaceConfiguration;
38import android.net.LinkAddress;
39import android.net.LinkProperties;
40import android.net.Network;
41import android.net.NetworkCapabilities;
42import android.net.NetworkInfo;
43import android.net.NetworkRequest;
44import android.net.NetworkState;
45import android.net.NetworkUtils;
46import android.net.RouteInfo;
47import android.net.wifi.WifiManager;
48import android.os.Binder;
49import android.os.Bundle;
50import android.os.INetworkManagementService;
51import android.os.Looper;
52import android.os.Message;
53import android.os.Parcel;
54import android.os.ResultReceiver;
55import android.os.SystemProperties;
56import android.os.UserHandle;
57import android.provider.Settings;
58import android.telephony.CarrierConfigManager;
59import android.telephony.TelephonyManager;
60import android.text.TextUtils;
61import android.util.Log;
62import android.util.SparseArray;
63
64import com.android.internal.telephony.IccCardConstants;
65import com.android.internal.telephony.TelephonyIntents;
66import com.android.internal.util.IState;
67import com.android.internal.util.IndentingPrintWriter;
68import com.android.internal.util.MessageUtils;
69import com.android.internal.util.Protocol;
70import com.android.internal.util.State;
71import com.android.internal.util.StateMachine;
72import com.android.server.IoThread;
73import com.android.server.net.BaseNetworkObserver;
74
75import java.io.FileDescriptor;
76import java.io.PrintWriter;
77import java.net.Inet4Address;
78import java.net.InetAddress;
79import java.util.ArrayList;
80import java.util.Arrays;
81import java.util.Collection;
82import java.util.HashMap;
83import java.util.Iterator;
84import java.util.Set;
85import java.util.concurrent.atomic.AtomicInteger;
86
87
88/**
89 * @hide
90 *
91 * Timeout
92 *
93 * TODO - look for parent classes and code sharing
94 */
95public class Tethering extends BaseNetworkObserver {
96
97    private final Context mContext;
98    private final static String TAG = "Tethering";
99    private final static boolean DBG = false;
100    private final static boolean VDBG = false;
101
102    private static final Class[] messageClasses = {
103            Tethering.class, TetherMasterSM.class, TetherInterfaceSM.class
104    };
105    private static final SparseArray<String> sMagicDecoderRing =
106            MessageUtils.findMessageNames(messageClasses);
107
108    // TODO - remove both of these - should be part of interface inspection/selection stuff
109    private String[] mTetherableUsbRegexs;
110    private String[] mTetherableWifiRegexs;
111    private String[] mTetherableBluetoothRegexs;
112    private Collection<Integer> mUpstreamIfaceTypes;
113
114    // used to synchronize public access to members
115    private final Object mPublicSync;
116
117    private static final Integer MOBILE_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE);
118    private static final Integer HIPRI_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE_HIPRI);
119    private static final Integer DUN_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE_DUN);
120
121    // if we have to connect to mobile, what APN type should we use?  Calculated by examining the
122    // upstream type list and the DUN_REQUIRED secure-setting
123    private int mPreferredUpstreamMobileApn = ConnectivityManager.TYPE_NONE;
124
125    private final INetworkManagementService mNMService;
126    private final INetworkStatsService mStatsService;
127    private final Looper mLooper;
128
129    private HashMap<String, TetherInterfaceSM> mIfaces; // all tethered/tetherable ifaces
130
131    private BroadcastReceiver mStateReceiver;
132
133    // {@link ComponentName} of the Service used to run tether provisioning.
134    private static final ComponentName TETHER_SERVICE = ComponentName.unflattenFromString(Resources
135            .getSystem().getString(com.android.internal.R.string.config_wifi_tether_enable));
136
137    private static final String USB_NEAR_IFACE_ADDR      = "192.168.42.129";
138    private static final int USB_PREFIX_LENGTH        = 24;
139
140    // USB is  192.168.42.1 and 255.255.255.0
141    // Wifi is 192.168.43.1 and 255.255.255.0
142    // BT is limited to max default of 5 connections. 192.168.44.1 to 192.168.48.1
143    // with 255.255.255.0
144    // P2P is 192.168.49.1 and 255.255.255.0
145
146    private String[] mDhcpRange;
147    private static final String[] DHCP_DEFAULT_RANGE = {
148        "192.168.42.2", "192.168.42.254", "192.168.43.2", "192.168.43.254",
149        "192.168.44.2", "192.168.44.254", "192.168.45.2", "192.168.45.254",
150        "192.168.46.2", "192.168.46.254", "192.168.47.2", "192.168.47.254",
151        "192.168.48.2", "192.168.48.254", "192.168.49.2", "192.168.49.254",
152    };
153
154    private String[] mDefaultDnsServers;
155    private static final String DNS_DEFAULT_SERVER1 = "8.8.8.8";
156    private static final String DNS_DEFAULT_SERVER2 = "8.8.4.4";
157
158    private final StateMachine mTetherMasterSM;
159    private final UpstreamNetworkMonitor mUpstreamNetworkMonitor;
160    private String mCurrentUpstreamIface;
161
162    private Notification.Builder mTetheredNotificationBuilder;
163    private int mLastNotificationId;
164
165    private boolean mRndisEnabled;       // track the RNDIS function enabled state
166    private boolean mUsbTetherRequested; // true if USB tethering should be started
167                                         // when RNDIS is enabled
168
169    public Tethering(Context context, INetworkManagementService nmService,
170            INetworkStatsService statsService) {
171        mContext = context;
172        mNMService = nmService;
173        mStatsService = statsService;
174
175        mPublicSync = new Object();
176
177        mIfaces = new HashMap<String, TetherInterfaceSM>();
178
179        // make our own thread so we don't anr the system
180        mLooper = IoThread.get().getLooper();
181        mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper);
182        mTetherMasterSM.start();
183
184        mUpstreamNetworkMonitor = new UpstreamNetworkMonitor();
185
186        mStateReceiver = new StateReceiver();
187        IntentFilter filter = new IntentFilter();
188        filter.addAction(UsbManager.ACTION_USB_STATE);
189        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
190        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
191        mContext.registerReceiver(mStateReceiver, filter);
192
193        filter = new IntentFilter();
194        filter.addAction(Intent.ACTION_MEDIA_SHARED);
195        filter.addAction(Intent.ACTION_MEDIA_UNSHARED);
196        filter.addDataScheme("file");
197        mContext.registerReceiver(mStateReceiver, filter);
198
199        mDhcpRange = context.getResources().getStringArray(
200                com.android.internal.R.array.config_tether_dhcp_range);
201        if ((mDhcpRange.length == 0) || (mDhcpRange.length % 2 ==1)) {
202            mDhcpRange = DHCP_DEFAULT_RANGE;
203        }
204
205        // load device config info
206        updateConfiguration();
207
208        // TODO - remove and rely on real notifications of the current iface
209        mDefaultDnsServers = new String[2];
210        mDefaultDnsServers[0] = DNS_DEFAULT_SERVER1;
211        mDefaultDnsServers[1] = DNS_DEFAULT_SERVER2;
212    }
213
214    // We can't do this once in the Tethering() constructor and cache the value, because the
215    // CONNECTIVITY_SERVICE is registered only after the Tethering() constructor has completed.
216    private ConnectivityManager getConnectivityManager() {
217        return (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
218    }
219
220    void updateConfiguration() {
221        String[] tetherableUsbRegexs = mContext.getResources().getStringArray(
222                com.android.internal.R.array.config_tether_usb_regexs);
223        String[] tetherableWifiRegexs = mContext.getResources().getStringArray(
224                com.android.internal.R.array.config_tether_wifi_regexs);
225        String[] tetherableBluetoothRegexs = mContext.getResources().getStringArray(
226                com.android.internal.R.array.config_tether_bluetooth_regexs);
227
228        int ifaceTypes[] = mContext.getResources().getIntArray(
229                com.android.internal.R.array.config_tether_upstream_types);
230        Collection<Integer> upstreamIfaceTypes = new ArrayList();
231        for (int i : ifaceTypes) {
232            upstreamIfaceTypes.add(new Integer(i));
233        }
234
235        synchronized (mPublicSync) {
236            mTetherableUsbRegexs = tetherableUsbRegexs;
237            mTetherableWifiRegexs = tetherableWifiRegexs;
238            mTetherableBluetoothRegexs = tetherableBluetoothRegexs;
239            mUpstreamIfaceTypes = upstreamIfaceTypes;
240        }
241
242        // check if the upstream type list needs to be modified due to secure-settings
243        checkDunRequired();
244    }
245
246    @Override
247    public void interfaceStatusChanged(String iface, boolean up) {
248        // Never called directly: only called from interfaceLinkStateChanged.
249        // See NetlinkHandler.cpp:71.
250        if (VDBG) Log.d(TAG, "interfaceStatusChanged " + iface + ", " + up);
251        boolean found = false;
252        boolean usb = false;
253        synchronized (mPublicSync) {
254            if (isWifi(iface)) {
255                found = true;
256            } else if (isUsb(iface)) {
257                found = true;
258                usb = true;
259            } else if (isBluetooth(iface)) {
260                found = true;
261            }
262            if (found == false) return;
263
264            TetherInterfaceSM sm = mIfaces.get(iface);
265            if (up) {
266                if (sm == null) {
267                    sm = new TetherInterfaceSM(iface, mLooper, usb);
268                    mIfaces.put(iface, sm);
269                    sm.start();
270                }
271            } else {
272                if (isUsb(iface)) {
273                    // ignore usb0 down after enabling RNDIS
274                    // we will handle disconnect in interfaceRemoved instead
275                    if (VDBG) Log.d(TAG, "ignore interface down for " + iface);
276                } else if (sm != null) {
277                    sm.sendMessage(TetherInterfaceSM.CMD_INTERFACE_DOWN);
278                    mIfaces.remove(iface);
279                }
280            }
281        }
282    }
283
284    @Override
285    public void interfaceLinkStateChanged(String iface, boolean up) {
286        interfaceStatusChanged(iface, up);
287    }
288
289    private boolean isUsb(String iface) {
290        synchronized (mPublicSync) {
291            for (String regex : mTetherableUsbRegexs) {
292                if (iface.matches(regex)) return true;
293            }
294            return false;
295        }
296    }
297
298    public boolean isWifi(String iface) {
299        synchronized (mPublicSync) {
300            for (String regex : mTetherableWifiRegexs) {
301                if (iface.matches(regex)) return true;
302            }
303            return false;
304        }
305    }
306
307    public boolean isBluetooth(String iface) {
308        synchronized (mPublicSync) {
309            for (String regex : mTetherableBluetoothRegexs) {
310                if (iface.matches(regex)) return true;
311            }
312            return false;
313        }
314    }
315
316    @Override
317    public void interfaceAdded(String iface) {
318        if (VDBG) Log.d(TAG, "interfaceAdded " + iface);
319        boolean found = false;
320        boolean usb = false;
321        synchronized (mPublicSync) {
322            if (isWifi(iface)) {
323                found = true;
324            }
325            if (isUsb(iface)) {
326                found = true;
327                usb = true;
328            }
329            if (isBluetooth(iface)) {
330                found = true;
331            }
332            if (found == false) {
333                if (VDBG) Log.d(TAG, iface + " is not a tetherable iface, ignoring");
334                return;
335            }
336
337            TetherInterfaceSM sm = mIfaces.get(iface);
338            if (sm != null) {
339                if (VDBG) Log.d(TAG, "active iface (" + iface + ") reported as added, ignoring");
340                return;
341            }
342            sm = new TetherInterfaceSM(iface, mLooper, usb);
343            mIfaces.put(iface, sm);
344            sm.start();
345        }
346    }
347
348    @Override
349    public void interfaceRemoved(String iface) {
350        if (VDBG) Log.d(TAG, "interfaceRemoved " + iface);
351        synchronized (mPublicSync) {
352            TetherInterfaceSM sm = mIfaces.get(iface);
353            if (sm == null) {
354                if (VDBG) {
355                    Log.e(TAG, "attempting to remove unknown iface (" + iface + "), ignoring");
356                }
357                return;
358            }
359            sm.sendMessage(TetherInterfaceSM.CMD_INTERFACE_DOWN);
360            mIfaces.remove(iface);
361        }
362    }
363
364    public void startTethering(int type, ResultReceiver receiver,
365            boolean showProvisioningUi) {
366        if (!isTetherProvisioningRequired()) {
367            enableTetheringInternal(type, true, receiver);
368            return;
369        }
370
371        if (showProvisioningUi) {
372            runUiTetherProvisioningAndEnable(type, receiver);
373        } else {
374            runSilentTetherProvisioningAndEnable(type, receiver);
375        }
376    }
377
378    public void stopTethering(int type) {
379        enableTetheringInternal(type, false, null);
380        if (isTetherProvisioningRequired()) {
381            cancelTetherProvisioningRechecks(type);
382        }
383    }
384
385    /**
386     * Check if the device requires a provisioning check in order to enable tethering.
387     *
388     * @return a boolean - {@code true} indicating tether provisioning is required by the carrier.
389     */
390    private boolean isTetherProvisioningRequired() {
391        String[] provisionApp = mContext.getResources().getStringArray(
392                com.android.internal.R.array.config_mobile_hotspot_provision_app);
393        if (SystemProperties.getBoolean("net.tethering.noprovisioning", false)
394                || provisionApp == null) {
395            return false;
396        }
397
398        // Check carrier config for entitlement checks
399        final CarrierConfigManager configManager = (CarrierConfigManager) mContext
400             .getSystemService(Context.CARRIER_CONFIG_SERVICE);
401        boolean isEntitlementCheckRequired = configManager.getConfig().getBoolean(
402             CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL);
403
404        if (!isEntitlementCheckRequired) {
405            return false;
406        }
407        return (provisionApp.length == 2);
408    }
409
410    /**
411     * Enables or disables tethering for the given type. This should only be called once
412     * provisioning has succeeded or is not necessary. It will also schedule provisioning rechecks
413     * for the specified interface.
414     */
415    private void enableTetheringInternal(int type, boolean enable, ResultReceiver receiver) {
416        boolean isProvisioningRequired = isTetherProvisioningRequired();
417        switch (type) {
418            case ConnectivityManager.TETHERING_WIFI:
419                final WifiManager wifiManager =
420                        (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
421                if (wifiManager.setWifiApEnabled(null, enable)) {
422                    sendTetherResult(receiver, ConnectivityManager.TETHER_ERROR_NO_ERROR);
423                    if (enable && isProvisioningRequired) {
424                        scheduleProvisioningRechecks(type);
425                    }
426                } else{
427                    sendTetherResult(receiver, ConnectivityManager.TETHER_ERROR_MASTER_ERROR);
428                }
429                break;
430            case ConnectivityManager.TETHERING_USB:
431                int result = setUsbTethering(enable);
432                if (enable && isProvisioningRequired &&
433                        result == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
434                    scheduleProvisioningRechecks(type);
435                }
436                sendTetherResult(receiver, result);
437                break;
438            case ConnectivityManager.TETHERING_BLUETOOTH:
439                setBluetoothTethering(enable, receiver);
440                break;
441            default:
442                Log.w(TAG, "Invalid tether type.");
443                sendTetherResult(receiver, ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE);
444        }
445    }
446
447    private void sendTetherResult(ResultReceiver receiver, int result) {
448        if (receiver != null) {
449            receiver.send(result, null);
450        }
451    }
452
453    private void setBluetoothTethering(final boolean enable, final ResultReceiver receiver) {
454        final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
455        if (adapter == null || !adapter.isEnabled()) {
456            Log.w(TAG, "Tried to enable bluetooth tethering with null or disabled adapter. null: " +
457                    (adapter == null));
458            sendTetherResult(receiver, ConnectivityManager.TETHER_ERROR_SERVICE_UNAVAIL);
459            return;
460        }
461
462        adapter.getProfileProxy(mContext, new ServiceListener() {
463            @Override
464            public void onServiceDisconnected(int profile) { }
465
466            @Override
467            public void onServiceConnected(int profile, BluetoothProfile proxy) {
468                ((BluetoothPan) proxy).setBluetoothTethering(enable);
469                // TODO: Enabling bluetooth tethering can fail asynchronously here.
470                // We should figure out a way to bubble up that failure instead of sending success.
471                int result = ((BluetoothPan) proxy).isTetheringOn() == enable ?
472                        ConnectivityManager.TETHER_ERROR_NO_ERROR :
473                        ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
474                sendTetherResult(receiver, result);
475                if (enable && isTetherProvisioningRequired()) {
476                    scheduleProvisioningRechecks(ConnectivityManager.TETHERING_BLUETOOTH);
477                }
478                adapter.closeProfileProxy(BluetoothProfile.PAN, proxy);
479            }
480        }, BluetoothProfile.PAN);
481    }
482
483    private void runUiTetherProvisioningAndEnable(int type, ResultReceiver receiver) {
484        ResultReceiver proxyReceiver = getProxyReceiver(type, receiver);
485        sendUiTetherProvisionIntent(type, proxyReceiver);
486    }
487
488    private void sendUiTetherProvisionIntent(int type, ResultReceiver receiver) {
489        Intent intent = new Intent(Settings.ACTION_TETHER_PROVISIONING);
490        intent.putExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE, type);
491        intent.putExtra(ConnectivityManager.EXTRA_PROVISION_CALLBACK, receiver);
492        final long ident = Binder.clearCallingIdentity();
493        try {
494            mContext.startActivityAsUser(intent, UserHandle.CURRENT);
495        } finally {
496            Binder.restoreCallingIdentity(ident);
497        }
498    }
499
500    /**
501     * Creates a proxy {@link ResultReceiver} which enables tethering if the provsioning result is
502     * successful before firing back up to the wrapped receiver.
503     *
504     * @param type The type of tethering being enabled.
505     * @param receiver A ResultReceiver which will be called back with an int resultCode.
506     * @return The proxy receiver.
507     */
508    private ResultReceiver getProxyReceiver(final int type, final ResultReceiver receiver) {
509        ResultReceiver rr = new ResultReceiver(null) {
510            @Override
511            protected void onReceiveResult(int resultCode, Bundle resultData) {
512                // If provisioning is successful, enable tethering, otherwise just send the error.
513                if (resultCode == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
514                    enableTetheringInternal(type, true, receiver);
515                } else {
516                    sendTetherResult(receiver, resultCode);
517                }
518            }
519        };
520
521        // The following is necessary to avoid unmarshalling issues when sending the receiver
522        // across processes.
523        Parcel parcel = Parcel.obtain();
524        rr.writeToParcel(parcel,0);
525        parcel.setDataPosition(0);
526        ResultReceiver receiverForSending = ResultReceiver.CREATOR.createFromParcel(parcel);
527        parcel.recycle();
528        return receiverForSending;
529    }
530
531    private void scheduleProvisioningRechecks(int type) {
532        Intent intent = new Intent();
533        intent.putExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE, type);
534        intent.putExtra(ConnectivityManager.EXTRA_SET_ALARM, true);
535        intent.setComponent(TETHER_SERVICE);
536        final long ident = Binder.clearCallingIdentity();
537        try {
538            mContext.startServiceAsUser(intent, UserHandle.CURRENT);
539        } finally {
540            Binder.restoreCallingIdentity(ident);
541        }
542    }
543
544    private void runSilentTetherProvisioningAndEnable(int type, ResultReceiver receiver) {
545        ResultReceiver proxyReceiver = getProxyReceiver(type, receiver);
546        sendSilentTetherProvisionIntent(type, proxyReceiver);
547    }
548
549    private void sendSilentTetherProvisionIntent(int type, ResultReceiver receiver) {
550        Intent intent = new Intent();
551        intent.putExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE, type);
552        intent.putExtra(ConnectivityManager.EXTRA_RUN_PROVISION, true);
553        intent.putExtra(ConnectivityManager.EXTRA_PROVISION_CALLBACK, receiver);
554        intent.setComponent(TETHER_SERVICE);
555        final long ident = Binder.clearCallingIdentity();
556        try {
557            mContext.startServiceAsUser(intent, UserHandle.CURRENT);
558        } finally {
559            Binder.restoreCallingIdentity(ident);
560        }
561    }
562
563    private void cancelTetherProvisioningRechecks(int type) {
564        if (getConnectivityManager().isTetheringSupported()) {
565            Intent intent = new Intent();
566            intent.putExtra(ConnectivityManager.EXTRA_REM_TETHER_TYPE, type);
567            intent.setComponent(TETHER_SERVICE);
568            final long ident = Binder.clearCallingIdentity();
569            try {
570                mContext.startServiceAsUser(intent, UserHandle.CURRENT);
571            } finally {
572                Binder.restoreCallingIdentity(ident);
573            }
574        }
575    }
576
577    public int tether(String iface) {
578        if (DBG) Log.d(TAG, "Tethering " + iface);
579        TetherInterfaceSM sm = null;
580        synchronized (mPublicSync) {
581            sm = mIfaces.get(iface);
582        }
583        if (sm == null) {
584            Log.e(TAG, "Tried to Tether an unknown iface :" + iface + ", ignoring");
585            return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
586        }
587        if (!sm.isAvailable() && !sm.isErrored()) {
588            Log.e(TAG, "Tried to Tether an unavailable iface :" + iface + ", ignoring");
589            return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
590        }
591        sm.sendMessage(TetherInterfaceSM.CMD_TETHER_REQUESTED);
592        return ConnectivityManager.TETHER_ERROR_NO_ERROR;
593    }
594
595    public int untether(String iface) {
596        if (DBG) Log.d(TAG, "Untethering " + iface);
597        TetherInterfaceSM sm = null;
598        synchronized (mPublicSync) {
599            sm = mIfaces.get(iface);
600        }
601        if (sm == null) {
602            Log.e(TAG, "Tried to Untether an unknown iface :" + iface + ", ignoring");
603            return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
604        }
605        if (sm.isErrored()) {
606            Log.e(TAG, "Tried to Untethered an errored iface :" + iface + ", ignoring");
607            return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
608        }
609        sm.sendMessage(TetherInterfaceSM.CMD_TETHER_UNREQUESTED);
610        return ConnectivityManager.TETHER_ERROR_NO_ERROR;
611    }
612
613    public int getLastTetherError(String iface) {
614        TetherInterfaceSM sm = null;
615        synchronized (mPublicSync) {
616            sm = mIfaces.get(iface);
617            if (sm == null) {
618                Log.e(TAG, "Tried to getLastTetherError on an unknown iface :" + iface +
619                        ", ignoring");
620                return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
621            }
622            return sm.getLastError();
623        }
624    }
625
626    // TODO - move all private methods used only by the state machine into the state machine
627    // to clarify what needs synchronized protection.
628    private void sendTetherStateChangedBroadcast() {
629        if (!getConnectivityManager().isTetheringSupported()) return;
630
631        ArrayList<String> availableList = new ArrayList<String>();
632        ArrayList<String> activeList = new ArrayList<String>();
633        ArrayList<String> erroredList = new ArrayList<String>();
634
635        boolean wifiTethered = false;
636        boolean usbTethered = false;
637        boolean bluetoothTethered = false;
638
639        synchronized (mPublicSync) {
640            Set ifaces = mIfaces.keySet();
641            for (Object iface : ifaces) {
642                TetherInterfaceSM sm = mIfaces.get(iface);
643                if (sm != null) {
644                    if (sm.isErrored()) {
645                        erroredList.add((String)iface);
646                    } else if (sm.isAvailable()) {
647                        availableList.add((String)iface);
648                    } else if (sm.isTethered()) {
649                        if (isUsb((String)iface)) {
650                            usbTethered = true;
651                        } else if (isWifi((String)iface)) {
652                            wifiTethered = true;
653                      } else if (isBluetooth((String)iface)) {
654                            bluetoothTethered = true;
655                        }
656                        activeList.add((String)iface);
657                    }
658                }
659            }
660        }
661        Intent broadcast = new Intent(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
662        broadcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
663                Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
664        broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_AVAILABLE_TETHER,
665                availableList);
666        broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_TETHER, activeList);
667        broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ERRORED_TETHER,
668                erroredList);
669        mContext.sendStickyBroadcastAsUser(broadcast, UserHandle.ALL);
670        if (DBG) {
671            Log.d(TAG, String.format(
672                    "sendTetherStateChangedBroadcast avail=[%s] active=[%s] error=[%s]",
673                    TextUtils.join(",", availableList),
674                    TextUtils.join(",", activeList),
675                    TextUtils.join(",", erroredList)));
676        }
677
678        if (usbTethered) {
679            if (wifiTethered || bluetoothTethered) {
680                showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_general);
681            } else {
682                showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_usb);
683            }
684        } else if (wifiTethered) {
685            if (bluetoothTethered) {
686                showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_general);
687            } else {
688                /* We now have a status bar icon for WifiTethering, so drop the notification */
689                clearTetheredNotification();
690            }
691        } else if (bluetoothTethered) {
692            showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_bluetooth);
693        } else {
694            clearTetheredNotification();
695        }
696    }
697
698    private void showTetheredNotification(int icon) {
699        NotificationManager notificationManager =
700                (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE);
701        if (notificationManager == null) {
702            return;
703        }
704
705        if (mLastNotificationId != 0) {
706            if (mLastNotificationId == icon) {
707                return;
708            }
709            notificationManager.cancelAsUser(null, mLastNotificationId,
710                    UserHandle.ALL);
711            mLastNotificationId = 0;
712        }
713
714        Intent intent = new Intent();
715        intent.setClassName("com.android.settings", "com.android.settings.TetherSettings");
716        intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
717
718        PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0, intent, 0,
719                null, UserHandle.CURRENT);
720
721        Resources r = Resources.getSystem();
722        CharSequence title = r.getText(com.android.internal.R.string.tethered_notification_title);
723        CharSequence message = r.getText(com.android.internal.R.string.
724                tethered_notification_message);
725
726        if (mTetheredNotificationBuilder == null) {
727            mTetheredNotificationBuilder = new Notification.Builder(mContext);
728            mTetheredNotificationBuilder.setWhen(0)
729                    .setOngoing(true)
730                    .setColor(mContext.getColor(
731                            com.android.internal.R.color.system_notification_accent_color))
732                    .setVisibility(Notification.VISIBILITY_PUBLIC)
733                    .setCategory(Notification.CATEGORY_STATUS);
734        }
735        mTetheredNotificationBuilder.setSmallIcon(icon)
736                .setContentTitle(title)
737                .setContentText(message)
738                .setContentIntent(pi);
739        mLastNotificationId = icon;
740
741        notificationManager.notifyAsUser(null, mLastNotificationId,
742                mTetheredNotificationBuilder.build(), UserHandle.ALL);
743    }
744
745    private void clearTetheredNotification() {
746        NotificationManager notificationManager =
747            (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE);
748        if (notificationManager != null && mLastNotificationId != 0) {
749            notificationManager.cancelAsUser(null, mLastNotificationId,
750                    UserHandle.ALL);
751            mLastNotificationId = 0;
752        }
753    }
754
755    private class StateReceiver extends BroadcastReceiver {
756        @Override
757        public void onReceive(Context content, Intent intent) {
758            String action = intent.getAction();
759            if (action == null) { return; }
760            if (action.equals(UsbManager.ACTION_USB_STATE)) {
761                synchronized (Tethering.this.mPublicSync) {
762                    boolean usbConnected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false);
763                    mRndisEnabled = intent.getBooleanExtra(UsbManager.USB_FUNCTION_RNDIS, false);
764                    // start tethering if we have a request pending
765                    if (usbConnected && mRndisEnabled && mUsbTetherRequested) {
766                        tetherUsb(true);
767                    }
768                    mUsbTetherRequested = false;
769                }
770            } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
771                NetworkInfo networkInfo = (NetworkInfo)intent.getParcelableExtra(
772                        ConnectivityManager.EXTRA_NETWORK_INFO);
773                if (networkInfo != null &&
774                        networkInfo.getDetailedState() != NetworkInfo.DetailedState.FAILED) {
775                    if (VDBG) Log.d(TAG, "Tethering got CONNECTIVITY_ACTION");
776                    mTetherMasterSM.sendMessage(TetherMasterSM.CMD_UPSTREAM_CHANGED);
777                }
778            } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
779                updateConfiguration();
780            }
781        }
782    }
783
784    private void tetherUsb(boolean enable) {
785        if (VDBG) Log.d(TAG, "tetherUsb " + enable);
786
787        String[] ifaces = new String[0];
788        try {
789            ifaces = mNMService.listInterfaces();
790        } catch (Exception e) {
791            Log.e(TAG, "Error listing Interfaces", e);
792            return;
793        }
794        for (String iface : ifaces) {
795            if (isUsb(iface)) {
796                int result = (enable ? tether(iface) : untether(iface));
797                if (result == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
798                    return;
799                }
800            }
801        }
802        Log.e(TAG, "unable start or stop USB tethering");
803    }
804
805    // configured when we start tethering and unconfig'd on error or conclusion
806    private boolean configureUsbIface(boolean enabled) {
807        if (VDBG) Log.d(TAG, "configureUsbIface(" + enabled + ")");
808
809        // toggle the USB interfaces
810        String[] ifaces = new String[0];
811        try {
812            ifaces = mNMService.listInterfaces();
813        } catch (Exception e) {
814            Log.e(TAG, "Error listing Interfaces", e);
815            return false;
816        }
817        for (String iface : ifaces) {
818            if (isUsb(iface)) {
819                InterfaceConfiguration ifcg = null;
820                try {
821                    ifcg = mNMService.getInterfaceConfig(iface);
822                    if (ifcg != null) {
823                        InetAddress addr = NetworkUtils.numericToInetAddress(USB_NEAR_IFACE_ADDR);
824                        ifcg.setLinkAddress(new LinkAddress(addr, USB_PREFIX_LENGTH));
825                        if (enabled) {
826                            ifcg.setInterfaceUp();
827                        } else {
828                            ifcg.setInterfaceDown();
829                        }
830                        ifcg.clearFlag("running");
831                        mNMService.setInterfaceConfig(iface, ifcg);
832                    }
833                } catch (Exception e) {
834                    Log.e(TAG, "Error configuring interface " + iface, e);
835                    return false;
836                }
837            }
838         }
839
840        return true;
841    }
842
843    // TODO - return copies so people can't tamper
844    public String[] getTetherableUsbRegexs() {
845        return mTetherableUsbRegexs;
846    }
847
848    public String[] getTetherableWifiRegexs() {
849        return mTetherableWifiRegexs;
850    }
851
852    public String[] getTetherableBluetoothRegexs() {
853        return mTetherableBluetoothRegexs;
854    }
855
856    public int setUsbTethering(boolean enable) {
857        if (VDBG) Log.d(TAG, "setUsbTethering(" + enable + ")");
858        UsbManager usbManager = (UsbManager)mContext.getSystemService(Context.USB_SERVICE);
859
860        synchronized (mPublicSync) {
861            if (enable) {
862                if (mRndisEnabled) {
863                    final long ident = Binder.clearCallingIdentity();
864                    try {
865                        tetherUsb(true);
866                    } finally {
867                        Binder.restoreCallingIdentity(ident);
868                    }
869                } else {
870                    mUsbTetherRequested = true;
871                    usbManager.setCurrentFunction(UsbManager.USB_FUNCTION_RNDIS);
872                }
873            } else {
874                final long ident = Binder.clearCallingIdentity();
875                try {
876                    tetherUsb(false);
877                } finally {
878                    Binder.restoreCallingIdentity(ident);
879                }
880                if (mRndisEnabled) {
881                    usbManager.setCurrentFunction(null);
882                }
883                mUsbTetherRequested = false;
884            }
885        }
886        return ConnectivityManager.TETHER_ERROR_NO_ERROR;
887    }
888
889    public int[] getUpstreamIfaceTypes() {
890        int values[];
891        synchronized (mPublicSync) {
892            updateConfiguration();  // TODO - remove?
893            values = new int[mUpstreamIfaceTypes.size()];
894            Iterator<Integer> iterator = mUpstreamIfaceTypes.iterator();
895            for (int i=0; i < mUpstreamIfaceTypes.size(); i++) {
896                values[i] = iterator.next();
897            }
898        }
899        return values;
900    }
901
902    private void checkDunRequired() {
903        int secureSetting = 2;
904        TelephonyManager tm = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
905        if (tm != null) {
906            secureSetting = tm.getTetherApnRequired();
907        }
908        synchronized (mPublicSync) {
909            // 2 = not set, 0 = DUN not required, 1 = DUN required
910            if (secureSetting != 2) {
911                int requiredApn = (secureSetting == 1 ?
912                        ConnectivityManager.TYPE_MOBILE_DUN :
913                        ConnectivityManager.TYPE_MOBILE_HIPRI);
914                if (requiredApn == ConnectivityManager.TYPE_MOBILE_DUN) {
915                    while (mUpstreamIfaceTypes.contains(MOBILE_TYPE)) {
916                        mUpstreamIfaceTypes.remove(MOBILE_TYPE);
917                    }
918                    while (mUpstreamIfaceTypes.contains(HIPRI_TYPE)) {
919                        mUpstreamIfaceTypes.remove(HIPRI_TYPE);
920                    }
921                    if (mUpstreamIfaceTypes.contains(DUN_TYPE) == false) {
922                        mUpstreamIfaceTypes.add(DUN_TYPE);
923                    }
924                } else {
925                    while (mUpstreamIfaceTypes.contains(DUN_TYPE)) {
926                        mUpstreamIfaceTypes.remove(DUN_TYPE);
927                    }
928                    if (mUpstreamIfaceTypes.contains(MOBILE_TYPE) == false) {
929                        mUpstreamIfaceTypes.add(MOBILE_TYPE);
930                    }
931                    if (mUpstreamIfaceTypes.contains(HIPRI_TYPE) == false) {
932                        mUpstreamIfaceTypes.add(HIPRI_TYPE);
933                    }
934                }
935            }
936            if (mUpstreamIfaceTypes.contains(DUN_TYPE)) {
937                mPreferredUpstreamMobileApn = ConnectivityManager.TYPE_MOBILE_DUN;
938            } else {
939                mPreferredUpstreamMobileApn = ConnectivityManager.TYPE_MOBILE_HIPRI;
940            }
941        }
942    }
943
944    // TODO review API - maybe return ArrayList<String> here and below?
945    public String[] getTetheredIfaces() {
946        ArrayList<String> list = new ArrayList<String>();
947        synchronized (mPublicSync) {
948            Set keys = mIfaces.keySet();
949            for (Object key : keys) {
950                TetherInterfaceSM sm = mIfaces.get(key);
951                if (sm.isTethered()) {
952                    list.add((String)key);
953                }
954            }
955        }
956        String[] retVal = new String[list.size()];
957        for (int i=0; i < list.size(); i++) {
958            retVal[i] = list.get(i);
959        }
960        return retVal;
961    }
962
963    public String[] getTetherableIfaces() {
964        ArrayList<String> list = new ArrayList<String>();
965        synchronized (mPublicSync) {
966            Set keys = mIfaces.keySet();
967            for (Object key : keys) {
968                TetherInterfaceSM sm = mIfaces.get(key);
969                if (sm.isAvailable()) {
970                    list.add((String)key);
971                }
972            }
973        }
974        String[] retVal = new String[list.size()];
975        for (int i=0; i < list.size(); i++) {
976            retVal[i] = list.get(i);
977        }
978        return retVal;
979    }
980
981    public String[] getTetheredDhcpRanges() {
982        return mDhcpRange;
983    }
984
985    public String[] getErroredIfaces() {
986        ArrayList<String> list = new ArrayList<String>();
987        synchronized (mPublicSync) {
988            Set keys = mIfaces.keySet();
989            for (Object key : keys) {
990                TetherInterfaceSM sm = mIfaces.get(key);
991                if (sm.isErrored()) {
992                    list.add((String)key);
993                }
994            }
995        }
996        String[] retVal = new String[list.size()];
997        for (int i= 0; i< list.size(); i++) {
998            retVal[i] = list.get(i);
999        }
1000        return retVal;
1001    }
1002
1003    private void maybeLogMessage(State state, int what) {
1004        if (DBG) {
1005            Log.d(TAG, state.getName() + " got " +
1006                    sMagicDecoderRing.get(what, Integer.toString(what)));
1007        }
1008    }
1009
1010    class TetherInterfaceSM extends StateMachine {
1011        private static final int BASE_IFACE              = Protocol.BASE_TETHERING + 100;
1012        // notification from the master SM that it's not in tether mode
1013        static final int CMD_TETHER_MODE_DEAD            = BASE_IFACE + 1;
1014        // request from the user that it wants to tether
1015        static final int CMD_TETHER_REQUESTED            = BASE_IFACE + 2;
1016        // request from the user that it wants to untether
1017        static final int CMD_TETHER_UNREQUESTED          = BASE_IFACE + 3;
1018        // notification that this interface is down
1019        static final int CMD_INTERFACE_DOWN              = BASE_IFACE + 4;
1020        // notification that this interface is up
1021        static final int CMD_INTERFACE_UP                = BASE_IFACE + 5;
1022        // notification from the master SM that it had an error turning on cellular dun
1023        static final int CMD_CELL_DUN_ERROR              = BASE_IFACE + 6;
1024        // notification from the master SM that it had trouble enabling IP Forwarding
1025        static final int CMD_IP_FORWARDING_ENABLE_ERROR  = BASE_IFACE + 7;
1026        // notification from the master SM that it had trouble disabling IP Forwarding
1027        static final int CMD_IP_FORWARDING_DISABLE_ERROR = BASE_IFACE + 8;
1028        // notification from the master SM that it had trouble starting tethering
1029        static final int CMD_START_TETHERING_ERROR       = BASE_IFACE + 9;
1030        // notification from the master SM that it had trouble stopping tethering
1031        static final int CMD_STOP_TETHERING_ERROR        = BASE_IFACE + 10;
1032        // notification from the master SM that it had trouble setting the DNS forwarders
1033        static final int CMD_SET_DNS_FORWARDERS_ERROR    = BASE_IFACE + 11;
1034        // the upstream connection has changed
1035        static final int CMD_TETHER_CONNECTION_CHANGED   = BASE_IFACE + 12;
1036
1037        private State mDefaultState;
1038
1039        private State mInitialState;
1040        private State mStartingState;
1041        private State mTetheredState;
1042
1043        private State mUnavailableState;
1044
1045        private boolean mAvailable;
1046        private boolean mTethered;
1047        int mLastError;
1048
1049        String mIfaceName;
1050        String mMyUpstreamIfaceName;  // may change over time
1051
1052        boolean mUsb;
1053
1054        TetherInterfaceSM(String name, Looper looper, boolean usb) {
1055            super(name, looper);
1056            mIfaceName = name;
1057            mUsb = usb;
1058            setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR);
1059
1060            mInitialState = new InitialState();
1061            addState(mInitialState);
1062            mStartingState = new StartingState();
1063            addState(mStartingState);
1064            mTetheredState = new TetheredState();
1065            addState(mTetheredState);
1066            mUnavailableState = new UnavailableState();
1067            addState(mUnavailableState);
1068
1069            setInitialState(mInitialState);
1070        }
1071
1072        public String toString() {
1073            String res = new String();
1074            res += mIfaceName + " - ";
1075            IState current = getCurrentState();
1076            if (current == mInitialState) res += "InitialState";
1077            if (current == mStartingState) res += "StartingState";
1078            if (current == mTetheredState) res += "TetheredState";
1079            if (current == mUnavailableState) res += "UnavailableState";
1080            if (mAvailable) res += " - Available";
1081            if (mTethered) res += " - Tethered";
1082            res += " - lastError =" + mLastError;
1083            return res;
1084        }
1085
1086        public int getLastError() {
1087            synchronized (Tethering.this.mPublicSync) {
1088                return mLastError;
1089            }
1090        }
1091
1092        private void setLastError(int error) {
1093            synchronized (Tethering.this.mPublicSync) {
1094                mLastError = error;
1095
1096                if (isErrored()) {
1097                    if (mUsb) {
1098                        // note everything's been unwound by this point so nothing to do on
1099                        // further error..
1100                        Tethering.this.configureUsbIface(false);
1101                    }
1102                }
1103            }
1104        }
1105
1106        public boolean isAvailable() {
1107            synchronized (Tethering.this.mPublicSync) {
1108                return mAvailable;
1109            }
1110        }
1111
1112        private void setAvailable(boolean available) {
1113            synchronized (Tethering.this.mPublicSync) {
1114                mAvailable = available;
1115            }
1116        }
1117
1118        public boolean isTethered() {
1119            synchronized (Tethering.this.mPublicSync) {
1120                return mTethered;
1121            }
1122        }
1123
1124        private void setTethered(boolean tethered) {
1125            synchronized (Tethering.this.mPublicSync) {
1126                mTethered = tethered;
1127            }
1128        }
1129
1130        public boolean isErrored() {
1131            synchronized (Tethering.this.mPublicSync) {
1132                return (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR);
1133            }
1134        }
1135
1136        class InitialState extends State {
1137            @Override
1138            public void enter() {
1139                setAvailable(true);
1140                setTethered(false);
1141                sendTetherStateChangedBroadcast();
1142            }
1143
1144            @Override
1145            public boolean processMessage(Message message) {
1146                maybeLogMessage(this, message.what);
1147                boolean retValue = true;
1148                switch (message.what) {
1149                    case CMD_TETHER_REQUESTED:
1150                        setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR);
1151                        mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_REQUESTED,
1152                                TetherInterfaceSM.this);
1153                        transitionTo(mStartingState);
1154                        break;
1155                    case CMD_INTERFACE_DOWN:
1156                        transitionTo(mUnavailableState);
1157                        break;
1158                    default:
1159                        retValue = false;
1160                        break;
1161                }
1162                return retValue;
1163            }
1164        }
1165
1166        class StartingState extends State {
1167            @Override
1168            public void enter() {
1169                setAvailable(false);
1170                if (mUsb) {
1171                    if (!Tethering.this.configureUsbIface(true)) {
1172                        mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED,
1173                                TetherInterfaceSM.this);
1174                        setLastError(ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
1175
1176                        transitionTo(mInitialState);
1177                        return;
1178                    }
1179                }
1180                sendTetherStateChangedBroadcast();
1181
1182                // Skipping StartingState
1183                transitionTo(mTetheredState);
1184            }
1185            @Override
1186            public boolean processMessage(Message message) {
1187                maybeLogMessage(this, message.what);
1188                boolean retValue = true;
1189                switch (message.what) {
1190                    // maybe a parent class?
1191                    case CMD_TETHER_UNREQUESTED:
1192                        mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED,
1193                                TetherInterfaceSM.this);
1194                        if (mUsb) {
1195                            if (!Tethering.this.configureUsbIface(false)) {
1196                                setLastErrorAndTransitionToInitialState(
1197                                    ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
1198                                break;
1199                            }
1200                        }
1201                        transitionTo(mInitialState);
1202                        break;
1203                    case CMD_CELL_DUN_ERROR:
1204                    case CMD_IP_FORWARDING_ENABLE_ERROR:
1205                    case CMD_IP_FORWARDING_DISABLE_ERROR:
1206                    case CMD_START_TETHERING_ERROR:
1207                    case CMD_STOP_TETHERING_ERROR:
1208                    case CMD_SET_DNS_FORWARDERS_ERROR:
1209                        setLastErrorAndTransitionToInitialState(
1210                                ConnectivityManager.TETHER_ERROR_MASTER_ERROR);
1211                        break;
1212                    case CMD_INTERFACE_DOWN:
1213                        mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED,
1214                                TetherInterfaceSM.this);
1215                        transitionTo(mUnavailableState);
1216                        break;
1217                    default:
1218                        retValue = false;
1219                }
1220                return retValue;
1221            }
1222        }
1223
1224        class TetheredState extends State {
1225            @Override
1226            public void enter() {
1227                try {
1228                    mNMService.tetherInterface(mIfaceName);
1229                } catch (Exception e) {
1230                    Log.e(TAG, "Error Tethering: " + e.toString());
1231                    setLastError(ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR);
1232
1233                    try {
1234                        mNMService.untetherInterface(mIfaceName);
1235                    } catch (Exception ee) {
1236                        Log.e(TAG, "Error untethering after failure!" + ee.toString());
1237                    }
1238                    transitionTo(mInitialState);
1239                    return;
1240                }
1241                if (DBG) Log.d(TAG, "Tethered " + mIfaceName);
1242                setAvailable(false);
1243                setTethered(true);
1244                sendTetherStateChangedBroadcast();
1245            }
1246
1247            private void cleanupUpstream() {
1248                if (mMyUpstreamIfaceName != null) {
1249                    // note that we don't care about errors here.
1250                    // sometimes interfaces are gone before we get
1251                    // to remove their rules, which generates errors.
1252                    // just do the best we can.
1253                    try {
1254                        // about to tear down NAT; gather remaining statistics
1255                        mStatsService.forceUpdate();
1256                    } catch (Exception e) {
1257                        if (VDBG) Log.e(TAG, "Exception in forceUpdate: " + e.toString());
1258                    }
1259                    try {
1260                        mNMService.stopInterfaceForwarding(mIfaceName, mMyUpstreamIfaceName);
1261                    } catch (Exception e) {
1262                        if (VDBG) Log.e(
1263                                TAG, "Exception in removeInterfaceForward: " + e.toString());
1264                    }
1265                    try {
1266                        mNMService.disableNat(mIfaceName, mMyUpstreamIfaceName);
1267                    } catch (Exception e) {
1268                        if (VDBG) Log.e(TAG, "Exception in disableNat: " + e.toString());
1269                    }
1270                    mMyUpstreamIfaceName = null;
1271                }
1272                return;
1273            }
1274
1275            @Override
1276            public boolean processMessage(Message message) {
1277                maybeLogMessage(this, message.what);
1278                boolean retValue = true;
1279                boolean error = false;
1280                switch (message.what) {
1281                    case CMD_TETHER_UNREQUESTED:
1282                    case CMD_INTERFACE_DOWN:
1283                        cleanupUpstream();
1284                        try {
1285                            mNMService.untetherInterface(mIfaceName);
1286                        } catch (Exception e) {
1287                            setLastErrorAndTransitionToInitialState(
1288                                    ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR);
1289                            break;
1290                        }
1291                        mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED,
1292                                TetherInterfaceSM.this);
1293                        if (message.what == CMD_TETHER_UNREQUESTED) {
1294                            if (mUsb) {
1295                                if (!Tethering.this.configureUsbIface(false)) {
1296                                    setLastError(
1297                                            ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
1298                                }
1299                            }
1300                            transitionTo(mInitialState);
1301                        } else if (message.what == CMD_INTERFACE_DOWN) {
1302                            transitionTo(mUnavailableState);
1303                        }
1304                        if (DBG) Log.d(TAG, "Untethered " + mIfaceName);
1305                        break;
1306                    case CMD_TETHER_CONNECTION_CHANGED:
1307                        String newUpstreamIfaceName = (String)(message.obj);
1308                        if ((mMyUpstreamIfaceName == null && newUpstreamIfaceName == null) ||
1309                                (mMyUpstreamIfaceName != null &&
1310                                mMyUpstreamIfaceName.equals(newUpstreamIfaceName))) {
1311                            if (VDBG) Log.d(TAG, "Connection changed noop - dropping");
1312                            break;
1313                        }
1314                        cleanupUpstream();
1315                        if (newUpstreamIfaceName != null) {
1316                            try {
1317                                mNMService.enableNat(mIfaceName, newUpstreamIfaceName);
1318                                mNMService.startInterfaceForwarding(mIfaceName,
1319                                        newUpstreamIfaceName);
1320                            } catch (Exception e) {
1321                                Log.e(TAG, "Exception enabling Nat: " + e.toString());
1322                                try {
1323                                    mNMService.disableNat(mIfaceName, newUpstreamIfaceName);
1324                                } catch (Exception ee) {}
1325                                try {
1326                                    mNMService.untetherInterface(mIfaceName);
1327                                } catch (Exception ee) {}
1328
1329                                setLastError(ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR);
1330                                transitionTo(mInitialState);
1331                                return true;
1332                            }
1333                        }
1334                        mMyUpstreamIfaceName = newUpstreamIfaceName;
1335                        break;
1336                    case CMD_CELL_DUN_ERROR:
1337                    case CMD_IP_FORWARDING_ENABLE_ERROR:
1338                    case CMD_IP_FORWARDING_DISABLE_ERROR:
1339                    case CMD_START_TETHERING_ERROR:
1340                    case CMD_STOP_TETHERING_ERROR:
1341                    case CMD_SET_DNS_FORWARDERS_ERROR:
1342                        error = true;
1343                        // fall through
1344                    case CMD_TETHER_MODE_DEAD:
1345                        cleanupUpstream();
1346                        try {
1347                            mNMService.untetherInterface(mIfaceName);
1348                        } catch (Exception e) {
1349                            setLastErrorAndTransitionToInitialState(
1350                                    ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR);
1351                            break;
1352                        }
1353                        if (error) {
1354                            setLastErrorAndTransitionToInitialState(
1355                                    ConnectivityManager.TETHER_ERROR_MASTER_ERROR);
1356                            break;
1357                        }
1358                        if (DBG) Log.d(TAG, "Tether lost upstream connection " + mIfaceName);
1359                        sendTetherStateChangedBroadcast();
1360                        if (mUsb) {
1361                            if (!Tethering.this.configureUsbIface(false)) {
1362                                setLastError(ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
1363                            }
1364                        }
1365                        transitionTo(mInitialState);
1366                        break;
1367                    default:
1368                        retValue = false;
1369                        break;
1370                }
1371                return retValue;
1372            }
1373        }
1374
1375        class UnavailableState extends State {
1376            @Override
1377            public void enter() {
1378                setAvailable(false);
1379                setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR);
1380                setTethered(false);
1381                sendTetherStateChangedBroadcast();
1382            }
1383            @Override
1384            public boolean processMessage(Message message) {
1385                boolean retValue = true;
1386                switch (message.what) {
1387                    case CMD_INTERFACE_UP:
1388                        transitionTo(mInitialState);
1389                        break;
1390                    default:
1391                        retValue = false;
1392                        break;
1393                }
1394                return retValue;
1395            }
1396        }
1397
1398        void setLastErrorAndTransitionToInitialState(int error) {
1399            setLastError(error);
1400            transitionTo(mInitialState);
1401        }
1402
1403    }
1404
1405    /**
1406     * A NetworkCallback class that relays information of interest to the
1407     * tethering master state machine thread for subsequent processing.
1408     */
1409    class UpstreamNetworkCallback extends NetworkCallback {
1410        @Override
1411        public void onLinkPropertiesChanged(Network network, LinkProperties newLp) {
1412            mTetherMasterSM.sendMessage(
1413                    TetherMasterSM.EVENT_UPSTREAM_LINKPROPERTIES_CHANGED,
1414                    new NetworkState(null, newLp, null, network, null, null));
1415        }
1416
1417        @Override
1418        public void onLost(Network network) {
1419            mTetherMasterSM.sendMessage(TetherMasterSM.EVENT_UPSTREAM_LOST, network);
1420        }
1421    }
1422
1423    /**
1424     * A class to centralize all the network and link properties information
1425     * pertaining to the current and any potential upstream network.
1426     *
1427     * Calling #start() registers two callbacks: one to track the system default
1428     * network and a second to specifically observe TYPE_MOBILE_DUN networks.
1429     *
1430     * The methods and data members of this class are only to be accessed and
1431     * modified from the tethering master state machine thread. Any other
1432     * access semantics would necessitate the addition of locking.
1433     *
1434     * TODO: Investigate whether more "upstream-specific" logic/functionality
1435     * could/should be moved here.
1436     */
1437    class UpstreamNetworkMonitor {
1438        final HashMap<Network, NetworkState> mNetworkMap = new HashMap();
1439        NetworkCallback mDefaultNetworkCallback;
1440        NetworkCallback mDunTetheringCallback;
1441
1442        void start() {
1443            stop();
1444
1445            mDefaultNetworkCallback = new UpstreamNetworkCallback();
1446            getConnectivityManager().registerDefaultNetworkCallback(mDefaultNetworkCallback);
1447
1448            final NetworkRequest dunTetheringRequest = new NetworkRequest.Builder()
1449                    .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
1450                    .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
1451                    .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN)
1452                    .build();
1453            mDunTetheringCallback = new UpstreamNetworkCallback();
1454            getConnectivityManager().registerNetworkCallback(
1455                    dunTetheringRequest, mDunTetheringCallback);
1456        }
1457
1458        void stop() {
1459            if (mDefaultNetworkCallback != null) {
1460                getConnectivityManager().unregisterNetworkCallback(mDefaultNetworkCallback);
1461                mDefaultNetworkCallback = null;
1462            }
1463
1464            if (mDunTetheringCallback != null) {
1465                getConnectivityManager().unregisterNetworkCallback(mDunTetheringCallback);
1466                mDunTetheringCallback = null;
1467            }
1468
1469            mNetworkMap.clear();
1470        }
1471
1472        // Returns true if these updated LinkProperties pertain to the current
1473        // upstream network interface, false otherwise (or if there is not
1474        // currently any upstream tethering interface).
1475        boolean processLinkPropertiesChanged(NetworkState networkState) {
1476            if (networkState == null ||
1477                    networkState.network == null ||
1478                    networkState.linkProperties == null) {
1479                return false;
1480            }
1481
1482            mNetworkMap.put(networkState.network, networkState);
1483
1484            if (mCurrentUpstreamIface != null) {
1485                for (String ifname : networkState.linkProperties.getAllInterfaceNames()) {
1486                    if (mCurrentUpstreamIface.equals(ifname)) {
1487                        return true;
1488                    }
1489                }
1490            }
1491            return false;
1492        }
1493
1494        void processNetworkLost(Network network) {
1495            if (network != null) {
1496                mNetworkMap.remove(network);
1497            }
1498        }
1499    }
1500
1501    class TetherMasterSM extends StateMachine {
1502        private static final int BASE_MASTER                    = Protocol.BASE_TETHERING;
1503        // an interface SM has requested Tethering
1504        static final int CMD_TETHER_MODE_REQUESTED              = BASE_MASTER + 1;
1505        // an interface SM has unrequested Tethering
1506        static final int CMD_TETHER_MODE_UNREQUESTED            = BASE_MASTER + 2;
1507        // upstream connection change - do the right thing
1508        static final int CMD_UPSTREAM_CHANGED                   = BASE_MASTER + 3;
1509        // we don't have a valid upstream conn, check again after a delay
1510        static final int CMD_RETRY_UPSTREAM                     = BASE_MASTER + 4;
1511        // Events from NetworkCallbacks that we process on the master state
1512        // machine thread on behalf of the UpstreamNetworkMonitor.
1513        static final int EVENT_UPSTREAM_LINKPROPERTIES_CHANGED  = BASE_MASTER + 5;
1514        static final int EVENT_UPSTREAM_LOST                    = BASE_MASTER + 6;
1515
1516        // This indicates what a timeout event relates to.  A state that
1517        // sends itself a delayed timeout event and handles incoming timeout events
1518        // should inc this when it is entered and whenever it sends a new timeout event.
1519        // We do not flush the old ones.
1520        private int mSequenceNumber;
1521
1522        private State mInitialState;
1523        private State mTetherModeAliveState;
1524
1525        private State mSetIpForwardingEnabledErrorState;
1526        private State mSetIpForwardingDisabledErrorState;
1527        private State mStartTetheringErrorState;
1528        private State mStopTetheringErrorState;
1529        private State mSetDnsForwardersErrorState;
1530
1531        private ArrayList<TetherInterfaceSM> mNotifyList;
1532
1533        private int mMobileApnReserved = ConnectivityManager.TYPE_NONE;
1534        private NetworkCallback mMobileUpstreamCallback;
1535
1536        private static final int UPSTREAM_SETTLE_TIME_MS     = 10000;
1537
1538        TetherMasterSM(String name, Looper looper) {
1539            super(name, looper);
1540
1541            //Add states
1542            mInitialState = new InitialState();
1543            addState(mInitialState);
1544            mTetherModeAliveState = new TetherModeAliveState();
1545            addState(mTetherModeAliveState);
1546
1547            mSetIpForwardingEnabledErrorState = new SetIpForwardingEnabledErrorState();
1548            addState(mSetIpForwardingEnabledErrorState);
1549            mSetIpForwardingDisabledErrorState = new SetIpForwardingDisabledErrorState();
1550            addState(mSetIpForwardingDisabledErrorState);
1551            mStartTetheringErrorState = new StartTetheringErrorState();
1552            addState(mStartTetheringErrorState);
1553            mStopTetheringErrorState = new StopTetheringErrorState();
1554            addState(mStopTetheringErrorState);
1555            mSetDnsForwardersErrorState = new SetDnsForwardersErrorState();
1556            addState(mSetDnsForwardersErrorState);
1557
1558            mNotifyList = new ArrayList<TetherInterfaceSM>();
1559            setInitialState(mInitialState);
1560        }
1561
1562        class TetherMasterUtilState extends State {
1563            @Override
1564            public boolean processMessage(Message m) {
1565                return false;
1566            }
1567
1568            protected boolean turnOnUpstreamMobileConnection(int apnType) {
1569                if (apnType == ConnectivityManager.TYPE_NONE) { return false; }
1570
1571                if (apnType != mMobileApnReserved) {
1572                    // Unregister any previous mobile upstream callback because
1573                    // this request, if any, will be different.
1574                    turnOffUpstreamMobileConnection();
1575                }
1576
1577                if (mMobileUpstreamCallback != null) {
1578                    // Looks like we already filed a request for this apnType.
1579                    return true;
1580                }
1581
1582                switch (apnType) {
1583                    case ConnectivityManager.TYPE_MOBILE_DUN:
1584                    case ConnectivityManager.TYPE_MOBILE:
1585                    case ConnectivityManager.TYPE_MOBILE_HIPRI:
1586                        mMobileApnReserved = apnType;
1587                        break;
1588                    default:
1589                        return false;
1590                }
1591
1592                final NetworkRequest.Builder builder = new NetworkRequest.Builder()
1593                        .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
1594                if (apnType == ConnectivityManager.TYPE_MOBILE_DUN) {
1595                    builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
1596                           .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN);
1597                } else {
1598                    builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
1599                }
1600                final NetworkRequest mobileUpstreamRequest = builder.build();
1601
1602                // The UpstreamNetworkMonitor's callback will be notified.
1603                // Therefore, to avoid duplicate notifications, we only register a no-op.
1604                mMobileUpstreamCallback = new NetworkCallback();
1605
1606                // TODO: Change the timeout from 0 (no onUnavailable callback) to use some
1607                // moderate callback time (once timeout callbacks are implemented). This might
1608                // be useful for updating some UI. Additionally, we should definitely log a
1609                // message to aid in any subsequent debugging
1610                if (DBG) Log.d(TAG, "requesting mobile upstream network: " + mobileUpstreamRequest);
1611                getConnectivityManager().requestNetwork(
1612                        mobileUpstreamRequest, mMobileUpstreamCallback, 0, apnType);
1613                return true;
1614            }
1615
1616            protected void turnOffUpstreamMobileConnection() {
1617                if (mMobileUpstreamCallback != null) {
1618                    getConnectivityManager().unregisterNetworkCallback(mMobileUpstreamCallback);
1619                    mMobileUpstreamCallback = null;
1620                }
1621                mMobileApnReserved = ConnectivityManager.TYPE_NONE;
1622            }
1623
1624            protected boolean turnOnMasterTetherSettings() {
1625                try {
1626                    mNMService.setIpForwardingEnabled(true);
1627                } catch (Exception e) {
1628                    transitionTo(mSetIpForwardingEnabledErrorState);
1629                    return false;
1630                }
1631                try {
1632                    mNMService.startTethering(mDhcpRange);
1633                } catch (Exception e) {
1634                    try {
1635                        mNMService.stopTethering();
1636                        mNMService.startTethering(mDhcpRange);
1637                    } catch (Exception ee) {
1638                        transitionTo(mStartTetheringErrorState);
1639                        return false;
1640                    }
1641                }
1642                return true;
1643            }
1644
1645            protected boolean turnOffMasterTetherSettings() {
1646                try {
1647                    mNMService.stopTethering();
1648                } catch (Exception e) {
1649                    transitionTo(mStopTetheringErrorState);
1650                    return false;
1651                }
1652                try {
1653                    mNMService.setIpForwardingEnabled(false);
1654                } catch (Exception e) {
1655                    transitionTo(mSetIpForwardingDisabledErrorState);
1656                    return false;
1657                }
1658                transitionTo(mInitialState);
1659                return true;
1660            }
1661
1662            protected void chooseUpstreamType(boolean tryCell) {
1663                int upType = ConnectivityManager.TYPE_NONE;
1664                String iface = null;
1665
1666                updateConfiguration(); // TODO - remove?
1667
1668                synchronized (mPublicSync) {
1669                    if (VDBG) {
1670                        Log.d(TAG, "chooseUpstreamType has upstream iface types:");
1671                        for (Integer netType : mUpstreamIfaceTypes) {
1672                            Log.d(TAG, " " + netType);
1673                        }
1674                    }
1675
1676                    for (Integer netType : mUpstreamIfaceTypes) {
1677                        NetworkInfo info =
1678                                getConnectivityManager().getNetworkInfo(netType.intValue());
1679                        if ((info != null) && info.isConnected()) {
1680                            upType = netType.intValue();
1681                            break;
1682                        }
1683                    }
1684                }
1685
1686                if (DBG) {
1687                    Log.d(TAG, "chooseUpstreamType(" + tryCell + "),"
1688                            + " preferredApn="
1689                            + ConnectivityManager.getNetworkTypeName(mPreferredUpstreamMobileApn)
1690                            + ", got type="
1691                            + ConnectivityManager.getNetworkTypeName(upType));
1692                }
1693
1694                switch (upType) {
1695                    case ConnectivityManager.TYPE_MOBILE_DUN:
1696                    case ConnectivityManager.TYPE_MOBILE_HIPRI:
1697                        // If we're on DUN, put our own grab on it.
1698                        turnOnUpstreamMobileConnection(upType);
1699                        break;
1700                    case ConnectivityManager.TYPE_NONE:
1701                        if (tryCell &&
1702                                turnOnUpstreamMobileConnection(mPreferredUpstreamMobileApn)) {
1703                            // We think mobile should be coming up; don't set a retry.
1704                        } else {
1705                            sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS);
1706                        }
1707                        break;
1708                    default:
1709                        /* If we've found an active upstream connection that's not DUN/HIPRI
1710                         * we should stop any outstanding DUN/HIPRI start requests.
1711                         *
1712                         * If we found NONE we don't want to do this as we want any previous
1713                         * requests to keep trying to bring up something we can use.
1714                         */
1715                        turnOffUpstreamMobileConnection();
1716                        break;
1717                }
1718
1719                if (upType != ConnectivityManager.TYPE_NONE) {
1720                    LinkProperties linkProperties =
1721                            getConnectivityManager().getLinkProperties(upType);
1722                    if (linkProperties != null) {
1723                        // Find the interface with the default IPv4 route. It may be the
1724                        // interface described by linkProperties, or one of the interfaces
1725                        // stacked on top of it.
1726                        Log.i(TAG, "Finding IPv4 upstream interface on: " + linkProperties);
1727                        RouteInfo ipv4Default = RouteInfo.selectBestRoute(
1728                            linkProperties.getAllRoutes(), Inet4Address.ANY);
1729                        if (ipv4Default != null) {
1730                            iface = ipv4Default.getInterface();
1731                            Log.i(TAG, "Found interface " + ipv4Default.getInterface());
1732                        } else {
1733                            Log.i(TAG, "No IPv4 upstream interface, giving up.");
1734                        }
1735                    }
1736
1737                    if (iface != null) {
1738                        Network network = getConnectivityManager().getNetworkForType(upType);
1739                        if (network == null) {
1740                            Log.e(TAG, "No Network for upstream type " + upType + "!");
1741                        }
1742                        setDnsForwarders(network, linkProperties);
1743                    }
1744                }
1745                notifyTetheredOfNewUpstreamIface(iface);
1746            }
1747
1748            protected void setDnsForwarders(final Network network, final LinkProperties lp) {
1749                String[] dnsServers = mDefaultDnsServers;
1750                final Collection<InetAddress> dnses = lp.getDnsServers();
1751                // TODO: Properly support the absence of DNS servers.
1752                if (dnses != null && !dnses.isEmpty()) {
1753                    // TODO: remove this invocation of NetworkUtils.makeStrings().
1754                    dnsServers = NetworkUtils.makeStrings(dnses);
1755                }
1756                if (VDBG) {
1757                    Log.d(TAG, "Setting DNS forwarders: Network=" + network +
1758                           ", dnsServers=" + Arrays.toString(dnsServers));
1759                }
1760                try {
1761                    mNMService.setDnsForwarders(network, dnsServers);
1762                } catch (Exception e) {
1763                    // TODO: Investigate how this can fail and what exactly
1764                    // happens if/when such failures occur.
1765                    Log.e(TAG, "Setting DNS forwarders failed!");
1766                    transitionTo(mSetDnsForwardersErrorState);
1767                }
1768            }
1769
1770            protected void notifyTetheredOfNewUpstreamIface(String ifaceName) {
1771                if (DBG) Log.d(TAG, "Notifying tethered with upstream=" + ifaceName);
1772                mCurrentUpstreamIface = ifaceName;
1773                for (TetherInterfaceSM sm : mNotifyList) {
1774                    sm.sendMessage(TetherInterfaceSM.CMD_TETHER_CONNECTION_CHANGED,
1775                            ifaceName);
1776                }
1777            }
1778        }
1779
1780        private final AtomicInteger mSimBcastGenerationNumber = new AtomicInteger(0);
1781        private SimChangeBroadcastReceiver mBroadcastReceiver = null;
1782
1783        private void startListeningForSimChanges() {
1784            if (DBG) Log.d(TAG, "startListeningForSimChanges");
1785            if (mBroadcastReceiver == null) {
1786                mBroadcastReceiver = new SimChangeBroadcastReceiver(
1787                        mSimBcastGenerationNumber.incrementAndGet());
1788                final IntentFilter filter = new IntentFilter();
1789                filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
1790
1791                mContext.registerReceiver(mBroadcastReceiver, filter);
1792            }
1793        }
1794
1795        private void stopListeningForSimChanges() {
1796            if (DBG) Log.d(TAG, "stopListeningForSimChanges");
1797            if (mBroadcastReceiver != null) {
1798                mSimBcastGenerationNumber.incrementAndGet();
1799                mContext.unregisterReceiver(mBroadcastReceiver);
1800                mBroadcastReceiver = null;
1801            }
1802        }
1803
1804        class SimChangeBroadcastReceiver extends BroadcastReceiver {
1805            // used to verify this receiver is still current
1806            final private int mGenerationNumber;
1807
1808            // we're interested in edge-triggered LOADED notifications, so
1809            // ignore LOADED unless we saw an ABSENT state first
1810            private boolean mSimAbsentSeen = false;
1811
1812            public SimChangeBroadcastReceiver(int generationNumber) {
1813                super();
1814                mGenerationNumber = generationNumber;
1815            }
1816
1817            @Override
1818            public void onReceive(Context context, Intent intent) {
1819                if (DBG) {
1820                    Log.d(TAG, "simchange mGenerationNumber=" + mGenerationNumber +
1821                            ", current generationNumber=" + mSimBcastGenerationNumber.get());
1822                }
1823                if (mGenerationNumber != mSimBcastGenerationNumber.get()) return;
1824
1825                final String state =
1826                        intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
1827
1828                Log.d(TAG, "got Sim changed to state " + state + ", mSimAbsentSeen=" +
1829                        mSimAbsentSeen);
1830                if (!mSimAbsentSeen && IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(state)) {
1831                    mSimAbsentSeen = true;
1832                }
1833
1834                if (mSimAbsentSeen && IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(state)) {
1835                    mSimAbsentSeen = false;
1836                    try {
1837                        if (mContext.getResources().getString(com.android.internal.R.string.
1838                                config_mobile_hotspot_provision_app_no_ui).isEmpty() == false) {
1839                            ArrayList<Integer> tethered = new ArrayList<Integer>();
1840                            synchronized (mPublicSync) {
1841                                Set ifaces = mIfaces.keySet();
1842                                for (Object iface : ifaces) {
1843                                    TetherInterfaceSM sm = mIfaces.get(iface);
1844                                    if (sm != null && sm.isTethered()) {
1845                                        if (isUsb((String)iface)) {
1846                                            tethered.add(new Integer(
1847                                                    ConnectivityManager.TETHERING_USB));
1848                                        } else if (isWifi((String)iface)) {
1849                                            tethered.add(new Integer(
1850                                                    ConnectivityManager.TETHERING_WIFI));
1851                                        } else if (isBluetooth((String)iface)) {
1852                                            tethered.add(new Integer(
1853                                                    ConnectivityManager.TETHERING_BLUETOOTH));
1854                                        }
1855                                    }
1856                                }
1857                            }
1858                            for (int tetherType : tethered) {
1859                                Intent startProvIntent = new Intent();
1860                                startProvIntent.putExtra(
1861                                        ConnectivityManager.EXTRA_ADD_TETHER_TYPE, tetherType);
1862                                startProvIntent.putExtra(
1863                                        ConnectivityManager.EXTRA_RUN_PROVISION, true);
1864                                startProvIntent.setComponent(TETHER_SERVICE);
1865                                mContext.startServiceAsUser(startProvIntent, UserHandle.CURRENT);
1866                            }
1867                            Log.d(TAG, "re-evaluate provisioning");
1868                        } else {
1869                            Log.d(TAG, "no prov-check needed for new SIM");
1870                        }
1871                    } catch (Resources.NotFoundException e) {
1872                        Log.d(TAG, "no prov-check needed for new SIM");
1873                        // not defined, do nothing
1874                    }
1875                }
1876            }
1877        }
1878
1879        class InitialState extends TetherMasterUtilState {
1880            @Override
1881            public void enter() {
1882            }
1883            @Override
1884            public boolean processMessage(Message message) {
1885                maybeLogMessage(this, message.what);
1886                boolean retValue = true;
1887                switch (message.what) {
1888                    case CMD_TETHER_MODE_REQUESTED:
1889                        TetherInterfaceSM who = (TetherInterfaceSM)message.obj;
1890                        if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
1891                        mNotifyList.add(who);
1892                        transitionTo(mTetherModeAliveState);
1893                        break;
1894                    case CMD_TETHER_MODE_UNREQUESTED:
1895                        who = (TetherInterfaceSM)message.obj;
1896                        if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
1897                        int index = mNotifyList.indexOf(who);
1898                        if (index != -1) {
1899                            mNotifyList.remove(who);
1900                        }
1901                        break;
1902                    default:
1903                        retValue = false;
1904                        break;
1905                }
1906                return retValue;
1907            }
1908        }
1909
1910        class TetherModeAliveState extends TetherMasterUtilState {
1911            boolean mTryCell = true;
1912            @Override
1913            public void enter() {
1914                // TODO: examine if we should check the return value.
1915                turnOnMasterTetherSettings(); // may transition us out
1916                startListeningForSimChanges();
1917                mUpstreamNetworkMonitor.start();
1918
1919                mTryCell = true;  // better try something first pass or crazy tests cases will fail
1920                chooseUpstreamType(mTryCell);
1921                mTryCell = !mTryCell;
1922            }
1923            @Override
1924            public void exit() {
1925                // TODO: examine if we should check the return value.
1926                turnOffUpstreamMobileConnection();
1927                mUpstreamNetworkMonitor.stop();
1928                stopListeningForSimChanges();
1929                notifyTetheredOfNewUpstreamIface(null);
1930            }
1931            @Override
1932            public boolean processMessage(Message message) {
1933                maybeLogMessage(this, message.what);
1934                boolean retValue = true;
1935                switch (message.what) {
1936                    case CMD_TETHER_MODE_REQUESTED:
1937                        TetherInterfaceSM who = (TetherInterfaceSM)message.obj;
1938                        if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
1939                        mNotifyList.add(who);
1940                        who.sendMessage(TetherInterfaceSM.CMD_TETHER_CONNECTION_CHANGED,
1941                                mCurrentUpstreamIface);
1942                        break;
1943                    case CMD_TETHER_MODE_UNREQUESTED:
1944                        who = (TetherInterfaceSM)message.obj;
1945                        if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
1946                        int index = mNotifyList.indexOf(who);
1947                        if (index != -1) {
1948                            if (DBG) Log.d(TAG, "TetherModeAlive removing notifyee " + who);
1949                            mNotifyList.remove(index);
1950                            if (mNotifyList.isEmpty()) {
1951                                turnOffMasterTetherSettings(); // transitions appropriately
1952                            } else {
1953                                if (DBG) {
1954                                    Log.d(TAG, "TetherModeAlive still has " + mNotifyList.size() +
1955                                            " live requests:");
1956                                    for (Object o : mNotifyList) Log.d(TAG, "  " + o);
1957                                }
1958                            }
1959                        } else {
1960                           Log.e(TAG, "TetherModeAliveState UNREQUESTED has unknown who: " + who);
1961                        }
1962                        break;
1963                    case CMD_UPSTREAM_CHANGED:
1964                        // need to try DUN immediately if Wifi goes down
1965                        mTryCell = true;
1966                        chooseUpstreamType(mTryCell);
1967                        mTryCell = !mTryCell;
1968                        break;
1969                    case CMD_RETRY_UPSTREAM:
1970                        chooseUpstreamType(mTryCell);
1971                        mTryCell = !mTryCell;
1972                        break;
1973                    case EVENT_UPSTREAM_LINKPROPERTIES_CHANGED:
1974                        NetworkState state = (NetworkState) message.obj;
1975                        if (mUpstreamNetworkMonitor.processLinkPropertiesChanged(state)) {
1976                            setDnsForwarders(state.network, state.linkProperties);
1977                        } else if (mCurrentUpstreamIface == null) {
1978                            // If we have no upstream interface, try to run through upstream
1979                            // selection again.  If, for example, IPv4 connectivity has shown up
1980                            // after IPv6 (e.g., 464xlat became available) we want the chance to
1981                            // notice and act accordingly.
1982                            chooseUpstreamType(false);
1983                        }
1984                        break;
1985                    case EVENT_UPSTREAM_LOST:
1986                        // TODO: Re-evaluate possible upstreams. Currently upstream reevaluation
1987                        // is triggered via received CONNECTIVITY_ACTION broadcasts that result
1988                        // in being passed a TetherMasterSM.CMD_UPSTREAM_CHANGED.
1989                        mUpstreamNetworkMonitor.processNetworkLost((Network) message.obj);
1990                        break;
1991                    default:
1992                        retValue = false;
1993                        break;
1994                }
1995                return retValue;
1996            }
1997        }
1998
1999        class ErrorState extends State {
2000            int mErrorNotification;
2001            @Override
2002            public boolean processMessage(Message message) {
2003                boolean retValue = true;
2004                switch (message.what) {
2005                    case CMD_TETHER_MODE_REQUESTED:
2006                        TetherInterfaceSM who = (TetherInterfaceSM)message.obj;
2007                        who.sendMessage(mErrorNotification);
2008                        break;
2009                    default:
2010                       retValue = false;
2011                }
2012                return retValue;
2013            }
2014            void notify(int msgType) {
2015                mErrorNotification = msgType;
2016                for (Object o : mNotifyList) {
2017                    TetherInterfaceSM sm = (TetherInterfaceSM)o;
2018                    sm.sendMessage(msgType);
2019                }
2020            }
2021
2022        }
2023        class SetIpForwardingEnabledErrorState extends ErrorState {
2024            @Override
2025            public void enter() {
2026                Log.e(TAG, "Error in setIpForwardingEnabled");
2027                notify(TetherInterfaceSM.CMD_IP_FORWARDING_ENABLE_ERROR);
2028            }
2029        }
2030
2031        class SetIpForwardingDisabledErrorState extends ErrorState {
2032            @Override
2033            public void enter() {
2034                Log.e(TAG, "Error in setIpForwardingDisabled");
2035                notify(TetherInterfaceSM.CMD_IP_FORWARDING_DISABLE_ERROR);
2036            }
2037        }
2038
2039        class StartTetheringErrorState extends ErrorState {
2040            @Override
2041            public void enter() {
2042                Log.e(TAG, "Error in startTethering");
2043                notify(TetherInterfaceSM.CMD_START_TETHERING_ERROR);
2044                try {
2045                    mNMService.setIpForwardingEnabled(false);
2046                } catch (Exception e) {}
2047            }
2048        }
2049
2050        class StopTetheringErrorState extends ErrorState {
2051            @Override
2052            public void enter() {
2053                Log.e(TAG, "Error in stopTethering");
2054                notify(TetherInterfaceSM.CMD_STOP_TETHERING_ERROR);
2055                try {
2056                    mNMService.setIpForwardingEnabled(false);
2057                } catch (Exception e) {}
2058            }
2059        }
2060
2061        class SetDnsForwardersErrorState extends ErrorState {
2062            @Override
2063            public void enter() {
2064                Log.e(TAG, "Error in setDnsForwarders");
2065                notify(TetherInterfaceSM.CMD_SET_DNS_FORWARDERS_ERROR);
2066                try {
2067                    mNMService.stopTethering();
2068                } catch (Exception e) {}
2069                try {
2070                    mNMService.setIpForwardingEnabled(false);
2071                } catch (Exception e) {}
2072            }
2073        }
2074    }
2075
2076    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
2077        final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
2078
2079        if (mContext.checkCallingOrSelfPermission(
2080                android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) {
2081            pw.println("Permission Denial: can't dump ConnectivityService.Tether " +
2082                    "from from pid=" + Binder.getCallingPid() + ", uid=" +
2083                    Binder.getCallingUid());
2084                    return;
2085        }
2086
2087        pw.println("Tethering:");
2088        pw.increaseIndent();
2089        pw.print("mUpstreamIfaceTypes:");
2090        synchronized (mPublicSync) {
2091            for (Integer netType : mUpstreamIfaceTypes) {
2092                pw.print(" " + ConnectivityManager.getNetworkTypeName(netType));
2093            }
2094            pw.println();
2095
2096            pw.println("Tether state:");
2097            pw.increaseIndent();
2098            for (Object o : mIfaces.values()) {
2099                pw.println(o);
2100            }
2101            pw.decreaseIndent();
2102        }
2103        pw.decreaseIndent();
2104        return;
2105    }
2106}
2107