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