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