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

Commit fc0b863b authored by Erik Kline's avatar Erik Kline Committed by android-build-merger
Browse files

Merge "Switch to listening for CarrierConfig changes for provisioning rechecks" am: c21effd5

am: 166c2744

Change-Id: I16c6e768d8df46d2d11947edc0c5620dd3f1b2a9
parents 37de23b4 166c2744
Loading
Loading
Loading
Loading
+47 −11
Original line number Diff line number Diff line
@@ -28,6 +28,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.IFACE_IP_MODE_UNSPECIFIED;
import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
import static com.android.server.ConnectivityService.SHORT_ARG;

import android.app.Notification;
@@ -60,6 +61,7 @@ import android.net.NetworkUtils;
import android.net.RouteInfo;
import android.net.util.PrefixUtils;
import android.net.util.SharedLog;
import android.net.util.VersionedBroadcastListener;
import android.net.wifi.WifiManager;
import android.os.Binder;
import android.os.Bundle;
@@ -68,6 +70,7 @@ import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.UserHandle;
@@ -180,6 +183,8 @@ public class Tethering extends BaseNetworkObserver {
    // TODO: Figure out how to merge this and other downstream-tracking objects
    // into a single coherent structure.
    private final HashSet<TetherInterfaceStateMachine> mForwardedDownstreams;
    private final VersionedBroadcastListener mCarrierConfigChange;
    // TODO: Delete SimChangeListener; it's obsolete.
    private final SimChangeListener mSimChange;

    private volatile TetheringConfiguration mConfig;
@@ -220,11 +225,26 @@ public class Tethering extends BaseNetworkObserver {
        mUpstreamNetworkMonitor = new UpstreamNetworkMonitor(
                mContext, mTetherMasterSM, mLog, TetherMasterSM.EVENT_UPSTREAM_CALLBACK);
        mForwardedDownstreams = new HashSet<>();

        IntentFilter filter = new IntentFilter();
        filter.addAction(ACTION_CARRIER_CONFIG_CHANGED);
        mCarrierConfigChange = new VersionedBroadcastListener(
                "CarrierConfigChangeListener", mContext, smHandler, filter,
                (Intent ignored) -> {
                    mLog.log("OBSERVED carrier config change");
                    reevaluateSimCardProvisioning();
                });
        // TODO: Remove SimChangeListener altogether. For now, we retain it
        // for logging purposes in case we need to debug something that might
        // be related to changing signals from ACTION_SIM_STATE_CHANGED to
        // ACTION_CARRIER_CONFIG_CHANGED.
        mSimChange = new SimChangeListener(
                mContext, smHandler, () -> reevaluateSimCardProvisioning());
                mContext, smHandler, () -> {
                    mLog.log("OBSERVED SIM card change");
                });

        mStateReceiver = new StateReceiver();
        IntentFilter filter = new IntentFilter();
        filter = new IntentFilter();
        filter.addAction(UsbManager.ACTION_USB_STATE);
        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
@@ -353,18 +373,30 @@ public class Tethering extends BaseNetworkObserver {
            return false;
        }

        if (carrierConfigAffirmsEntitlementCheckNotRequired()) {
            return false;
        }
        return (provisionApp.length == 2);
    }

    // The logic here is aimed solely at confirming that a CarrierConfig exists
    // and affirms that entitlement checks are not required.
    //
    // TODO: find a better way to express this, or alter the checking process
    // entirely so that this is more intuitive.
    private boolean carrierConfigAffirmsEntitlementCheckNotRequired() {
        // Check carrier config for entitlement checks
        final CarrierConfigManager configManager = (CarrierConfigManager) mContext
             .getSystemService(Context.CARRIER_CONFIG_SERVICE);
        if (configManager != null && configManager.getConfig() != null) {
            // we do have a CarrierConfigManager and it has a config.
            boolean isEntitlementCheckRequired = configManager.getConfig().getBoolean(
        if (configManager == null) return false;

        final PersistableBundle carrierConfig = configManager.getConfig();
        if (carrierConfig == null) return false;

        // A CarrierConfigManager was found and it has a config.
        final boolean isEntitlementCheckRequired = carrierConfig.getBoolean(
                CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL);
            if (!isEntitlementCheckRequired) {
                return false;
            }
        }
        return (provisionApp.length == 2);
        return !isEntitlementCheckRequired;
    }

    // Used by the SIM card change observation code.
@@ -794,6 +826,7 @@ public class Tethering extends BaseNetworkObserver {
            } else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
                handleWifiApAction(intent);
            } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
                mLog.log("OBSERVED configuration changed");
                updateConfiguration();
            }
        }
