[go: nahoru, domu]

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