Tethering.java revision fb41343c8c0649ff941808d3e6fadf3d6ea53b78
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 static android.hardware.usb.UsbManager.USB_CONNECTED;
20import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
21import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
22import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
23
24import android.app.Notification;
25import android.app.NotificationManager;
26import android.app.PendingIntent;
27import android.bluetooth.BluetoothAdapter;
28import android.bluetooth.BluetoothPan;
29import android.bluetooth.BluetoothProfile;
30import android.bluetooth.BluetoothProfile.ServiceListener;
31import android.content.BroadcastReceiver;
32import android.content.ComponentName;
33import android.content.Context;
34import android.content.Intent;
35import android.content.IntentFilter;
36import android.content.pm.PackageManager;
37import android.content.res.Resources;
38import android.hardware.usb.UsbManager;
39import android.net.ConnectivityManager;
40import android.net.INetworkPolicyManager;
41import android.net.INetworkStatsService;
42import android.net.LinkProperties;
43import android.net.Network;
44import android.net.NetworkCapabilities;
45import android.net.NetworkInfo;
46import android.net.NetworkRequest;
47import android.net.NetworkState;
48import android.net.NetworkUtils;
49import android.net.RouteInfo;
50import android.net.wifi.WifiManager;
51import android.os.Binder;
52import android.os.Bundle;
53import android.os.INetworkManagementService;
54import android.os.Looper;
55import android.os.Message;
56import android.os.Parcel;
57import android.os.RemoteException;
58import android.os.ResultReceiver;
59import android.os.UserHandle;
60import android.provider.Settings;
61import android.telephony.CarrierConfigManager;
62import android.telephony.TelephonyManager;
63import android.text.TextUtils;
64import android.util.ArrayMap;
65import android.util.Log;
66import android.util.SparseArray;
67
68import com.android.internal.annotations.VisibleForTesting;
69import com.android.internal.telephony.IccCardConstants;
70import com.android.internal.telephony.TelephonyIntents;
71import com.android.internal.util.IndentingPrintWriter;
72import com.android.internal.util.MessageUtils;
73import com.android.internal.util.Protocol;
74import com.android.internal.util.State;
75import com.android.internal.util.StateMachine;
76import com.android.server.connectivity.tethering.IControlsTethering;
77import com.android.server.connectivity.tethering.IPv6TetheringCoordinator;
78import com.android.server.connectivity.tethering.IPv6TetheringInterfaceServices;
79import com.android.server.connectivity.tethering.TetheringConfiguration;
80import com.android.server.connectivity.tethering.TetherInterfaceStateMachine;
81import com.android.server.connectivity.tethering.UpstreamNetworkMonitor;
82import com.android.server.net.BaseNetworkObserver;
83
84import java.io.FileDescriptor;
85import java.io.PrintWriter;
86import java.net.Inet4Address;
87import java.net.InetAddress;
88import java.util.ArrayList;
89import java.util.Arrays;
90import java.util.Collection;
91import java.util.HashMap;
92import java.util.Iterator;
93import java.util.concurrent.atomic.AtomicInteger;
94
95
96/**
97 * @hide
98 *
99 * This class holds much of the business logic to allow Android devices
100 * to act as IP gateways via USB, BT, and WiFi interfaces.
101 */
102public class Tethering extends BaseNetworkObserver implements IControlsTethering {
103
104    private final Context mContext;
105    private final static String TAG = "Tethering";
106    private final static boolean DBG = false;
107    private final static boolean VDBG = false;
108
109    protected static final String DISABLE_PROVISIONING_SYSPROP_KEY = "net.tethering.noprovisioning";
110
111    private static final Class[] messageClasses = {
112            Tethering.class, TetherMasterSM.class, TetherInterfaceStateMachine.class
113    };
114    private static final SparseArray<String> sMagicDecoderRing =
115            MessageUtils.findMessageNames(messageClasses);
116
117    private volatile TetheringConfiguration mConfig;
118
119    // used to synchronize public access to members
120    private final Object mPublicSync;
121
122    private final INetworkManagementService mNMService;
123    private final INetworkStatsService mStatsService;
124    private final INetworkPolicyManager mPolicyManager;
125    private final Looper mLooper;
126    private final MockableSystemProperties mSystemProperties;
127
128    private static class TetherState {
129        public final TetherInterfaceStateMachine mStateMachine;
130        public int mLastState;
131        public int mLastError;
132        public TetherState(TetherInterfaceStateMachine sm) {
133            mStateMachine = sm;
134            // Assume all state machines start out available and with no errors.
135            mLastState = IControlsTethering.STATE_AVAILABLE;
136            mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
137        }
138    }
139    private final ArrayMap<String, TetherState> mTetherStates;
140
141    private final BroadcastReceiver mStateReceiver;
142
143    // {@link ComponentName} of the Service used to run tether provisioning.
144    private static final ComponentName TETHER_SERVICE = ComponentName.unflattenFromString(Resources
145            .getSystem().getString(com.android.internal.R.string.config_wifi_tether_enable));
146
147    private final StateMachine mTetherMasterSM;
148    private final UpstreamNetworkMonitor mUpstreamNetworkMonitor;
149    private String mCurrentUpstreamIface;
150
151    private Notification.Builder mTetheredNotificationBuilder;
152    private int mLastNotificationId;
153
154    private boolean mRndisEnabled;       // track the RNDIS function enabled state
155    private boolean mUsbTetherRequested; // true if USB tethering should be started
156                                         // when RNDIS is enabled
157
158    // True iff WiFi tethering should be started when soft AP is ready.
159    private boolean mWifiTetherRequested;
160
161    public Tethering(Context context, INetworkManagementService nmService,
162            INetworkStatsService statsService, INetworkPolicyManager policyManager,
163            Looper looper, MockableSystemProperties systemProperties) {
164        mContext = context;
165        mNMService = nmService;
166        mStatsService = statsService;
167        mPolicyManager = policyManager;
168        mLooper = looper;
169        mSystemProperties = systemProperties;
170
171        mPublicSync = new Object();
172
173        mTetherStates = new ArrayMap<>();
174
175        mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper);
176        mTetherMasterSM.start();
177
178        mUpstreamNetworkMonitor = new UpstreamNetworkMonitor(
179                mContext, mTetherMasterSM, TetherMasterSM.EVENT_UPSTREAM_CALLBACK);
180
181        mStateReceiver = new StateReceiver();
182        IntentFilter filter = new IntentFilter();
183        filter.addAction(UsbManager.ACTION_USB_STATE);
184        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
185        filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
186        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
187        mContext.registerReceiver(mStateReceiver, filter, null, mTetherMasterSM.getHandler());
188
189        filter = new IntentFilter();
190        filter.addAction(Intent.ACTION_MEDIA_SHARED);
191        filter.addAction(Intent.ACTION_MEDIA_UNSHARED);
192        filter.addDataScheme("file");
193        mContext.registerReceiver(mStateReceiver, filter, null, mTetherMasterSM.getHandler());
194
195        // load device config info
196        updateConfiguration();
197    }
198
199    // We can't do this once in the Tethering() constructor and cache the value, because the
200    // CONNECTIVITY_SERVICE is registered only after the Tethering() constructor has completed.
201    private ConnectivityManager getConnectivityManager() {
202        return (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
203    }
204
205    private void updateConfiguration() {
206        mConfig = new TetheringConfiguration(mContext);
207    }
208
209    @Override
210    public void interfaceStatusChanged(String iface, boolean up) {
211        // Never called directly: only called from interfaceLinkStateChanged.
212        // See NetlinkHandler.cpp:71.
213        if (VDBG) Log.d(TAG, "interfaceStatusChanged " + iface + ", " + up);
214        synchronized (mPublicSync) {
215            int interfaceType = ifaceNameToType(iface);
216            if (interfaceType == ConnectivityManager.TETHERING_INVALID) {
217                return;
218            }
219
220            TetherState tetherState = mTetherStates.get(iface);
221            if (up) {
222                if (tetherState == null) {
223                    trackNewTetherableInterface(iface, interfaceType);
224                }
225            } else {
226                if (interfaceType == ConnectivityManager.TETHERING_BLUETOOTH) {
227                    tetherState.mStateMachine.sendMessage(
228                            TetherInterfaceStateMachine.CMD_INTERFACE_DOWN);
229                    mTetherStates.remove(iface);
230                } else {
231                    // Ignore usb0 down after enabling RNDIS.
232                    // We will handle disconnect in interfaceRemoved.
233                    // Similarly, ignore interface down for WiFi.  We monitor WiFi AP status
234                    // through the WifiManager.WIFI_AP_STATE_CHANGED_ACTION intent.
235                    if (VDBG) Log.d(TAG, "ignore interface down for " + iface);
236                }
237            }
238        }
239    }
240
241    @Override
242    public void interfaceLinkStateChanged(String iface, boolean up) {
243        interfaceStatusChanged(iface, up);
244    }
245
246    private int ifaceNameToType(String iface) {
247        final TetheringConfiguration cfg = mConfig;
248
249        if (cfg.isWifi(iface)) {
250            return ConnectivityManager.TETHERING_WIFI;
251        } else if (cfg.isUsb(iface)) {
252            return ConnectivityManager.TETHERING_USB;
253        } else if (cfg.isBluetooth(iface)) {
254            return ConnectivityManager.TETHERING_BLUETOOTH;
255        }
256        return ConnectivityManager.TETHERING_INVALID;
257    }
258
259    @Override
260    public void interfaceAdded(String iface) {
261        if (VDBG) Log.d(TAG, "interfaceAdded " + iface);
262        synchronized (mPublicSync) {
263            int interfaceType = ifaceNameToType(iface);
264            if (interfaceType == ConnectivityManager.TETHERING_INVALID) {
265                if (VDBG) Log.d(TAG, iface + " is not a tetherable iface, ignoring");
266                return;
267            }
268
269            TetherState tetherState = mTetherStates.get(iface);
270            if (tetherState == null) {
271                trackNewTetherableInterface(iface, interfaceType);
272            } else {
273                if (VDBG) Log.d(TAG, "active iface (" + iface + ") reported as added, ignoring");
274            }
275        }
276    }
277
278    @Override
279    public void interfaceRemoved(String iface) {
280        if (VDBG) Log.d(TAG, "interfaceRemoved " + iface);
281        synchronized (mPublicSync) {
282            TetherState tetherState = mTetherStates.get(iface);
283            if (tetherState == null) {
284                if (VDBG) {
285                    Log.e(TAG, "attempting to remove unknown iface (" + iface + "), ignoring");
286                }
287                return;
288            }
289            tetherState.mStateMachine.sendMessage(TetherInterfaceStateMachine.CMD_INTERFACE_DOWN);
290            mTetherStates.remove(iface);
291        }
292    }
293
294    public void startTethering(int type, ResultReceiver receiver,
295            boolean showProvisioningUi) {
296        if (!isTetherProvisioningRequired()) {
297            enableTetheringInternal(type, true, receiver);
298            return;
299        }
300
301        if (showProvisioningUi) {
302            runUiTetherProvisioningAndEnable(type, receiver);
303        } else {
304            runSilentTetherProvisioningAndEnable(type, receiver);
305        }
306    }
307
308    public void stopTethering(int type) {
309        enableTetheringInternal(type, false, null);
310        if (isTetherProvisioningRequired()) {
311            cancelTetherProvisioningRechecks(type);
312        }
313    }
314
315    /**
316     * Check if the device requires a provisioning check in order to enable tethering.
317     *
318     * @return a boolean - {@code true} indicating tether provisioning is required by the carrier.
319     */
320    @VisibleForTesting
321    protected boolean isTetherProvisioningRequired() {
322        String[] provisionApp = mContext.getResources().getStringArray(
323                com.android.internal.R.array.config_mobile_hotspot_provision_app);
324        if (mSystemProperties.getBoolean(DISABLE_PROVISIONING_SYSPROP_KEY, false)
325                || provisionApp == null) {
326            return false;
327        }
328
329        // Check carrier config for entitlement checks
330        final CarrierConfigManager configManager = (CarrierConfigManager) mContext
331             .getSystemService(Context.CARRIER_CONFIG_SERVICE);
332        if (configManager != null && configManager.getConfig() != null) {
333            // we do have a CarrierConfigManager and it has a config.
334            boolean isEntitlementCheckRequired = configManager.getConfig().getBoolean(
335                    CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL);
336            if (!isEntitlementCheckRequired) {
337                return false;
338            }
339        }
340        return (provisionApp.length == 2);
341    }
342
343    /**
344     * Enables or disables tethering for the given type. This should only be called once
345     * provisioning has succeeded or is not necessary. It will also schedule provisioning rechecks
346     * for the specified interface.
347     */
348    private void enableTetheringInternal(int type, boolean enable, ResultReceiver receiver) {
349        boolean isProvisioningRequired = enable && isTetherProvisioningRequired();
350        int result;
351        switch (type) {
352            case ConnectivityManager.TETHERING_WIFI:
353                result = setWifiTethering(enable);
354                if (isProvisioningRequired && result == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
355                    scheduleProvisioningRechecks(type);
356                }
357                sendTetherResult(receiver, result);
358                break;
359            case ConnectivityManager.TETHERING_USB:
360                result = setUsbTethering(enable);
361                if (isProvisioningRequired && result == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
362                    scheduleProvisioningRechecks(type);
363                }
364                sendTetherResult(receiver, result);
365                break;
366            case ConnectivityManager.TETHERING_BLUETOOTH:
367                setBluetoothTethering(enable, receiver);
368                break;
369            default:
370                Log.w(TAG, "Invalid tether type.");
371                sendTetherResult(receiver, ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE);
372        }
373    }
374
375    private void sendTetherResult(ResultReceiver receiver, int result) {
376        if (receiver != null) {
377            receiver.send(result, null);
378        }
379    }
380
381    private int setWifiTethering(final boolean enable) {
382        synchronized (mPublicSync) {
383            mWifiTetherRequested = enable;
384            final WifiManager wifiManager =
385                    (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
386            if (wifiManager.setWifiApEnabled(null /* use existing wifi config */, enable)) {
387                return ConnectivityManager.TETHER_ERROR_NO_ERROR;
388            }
389            return ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
390        }
391    }
392
393    private void setBluetoothTethering(final boolean enable, final ResultReceiver receiver) {
394        final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
395        if (adapter == null || !adapter.isEnabled()) {
396            Log.w(TAG, "Tried to enable bluetooth tethering with null or disabled adapter. null: " +
397                    (adapter == null));
398            sendTetherResult(receiver, ConnectivityManager.TETHER_ERROR_SERVICE_UNAVAIL);
399            return;
400        }
401
402        adapter.getProfileProxy(mContext, new ServiceListener() {
403            @Override
404            public void onServiceDisconnected(int profile) { }
405
406            @Override
407            public void onServiceConnected(int profile, BluetoothProfile proxy) {
408                ((BluetoothPan) proxy).setBluetoothTethering(enable);
409                // TODO: Enabling bluetooth tethering can fail asynchronously here.
410                // We should figure out a way to bubble up that failure instead of sending success.
411                int result = ((BluetoothPan) proxy).isTetheringOn() == enable ?
412                        ConnectivityManager.TETHER_ERROR_NO_ERROR :
413                        ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
414                sendTetherResult(receiver, result);
415                if (enable && isTetherProvisioningRequired()) {
416                    scheduleProvisioningRechecks(ConnectivityManager.TETHERING_BLUETOOTH);
417                }
418                adapter.closeProfileProxy(BluetoothProfile.PAN, proxy);
419            }
420        }, BluetoothProfile.PAN);
421    }
422
423    private void runUiTetherProvisioningAndEnable(int type, ResultReceiver receiver) {
424        ResultReceiver proxyReceiver = getProxyReceiver(type, receiver);
425        sendUiTetherProvisionIntent(type, proxyReceiver);
426    }
427
428    private void sendUiTetherProvisionIntent(int type, ResultReceiver receiver) {
429        Intent intent = new Intent(Settings.ACTION_TETHER_PROVISIONING);
430        intent.putExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE, type);
431        intent.putExtra(ConnectivityManager.EXTRA_PROVISION_CALLBACK, receiver);
432        final long ident = Binder.clearCallingIdentity();
433        try {
434            mContext.startActivityAsUser(intent, UserHandle.CURRENT);
435        } finally {
436            Binder.restoreCallingIdentity(ident);
437        }
438    }
439
440    /**
441     * Creates a proxy {@link ResultReceiver} which enables tethering if the provisioning result
442     * is successful before firing back up to the wrapped receiver.
443     *
444     * @param type The type of tethering being enabled.
445     * @param receiver A ResultReceiver which will be called back with an int resultCode.
446     * @return The proxy receiver.
447     */
448    private ResultReceiver getProxyReceiver(final int type, final ResultReceiver receiver) {
449        ResultReceiver rr = new ResultReceiver(null) {
450            @Override
451            protected void onReceiveResult(int resultCode, Bundle resultData) {
452                // If provisioning is successful, enable tethering, otherwise just send the error.
453                if (resultCode == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
454                    enableTetheringInternal(type, true, receiver);
455                } else {
456                    sendTetherResult(receiver, resultCode);
457                }
458            }
459        };
460
461        // The following is necessary to avoid unmarshalling issues when sending the receiver
462        // across processes.
463        Parcel parcel = Parcel.obtain();
464        rr.writeToParcel(parcel,0);
465        parcel.setDataPosition(0);
466        ResultReceiver receiverForSending = ResultReceiver.CREATOR.createFromParcel(parcel);
467        parcel.recycle();
468        return receiverForSending;
469    }
470
471    private void scheduleProvisioningRechecks(int type) {
472        Intent intent = new Intent();
473        intent.putExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE, type);
474        intent.putExtra(ConnectivityManager.EXTRA_SET_ALARM, true);
475        intent.setComponent(TETHER_SERVICE);
476        final long ident = Binder.clearCallingIdentity();
477        try {
478            mContext.startServiceAsUser(intent, UserHandle.CURRENT);
479        } finally {
480            Binder.restoreCallingIdentity(ident);
481        }
482    }
483
484    private void runSilentTetherProvisioningAndEnable(int type, ResultReceiver receiver) {
485        ResultReceiver proxyReceiver = getProxyReceiver(type, receiver);
486        sendSilentTetherProvisionIntent(type, proxyReceiver);
487    }
488
489    private void sendSilentTetherProvisionIntent(int type, ResultReceiver receiver) {
490        Intent intent = new Intent();
491        intent.putExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE, type);
492        intent.putExtra(ConnectivityManager.EXTRA_RUN_PROVISION, true);
493        intent.putExtra(ConnectivityManager.EXTRA_PROVISION_CALLBACK, receiver);
494        intent.setComponent(TETHER_SERVICE);
495        final long ident = Binder.clearCallingIdentity();
496        try {
497            mContext.startServiceAsUser(intent, UserHandle.CURRENT);
498        } finally {
499            Binder.restoreCallingIdentity(ident);
500        }
501    }
502
503    private void cancelTetherProvisioningRechecks(int type) {
504        if (getConnectivityManager().isTetheringSupported()) {
505            Intent intent = new Intent();
506            intent.putExtra(ConnectivityManager.EXTRA_REM_TETHER_TYPE, type);
507            intent.setComponent(TETHER_SERVICE);
508            final long ident = Binder.clearCallingIdentity();
509            try {
510                mContext.startServiceAsUser(intent, UserHandle.CURRENT);
511            } finally {
512                Binder.restoreCallingIdentity(ident);
513            }
514        }
515    }
516
517    public int tether(String iface) {
518        if (DBG) Log.d(TAG, "Tethering " + iface);
519        synchronized (mPublicSync) {
520            TetherState tetherState = mTetherStates.get(iface);
521            if (tetherState == null) {
522                Log.e(TAG, "Tried to Tether an unknown iface: " + iface + ", ignoring");
523                return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
524            }
525            // Ignore the error status of the interface.  If the interface is available,
526            // the errors are referring to past tethering attempts anyway.
527            if (tetherState.mLastState != IControlsTethering.STATE_AVAILABLE) {
528                Log.e(TAG, "Tried to Tether an unavailable iface: " + iface + ", ignoring");
529                return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
530            }
531            tetherState.mStateMachine.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED);
532            return ConnectivityManager.TETHER_ERROR_NO_ERROR;
533        }
534    }
535
536    public int untether(String iface) {
537        if (DBG) Log.d(TAG, "Untethering " + iface);
538        synchronized (mPublicSync) {
539            TetherState tetherState = mTetherStates.get(iface);
540            if (tetherState == null) {
541                Log.e(TAG, "Tried to Untether an unknown iface :" + iface + ", ignoring");
542                return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
543            }
544            if (tetherState.mLastState != IControlsTethering.STATE_TETHERED) {
545                Log.e(TAG, "Tried to untether an untethered iface :" + iface + ", ignoring");
546                return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
547            }
548            tetherState.mStateMachine.sendMessage(
549                    TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
550            return ConnectivityManager.TETHER_ERROR_NO_ERROR;
551        }
552    }
553
554    public void untetherAll() {
555        stopTethering(ConnectivityManager.TETHERING_WIFI);
556        stopTethering(ConnectivityManager.TETHERING_USB);
557        stopTethering(ConnectivityManager.TETHERING_BLUETOOTH);
558    }
559
560    public int getLastTetherError(String iface) {
561        synchronized (mPublicSync) {
562            TetherState tetherState = mTetherStates.get(iface);
563            if (tetherState == null) {
564                Log.e(TAG, "Tried to getLastTetherError on an unknown iface :" + iface +
565                        ", ignoring");
566                return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
567            }
568            return tetherState.mLastError;
569        }
570    }
571
572    private void sendTetherStateChangedBroadcast() {
573        if (!getConnectivityManager().isTetheringSupported()) return;
574
575        ArrayList<String> availableList = new ArrayList<String>();
576        ArrayList<String> activeList = new ArrayList<String>();
577        ArrayList<String> erroredList = new ArrayList<String>();
578
579        boolean wifiTethered = false;
580        boolean usbTethered = false;
581        boolean bluetoothTethered = false;
582
583        final TetheringConfiguration cfg = mConfig;
584
585        synchronized (mPublicSync) {
586            for (int i = 0; i < mTetherStates.size(); i++) {
587                TetherState tetherState = mTetherStates.valueAt(i);
588                String iface = mTetherStates.keyAt(i);
589                if (tetherState.mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
590                    erroredList.add(iface);
591                } else if (tetherState.mLastState == IControlsTethering.STATE_AVAILABLE) {
592                    availableList.add(iface);
593                } else if (tetherState.mLastState == IControlsTethering.STATE_TETHERED) {
594                    if (cfg.isUsb(iface)) {
595                        usbTethered = true;
596                    } else if (cfg.isWifi(iface)) {
597                        wifiTethered = true;
598                    } else if (cfg.isBluetooth(iface)) {
599                        bluetoothTethered = true;
600                    }
601                    activeList.add(iface);
602                }
603            }
604        }
605        Intent broadcast = new Intent(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
606        broadcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
607                Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
608        broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_AVAILABLE_TETHER,
609                availableList);
610        broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_TETHER, activeList);
611        broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ERRORED_TETHER,
612                erroredList);
613        mContext.sendStickyBroadcastAsUser(broadcast, UserHandle.ALL);
614        if (DBG) {
615            Log.d(TAG, String.format(
616                    "sendTetherStateChangedBroadcast avail=[%s] active=[%s] error=[%s]",
617                    TextUtils.join(",", availableList),
618                    TextUtils.join(",", activeList),
619                    TextUtils.join(",", erroredList)));
620        }
621
622        if (usbTethered) {
623            if (wifiTethered || bluetoothTethered) {
624                showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_general);
625            } else {
626                showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_usb);
627            }
628        } else if (wifiTethered) {
629            if (bluetoothTethered) {
630                showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_general);
631            } else {
632                /* We now have a status bar icon for WifiTethering, so drop the notification */
633                clearTetheredNotification();
634            }
635        } else if (bluetoothTethered) {
636            showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_bluetooth);
637        } else {
638            clearTetheredNotification();
639        }
640    }
641
642    private void showTetheredNotification(int icon) {
643        NotificationManager notificationManager =
644                (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE);
645        if (notificationManager == null) {
646            return;
647        }
648
649        if (mLastNotificationId != 0) {
650            if (mLastNotificationId == icon) {
651                return;
652            }
653            notificationManager.cancelAsUser(null, mLastNotificationId,
654                    UserHandle.ALL);
655            mLastNotificationId = 0;
656        }
657
658        Intent intent = new Intent();
659        intent.setClassName("com.android.settings", "com.android.settings.TetherSettings");
660        intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
661
662        PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0, intent, 0,
663                null, UserHandle.CURRENT);
664
665        Resources r = Resources.getSystem();
666        CharSequence title = r.getText(com.android.internal.R.string.tethered_notification_title);
667        CharSequence message = r.getText(com.android.internal.R.string.
668                tethered_notification_message);
669
670        if (mTetheredNotificationBuilder == null) {
671            mTetheredNotificationBuilder = new Notification.Builder(mContext);
672            mTetheredNotificationBuilder.setWhen(0)
673                    .setOngoing(true)
674                    .setColor(mContext.getColor(
675                            com.android.internal.R.color.system_notification_accent_color))
676                    .setVisibility(Notification.VISIBILITY_PUBLIC)
677                    .setCategory(Notification.CATEGORY_STATUS);
678        }
679        mTetheredNotificationBuilder.setSmallIcon(icon)
680                .setContentTitle(title)
681                .setContentText(message)
682                .setContentIntent(pi);
683        mLastNotificationId = icon;
684
685        notificationManager.notifyAsUser(null, mLastNotificationId,
686                mTetheredNotificationBuilder.build(), UserHandle.ALL);
687    }
688
689    private void clearTetheredNotification() {
690        NotificationManager notificationManager =
691            (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE);
692        if (notificationManager != null && mLastNotificationId != 0) {
693            notificationManager.cancelAsUser(null, mLastNotificationId,
694                    UserHandle.ALL);
695            mLastNotificationId = 0;
696        }
697    }
698
699    private class StateReceiver extends BroadcastReceiver {
700        @Override
701        public void onReceive(Context content, Intent intent) {
702            final String action = intent.getAction();
703            if (action == null) return;
704
705            if (action.equals(UsbManager.ACTION_USB_STATE)) {
706                handleUsbAction(intent);
707            } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
708                handleConnectivityAction(intent);
709            } else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
710                handleWifiApAction(intent);
711            } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
712                updateConfiguration();
713            }
714        }
715
716        private void handleConnectivityAction(Intent intent) {
717            final NetworkInfo networkInfo = (NetworkInfo)intent.getParcelableExtra(
718                    ConnectivityManager.EXTRA_NETWORK_INFO);
719            if (networkInfo == null ||
720                    networkInfo.getDetailedState() == NetworkInfo.DetailedState.FAILED) {
721                return;
722            }
723
724            if (VDBG) Log.d(TAG, "Tethering got CONNECTIVITY_ACTION: " + networkInfo.toString());
725            mTetherMasterSM.sendMessage(TetherMasterSM.CMD_UPSTREAM_CHANGED);
726        }
727
728        private void handleUsbAction(Intent intent) {
729            final boolean usbConnected = intent.getBooleanExtra(USB_CONNECTED, false);
730            final boolean rndisEnabled = intent.getBooleanExtra(USB_FUNCTION_RNDIS, false);
731            synchronized (Tethering.this.mPublicSync) {
732                mRndisEnabled = rndisEnabled;
733                // start tethering if we have a request pending
734                if (usbConnected && mRndisEnabled && mUsbTetherRequested) {
735                    tetherMatchingInterfaces(true, ConnectivityManager.TETHERING_USB);
736                }
737                mUsbTetherRequested = false;
738            }
739        }
740
741        private void handleWifiApAction(Intent intent) {
742            final int curState =  intent.getIntExtra(EXTRA_WIFI_AP_STATE, WIFI_AP_STATE_DISABLED);
743            synchronized (Tethering.this.mPublicSync) {
744                switch (curState) {
745                    case WifiManager.WIFI_AP_STATE_ENABLING:
746                        // We can see this state on the way to both enabled and failure states.
747                        break;
748                    case WifiManager.WIFI_AP_STATE_ENABLED:
749                        // When the AP comes up and we've been requested to tether it, do so.
750                        if (mWifiTetherRequested) {
751                            tetherMatchingInterfaces(true, ConnectivityManager.TETHERING_WIFI);
752                        }
753                        break;
754                    case WifiManager.WIFI_AP_STATE_DISABLED:
755                    case WifiManager.WIFI_AP_STATE_DISABLING:
756                    case WifiManager.WIFI_AP_STATE_FAILED:
757                    default:
758                        if (DBG) {
759                            Log.d(TAG, "Canceling WiFi tethering request - AP_STATE=" +
760                                curState);
761                        }
762                        // Tell appropriate interface state machines that they should tear
763                        // themselves down.
764                        for (int i = 0; i < mTetherStates.size(); i++) {
765                            TetherInterfaceStateMachine tism =
766                                    mTetherStates.valueAt(i).mStateMachine;
767                            if (tism.interfaceType() == ConnectivityManager.TETHERING_WIFI) {
768                                tism.sendMessage(
769                                        TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
770                                break;  // There should be at most one of these.
771                            }
772                        }
773                        // Regardless of whether we requested this transition, the AP has gone
774                        // down.  Don't try to tether again unless we're requested to do so.
775                        mWifiTetherRequested = false;
776                    break;
777                }
778            }
779        }
780    }
781
782    private void tetherMatchingInterfaces(boolean enable, int interfaceType) {
783        if (VDBG) Log.d(TAG, "tetherMatchingInterfaces(" + enable + ", " + interfaceType + ")");
784
785        String[] ifaces = null;
786        try {
787            ifaces = mNMService.listInterfaces();
788        } catch (Exception e) {
789            Log.e(TAG, "Error listing Interfaces", e);
790            return;
791        }
792        String chosenIface = null;
793        if (ifaces != null) {
794            for (String iface : ifaces) {
795                if (ifaceNameToType(iface) == interfaceType) {
796                    chosenIface = iface;
797                    break;
798                }
799            }
800        }
801        if (chosenIface == null) {
802            Log.e(TAG, "could not find iface of type " + interfaceType);
803            return;
804        }
805
806        int result = (enable ? tether(chosenIface) : untether(chosenIface));
807        if (result != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
808            Log.e(TAG, "unable start or stop tethering on iface " + chosenIface);
809            return;
810        }
811    }
812
813    public TetheringConfiguration getTetheringConfiguration() {
814        return mConfig;
815    }
816
817    public boolean hasTetherableConfiguration() {
818        final TetheringConfiguration cfg = mConfig;
819        final boolean hasDownstreamConfiguration =
820                (cfg.tetherableUsbRegexs.length != 0) ||
821                (cfg.tetherableWifiRegexs.length != 0) ||
822                (cfg.tetherableBluetoothRegexs.length != 0);
823        final boolean hasUpstreamConfiguration = !cfg.preferredUpstreamIfaceTypes.isEmpty();
824
825        return hasDownstreamConfiguration && hasUpstreamConfiguration;
826    }
827
828    // TODO - update callers to use getTetheringConfiguration(),
829    // which has only final members.
830    public String[] getTetherableUsbRegexs() {
831        return copy(mConfig.tetherableUsbRegexs);
832    }
833
834    public String[] getTetherableWifiRegexs() {
835        return copy(mConfig.tetherableWifiRegexs);
836    }
837
838    public String[] getTetherableBluetoothRegexs() {
839        return copy(mConfig.tetherableBluetoothRegexs);
840    }
841
842    public int setUsbTethering(boolean enable) {
843        if (VDBG) Log.d(TAG, "setUsbTethering(" + enable + ")");
844        UsbManager usbManager = mContext.getSystemService(UsbManager.class);
845
846        synchronized (mPublicSync) {
847            if (enable) {
848                if (mRndisEnabled) {
849                    final long ident = Binder.clearCallingIdentity();
850                    try {
851                        tetherMatchingInterfaces(true, ConnectivityManager.TETHERING_USB);
852                    } finally {
853                        Binder.restoreCallingIdentity(ident);
854                    }
855                } else {
856                    mUsbTetherRequested = true;
857                    usbManager.setCurrentFunction(UsbManager.USB_FUNCTION_RNDIS, false);
858                }
859            } else {
860                final long ident = Binder.clearCallingIdentity();
861                try {
862                    tetherMatchingInterfaces(false, ConnectivityManager.TETHERING_USB);
863                } finally {
864                    Binder.restoreCallingIdentity(ident);
865                }
866                if (mRndisEnabled) {
867                    usbManager.setCurrentFunction(null, false);
868                }
869                mUsbTetherRequested = false;
870            }
871        }
872        return ConnectivityManager.TETHER_ERROR_NO_ERROR;
873    }
874
875    // TODO review API - maybe return ArrayList<String> here and below?
876    public String[] getTetheredIfaces() {
877        ArrayList<String> list = new ArrayList<String>();
878        synchronized (mPublicSync) {
879            for (int i = 0; i < mTetherStates.size(); i++) {
880                TetherState tetherState = mTetherStates.valueAt(i);
881                if (tetherState.mLastState == IControlsTethering.STATE_TETHERED) {
882                    list.add(mTetherStates.keyAt(i));
883                }
884            }
885        }
886        return list.toArray(new String[list.size()]);
887    }
888
889    public String[] getTetherableIfaces() {
890        ArrayList<String> list = new ArrayList<String>();
891        synchronized (mPublicSync) {
892            for (int i = 0; i < mTetherStates.size(); i++) {
893                TetherState tetherState = mTetherStates.valueAt(i);
894                if (tetherState.mLastState == IControlsTethering.STATE_AVAILABLE) {
895                    list.add(mTetherStates.keyAt(i));
896                }
897            }
898        }
899        return list.toArray(new String[list.size()]);
900    }
901
902    public String[] getTetheredDhcpRanges() {
903        return mConfig.dhcpRanges;
904    }
905
906    public String[] getErroredIfaces() {
907        ArrayList<String> list = new ArrayList<String>();
908        synchronized (mPublicSync) {
909            for (int i = 0; i < mTetherStates.size(); i++) {
910                TetherState tetherState = mTetherStates.valueAt(i);
911                if (tetherState.mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
912                    list.add(mTetherStates.keyAt(i));
913                }
914            }
915        }
916        return list.toArray(new String[list.size()]);
917    }
918
919    private void maybeLogMessage(State state, int what) {
920        if (DBG) {
921            Log.d(TAG, state.getName() + " got " +
922                    sMagicDecoderRing.get(what, Integer.toString(what)));
923        }
924    }
925
926    // Needed because the canonical source of upstream truth is just the
927    // upstream interface name, |mCurrentUpstreamIface|.  This is ripe for
928    // future simplification, once the upstream Network is canonical.
929    boolean pertainsToCurrentUpstream(NetworkState ns) {
930        if (ns != null && ns.linkProperties != null && mCurrentUpstreamIface != null) {
931            for (String ifname : ns.linkProperties.getAllInterfaceNames()) {
932                if (mCurrentUpstreamIface.equals(ifname)) {
933                    return true;
934                }
935            }
936        }
937        return false;
938    }
939
940    class TetherMasterSM extends StateMachine {
941        private static final int BASE_MASTER                    = Protocol.BASE_TETHERING;
942        // an interface SM has requested Tethering
943        static final int CMD_TETHER_MODE_REQUESTED              = BASE_MASTER + 1;
944        // an interface SM has unrequested Tethering
945        static final int CMD_TETHER_MODE_UNREQUESTED            = BASE_MASTER + 2;
946        // upstream connection change - do the right thing
947        static final int CMD_UPSTREAM_CHANGED                   = BASE_MASTER + 3;
948        // we don't have a valid upstream conn, check again after a delay
949        static final int CMD_RETRY_UPSTREAM                     = BASE_MASTER + 4;
950        // Events from NetworkCallbacks that we process on the master state
951        // machine thread on behalf of the UpstreamNetworkMonitor.
952        static final int EVENT_UPSTREAM_CALLBACK                = BASE_MASTER + 5;
953
954        private State mInitialState;
955        private State mTetherModeAliveState;
956
957        private State mSetIpForwardingEnabledErrorState;
958        private State mSetIpForwardingDisabledErrorState;
959        private State mStartTetheringErrorState;
960        private State mStopTetheringErrorState;
961        private State mSetDnsForwardersErrorState;
962
963        // This list is a little subtle.  It contains all the interfaces that currently are
964        // requesting tethering, regardless of whether these interfaces are still members of
965        // mTetherStates.  This allows us to maintain the following predicates:
966        //
967        // 1) mTetherStates contains the set of all currently existing, tetherable, link state up
968        //    interfaces.
969        // 2) mNotifyList contains all state machines that may have outstanding tethering state
970        //    that needs to be torn down.
971        //
972        // Because we excise interfaces immediately from mTetherStates, we must maintain mNotifyList
973        // so that the garbage collector does not clean up the state machine before it has a chance
974        // to tear itself down.
975        private final ArrayList<TetherInterfaceStateMachine> mNotifyList;
976        private final IPv6TetheringCoordinator mIPv6TetheringCoordinator;
977
978        private static final int UPSTREAM_SETTLE_TIME_MS     = 10000;
979
980        TetherMasterSM(String name, Looper looper) {
981            super(name, looper);
982
983            //Add states
984            mInitialState = new InitialState();
985            addState(mInitialState);
986            mTetherModeAliveState = new TetherModeAliveState();
987            addState(mTetherModeAliveState);
988
989            mSetIpForwardingEnabledErrorState = new SetIpForwardingEnabledErrorState();
990            addState(mSetIpForwardingEnabledErrorState);
991            mSetIpForwardingDisabledErrorState = new SetIpForwardingDisabledErrorState();
992            addState(mSetIpForwardingDisabledErrorState);
993            mStartTetheringErrorState = new StartTetheringErrorState();
994            addState(mStartTetheringErrorState);
995            mStopTetheringErrorState = new StopTetheringErrorState();
996            addState(mStopTetheringErrorState);
997            mSetDnsForwardersErrorState = new SetDnsForwardersErrorState();
998            addState(mSetDnsForwardersErrorState);
999
1000            mNotifyList = new ArrayList<>();
1001            mIPv6TetheringCoordinator = new IPv6TetheringCoordinator(mNotifyList);
1002            setInitialState(mInitialState);
1003        }
1004
1005        class TetherMasterUtilState extends State {
1006            @Override
1007            public boolean processMessage(Message m) {
1008                return false;
1009            }
1010
1011            protected void requestUpstreamMobileConnection() {
1012                mUpstreamNetworkMonitor.updateMobileRequiresDun(mConfig.isDunRequired);
1013                mUpstreamNetworkMonitor.registerMobileNetworkRequest();
1014            }
1015
1016            protected void unrequestUpstreamMobileConnection() {
1017                mUpstreamNetworkMonitor.releaseMobileNetworkRequest();
1018            }
1019
1020            protected boolean turnOnMasterTetherSettings() {
1021                final TetheringConfiguration cfg = mConfig;
1022                try {
1023                    mNMService.setIpForwardingEnabled(true);
1024                } catch (Exception e) {
1025                    transitionTo(mSetIpForwardingEnabledErrorState);
1026                    return false;
1027                }
1028                try {
1029                    mNMService.startTethering(cfg.dhcpRanges);
1030                } catch (Exception e) {
1031                    try {
1032                        mNMService.stopTethering();
1033                        mNMService.startTethering(cfg.dhcpRanges);
1034                    } catch (Exception ee) {
1035                        transitionTo(mStartTetheringErrorState);
1036                        return false;
1037                    }
1038                }
1039                return true;
1040            }
1041
1042            protected boolean turnOffMasterTetherSettings() {
1043                try {
1044                    mNMService.stopTethering();
1045                } catch (Exception e) {
1046                    transitionTo(mStopTetheringErrorState);
1047                    return false;
1048                }
1049                try {
1050                    mNMService.setIpForwardingEnabled(false);
1051                } catch (Exception e) {
1052                    transitionTo(mSetIpForwardingDisabledErrorState);
1053                    return false;
1054                }
1055                transitionTo(mInitialState);
1056                return true;
1057            }
1058
1059            protected void chooseUpstreamType(boolean tryCell) {
1060                final ConnectivityManager cm = getConnectivityManager();
1061                int upType = ConnectivityManager.TYPE_NONE;
1062                String iface = null;
1063
1064                updateConfiguration(); // TODO - remove?
1065
1066                final TetheringConfiguration cfg = mConfig;
1067                if (VDBG) {
1068                    Log.d(TAG, "chooseUpstreamType has upstream iface types:");
1069                    for (Integer netType : cfg.preferredUpstreamIfaceTypes) {
1070                        Log.d(TAG, " " + netType);
1071                    }
1072                }
1073
1074                for (Integer netType : cfg.preferredUpstreamIfaceTypes) {
1075                    NetworkInfo info = cm.getNetworkInfo(netType.intValue());
1076                    // TODO: if the network is suspended we should consider
1077                    // that to be the same as connected here.
1078                    if ((info != null) && info.isConnected()) {
1079                        upType = netType.intValue();
1080                        break;
1081                    }
1082                }
1083
1084                final int preferredUpstreamMobileApn = cfg.isDunRequired
1085                        ? ConnectivityManager.TYPE_MOBILE_DUN
1086                        : ConnectivityManager.TYPE_MOBILE_HIPRI;
1087                if (DBG) {
1088                    Log.d(TAG, "chooseUpstreamType(" + tryCell + "),"
1089                            + " preferredApn="
1090                            + ConnectivityManager.getNetworkTypeName(preferredUpstreamMobileApn)
1091                            + ", got type="
1092                            + ConnectivityManager.getNetworkTypeName(upType));
1093                }
1094
1095                switch (upType) {
1096                    case ConnectivityManager.TYPE_MOBILE_DUN:
1097                    case ConnectivityManager.TYPE_MOBILE_HIPRI:
1098                        // If we're on DUN, put our own grab on it.
1099                        requestUpstreamMobileConnection();
1100                        break;
1101                    case ConnectivityManager.TYPE_NONE:
1102                        if (tryCell) {
1103                            requestUpstreamMobileConnection();
1104                            // We think mobile should be coming up; don't set a retry.
1105                        } else {
1106                            sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS);
1107                        }
1108                        break;
1109                    default:
1110                        /* If we've found an active upstream connection that's not DUN/HIPRI
1111                         * we should stop any outstanding DUN/HIPRI start requests.
1112                         *
1113                         * If we found NONE we don't want to do this as we want any previous
1114                         * requests to keep trying to bring up something we can use.
1115                         */
1116                        unrequestUpstreamMobileConnection();
1117                        break;
1118                }
1119
1120                Network network = null;
1121                if (upType != ConnectivityManager.TYPE_NONE) {
1122                    LinkProperties linkProperties = cm.getLinkProperties(upType);
1123                    if (linkProperties != null) {
1124                        // Find the interface with the default IPv4 route. It may be the
1125                        // interface described by linkProperties, or one of the interfaces
1126                        // stacked on top of it.
1127                        Log.i(TAG, "Finding IPv4 upstream interface on: " + linkProperties);
1128                        RouteInfo ipv4Default = RouteInfo.selectBestRoute(
1129                            linkProperties.getAllRoutes(), Inet4Address.ANY);
1130                        if (ipv4Default != null) {
1131                            iface = ipv4Default.getInterface();
1132                            Log.i(TAG, "Found interface " + ipv4Default.getInterface());
1133                        } else {
1134                            Log.i(TAG, "No IPv4 upstream interface, giving up.");
1135                        }
1136                    }
1137
1138                    if (iface != null) {
1139                        network = cm.getNetworkForType(upType);
1140                        if (network == null) {
1141                            Log.e(TAG, "No Network for upstream type " + upType + "!");
1142                        }
1143                        setDnsForwarders(network, linkProperties);
1144                    }
1145                }
1146                notifyTetheredOfNewUpstreamIface(iface);
1147                NetworkState ns = mUpstreamNetworkMonitor.lookup(network);
1148                if (ns != null && pertainsToCurrentUpstream(ns)) {
1149                    // If we already have NetworkState for this network examine
1150                    // it immediately, because there likely will be no second
1151                    // EVENT_ON_AVAILABLE (it was already received).
1152                    handleNewUpstreamNetworkState(ns);
1153                } else if (mCurrentUpstreamIface == null) {
1154                    // There are no available upstream networks, or none that
1155                    // have an IPv4 default route (current metric for success).
1156                    handleNewUpstreamNetworkState(null);
1157                }
1158            }
1159
1160            protected void setDnsForwarders(final Network network, final LinkProperties lp) {
1161                // TODO: Set v4 and/or v6 DNS per available connectivity.
1162                String[] dnsServers = mConfig.defaultIPv4DNS;
1163                final Collection<InetAddress> dnses = lp.getDnsServers();
1164                // TODO: Properly support the absence of DNS servers.
1165                if (dnses != null && !dnses.isEmpty()) {
1166                    // TODO: remove this invocation of NetworkUtils.makeStrings().
1167                    dnsServers = NetworkUtils.makeStrings(dnses);
1168                }
1169                if (VDBG) {
1170                    Log.d(TAG, "Setting DNS forwarders: Network=" + network +
1171                           ", dnsServers=" + Arrays.toString(dnsServers));
1172                }
1173                try {
1174                    mNMService.setDnsForwarders(network, dnsServers);
1175                } catch (Exception e) {
1176                    // TODO: Investigate how this can fail and what exactly
1177                    // happens if/when such failures occur.
1178                    Log.e(TAG, "Setting DNS forwarders failed!");
1179                    transitionTo(mSetDnsForwardersErrorState);
1180                }
1181            }
1182
1183            protected void notifyTetheredOfNewUpstreamIface(String ifaceName) {
1184                if (DBG) Log.d(TAG, "Notifying tethered with upstream=" + ifaceName);
1185                mCurrentUpstreamIface = ifaceName;
1186                for (TetherInterfaceStateMachine sm : mNotifyList) {
1187                    sm.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED,
1188                            ifaceName);
1189                }
1190            }
1191
1192            protected void handleNewUpstreamNetworkState(NetworkState ns) {
1193                mIPv6TetheringCoordinator.updateUpstreamNetworkState(ns);
1194            }
1195        }
1196
1197        private class SimChangeListener {
1198            private final Context mContext;
1199            private final AtomicInteger mSimBcastGenerationNumber;
1200            private BroadcastReceiver mBroadcastReceiver;
1201
1202            SimChangeListener(Context ctx) {
1203                mContext = ctx;
1204                mSimBcastGenerationNumber = new AtomicInteger(0);
1205            }
1206
1207            public int generationNumber() {
1208                return mSimBcastGenerationNumber.get();
1209            }
1210
1211            public void startListening() {
1212                if (DBG) Log.d(TAG, "startListening for SIM changes");
1213
1214                if (mBroadcastReceiver != null) return;
1215
1216                mBroadcastReceiver = new SimChangeBroadcastReceiver(
1217                        mSimBcastGenerationNumber.incrementAndGet());
1218                final IntentFilter filter = new IntentFilter();
1219                filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
1220
1221                mContext.registerReceiver(mBroadcastReceiver, filter, null,
1222                        mTetherMasterSM.getHandler());
1223            }
1224
1225            public void stopListening() {
1226                if (DBG) Log.d(TAG, "stopListening for SIM changes");
1227
1228                if (mBroadcastReceiver == null) return;
1229
1230                mSimBcastGenerationNumber.incrementAndGet();
1231                mContext.unregisterReceiver(mBroadcastReceiver);
1232                mBroadcastReceiver = null;
1233            }
1234
1235            public boolean hasMobileHotspotProvisionApp() {
1236                try {
1237                    if (!mContext.getResources().getString(com.android.internal.R.string.
1238                            config_mobile_hotspot_provision_app_no_ui).isEmpty()) {
1239                        Log.d(TAG, "re-evaluate provisioning");
1240                        return true;
1241                    }
1242                } catch (Resources.NotFoundException e) {}
1243                Log.d(TAG, "no prov-check needed for new SIM");
1244                return false;
1245            }
1246
1247            private boolean isSimCardAbsent(String state) {
1248                return IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(state);
1249            }
1250
1251            private boolean isSimCardLoaded(String state) {
1252                return IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(state);
1253            }
1254
1255            private void startProvisionIntent(int tetherType) {
1256                final Intent startProvIntent = new Intent();
1257                startProvIntent.putExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE, tetherType);
1258                startProvIntent.putExtra(ConnectivityManager.EXTRA_RUN_PROVISION, true);
1259                startProvIntent.setComponent(TETHER_SERVICE);
1260                mContext.startServiceAsUser(startProvIntent, UserHandle.CURRENT);
1261            }
1262
1263            private class SimChangeBroadcastReceiver extends BroadcastReceiver {
1264                // used to verify this receiver is still current
1265                final private int mGenerationNumber;
1266
1267                // we're interested in edge-triggered LOADED notifications, so
1268                // ignore LOADED unless we saw an ABSENT state first
1269                private boolean mSimAbsentSeen = false;
1270
1271                public SimChangeBroadcastReceiver(int generationNumber) {
1272                    mGenerationNumber = generationNumber;
1273                }
1274
1275                @Override
1276                public void onReceive(Context context, Intent intent) {
1277                    final int currentGenerationNumber = mSimBcastGenerationNumber.get();
1278
1279                    if (DBG) {
1280                        Log.d(TAG, "simchange mGenerationNumber=" + mGenerationNumber +
1281                                ", current generationNumber=" + currentGenerationNumber);
1282                    }
1283                    if (mGenerationNumber != currentGenerationNumber) return;
1284
1285                    final String state = intent.getStringExtra(
1286                            IccCardConstants.INTENT_KEY_ICC_STATE);
1287                    Log.d(TAG, "got Sim changed to state " + state + ", mSimAbsentSeen=" +
1288                            mSimAbsentSeen);
1289
1290                    if (isSimCardAbsent(state)) {
1291                        if (!mSimAbsentSeen) mSimAbsentSeen = true;
1292                        return;
1293                    }
1294
1295                    if (isSimCardLoaded(state) && mSimAbsentSeen) {
1296                        mSimAbsentSeen = false;
1297
1298                        if (!hasMobileHotspotProvisionApp()) return;
1299
1300                        ArrayList<Integer> tethered = new ArrayList<Integer>();
1301                        synchronized (mPublicSync) {
1302                            for (int i = 0; i < mTetherStates.size(); i++) {
1303                                TetherState tetherState = mTetherStates.valueAt(i);
1304                                if (tetherState.mLastState != IControlsTethering.STATE_TETHERED) {
1305                                    continue;  // Skip interfaces that aren't tethered.
1306                                }
1307                                String iface = mTetherStates.keyAt(i);
1308                                int interfaceType = ifaceNameToType(iface);
1309                                if (interfaceType != ConnectivityManager.TETHERING_INVALID) {
1310                                    tethered.add(new Integer(interfaceType));
1311                                }
1312                            }
1313                        }
1314
1315                        for (int tetherType : tethered) {
1316                            startProvisionIntent(tetherType);
1317                        }
1318                    }
1319                }
1320            }
1321        }
1322
1323        class InitialState extends TetherMasterUtilState {
1324            @Override
1325            public boolean processMessage(Message message) {
1326                maybeLogMessage(this, message.what);
1327                boolean retValue = true;
1328                switch (message.what) {
1329                    case CMD_TETHER_MODE_REQUESTED:
1330                        TetherInterfaceStateMachine who = (TetherInterfaceStateMachine)message.obj;
1331                        if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
1332                        if (mNotifyList.indexOf(who) < 0) {
1333                            mNotifyList.add(who);
1334                            mIPv6TetheringCoordinator.addActiveDownstream(who);
1335                        }
1336                        transitionTo(mTetherModeAliveState);
1337                        break;
1338                    case CMD_TETHER_MODE_UNREQUESTED:
1339                        who = (TetherInterfaceStateMachine)message.obj;
1340                        if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
1341                        mNotifyList.remove(who);
1342                        mIPv6TetheringCoordinator.removeActiveDownstream(who);
1343                        break;
1344                    default:
1345                        retValue = false;
1346                        break;
1347                }
1348                return retValue;
1349            }
1350        }
1351
1352        class TetherModeAliveState extends TetherMasterUtilState {
1353            final SimChangeListener simChange = new SimChangeListener(mContext);
1354            boolean mTryCell = true;
1355            @Override
1356            public void enter() {
1357                // TODO: examine if we should check the return value.
1358                turnOnMasterTetherSettings(); // may transition us out
1359                simChange.startListening();
1360                mUpstreamNetworkMonitor.start();
1361
1362                // Better try something first pass or crazy tests cases will fail.
1363                chooseUpstreamType(true);
1364                mTryCell = false;
1365            }
1366
1367            @Override
1368            public void exit() {
1369                unrequestUpstreamMobileConnection();
1370                mUpstreamNetworkMonitor.stop();
1371                simChange.stopListening();
1372                notifyTetheredOfNewUpstreamIface(null);
1373                handleNewUpstreamNetworkState(null);
1374            }
1375
1376            @Override
1377            public boolean processMessage(Message message) {
1378                maybeLogMessage(this, message.what);
1379                boolean retValue = true;
1380                switch (message.what) {
1381                    case CMD_TETHER_MODE_REQUESTED: {
1382                        TetherInterfaceStateMachine who = (TetherInterfaceStateMachine)message.obj;
1383                        if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
1384                        if (mNotifyList.indexOf(who) < 0) {
1385                            mNotifyList.add(who);
1386                            mIPv6TetheringCoordinator.addActiveDownstream(who);
1387                        }
1388                        who.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED,
1389                                mCurrentUpstreamIface);
1390                        break;
1391                    }
1392                    case CMD_TETHER_MODE_UNREQUESTED: {
1393                        TetherInterfaceStateMachine who = (TetherInterfaceStateMachine)message.obj;
1394                        if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
1395                        if (mNotifyList.remove(who)) {
1396                            if (DBG) Log.d(TAG, "TetherModeAlive removing notifyee " + who);
1397                            if (mNotifyList.isEmpty()) {
1398                                turnOffMasterTetherSettings(); // transitions appropriately
1399                            } else {
1400                                if (DBG) {
1401                                    Log.d(TAG, "TetherModeAlive still has " + mNotifyList.size() +
1402                                            " live requests:");
1403                                    for (TetherInterfaceStateMachine o : mNotifyList) {
1404                                        Log.d(TAG, "  " + o);
1405                                    }
1406                                }
1407                            }
1408                        } else {
1409                           Log.e(TAG, "TetherModeAliveState UNREQUESTED has unknown who: " + who);
1410                        }
1411                        mIPv6TetheringCoordinator.removeActiveDownstream(who);
1412                        break;
1413                    }
1414                    case CMD_UPSTREAM_CHANGED:
1415                        // Need to try DUN immediately if Wi-Fi goes down.
1416                        chooseUpstreamType(true);
1417                        mTryCell = false;
1418                        break;
1419                    case CMD_RETRY_UPSTREAM:
1420                        chooseUpstreamType(mTryCell);
1421                        mTryCell = !mTryCell;
1422                        break;
1423                    case EVENT_UPSTREAM_CALLBACK: {
1424                        final NetworkState ns = (NetworkState) message.obj;
1425
1426                        if (ns == null || !pertainsToCurrentUpstream(ns)) {
1427                            // TODO: In future, this is where upstream evaluation and selection
1428                            // could be handled for notifications which include sufficient data.
1429                            // For example, after CONNECTIVITY_ACTION listening is removed, here
1430                            // is where we could observe a Wi-Fi network becoming available and
1431                            // passing validation.
1432                            if (mCurrentUpstreamIface == null) {
1433                                // If we have no upstream interface, try to run through upstream
1434                                // selection again.  If, for example, IPv4 connectivity has shown up
1435                                // after IPv6 (e.g., 464xlat became available) we want the chance to
1436                                // notice and act accordingly.
1437                                chooseUpstreamType(false);
1438                            }
1439                            break;
1440                        }
1441
1442                        switch (message.arg1) {
1443                            case UpstreamNetworkMonitor.EVENT_ON_AVAILABLE:
1444                                // The default network changed, or DUN connected
1445                                // before this callback was processed. Updates
1446                                // for the current NetworkCapabilities and
1447                                // LinkProperties have been requested (default
1448                                // request) or are being sent shortly (DUN). Do
1449                                // nothing until they arrive; if no updates
1450                                // arrive there's nothing to do.
1451                                break;
1452                            case UpstreamNetworkMonitor.EVENT_ON_CAPABILITIES:
1453                                handleNewUpstreamNetworkState(ns);
1454                                break;
1455                            case UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES:
1456                                setDnsForwarders(ns.network, ns.linkProperties);
1457                                handleNewUpstreamNetworkState(ns);
1458                                break;
1459                            case UpstreamNetworkMonitor.EVENT_ON_LOST:
1460                                // TODO: Re-evaluate possible upstreams. Currently upstream
1461                                // reevaluation is triggered via received CONNECTIVITY_ACTION
1462                                // broadcasts that result in being passed a
1463                                // TetherMasterSM.CMD_UPSTREAM_CHANGED.
1464                                handleNewUpstreamNetworkState(null);
1465                                break;
1466                            default:
1467                                break;
1468                        }
1469                        break;
1470                    }
1471                    default:
1472                        retValue = false;
1473                        break;
1474                }
1475                return retValue;
1476            }
1477        }
1478
1479        class ErrorState extends State {
1480            int mErrorNotification;
1481            @Override
1482            public boolean processMessage(Message message) {
1483                boolean retValue = true;
1484                switch (message.what) {
1485                    case CMD_TETHER_MODE_REQUESTED:
1486                        TetherInterfaceStateMachine who = (TetherInterfaceStateMachine)message.obj;
1487                        who.sendMessage(mErrorNotification);
1488                        break;
1489                    default:
1490                       retValue = false;
1491                }
1492                return retValue;
1493            }
1494            void notify(int msgType) {
1495                mErrorNotification = msgType;
1496                for (TetherInterfaceStateMachine sm : mNotifyList) {
1497                    sm.sendMessage(msgType);
1498                }
1499            }
1500
1501        }
1502        class SetIpForwardingEnabledErrorState extends ErrorState {
1503            @Override
1504            public void enter() {
1505                Log.e(TAG, "Error in setIpForwardingEnabled");
1506                notify(TetherInterfaceStateMachine.CMD_IP_FORWARDING_ENABLE_ERROR);
1507            }
1508        }
1509
1510        class SetIpForwardingDisabledErrorState extends ErrorState {
1511            @Override
1512            public void enter() {
1513                Log.e(TAG, "Error in setIpForwardingDisabled");
1514                notify(TetherInterfaceStateMachine.CMD_IP_FORWARDING_DISABLE_ERROR);
1515            }
1516        }
1517
1518        class StartTetheringErrorState extends ErrorState {
1519            @Override
1520            public void enter() {
1521                Log.e(TAG, "Error in startTethering");
1522                notify(TetherInterfaceStateMachine.CMD_START_TETHERING_ERROR);
1523                try {
1524                    mNMService.setIpForwardingEnabled(false);
1525                } catch (Exception e) {}
1526            }
1527        }
1528
1529        class StopTetheringErrorState extends ErrorState {
1530            @Override
1531            public void enter() {
1532                Log.e(TAG, "Error in stopTethering");
1533                notify(TetherInterfaceStateMachine.CMD_STOP_TETHERING_ERROR);
1534                try {
1535                    mNMService.setIpForwardingEnabled(false);
1536                } catch (Exception e) {}
1537            }
1538        }
1539
1540        class SetDnsForwardersErrorState extends ErrorState {
1541            @Override
1542            public void enter() {
1543                Log.e(TAG, "Error in setDnsForwarders");
1544                notify(TetherInterfaceStateMachine.CMD_SET_DNS_FORWARDERS_ERROR);
1545                try {
1546                    mNMService.stopTethering();
1547                } catch (Exception e) {}
1548                try {
1549                    mNMService.setIpForwardingEnabled(false);
1550                } catch (Exception e) {}
1551            }
1552        }
1553    }
1554
1555    @Override
1556    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
1557        // Binder.java closes the resource for us.
1558        @SuppressWarnings("resource")
1559        final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
1560        if (mContext.checkCallingOrSelfPermission(
1561                android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) {
1562            pw.println("Permission Denial: can't dump ConnectivityService.Tether " +
1563                    "from from pid=" + Binder.getCallingPid() + ", uid=" +
1564                    Binder.getCallingUid());
1565                    return;
1566        }
1567
1568        pw.println("Tethering:");
1569        pw.increaseIndent();
1570        final TetheringConfiguration cfg = mConfig;
1571        pw.print("preferredUpstreamIfaceTypes:");
1572        synchronized (mPublicSync) {
1573            for (Integer netType : cfg.preferredUpstreamIfaceTypes) {
1574                pw.print(" " + ConnectivityManager.getNetworkTypeName(netType));
1575            }
1576            pw.println();
1577
1578            pw.println("Tether state:");
1579            pw.increaseIndent();
1580            for (int i = 0; i < mTetherStates.size(); i++) {
1581                final String iface = mTetherStates.keyAt(i);
1582                final TetherState tetherState = mTetherStates.valueAt(i);
1583                pw.print(iface + " - ");
1584
1585                switch (tetherState.mLastState) {
1586                    case IControlsTethering.STATE_UNAVAILABLE:
1587                        pw.print("UnavailableState");
1588                        break;
1589                    case IControlsTethering.STATE_AVAILABLE:
1590                        pw.print("AvailableState");
1591                        break;
1592                    case IControlsTethering.STATE_TETHERED:
1593                        pw.print("TetheredState");
1594                        break;
1595                    default:
1596                        pw.print("UnknownState");
1597                        break;
1598                }
1599                pw.println(" - lastError = " + tetherState.mLastError);
1600            }
1601            pw.decreaseIndent();
1602        }
1603        pw.decreaseIndent();
1604    }
1605
1606    @Override
1607    public void notifyInterfaceStateChange(String iface, TetherInterfaceStateMachine who,
1608                                           int state, int error) {
1609        synchronized (mPublicSync) {
1610            TetherState tetherState = mTetherStates.get(iface);
1611            if (tetherState != null && tetherState.mStateMachine.equals(who)) {
1612                tetherState.mLastState = state;
1613                tetherState.mLastError = error;
1614            } else {
1615                if (DBG) Log.d(TAG, "got notification from stale iface " + iface);
1616            }
1617        }
1618
1619        if (DBG) {
1620            Log.d(TAG, "iface " + iface + " notified that it was in state " + state +
1621                    " with error " + error);
1622        }
1623
1624        try {
1625            // Notify that we're tethering (or not) this interface.
1626            // This is how data saver for instance knows if the user explicitly
1627            // turned on tethering (thus keeping us from being in data saver mode).
1628            mPolicyManager.onTetheringChanged(iface, state == IControlsTethering.STATE_TETHERED);
1629        } catch (RemoteException e) {
1630            // Not really very much we can do here.
1631        }
1632
1633        switch (state) {
1634            case IControlsTethering.STATE_UNAVAILABLE:
1635            case IControlsTethering.STATE_AVAILABLE:
1636                mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED, who);
1637                break;
1638            case IControlsTethering.STATE_TETHERED:
1639                mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_REQUESTED, who);
1640                break;
1641        }
1642        sendTetherStateChangedBroadcast();
1643    }
1644
1645    private void trackNewTetherableInterface(String iface, int interfaceType) {
1646        TetherState tetherState;
1647        tetherState = new TetherState(new TetherInterfaceStateMachine(iface, mLooper,
1648                interfaceType, mNMService, mStatsService, this,
1649                new IPv6TetheringInterfaceServices(iface, mNMService)));
1650        mTetherStates.put(iface, tetherState);
1651        tetherState.mStateMachine.start();
1652    }
1653
1654    private static String[] copy(String[] strarray) {
1655        return Arrays.copyOf(strarray, strarray.length);
1656    }
1657}
1658