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

Commit c21effd5 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Switch to listening for CarrierConfig changes for provisioning rechecks"

parents 65d1e549 de63772e
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;