Tethering.java revision 8eb1fbf1bca71b94f6c5c8b8b4294942fb1792ee
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 int upstreamType = findPreferredUpstreamType(tryCell);
1061                setUpstreamByType(upstreamType);
1062            }
1063
1064            protected int findPreferredUpstreamType(boolean tryCell) {
1065                final ConnectivityManager cm = getConnectivityManager();
1066                int upType = ConnectivityManager.TYPE_NONE;
1067
1068                updateConfiguration(); // TODO - remove?
1069
1070                final TetheringConfiguration cfg = mConfig;
1071                if (VDBG) {
1072                    Log.d(TAG, "chooseUpstreamType has upstream iface types:");
1073                    for (Integer netType : cfg.preferredUpstreamIfaceTypes) {
1074                        Log.d(TAG, " " + netType);
1075                    }
1076                }
1077
1078                for (Integer netType : cfg.preferredUpstreamIfaceTypes) {
1079                    NetworkInfo info = cm.getNetworkInfo(netType.intValue());
1080                    // TODO: if the network is suspended we should consider
1081                    // that to be the same as connected here.
1082                    if ((info != null) && info.isConnected()) {
1083                        upType = netType.intValue();
1084                        break;
1085                    }
1086                }
1087
1088                final int preferredUpstreamMobileApn = cfg.isDunRequired
1089                        ? ConnectivityManager.TYPE_MOBILE_DUN
1090                        : ConnectivityManager.TYPE_MOBILE_HIPRI;
1091                if (DBG) {
1092                    Log.d(TAG, "chooseUpstreamType(" + tryCell + "),"
1093                            + " preferredApn="
1094                            + ConnectivityManager.getNetworkTypeName(preferredUpstreamMobileApn)
1095                            + ", got type="
1096                            + ConnectivityManager.getNetworkTypeName(upType));
1097                }
1098
1099                switch (upType) {
1100                    case ConnectivityManager.TYPE_MOBILE_DUN:
1101                    case ConnectivityManager.TYPE_MOBILE_HIPRI:
1102                        // If we're on DUN, put our own grab on it.
1103                        requestUpstreamMobileConnection();
1104                        break;
1105                    case ConnectivityManager.TYPE_NONE:
1106                        if (tryCell) {
1107                            requestUpstreamMobileConnection();
1108                            // We think mobile should be coming up; don't set a retry.
1109                        } else {
1110                            sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS);
1111                        }
1112                        break;
1113                    default:
1114                        /* If we've found an active upstream connection that's not DUN/HIPRI
1115                         * we should stop any outstanding DUN/HIPRI start requests.
1116                         *
1117                         * If we found NONE we don't want to do this as we want any previous
1118                         * requests to keep trying to bring up something we can use.
1119                         */
1120                        unrequestUpstreamMobileConnection();
1121                        break;
1122                }
1123
1124                return upType;
1125            }
1126
1127            protected void setUpstreamByType(int upType) {
1128                final ConnectivityManager cm = getConnectivityManager();
1129                Network network = null;
1130                String iface = null;
1131                if (upType != ConnectivityManager.TYPE_NONE) {
1132                    LinkProperties linkProperties = cm.getLinkProperties(upType);
1133                    if (linkProperties != null) {
1134                        // Find the interface with the default IPv4 route. It may be the
1135                        // interface described by linkProperties, or one of the interfaces
1136                        // stacked on top of it.
1137                        Log.i(TAG, "Finding IPv4 upstream interface on: " + linkProperties);
1138                        RouteInfo ipv4Default = RouteInfo.selectBestRoute(
1139                            linkProperties.getAllRoutes(), Inet4Address.ANY);
1140                        if (ipv4Default != null) {
1141                            iface = ipv4Default.getInterface();
1142                            Log.i(TAG, "Found interface " + ipv4Default.getInterface());
1143                        } else {
1144                            Log.i(TAG, "No IPv4 upstream interface, giving up.");
1145                        }
1146                    }
1147
1148                    if (iface != null) {
1149                        network = cm.getNetworkForType(upType);
1150                        if (network == null) {
1151                            Log.e(TAG, "No Network for upstream type " + upType + "!");
1152                        }
1153                        setDnsForwarders(network, linkProperties);
1154                    }
1155                }
1156                notifyTetheredOfNewUpstreamIface(iface);
1157                NetworkState ns = mUpstreamNetworkMonitor.lookup(network);
1158                if (ns != null && pertainsToCurrentUpstream(ns)) {
1159                    // If we already have NetworkState for this network examine
1160                    // it immediately, because there likely will be no second
1161                    // EVENT_ON_AVAILABLE (it was already received).
1162                    handleNewUpstreamNetworkState(ns);
1163                } else if (mCurrentUpstreamIface == null) {
1164                    // There are no available upstream networks, or none that
1165                    // have an IPv4 default route (current metric for success).
1166                    handleNewUpstreamNetworkState(null);
1167                }
1168            }
1169
1170            protected void setDnsForwarders(final Network network, final LinkProperties lp) {
1171                // TODO: Set v4 and/or v6 DNS per available connectivity.
1172                String[] dnsServers = mConfig.defaultIPv4DNS;
1173                final Collection<InetAddress> dnses = lp.getDnsServers();
1174                // TODO: Properly support the absence of DNS servers.
1175                if (dnses != null && !dnses.isEmpty()) {
1176                    // TODO: remove this invocation of NetworkUtils.makeStrings().
1177                    dnsServers = NetworkUtils.makeStrings(dnses);
1178                }
1179                if (VDBG) {
1180                    Log.d(TAG, "Setting DNS forwarders: Network=" + network +
1181                           ", dnsServers=" + Arrays.toString(dnsServers));
1182                }
1183                try {
1184                    mNMService.setDnsForwarders(network, dnsServers);
1185                } catch (Exception e) {
1186                    // TODO: Investigate how this can fail and what exactly
1187                    // happens if/when such failures occur.
1188                    Log.e(TAG, "Setting DNS forwarders failed!");
1189                    transitionTo(mSetDnsForwardersErrorState);
1190                }
1191            }
1192
1193            protected void notifyTetheredOfNewUpstreamIface(String ifaceName) {
1194                if (DBG) Log.d(TAG, "Notifying tethered with upstream=" + ifaceName);
1195                mCurrentUpstreamIface = ifaceName;
1196                for (TetherInterfaceStateMachine sm : mNotifyList) {
1197                    sm.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED,
1198                            ifaceName);
1199                }
1200            }
1201
1202            protected void handleNewUpstreamNetworkState(NetworkState ns) {
1203                mIPv6TetheringCoordinator.updateUpstreamNetworkState(ns);
1204            }
1205        }
1206
1207        private class SimChangeListener {
1208            private final Context mContext;
1209            private final AtomicInteger mSimBcastGenerationNumber;
1210            private BroadcastReceiver mBroadcastReceiver;
1211
1212            SimChangeListener(Context ctx) {
1213                mContext = ctx;
1214                mSimBcastGenerationNumber = new AtomicInteger(0);
1215            }
1216
1217            public int generationNumber() {
1218                return mSimBcastGenerationNumber.get();
1219            }
1220
1221            public void startListening() {
1222                if (DBG) Log.d(TAG, "startListening for SIM changes");
1223
1224                if (mBroadcastReceiver != null) return;
1225
1226                mBroadcastReceiver = new SimChangeBroadcastReceiver(
1227                        mSimBcastGenerationNumber.incrementAndGet());
1228                final IntentFilter filter = new IntentFilter();
1229                filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
1230
1231                mContext.registerReceiver(mBroadcastReceiver, filter, null,
1232                        mTetherMasterSM.getHandler());
1233            }
1234
1235            public void stopListening() {
1236                if (DBG) Log.d(TAG, "stopListening for SIM changes");
1237
1238                if (mBroadcastReceiver == null) return;
1239
1240                mSimBcastGenerationNumber.incrementAndGet();
1241                mContext.unregisterReceiver(mBroadcastReceiver);
1242                mBroadcastReceiver = null;
1243            }
1244
1245            public boolean hasMobileHotspotProvisionApp() {
1246                try {
1247                    if (!mContext.getResources().getString(com.android.internal.R.string.
1248                            config_mobile_hotspot_provision_app_no_ui).isEmpty()) {
1249                        Log.d(TAG, "re-evaluate provisioning");
1250                        return true;
1251                    }
1252                } catch (Resources.NotFoundException e) {}
1253                Log.d(TAG, "no prov-check needed for new SIM");
1254                return false;
1255            }
1256
1257            private boolean isSimCardLoaded(String state) {
1258                return IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(state);
1259            }
1260
1261            private void startProvisionIntent(int tetherType) {
1262                final Intent startProvIntent = new Intent();
1263                startProvIntent.putExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE, tetherType);
1264                startProvIntent.putExtra(ConnectivityManager.EXTRA_RUN_PROVISION, true);
1265                startProvIntent.setComponent(TETHER_SERVICE);
1266                mContext.startServiceAsUser(startProvIntent, UserHandle.CURRENT);
1267            }
1268
1269            private class SimChangeBroadcastReceiver extends BroadcastReceiver {
1270                // used to verify this receiver is still current
1271                final private int mGenerationNumber;
1272
1273                // used to check the sim state transition from non-loaded to loaded
1274                private boolean mSimNotLoadedSeen = false;
1275
1276                public SimChangeBroadcastReceiver(int generationNumber) {
1277                    mGenerationNumber = generationNumber;
1278                }
1279
1280                @Override
1281                public void onReceive(Context context, Intent intent) {
1282                    final int currentGenerationNumber = mSimBcastGenerationNumber.get();
1283
1284                    if (DBG) {
1285                        Log.d(TAG, "simchange mGenerationNumber=" + mGenerationNumber +
1286                                ", current generationNumber=" + currentGenerationNumber);
1287                    }
1288                    if (mGenerationNumber != currentGenerationNumber) return;
1289
1290                    final String state = intent.getStringExtra(
1291                            IccCardConstants.INTENT_KEY_ICC_STATE);
1292                    Log.d(TAG, "got Sim changed to state " + state + ", mSimNotLoadedSeen=" +
1293                            mSimNotLoadedSeen);
1294
1295                    if (!isSimCardLoaded(state)) {
1296                        if (!mSimNotLoadedSeen) mSimNotLoadedSeen = true;
1297                        return;
1298                    }
1299
1300                    if (isSimCardLoaded(state) && mSimNotLoadedSeen) {
1301                        mSimNotLoadedSeen = false;
1302
1303                        if (!hasMobileHotspotProvisionApp()) return;
1304
1305                        ArrayList<Integer> tethered = new ArrayList<Integer>();
1306                        synchronized (mPublicSync) {
1307                            for (int i = 0; i < mTetherStates.size(); i++) {
1308                                TetherState tetherState = mTetherStates.valueAt(i);
1309                                if (tetherState.mLastState != IControlsTethering.STATE_TETHERED) {
1310                                    continue;  // Skip interfaces that aren't tethered.
1311                                }
1312                                String iface = mTetherStates.keyAt(i);
1313                                int interfaceType = ifaceNameToType(iface);
1314                                if (interfaceType != ConnectivityManager.TETHERING_INVALID) {
1315                                    tethered.add(new Integer(interfaceType));
1316                                }
1317                            }
1318                        }
1319
1320                        for (int tetherType : tethered) {
1321                            startProvisionIntent(tetherType);
1322                        }
1323                    }
1324                }
1325            }
1326        }
1327
1328        class InitialState extends TetherMasterUtilState {
1329            @Override
1330            public boolean processMessage(Message message) {
1331                maybeLogMessage(this, message.what);
1332                boolean retValue = true;
1333                switch (message.what) {
1334                    case CMD_TETHER_MODE_REQUESTED:
1335                        TetherInterfaceStateMachine who = (TetherInterfaceStateMachine)message.obj;
1336                        if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
1337                        if (mNotifyList.indexOf(who) < 0) {
1338                            mNotifyList.add(who);
1339                            mIPv6TetheringCoordinator.addActiveDownstream(who);
1340                        }
1341                        transitionTo(mTetherModeAliveState);
1342                        break;
1343                    case CMD_TETHER_MODE_UNREQUESTED:
1344                        who = (TetherInterfaceStateMachine)message.obj;
1345                        if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
1346                        mNotifyList.remove(who);
1347                        mIPv6TetheringCoordinator.removeActiveDownstream(who);
1348                        break;
1349                    default:
1350                        retValue = false;
1351                        break;
1352                }
1353                return retValue;
1354            }
1355        }
1356
1357        class TetherModeAliveState extends TetherMasterUtilState {
1358            final SimChangeListener simChange = new SimChangeListener(mContext);
1359            boolean mTryCell = true;
1360            @Override
1361            public void enter() {
1362                // TODO: examine if we should check the return value.
1363                turnOnMasterTetherSettings(); // may transition us out
1364                simChange.startListening();
1365                mUpstreamNetworkMonitor.start();
1366
1367                // Better try something first pass or crazy tests cases will fail.
1368                chooseUpstreamType(true);
1369                mTryCell = false;
1370            }
1371
1372            @Override
1373            public void exit() {
1374                unrequestUpstreamMobileConnection();
1375                mUpstreamNetworkMonitor.stop();
1376                simChange.stopListening();
1377                notifyTetheredOfNewUpstreamIface(null);
1378                handleNewUpstreamNetworkState(null);
1379            }
1380
1381            @Override
1382            public boolean processMessage(Message message) {
1383                maybeLogMessage(this, message.what);
1384                boolean retValue = true;
1385                switch (message.what) {
1386                    case CMD_TETHER_MODE_REQUESTED: {
1387                        TetherInterfaceStateMachine who = (TetherInterfaceStateMachine)message.obj;
1388                        if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
1389                        if (mNotifyList.indexOf(who) < 0) {
1390                            mNotifyList.add(who);
1391                            mIPv6TetheringCoordinator.addActiveDownstream(who);
1392                        }
1393                        who.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED,
1394                                mCurrentUpstreamIface);
1395                        break;
1396                    }
1397                    case CMD_TETHER_MODE_UNREQUESTED: {
1398                        TetherInterfaceStateMachine who = (TetherInterfaceStateMachine)message.obj;
1399                        if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
1400                        if (mNotifyList.remove(who)) {
1401                            if (DBG) Log.d(TAG, "TetherModeAlive removing notifyee " + who);
1402                            if (mNotifyList.isEmpty()) {
1403                                turnOffMasterTetherSettings(); // transitions appropriately
1404                            } else {
1405                                if (DBG) {
1406                                    Log.d(TAG, "TetherModeAlive still has " + mNotifyList.size() +
1407                                            " live requests:");
1408                                    for (TetherInterfaceStateMachine o : mNotifyList) {
1409                                        Log.d(TAG, "  " + o);
1410                                    }
1411                                }
1412                            }
1413                        } else {
1414                           Log.e(TAG, "TetherModeAliveState UNREQUESTED has unknown who: " + who);
1415                        }
1416                        mIPv6TetheringCoordinator.removeActiveDownstream(who);
1417                        break;
1418                    }
1419                    case CMD_UPSTREAM_CHANGED:
1420                        // Need to try DUN immediately if Wi-Fi goes down.
1421                        chooseUpstreamType(true);
1422                        mTryCell = false;
1423                        break;
1424                    case CMD_RETRY_UPSTREAM:
1425                        chooseUpstreamType(mTryCell);
1426                        mTryCell = !mTryCell;
1427                        break;
1428                    case EVENT_UPSTREAM_CALLBACK: {
1429                        final NetworkState ns = (NetworkState) message.obj;
1430
1431                        if (ns == null || !pertainsToCurrentUpstream(ns)) {
1432                            // TODO: In future, this is where upstream evaluation and selection
1433                            // could be handled for notifications which include sufficient data.
1434                            // For example, after CONNECTIVITY_ACTION listening is removed, here
1435                            // is where we could observe a Wi-Fi network becoming available and
1436                            // passing validation.
1437                            if (mCurrentUpstreamIface == null) {
1438                                // If we have no upstream interface, try to run through upstream
1439                                // selection again.  If, for example, IPv4 connectivity has shown up
1440                                // after IPv6 (e.g., 464xlat became available) we want the chance to
1441                                // notice and act accordingly.
1442                                chooseUpstreamType(false);
1443                            }
1444                            break;
1445                        }
1446
1447                        switch (message.arg1) {
1448                            case UpstreamNetworkMonitor.EVENT_ON_AVAILABLE:
1449                                // The default network changed, or DUN connected
1450                                // before this callback was processed. Updates
1451                                // for the current NetworkCapabilities and
1452                                // LinkProperties have been requested (default
1453                                // request) or are being sent shortly (DUN). Do
1454                                // nothing until they arrive; if no updates
1455                                // arrive there's nothing to do.
1456                                break;
1457                            case UpstreamNetworkMonitor.EVENT_ON_CAPABILITIES:
1458                                handleNewUpstreamNetworkState(ns);
1459                                break;
1460                            case UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES:
1461                                setDnsForwarders(ns.network, ns.linkProperties);
1462                                handleNewUpstreamNetworkState(ns);
1463                                break;
1464                            case UpstreamNetworkMonitor.EVENT_ON_LOST:
1465                                // TODO: Re-evaluate possible upstreams. Currently upstream
1466                                // reevaluation is triggered via received CONNECTIVITY_ACTION
1467                                // broadcasts that result in being passed a
1468                                // TetherMasterSM.CMD_UPSTREAM_CHANGED.
1469                                handleNewUpstreamNetworkState(null);
1470                                break;
1471                            default:
1472                                break;
1473                        }
1474                        break;
1475                    }
1476                    default:
1477                        retValue = false;
1478                        break;
1479                }
1480                return retValue;
1481            }
1482        }
1483
1484        class ErrorState extends State {
1485            int mErrorNotification;
1486            @Override
1487            public boolean processMessage(Message message) {
1488                boolean retValue = true;
1489                switch (message.what) {
1490                    case CMD_TETHER_MODE_REQUESTED:
1491                        TetherInterfaceStateMachine who = (TetherInterfaceStateMachine)message.obj;
1492                        who.sendMessage(mErrorNotification);
1493                        break;
1494                    default:
1495                       retValue = false;
1496                }
1497                return retValue;
1498            }
1499            void notify(int msgType) {
1500                mErrorNotification = msgType;
1501                for (TetherInterfaceStateMachine sm : mNotifyList) {
1502                    sm.sendMessage(msgType);
1503                }
1504            }
1505
1506        }
1507        class SetIpForwardingEnabledErrorState extends ErrorState {
1508            @Override
1509            public void enter() {
1510                Log.e(TAG, "Error in setIpForwardingEnabled");
1511                notify(TetherInterfaceStateMachine.CMD_IP_FORWARDING_ENABLE_ERROR);
1512            }
1513        }
1514
1515        class SetIpForwardingDisabledErrorState extends ErrorState {
1516            @Override
1517            public void enter() {
1518                Log.e(TAG, "Error in setIpForwardingDisabled");
1519                notify(TetherInterfaceStateMachine.CMD_IP_FORWARDING_DISABLE_ERROR);
1520            }
1521        }
1522
1523        class StartTetheringErrorState extends ErrorState {
1524            @Override
1525            public void enter() {
1526                Log.e(TAG, "Error in startTethering");
1527                notify(TetherInterfaceStateMachine.CMD_START_TETHERING_ERROR);
1528                try {
1529                    mNMService.setIpForwardingEnabled(false);
1530                } catch (Exception e) {}
1531            }
1532        }
1533
1534        class StopTetheringErrorState extends ErrorState {
1535            @Override
1536            public void enter() {
1537                Log.e(TAG, "Error in stopTethering");
1538                notify(TetherInterfaceStateMachine.CMD_STOP_TETHERING_ERROR);
1539                try {
1540                    mNMService.setIpForwardingEnabled(false);
1541                } catch (Exception e) {}
1542            }
1543        }
1544
1545        class SetDnsForwardersErrorState extends ErrorState {
1546            @Override
1547            public void enter() {
1548                Log.e(TAG, "Error in setDnsForwarders");
1549                notify(TetherInterfaceStateMachine.CMD_SET_DNS_FORWARDERS_ERROR);
1550                try {
1551                    mNMService.stopTethering();
1552                } catch (Exception e) {}
1553                try {
1554                    mNMService.setIpForwardingEnabled(false);
1555                } catch (Exception e) {}
1556            }
1557        }
1558    }
1559
1560    @Override
1561    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
1562        // Binder.java closes the resource for us.
1563        @SuppressWarnings("resource")
1564        final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
1565        if (mContext.checkCallingOrSelfPermission(
1566                android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) {
1567            pw.println("Permission Denial: can't dump ConnectivityService.Tether " +
1568                    "from from pid=" + Binder.getCallingPid() + ", uid=" +
1569                    Binder.getCallingUid());
1570                    return;
1571        }
1572
1573        pw.println("Tethering:");
1574        pw.increaseIndent();
1575        final TetheringConfiguration cfg = mConfig;
1576        pw.print("preferredUpstreamIfaceTypes:");
1577        synchronized (mPublicSync) {
1578            for (Integer netType : cfg.preferredUpstreamIfaceTypes) {
1579                pw.print(" " + ConnectivityManager.getNetworkTypeName(netType));
1580            }
1581            pw.println();
1582
1583            pw.println("Tether state:");
1584            pw.increaseIndent();
1585            for (int i = 0; i < mTetherStates.size(); i++) {
1586                final String iface = mTetherStates.keyAt(i);
1587                final TetherState tetherState = mTetherStates.valueAt(i);
1588                pw.print(iface + " - ");
1589
1590                switch (tetherState.mLastState) {
1591                    case IControlsTethering.STATE_UNAVAILABLE:
1592                        pw.print("UnavailableState");
1593                        break;
1594                    case IControlsTethering.STATE_AVAILABLE:
1595                        pw.print("AvailableState");
1596                        break;
1597                    case IControlsTethering.STATE_TETHERED:
1598                        pw.print("TetheredState");
1599                        break;
1600                    default:
1601                        pw.print("UnknownState");
1602                        break;
1603                }
1604                pw.println(" - lastError = " + tetherState.mLastError);
1605            }
1606            pw.decreaseIndent();
1607        }
1608        pw.decreaseIndent();
1609    }
1610
1611    @Override
1612    public void notifyInterfaceStateChange(String iface, TetherInterfaceStateMachine who,
1613                                           int state, int error) {
1614        synchronized (mPublicSync) {
1615            TetherState tetherState = mTetherStates.get(iface);
1616            if (tetherState != null && tetherState.mStateMachine.equals(who)) {
1617                tetherState.mLastState = state;
1618                tetherState.mLastError = error;
1619            } else {
1620                if (DBG) Log.d(TAG, "got notification from stale iface " + iface);
1621            }
1622        }
1623
1624        if (DBG) {
1625            Log.d(TAG, "iface " + iface + " notified that it was in state " + state +
1626                    " with error " + error);
1627        }
1628
1629        try {
1630            // Notify that we're tethering (or not) this interface.
1631            // This is how data saver for instance knows if the user explicitly
1632            // turned on tethering (thus keeping us from being in data saver mode).
1633            mPolicyManager.onTetheringChanged(iface, state == IControlsTethering.STATE_TETHERED);
1634        } catch (RemoteException e) {
1635            // Not really very much we can do here.
1636        }
1637
1638        switch (state) {
1639            case IControlsTethering.STATE_UNAVAILABLE:
1640            case IControlsTethering.STATE_AVAILABLE:
1641                mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED, who);
1642                break;
1643            case IControlsTethering.STATE_TETHERED:
1644                mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_REQUESTED, who);
1645                break;
1646        }
1647        sendTetherStateChangedBroadcast();
1648    }
1649
1650    private void trackNewTetherableInterface(String iface, int interfaceType) {
1651        TetherState tetherState;
1652        tetherState = new TetherState(new TetherInterfaceStateMachine(iface, mLooper,
1653                interfaceType, mNMService, mStatsService, this,
1654                new IPv6TetheringInterfaceServices(iface, mNMService)));
1655        mTetherStates.put(iface, tetherState);
1656        tetherState.mStateMachine.start();
1657    }
1658
1659    private static String[] copy(String[] strarray) {
1660        return Arrays.copyOf(strarray, strarray.length);
1661    }
1662}
1663