Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7af34ab8 authored by Robert Greenwalt's avatar Robert Greenwalt Committed by Android (Google) Code Review
Browse files

Merge "resolved conflicts for merge of 7a652bc8 to master"

parents bd67cddd 5ff886e5
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -163,6 +163,12 @@ public class ConnectivityManager {
     */
    public static final String EXTRA_ERRORED_TETHER = "erroredArray";

    /**
     * The absence of APN..
     * @hide
     */
    public static final int TYPE_NONE        = -1;

    /**
     * The Default Mobile data connection.  When active, all data traffic
     * will use this connection by default.
+8 −12
Original line number Diff line number Diff line
@@ -98,7 +98,7 @@
    <!-- This string array should be overridden by the device to present a list of network
         attributes.  This is used by the connectivity manager to decide which networks can coexist
         based on the hardware -->
    <!-- An Array of "[Connection name],[ConnectivityManager connection type],
    <!-- An Array of "[Connection name],[ConnectivityManager.TYPE_xxxx],
         [associated radio-type],[priority],[restoral-timer(ms)],[dependencyMet]  -->
    <!-- the 5th element "resore-time" indicates the number of milliseconds to delay
         before automatically restore the default connection.  Set -1 if the connection
@@ -154,20 +154,16 @@
    <string-array translatable="false" name="config_tether_dhcp_range">
    </string-array>

    <!-- Regex array of allowable upstream ifaces for tethering - for example if you want
         tethering on a new interface called "foo2" add <item>"foo\\d"</item> to the array -->
    <!-- Interfaces will be prioritized according to the order listed -->
    <string-array translatable="false" name="config_tether_upstream_regexs">
    </string-array>

    <!-- Regex of wired ethernet ifaces -->
    <string translatable="false" name="config_ethernet_iface_regex">eth\\d</string>

    <!-- Boolean indicating if we require the use of DUN on mobile for tethering.
         Note that this defaults to false so that if you move to a carrier that
         hasn't configured anything tethering will still work.  If you'd rather
         make the device untetherable on unconfigured devices, set to true -->
    <bool translatable="false" name="config_tether_dun_required">false</bool>
    <!-- Array of ConnectivityManager.TYPE_xxxx values allowable for tethering -->
    <!-- Common options are [1, 4] for TYPE_WIFI and TYPE_MOBILE_DUN or
    <!== [0,1,5,7] for TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI and TYPE_BLUETOOTH -->
    <integer-array translatable="false" name="config_tether_upstream_types">
        <item>1</item>
        <item>4</item>
    </integer-array>

    <!-- String containing the apn value for tethering.  May be overriden by secure settings
         TETHER_DUN_APN.  Value is a comma separated series of strings:
+2 −18
Original line number Diff line number Diff line
@@ -466,12 +466,10 @@ public class ConnectivityService extends IConnectivityManager.Stub {
        INetworkManagementService nmService = INetworkManagementService.Stub.asInterface(b);

        mTethering = new Tethering(mContext, nmService, mHandler.getLooper());
        mTetheringConfigValid = (((mNetTrackers[ConnectivityManager.TYPE_MOBILE_DUN] != null) ||
                                  !mTethering.isDunRequired()) &&
                                 (mTethering.getTetherableUsbRegexs().length != 0 ||
        mTetheringConfigValid = ((mTethering.getTetherableUsbRegexs().length != 0 ||
                                  mTethering.getTetherableWifiRegexs().length != 0 ||
                                  mTethering.getTetherableBluetoothRegexs().length != 0) &&
                                 mTethering.getUpstreamIfaceRegexs().length != 0);
                                 mTethering.getUpstreamIfaceTypes().length != 0);

        mVpn = new Vpn(mContext, new VpnCallback());

@@ -1576,12 +1574,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
                }
                addPrivateDnsRoutes(mNetTrackers[netType]);
            }

            /** Notify TetheringService if interface name has been changed. */
            if (TextUtils.equals(mNetTrackers[netType].getNetworkInfo().getReason(),
                                 Phone.REASON_LINK_PROPERTIES_CHANGED)) {
                handleTetherIfaceChange(netType);
            }
        } else {
            if (mNetConfigs[netType].isDefault()) {
                removeDefaultRoute(mNetTrackers[netType]);
@@ -2412,14 +2404,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
        }
    }

    private void handleTetherIfaceChange(int type) {
        String iface = mNetTrackers[type].getLinkProperties().getInterfaceName();

        if (isTetheringSupported()) {
            mTethering.handleTetherIfaceChange(iface);
        }
    }

    private void log(String s) {
        Slog.d(TAG, s);
    }
