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