@@ -1136,6 +1169,7 @@ public class Tethering extends BaseNetworkObserver {

    private void reevaluateSimCardProvisioning() {
        if (!hasMobileHotspotProvisionApp()) return;
        if (carrierConfigAffirmsEntitlementCheckNotRequired()) return;

        ArrayList<Integer> tethered = new ArrayList<>();
        synchronized (mPublicSync) {
@@ -1503,6 +1537,7 @@ public class Tethering extends BaseNetworkObserver {
                    return;
                }

                mCarrierConfigChange.startListening();
                mSimChange.startListening();
                mUpstreamNetworkMonitor.start();

@@ -1520,6 +1555,7 @@ public class Tethering extends BaseNetworkObserver {
                mOffload.stop();
                mUpstreamNetworkMonitor.stop();
                mSimChange.stopListening();
                mCarrierConfigChange.stopListening();
                notifyDownstreamsOfNewUpstreamIface(null);
                handleNewUpstreamNetworkState(null);
            }
+27 −72
Original line number Diff line number Diff line
@@ -23,12 +23,15 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.util.VersionedBroadcastListener;
import android.net.util.VersionedBroadcastListener.IntentCallback;
import android.os.Handler;
import android.util.Log;

import com.android.internal.telephony.TelephonyIntents;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;


/**
@@ -37,88 +40,40 @@ import java.util.concurrent.atomic.AtomicInteger;
 *
 * @hide
 */
public class SimChangeListener {
public class SimChangeListener extends VersionedBroadcastListener {
    private static final String TAG = SimChangeListener.class.getSimpleName();
    private static final boolean DBG = false;

    private final Context mContext;
    private final Handler mTarget;
    private final AtomicInteger mSimBcastGenerationNumber;
    private final Runnable mCallback;
    private BroadcastReceiver mBroadcastReceiver;

    public SimChangeListener(Context ctx, Handler handler, Runnable onSimCardLoadedCallback) {
        mContext = ctx;
        mTarget = handler;
        mCallback = onSimCardLoadedCallback;
        mSimBcastGenerationNumber = new AtomicInteger(0);
    }

    public int generationNumber() {
        return mSimBcastGenerationNumber.get();
        super(TAG, ctx, handler, makeIntentFilter(), makeCallback(onSimCardLoadedCallback));
    }

    public void startListening() {
        if (DBG) Log.d(TAG, "startListening for SIM changes");

        if (mBroadcastReceiver != null) return;

        mBroadcastReceiver = new SimChangeBroadcastReceiver(
                mSimBcastGenerationNumber.incrementAndGet());
    private static IntentFilter makeIntentFilter() {
        final IntentFilter filter = new IntentFilter();
        filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);

        mContext.registerReceiver(mBroadcastReceiver, filter, null, mTarget);
    }

    public void stopListening() {
        if (DBG) Log.d(TAG, "stopListening for SIM changes");

        if (mBroadcastReceiver == null) return;

        mSimBcastGenerationNumber.incrementAndGet();
        mContext.unregisterReceiver(mBroadcastReceiver);
        mBroadcastReceiver = null;
    }

    private boolean isSimCardLoaded(String state) {
        return INTENT_VALUE_ICC_LOADED.equals(state);
        return filter;
    }

    private class SimChangeBroadcastReceiver extends BroadcastReceiver {
        // used to verify this receiver is still current
        final private int mGenerationNumber;

        // used to check the sim state transition from non-loaded to loaded
    private static Consumer<Intent> makeCallback(Runnable onSimCardLoadedCallback) {
        return new Consumer<Intent>() {
            private boolean mSimNotLoadedSeen = false;

        public SimChangeBroadcastReceiver(int generationNumber) {
            mGenerationNumber = generationNumber;
        }

            @Override
        public void onReceive(Context context, Intent intent) {
            final int currentGenerationNumber = mSimBcastGenerationNumber.get();

            if (DBG) {
                Log.d(TAG, "simchange mGenerationNumber=" + mGenerationNumber +
                        ", current generationNumber=" + currentGenerationNumber);
            }
            if (mGenerationNumber != currentGenerationNumber) return;

            public void accept(Intent intent) {
                final String state = intent.getStringExtra(INTENT_KEY_ICC_STATE);
                Log.d(TAG, "got Sim changed to state " + state + ", mSimNotLoadedSeen=" +
                        mSimNotLoadedSeen);

            if (!isSimCardLoaded(state)) {
                if (!INTENT_VALUE_ICC_LOADED.equals(state)) {
                    mSimNotLoadedSeen = true;
                    return;
                }

                if (mSimNotLoadedSeen) {
                    mSimNotLoadedSeen = false;
                mCallback.run();
                    onSimCardLoadedCallback.run();
                }
            }
        };
    }
}
+113 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.net.util;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.util.Log;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;


/**
 * A utility class that runs the provided callback on the provided handler when
 * intents matching the provided filter arrive. Intents received by a stale
 * receiver are safely ignored.
 *
 * Calls to startListening() and stopListening() must happen on the same thread.
 *
 * @hide
 */
public class VersionedBroadcastListener {
    private static final boolean DBG = false;

    public interface IntentCallback {
        public void run(Intent intent);
    }

    private final String mTag;
    private final Context mContext;
    private final Handler mHandler;
    private final IntentFilter mFilter;
    private final Consumer<Intent> mCallback;
    private final AtomicInteger mGenerationNumber;
    private BroadcastReceiver mReceiver;

    public VersionedBroadcastListener(String tag, Context ctx, Handler handler,
            IntentFilter filter, Consumer<Intent> callback) {
        mTag = tag;
        mContext = ctx;
        mHandler = handler;
        mFilter = filter;
        mCallback = callback;
        mGenerationNumber = new AtomicInteger(0);
    }

    public int generationNumber() {
        return mGenerationNumber.get();
    }

    public void startListening() {
        if (DBG) Log.d(mTag, "startListening");
        if (mReceiver != null) return;

        mReceiver = new Receiver(mTag, mGenerationNumber, mCallback);
        mContext.registerReceiver(mReceiver, mFilter, null, mHandler);
    }

    public void stopListening() {
        if (DBG) Log.d(mTag, "stopListening");
        if (mReceiver == null) return;

        mGenerationNumber.incrementAndGet();
        mContext.unregisterReceiver(mReceiver);
        mReceiver = null;
    }

    private static class Receiver extends BroadcastReceiver {
        public final String tag;
        public final AtomicInteger atomicGenerationNumber;
        public final Consumer<Intent> callback;
        // Used to verify this receiver is still current.
        public final int generationNumber;

        public Receiver(
                String tag, AtomicInteger atomicGenerationNumber, Consumer<Intent> callback) {
            this.tag = tag;
            this.atomicGenerationNumber = atomicGenerationNumber;
            this.callback = callback;
            generationNumber = atomicGenerationNumber.incrementAndGet();
        }

        @Override
        public void onReceive(Context context, Intent intent) {
            final int currentGenerationNumber = atomicGenerationNumber.get();

            if (DBG) {
                Log.d(tag, "receiver generationNumber=" + generationNumber +
                        ", current generationNumber=" + currentGenerationNumber);
            }
            if (generationNumber != currentGenerationNumber) return;

            callback.accept(intent);
        }
    }
}
+131 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.net.util;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.reset;

import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;

import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;

import com.android.internal.util.test.BroadcastInterceptingContext;

import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;


@RunWith(AndroidJUnit4.class)
@SmallTest
public class VersionedBroadcastListenerTest {
    private static final String TAG = VersionedBroadcastListenerTest.class.getSimpleName();
    private static final String ACTION_TEST = "action.test.happy.broadcasts";

    @Mock private Context mContext;
    private BroadcastInterceptingContext mServiceContext;
    private Handler mHandler;
    private VersionedBroadcastListener mListener;
    private int mCallbackCount;

    private void doCallback() { mCallbackCount++; }

    private class MockContext extends BroadcastInterceptingContext {
        MockContext(Context base) {
            super(base);
        }
    }

    @BeforeClass
    public static void setUpBeforeClass() throws Exception {
        if (Looper.myLooper() == null) {
            Looper.prepare();
        }
    }

    @Before public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        reset(mContext);
        mServiceContext = new MockContext(mContext);
        mHandler = new Handler(Looper.myLooper());
        mCallbackCount = 0;
        final IntentFilter filter = new IntentFilter();
        filter.addAction(ACTION_TEST);
        mListener = new VersionedBroadcastListener(
                TAG, mServiceContext, mHandler, filter, (Intent intent) -> doCallback());
    }

    @After public void tearDown() throws Exception {
        if (mListener != null) {
            mListener.stopListening();
            mListener = null;
        }
    }

    private void sendBroadcast() {
        final Intent intent = new Intent(ACTION_TEST);
        mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
    }

    @Test
    public void testBasicListening() {
        assertEquals(0, mCallbackCount);
        mListener.startListening();
        for (int i = 0; i < 5; i++) {
            sendBroadcast();
            assertEquals(i+1, mCallbackCount);
        }
        mListener.stopListening();
    }

    @Test
    public void testBroadcastsBeforeStartAreIgnored() {
        assertEquals(0, mCallbackCount);
        for (int i = 0; i < 5; i++) {
            sendBroadcast();
            assertEquals(0, mCallbackCount);
        }

        mListener.startListening();
        sendBroadcast();
        assertEquals(1, mCallbackCount);
    }

    @Test
    public void testBroadcastsAfterStopAreIgnored() {
        mListener.startListening();
        sendBroadcast();
        assertEquals(1, mCallbackCount);
        mListener.stopListening();

        for (int i = 0; i < 5; i++) {
            sendBroadcast();
            assertEquals(1, mCallbackCount);
        }
    }
}
+0 −2
Original line number Diff line number Diff line
@@ -48,8 +48,6 @@ import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class SimChangeListenerTest {
    private static final int EVENT_UNM_UPDATE = 1;

    @Mock private Context mContext;
    private BroadcastInterceptingContext mServiceContext;
    private Handler mHandler;