+115 −136
Original line number Diff line number Diff line
@@ -57,7 +57,9 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Set;
/**
@@ -82,7 +84,15 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
    private String[] mTetherableUsbRegexs;
    private String[] mTetherableWifiRegexs;
    private String[] mTetherableBluetoothRegexs;
    private String[] mUpstreamIfaceRegexs;
    private Collection<Integer> mUpstreamIfaceTypes;

    private static final Integer MOBILE_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE);
    private static final Integer HIPRI_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE_HIPRI);
    private static final Integer DUN_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE_DUN);

    // if we have to connect to mobile, what APN type should we use?  Calculated by examining the
    // upstream type list and the DUN_REQUIRED secure-setting
    private int mPreferredUpstreamMobileApn = ConnectivityManager.TYPE_NONE;

    private INetworkManagementService mNMService;
    private Looper mLooper;
@@ -112,9 +122,6 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
    private static final String DNS_DEFAULT_SERVER1 = "8.8.8.8";
    private static final String DNS_DEFAULT_SERVER2 = "8.8.4.4";

    // resampled each time we turn on tethering - used as cache for settings/config-val
    private boolean mDunRequired;  // configuration info - must use DUN apn on 3g

    private StateMachine mTetherMasterSM;

    private Notification mTetheredNotification;
@@ -159,7 +166,6 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
        if ((mDhcpRange.length == 0) || (mDhcpRange.length % 2 ==1)) {
            mDhcpRange = DHCP_DEFAULT_RANGE;
        }
        mDunRequired = false; // resample when we turn on

        mTetherableUsbRegexs = context.getResources().getStringArray(
                com.android.internal.R.array.config_tether_usb_regexs);
@@ -167,8 +173,15 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
                com.android.internal.R.array.config_tether_wifi_regexs);
        mTetherableBluetoothRegexs = context.getResources().getStringArray(
                com.android.internal.R.array.config_tether_bluetooth_regexs);
        mUpstreamIfaceRegexs = context.getResources().getStringArray(
                com.android.internal.R.array.config_tether_upstream_regexs);
        int ifaceTypes[] = context.getResources().getIntArray(
                com.android.internal.R.array.config_tether_upstream_types);
        mUpstreamIfaceTypes = new ArrayList();
        for (int i : ifaceTypes) {
            mUpstreamIfaceTypes.add(new Integer(i));
        }

        // check if the upstream type list needs to be modified due to secure-settings
        checkDunRequired();

        // TODO - remove and rely on real notifications of the current iface
        mDnsServers = new String[2];
@@ -582,16 +595,44 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
        return mTetherableBluetoothRegexs;
    }

    public String[] getUpstreamIfaceRegexs() {
        return mUpstreamIfaceRegexs;
    public int[] getUpstreamIfaceTypes() {
        int values[] = new int[mUpstreamIfaceTypes.size()];
        Iterator<Integer> iterator = mUpstreamIfaceTypes.iterator();
        for (int i=0; i < mUpstreamIfaceTypes.size(); i++) {
            values[i] = iterator.next();
        }
        return values;
    }

    public boolean isDunRequired() {
        boolean defaultVal = mContext.getResources().getBoolean(
                com.android.internal.R.bool.config_tether_dun_required);
        boolean result = (Settings.Secure.getInt(mContext.getContentResolver(),
                Settings.Secure.TETHER_DUN_REQUIRED, (defaultVal ? 1 : 0)) == 1);
        return result;
    public void checkDunRequired() {
        int requiredApn = ((Settings.Secure.getInt(mContext.getContentResolver(),
                Settings.Secure.TETHER_DUN_REQUIRED, 0) == 1) ?
                ConnectivityManager.TYPE_MOBILE_DUN :
                ConnectivityManager.TYPE_MOBILE_HIPRI);
        if (mPreferredUpstreamMobileApn != requiredApn) {
            if (requiredApn == ConnectivityManager.TYPE_MOBILE_DUN) {
                while (mUpstreamIfaceTypes.contains(MOBILE_TYPE)) {
                    mUpstreamIfaceTypes.remove(MOBILE_TYPE);
                }
                while (mUpstreamIfaceTypes.contains(HIPRI_TYPE)) {
                    mUpstreamIfaceTypes.remove(HIPRI_TYPE);
                }
                if (mUpstreamIfaceTypes.contains(DUN_TYPE) == false) {
                    mUpstreamIfaceTypes.add(DUN_TYPE);
                }
            } else {
                while (mUpstreamIfaceTypes.contains(DUN_TYPE)) {
                    mUpstreamIfaceTypes.remove(DUN_TYPE);
                }
                if (mUpstreamIfaceTypes.contains(MOBILE_TYPE) == false) {
                    mUpstreamIfaceTypes.add(MOBILE_TYPE);
                }
                if (mUpstreamIfaceTypes.contains(HIPRI_TYPE) == false) {
                    mUpstreamIfaceTypes.add(HIPRI_TYPE);
                }
            }
            mPreferredUpstreamMobileApn = requiredApn;
        }
    }

    public String[] getTetheredIfaces() {
@@ -648,17 +689,6 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
        return retVal;
    }

    public void handleTetherIfaceChange(String iface) {
        // check if iface is white listed
        for (String regex : mUpstreamIfaceRegexs) {
            if (iface.matches(regex)) {
                if (DEBUG) Log.d(TAG, "Tethering got Interface Change");
                mTetherMasterSM.sendMessage(TetherMasterSM.CMD_IFACE_CHANGED, iface);
                break;
            }
        }
    }

    class TetherInterfaceSM extends StateMachine {
        // notification from the master SM that it's not in tether mode
        static final int CMD_TETHER_MODE_DEAD            =  1;
@@ -1051,8 +1081,6 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
        static final int CMD_CELL_CONNECTION_RENEW   = 4;
        // we don't have a valid upstream conn, check again after a delay
        static final int CMD_RETRY_UPSTREAM          = 5;
        // received an indication that upstream interface has changed
        static final int CMD_IFACE_CHANGED           = 6;

        // This indicates what a timeout event relates to.  A state that
        // sends itself a delayed timeout event and handles incoming timeout events
@@ -1072,7 +1100,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
        private ArrayList mNotifyList;

        private int mCurrentConnectionSequence;
        private boolean mMobileReserved = false;
        private int mMobileApnReserved = ConnectivityManager.TYPE_NONE;

        private String mUpstreamIfaceName = null;

@@ -1111,22 +1139,34 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
            public boolean processMessage(Message m) {
                return false;
            }
            protected boolean turnOnMobileConnection() {
            protected String enableString(int apnType) {
                switch (apnType) {
                case ConnectivityManager.TYPE_MOBILE_DUN:
                    return Phone.FEATURE_ENABLE_DUN_ALWAYS;
                case ConnectivityManager.TYPE_MOBILE:
                case ConnectivityManager.TYPE_MOBILE_HIPRI:
                    return Phone.FEATURE_ENABLE_HIPRI;
                }
                return null;
            }
            protected boolean turnOnUpstreamMobileConnection(int apnType) {
                boolean retValue = true;
                if (mMobileReserved) return retValue;
                if (apnType == ConnectivityManager.TYPE_NONE) return false;
                if (apnType != mMobileApnReserved) turnOffUpstreamMobileConnection();
                IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
                IConnectivityManager cm = IConnectivityManager.Stub.asInterface(b);
                int result = Phone.APN_REQUEST_FAILED;
                String enableString = enableString(apnType);
                if (enableString == null) return false;
                try {
                    result = cm.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
                            (mDunRequired ? Phone.FEATURE_ENABLE_DUN_ALWAYS :
                            Phone.FEATURE_ENABLE_HIPRI), new Binder());
                            enableString, new Binder());
                } catch (Exception e) {
                }
                switch (result) {
                case Phone.APN_ALREADY_ACTIVE:
                case Phone.APN_REQUEST_STARTED:
                    mMobileReserved = true;
                    mMobileApnReserved = apnType;
                    Message m = obtainMessage(CMD_CELL_CONNECTION_RENEW);
                    m.arg1 = ++mCurrentConnectionSequence;
                    sendMessageDelayed(m, CELL_CONNECTION_RENEW_MS);
@@ -1139,18 +1179,17 @@ public class Tethering extends INetworkManagementEventObserver.Stub {

                return retValue;
            }
            protected boolean turnOffMobileConnection() {
                if (mMobileReserved) {
            protected boolean turnOffUpstreamMobileConnection() {
                if (mMobileApnReserved != ConnectivityManager.TYPE_NONE) {
                    IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
                    IConnectivityManager cm = IConnectivityManager.Stub.asInterface(b);
                    try {
                        cm.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
                                (mDunRequired? Phone.FEATURE_ENABLE_DUN_ALWAYS :
                                             Phone.FEATURE_ENABLE_HIPRI));
                                enableString(mMobileApnReserved));
                    } catch (Exception e) {
                        return false;
                    }
                    mMobileReserved = false;
                    mMobileApnReserved = ConnectivityManager.TYPE_NONE;
                }
                return true;
            }
@@ -1196,108 +1235,55 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
                transitionTo(mInitialState);
                return true;
            }
            protected String findActiveUpstreamIface() {
                // check for what iface we can use - if none found switch to error.

            protected void chooseUpstreamType(boolean tryCell) {
                IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
                IConnectivityManager cm = IConnectivityManager.Stub.asInterface(b);
                int upType = ConnectivityManager.TYPE_NONE;
                String iface = null;

                for (Integer netType : mUpstreamIfaceTypes) {
                    NetworkInfo info = null;
                    try {
                    LinkProperties defaultProp = cm.getActiveLinkProperties();
                    if (defaultProp != null) {
                        String iface = defaultProp.getInterfaceName();
                        for(String regex : mUpstreamIfaceRegexs) {
                            if (iface.matches(regex)) return iface;
                        }
                    }
                        info = cm.getNetworkInfo(netType.intValue());
                    } catch (RemoteException e) { }

                String[] ifaces = new String[0];
                try {
                    ifaces = mNMService.listInterfaces();
                } catch (Exception e) {
                    Log.e(TAG, "Error listing Interfaces", e);
                    return null;
                }

                for (String regex : mUpstreamIfaceRegexs) {
                    for (String iface : ifaces) {
                        if (iface.matches(regex)) {
                            // verify it is active
                            InterfaceConfiguration ifcg = null;
                            try {
                                ifcg = mNMService.getInterfaceConfig(iface);
                                if (ifcg.isActive()) {
                                    return iface;
                                }
                            } catch (Exception e) {
                                Log.e(TAG, "Error getting iface config", e);
                                // ignore - try next
                                continue;
                            }
                        }
                    }
                    if ((info != null) && info.isConnected()) {
                        upType = netType.intValue();
                        break;
                    }
                return null;
                }

            protected void chooseUpstreamType(boolean tryCell) {
                // decide if the current upstream is good or not and if not
                // do something about it (start up DUN if required or HiPri if not)
                String iface = findActiveUpstreamIface();
                IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
                IConnectivityManager cm = IConnectivityManager.Stub.asInterface(b);
                mMobileReserved = false;
                if (DEBUG) {
                    Log.d(TAG, "chooseUpstreamType(" + tryCell + "),  dunRequired ="
                            + mDunRequired + ", iface=" + iface);
                }
                if (iface != null) {
                    try {
                        if (mDunRequired) {
                            // check if Dun is on - we can use that
                            NetworkInfo info = cm.getNetworkInfo(
                                    ConnectivityManager.TYPE_MOBILE_DUN);
                            if (info.isConnected()) {
                                if (DEBUG) Log.d(TAG, "setting dun ifacename =" + iface);
                                // even if we're already connected - it may be somebody else's
                                // refcount, so add our own
                                turnOnMobileConnection();
                            } else {
                                // verify the iface is not the default mobile - can't use that!
                                info = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
                                if (info.isConnected()) {
                                    iface = null; // can't accept this one
                                }
                            }
                        } else {
                            if (DEBUG) Log.d(TAG, "checking if hipri brought us this connection");
                            NetworkInfo info = cm.getNetworkInfo(
                                    ConnectivityManager.TYPE_MOBILE_HIPRI);
                            if (info.isConnected()) {
                                if (DEBUG) Log.d(TAG, "yes - hipri in use");
                                // even if we're already connected - it may be sombody else's
                                // refcount, so add our own
                                turnOnMobileConnection();
                            }
                        }
                    } catch (RemoteException e) {
                        Log.e(TAG, "RemoteException calling ConnectivityManager", e);
                        iface = null;
                    Log.d(TAG, "chooseUpstreamType(" + tryCell + "), preferredApn ="
                            + mPreferredUpstreamMobileApn + ", got type=" + upType);
                }

                // if we're on DUN, put our own grab on it
                if (upType == ConnectivityManager.TYPE_MOBILE_DUN ||
                        upType == ConnectivityManager.TYPE_MOBILE_HIPRI) {
                    turnOnUpstreamMobileConnection(upType);
                }
                // may have been set to null in the if above
                if (iface == null ) {
                    boolean success = false;
                    if (tryCell == TRY_TO_SETUP_MOBILE_CONNECTION) {
                        success = turnOnMobileConnection();

                if (upType == ConnectivityManager.TYPE_NONE) {
                    boolean tryAgainLater = true;
                    if ((tryCell == TRY_TO_SETUP_MOBILE_CONNECTION) &&
                            (turnOnUpstreamMobileConnection(mPreferredUpstreamMobileApn) == true)) {
                        // we think mobile should be coming up - don't set a retry
                        tryAgainLater = false;
                    }
                    if (!success) {
                        // wait for things to settle and retry
                    if (tryAgainLater) {
                        sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS);
                    }
                } else {
                    LinkProperties linkProperties = null;
                    try {
                        linkProperties = cm.getLinkProperties(upType);
                    } catch (RemoteException e) { }
                    if (linkProperties != null) iface = linkProperties.getInterfaceName();
                }
                notifyTetheredOfNewUpstreamIface(iface);
            }

            protected void notifyTetheredOfNewUpstreamIface(String ifaceName) {
                if (DEBUG) Log.d(TAG, "notifying tethered with iface =" + ifaceName);
                mUpstreamIfaceName = ifaceName;
@@ -1312,7 +1298,6 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
        class InitialState extends TetherMasterUtilState {
            @Override
            public void enter() {
                mMobileReserved = false;
            }
            @Override
            public boolean processMessage(Message message) {
@@ -1320,7 +1305,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
                boolean retValue = true;
                switch (message.what) {
                    case CMD_TETHER_MODE_REQUESTED:
                        mDunRequired = isDunRequired();
                        checkDunRequired();
                        TetherInterfaceSM who = (TetherInterfaceSM)message.obj;
                        if (DEBUG) Log.d(TAG, "Tether Mode requested by " + who.toString());
                        mNotifyList.add(who);
@@ -1354,7 +1339,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
            }
            @Override
            public void exit() {
                turnOffMobileConnection();
                turnOffUpstreamMobileConnection();
                notifyTetheredOfNewUpstreamIface(null);
            }
            @Override
@@ -1392,19 +1377,13 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
                                Log.d(TAG, "renewing mobile connection - requeuing for another " +
                                        CELL_CONNECTION_RENEW_MS + "ms");
                            }
                            mMobileReserved = false; // need to renew it
                            turnOnMobileConnection();
                            turnOnUpstreamMobileConnection(mMobileApnReserved);
                        }
                        break;
                    case CMD_RETRY_UPSTREAM:
                        chooseUpstreamType(mTryCell);
                        mTryCell = !mTryCell;
                        break;
                    case CMD_IFACE_CHANGED:
                        String iface = (String)message.obj;
                        if (DEBUG) Log.d(TAG, "Activie upstream interface changed: " + iface);
                        notifyTetheredOfNewUpstreamIface(iface);
                        break;
                    default:
                        retValue = false;
                        break;