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

Commit 8fee3dee authored by Mark Chien's avatar Mark Chien Committed by Gerrit Code Review
Browse files

Merge "Support multi-SIM entitlement check"

parents 661bb041 0b595078
Loading
Loading
Loading
Loading
+14 −1
Original line number Diff line number Diff line
@@ -96,6 +96,7 @@ import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.MessageUtils;
@@ -180,6 +181,7 @@ public class Tethering extends BaseNetworkObserver {
    // into a single coherent structure.
    private final HashSet<IpServer> mForwardedDownstreams;
    private final VersionedBroadcastListener mCarrierConfigChange;
    private final VersionedBroadcastListener mDefaultSubscriptionChange;
    private final TetheringDependencies mDeps;
    private final EntitlementManager mEntitlementMgr;

@@ -232,6 +234,15 @@ public class Tethering extends BaseNetworkObserver {
                    mEntitlementMgr.reevaluateSimCardProvisioning();
                });

        filter = new IntentFilter();
        filter.addAction(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
        mDefaultSubscriptionChange = new VersionedBroadcastListener(
                "DefaultSubscriptionChangeListener", mContext, smHandler, filter,
                (Intent ignored) -> {
                    mLog.log("OBSERVED default data subscription change");
                    updateConfiguration();
                    mEntitlementMgr.reevaluateSimCardProvisioning();
                });
        mStateReceiver = new StateReceiver();

        // Load tethering configuration.
@@ -242,6 +253,7 @@ public class Tethering extends BaseNetworkObserver {

    private void startStateMachineUpdaters() {
        mCarrierConfigChange.startListening();
        mDefaultSubscriptionChange.startListening();

        final Handler handler = mTetherMasterSM.getHandler();
        IntentFilter filter = new IntentFilter();
@@ -270,7 +282,8 @@ public class Tethering extends BaseNetworkObserver {

    // NOTE: This is always invoked on the mLooper thread.
    private void updateConfiguration() {
        mConfig = new TetheringConfiguration(mContext, mLog);
        final int subId = mDeps.getDefaultDataSubscriptionId();
        mConfig = new TetheringConfiguration(mContext, mLog, subId);
        mUpstreamNetworkMonitor.updateMobileRequiresDun(mConfig.isDunRequired);
        mEntitlementMgr.updateConfiguration(mConfig);
    }
+43 −20
Original line number Diff line number Diff line
@@ -26,8 +26,8 @@ import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER;
import static com.android.internal.R.array.config_mobile_hotspot_provision_app;
import static com.android.internal.R.array.config_tether_bluetooth_regexs;
import static com.android.internal.R.array.config_tether_dhcp_range;
import static com.android.internal.R.array.config_tether_usb_regexs;
import static com.android.internal.R.array.config_tether_upstream_types;
import static com.android.internal.R.array.config_tether_usb_regexs;
import static com.android.internal.R.array.config_tether_wifi_regexs;
import static com.android.internal.R.bool.config_tether_upstream_automatic;
import static com.android.internal.R.string.config_mobile_hotspot_provision_app_no_ui;
@@ -38,6 +38,7 @@ import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.util.SharedLog;
import android.provider.Settings;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;

@@ -100,29 +101,34 @@ public class TetheringConfiguration {
    public final String[] provisioningApp;
    public final String provisioningAppNoUi;

    public TetheringConfiguration(Context ctx, SharedLog log) {
    public final int subId;

    public TetheringConfiguration(Context ctx, SharedLog log, int id) {
        final SharedLog configLog = log.forSubComponent("config");

        tetherableUsbRegexs = getResourceStringArray(ctx, config_tether_usb_regexs);
        subId = id;
        Resources res = getResources(ctx, subId);

        tetherableUsbRegexs = getResourceStringArray(res, config_tether_usb_regexs);
        // TODO: Evaluate deleting this altogether now that Wi-Fi always passes
        // us an interface name. Careful consideration needs to be given to
        // implications for Settings and for provisioning checks.
        tetherableWifiRegexs = getResourceStringArray(ctx, config_tether_wifi_regexs);
        tetherableBluetoothRegexs = getResourceStringArray(ctx, config_tether_bluetooth_regexs);
        tetherableWifiRegexs = getResourceStringArray(res, config_tether_wifi_regexs);
        tetherableBluetoothRegexs = getResourceStringArray(res, config_tether_bluetooth_regexs);

        dunCheck = checkDunRequired(ctx);
        configLog.log("DUN check returned: " + dunCheckString(dunCheck));

        chooseUpstreamAutomatically = getResourceBoolean(ctx, config_tether_upstream_automatic);
        preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(ctx, dunCheck);
        chooseUpstreamAutomatically = getResourceBoolean(res, config_tether_upstream_automatic);
        preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(res, dunCheck);
        isDunRequired = preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN);

        legacyDhcpRanges = getLegacyDhcpRanges(ctx);
        legacyDhcpRanges = getLegacyDhcpRanges(res);
        defaultIPv4DNS = copy(DEFAULT_IPV4_DNS);
        enableLegacyDhcpServer = getEnableLegacyDhcpServer(ctx);

        provisioningApp = getResourceStringArray(ctx, config_mobile_hotspot_provision_app);
        provisioningAppNoUi = getProvisioningAppNoUi(ctx);
        provisioningApp = getResourceStringArray(res, config_mobile_hotspot_provision_app);
        provisioningAppNoUi = getProvisioningAppNoUi(res);

        configLog.log(toString());
    }
@@ -144,6 +150,9 @@ public class TetheringConfiguration {
    }

    public void dump(PrintWriter pw) {
        pw.print("subId: ");
        pw.println(subId);

        dumpStringArray(pw, "tetherableUsbRegexs", tetherableUsbRegexs);
        dumpStringArray(pw, "tetherableWifiRegexs", tetherableWifiRegexs);
        dumpStringArray(pw, "tetherableBluetoothRegexs", tetherableBluetoothRegexs);
@@ -169,6 +178,7 @@ public class TetheringConfiguration {

    public String toString() {
        final StringJoiner sj = new StringJoiner(" ");
        sj.add(String.format("subId:%d", subId));
        sj.add(String.format("tetherableUsbRegexs:%s", makeString(tetherableUsbRegexs)));
        sj.add(String.format("tetherableWifiRegexs:%s", makeString(tetherableWifiRegexs)));
        sj.add(String.format("tetherableBluetoothRegexs:%s",
@@ -235,8 +245,8 @@ public class TetheringConfiguration {
        }
    }

    private static Collection<Integer> getUpstreamIfaceTypes(Context ctx, int dunCheck) {
        final int ifaceTypes[] = ctx.getResources().getIntArray(config_tether_upstream_types);
    private static Collection<Integer> getUpstreamIfaceTypes(Resources res, int dunCheck) {
        final int[] ifaceTypes = res.getIntArray(config_tether_upstream_types);
        final ArrayList<Integer> upstreamIfaceTypes = new ArrayList<>(ifaceTypes.length);
        for (int i : ifaceTypes) {
            switch (i) {
@@ -286,33 +296,33 @@ public class TetheringConfiguration {
        return false;
    }

    private static String[] getLegacyDhcpRanges(Context ctx) {
        final String[] fromResource = getResourceStringArray(ctx, config_tether_dhcp_range);
    private static String[] getLegacyDhcpRanges(Resources res) {
        final String[] fromResource = getResourceStringArray(res, config_tether_dhcp_range);
        if ((fromResource.length > 0) && (fromResource.length % 2 == 0)) {
            return fromResource;
        }
        return copy(LEGACY_DHCP_DEFAULT_RANGE);
    }

    private static String getProvisioningAppNoUi(Context ctx) {
    private static String getProvisioningAppNoUi(Resources res) {
        try {
            return ctx.getResources().getString(config_mobile_hotspot_provision_app_no_ui);
            return res.getString(config_mobile_hotspot_provision_app_no_ui);
        } catch (Resources.NotFoundException e) {
            return "";
        }
    }

    private static boolean getResourceBoolean(Context ctx, int resId) {
    private static boolean getResourceBoolean(Resources res, int resId) {
        try {
            return ctx.getResources().getBoolean(resId);
            return res.getBoolean(resId);
        } catch (Resources.NotFoundException e404) {
            return false;
        }
    }

    private static String[] getResourceStringArray(Context ctx, int resId) {
    private static String[] getResourceStringArray(Resources res, int resId) {
        try {
            final String[] strArray = ctx.getResources().getStringArray(resId);
            final String[] strArray = res.getStringArray(resId);
            return (strArray != null) ? strArray : EMPTY_STRING_ARRAY;
        } catch (Resources.NotFoundException e404) {
            return EMPTY_STRING_ARRAY;
@@ -325,6 +335,19 @@ public class TetheringConfiguration {
        return intVal != 0;
    }

    private Resources getResources(Context ctx, int subId) {
        if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
            return getResourcesForSubIdWrapper(ctx, subId);
        } else {
            return ctx.getResources();
        }
    }

    @VisibleForTesting
    protected Resources getResourcesForSubIdWrapper(Context ctx, int subId) {
        return SubscriptionManager.getResourcesForSubId(ctx, subId);
    }

    private static String[] copy(String[] strarray) {
        return Arrays.copyOf(strarray, strarray.length);
    }
+8 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.net.NetworkRequest;
import android.net.ip.IpServer;
import android.net.util.SharedLog;
import android.os.Handler;
import android.telephony.SubscriptionManager;

import com.android.internal.util.StateMachine;
import com.android.server.connectivity.MockableSystemProperties;
@@ -85,4 +86,11 @@ public class TetheringDependencies {
            SharedLog log, MockableSystemProperties systemProperties) {
        return new EntitlementManager(ctx, target, log, systemProperties);
    }

    /**
     * Get default data subscription id to build TetheringConfiguration.
     */
    public int getDefaultDataSubscriptionId() {
        return SubscriptionManager.getDefaultDataSubscriptionId();
    }
}
+6 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY;
import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED;
import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -274,6 +275,11 @@ public class TetheringTest {
            isTetheringSupportedCalls++;
            return true;
        }

        @Override
        public int getDefaultDataSubscriptionId() {
            return INVALID_SUBSCRIPTION_ID;
        }
    }

    private static NetworkState buildMobileUpstreamState(boolean withIPv4, boolean withIPv6,
+15 −7
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static android.net.ConnectivityManager.TETHERING_WIFI;
import static android.net.ConnectivityManager.TETHER_ERROR_ENTITLEMENT_UNKONWN;
import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
import static android.net.ConnectivityManager.TETHER_ERROR_PROVISION_FAILED;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -140,7 +141,8 @@ public final class EntitlementManagerTest {
        mMockContext = new MockContext(mContext);
        mSM = new TestStateMachine();
        mEnMgr = new WrappedEntitlementManager(mMockContext, mSM, mLog, mSystemProperties);
        mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog));
        mEnMgr.updateConfiguration(
                new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID));
    }

    @After
@@ -168,7 +170,8 @@ public final class EntitlementManagerTest {
    @Test
    public void canRequireProvisioning() {
        setupForRequiredProvisioning();
        mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog));
        mEnMgr.updateConfiguration(
                new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID));
        assertTrue(mEnMgr.isTetherProvisioningRequired());
    }

@@ -177,7 +180,8 @@ public final class EntitlementManagerTest {
        setupForRequiredProvisioning();
        when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
            .thenReturn(null);
        mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog));
        mEnMgr.updateConfiguration(
                new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID));
        // Couldn't get the CarrierConfigManager, but still had a declared provisioning app.
        // Therefore provisioning still be required.
        assertTrue(mEnMgr.isTetherProvisioningRequired());
@@ -187,7 +191,8 @@ public final class EntitlementManagerTest {
    public void toleratesCarrierConfigMissing() {
        setupForRequiredProvisioning();
        when(mCarrierConfigManager.getConfig()).thenReturn(null);
        mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog));
        mEnMgr.updateConfiguration(
                new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID));
        // We still have a provisioning app configured, so still require provisioning.
        assertTrue(mEnMgr.isTetherProvisioningRequired());
    }
@@ -197,11 +202,13 @@ public final class EntitlementManagerTest {
        setupForRequiredProvisioning();
        when(mResources.getStringArray(R.array.config_mobile_hotspot_provision_app))
            .thenReturn(null);
        mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog));
        mEnMgr.updateConfiguration(
                new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID));
        assertFalse(mEnMgr.isTetherProvisioningRequired());
        when(mResources.getStringArray(R.array.config_mobile_hotspot_provision_app))
            .thenReturn(new String[] {"malformedApp"});
        mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog));
        mEnMgr.updateConfiguration(
                new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID));
        assertFalse(mEnMgr.isTetherProvisioningRequired());
    }

@@ -223,7 +230,8 @@ public final class EntitlementManagerTest {
        assertFalse(mEnMgr.everRunUiEntitlement);

        setupForRequiredProvisioning();
        mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog));
        mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
                  INVALID_SUBSCRIPTION_ID));
        // 2. No cache value and don't need to run entitlement check.
        mEnMgr.everRunUiEntitlement = false;
        receiver = new ResultReceiver(null) {
Loading