Merge "Fix ConcurrentModExc in TelephonyListenerManager" into sc-dev

This commit is contained in:
Dave Mankoff
2021-04-01 19:47:35 +00:00
committed by Android (Google) Code Review
7 changed files with 73 additions and 42 deletions

View File

@@ -59,6 +59,7 @@ import android.permission.PermissionManager;
import android.service.dreams.DreamService;
import android.service.dreams.IDreamManager;
import android.telecom.TelecomManager;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.view.IWindowManager;
import android.view.ViewConfiguration;
@@ -326,6 +327,12 @@ public class FrameworkServicesModule {
return context.getSystemService(StatsManager.class);
}
@Provides
@Singleton
static SubscriptionManager provideSubcriptionManager(Context context) {
return context.getSystemService(SubscriptionManager.class);
}
@Provides
@Singleton
@Nullable

View File

@@ -21,6 +21,7 @@ import android.os.Message;
import android.telephony.SubscriptionInfo;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
@@ -32,6 +33,8 @@ import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
/**
* Implements network listeners and forwards the calls along onto other listeners but on
@@ -60,12 +63,9 @@ public class CallbackHandler extends Handler implements EmergencyListener, Signa
private int mHistoryIndex;
private String mLastCallback;
public CallbackHandler() {
super(Looper.getMainLooper());
}
@Inject
@VisibleForTesting
CallbackHandler(Looper looper) {
CallbackHandler(@Main Looper looper) {
super(looper);
}

View File

@@ -85,6 +85,7 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.Executor;
import javax.inject.Inject;
@@ -171,6 +172,8 @@ public class NetworkControllerImpl extends BroadcastReceiver
private NetworkCapabilities mLastDefaultNetworkCapabilities;
// Handler that all broadcasts are received on.
private final Handler mReceiverHandler;
private final Looper mBgLooper;
private final Executor mBgExecutor;
// Handler that all callbacks are made on.
private final CallbackHandler mCallbackHandler;
@@ -198,6 +201,9 @@ public class NetworkControllerImpl extends BroadcastReceiver
public NetworkControllerImpl(
Context context,
@Background Looper bgLooper,
@Background Executor bgExecutor,
SubscriptionManager subscriptionManager,
CallbackHandler callbackHandler,
DeviceProvisionedController deviceProvisionedController,
BroadcastDispatcher broadcastDispatcher,
ConnectivityManager connectivityManager,
@@ -212,8 +218,11 @@ public class NetworkControllerImpl extends BroadcastReceiver
telephonyListenerManager,
wifiManager,
networkScoreManager,
SubscriptionManager.from(context), Config.readConfig(context), bgLooper,
new CallbackHandler(),
subscriptionManager,
Config.readConfig(context),
bgLooper,
bgExecutor,
callbackHandler,
accessPointController,
new DataUsageController(context),
new SubscriptionDefaults(),
@@ -230,6 +239,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
WifiManager wifiManager,
NetworkScoreManager networkScoreManager,
SubscriptionManager subManager, Config config, Looper bgLooper,
Executor bgExecutor,
CallbackHandler callbackHandler,
AccessPointControllerImpl accessPointController,
DataUsageController dataUsageController,
@@ -241,6 +251,8 @@ public class NetworkControllerImpl extends BroadcastReceiver
mTelephonyListenerManager = telephonyListenerManager;
mConfig = config;
mReceiverHandler = new Handler(bgLooper);
mBgLooper = bgLooper;
mBgExecutor = bgExecutor;
mCallbackHandler = callbackHandler;
mDataSaverController = new DataSaverControllerImpl(context);
mBroadcastDispatcher = broadcastDispatcher;
@@ -377,21 +389,23 @@ public class NetworkControllerImpl extends BroadcastReceiver
// TODO: Move off of the deprecated CONNECTIVITY_ACTION broadcast and rely on callbacks
// exclusively for status bar icons.
mConnectivityManager.registerDefaultNetworkCallback(callback, mReceiverHandler);
// Register the listener on our bg looper
// Run the listener on our bg looper
mPhoneStateListener = subId -> {
// For data switching from A to B, we assume B is validated for up to 2 seconds iff:
// 1) A and B are in the same subscription group e.g. CBRS data switch. And
// 2) A was validated before the switch.
// This is to provide smooth transition for UI without showing cross during data
// switch.
if (keepCellularValidationBitInSwitch(mActiveMobileDataSubscription, subId)) {
if (DEBUG) Log.d(TAG, ": mForceCellularValidated to true.");
mForceCellularValidated = true;
mReceiverHandler.removeCallbacks(mClearForceValidated);
mReceiverHandler.postDelayed(mClearForceValidated, 2000);
}
mActiveMobileDataSubscription = subId;
doUpdateMobileControllers();
mBgExecutor.execute(() -> {
// For data switching from A to B, we assume B is validated for up to 2 seconds if:
// 1) A and B are in the same subscription group e.g. CBRS data switch. And
// 2) A was validated before the switch.
// This is to provide smooth transition for UI without showing cross during data
// switch.
if (keepCellularValidationBitInSwitch(mActiveMobileDataSubscription, subId)) {
if (DEBUG) Log.d(TAG, ": mForceCellularValidated to true.");
mForceCellularValidated = true;
mReceiverHandler.removeCallbacks(mClearForceValidated);
mReceiverHandler.postDelayed(mClearForceValidated, 2000);
}
mActiveMobileDataSubscription = subId;
doUpdateMobileControllers();
});
};
mDemoModeController.addCallback(this);
@@ -428,7 +442,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
mobileSignalController.registerListener();
}
if (mSubscriptionListener == null) {
mSubscriptionListener = new SubListener();
mSubscriptionListener = new SubListener(mBgLooper);
}
mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionListener);
mTelephonyListenerManager.addActiveDataSubscriptionIdListener(mPhoneStateListener);
@@ -1336,6 +1350,10 @@ public class NetworkControllerImpl extends BroadcastReceiver
}
private class SubListener extends OnSubscriptionsChangedListener {
SubListener(Looper looper) {
super(looper);
}
@Override
public void onSubscriptionsChanged() {
updateMobileControllers();
@@ -1346,10 +1364,5 @@ public class NetworkControllerImpl extends BroadcastReceiver
* Used to register listeners from the BG Looper, this way the PhoneStateListeners that
* get created will also run on the BG Looper.
*/
private final Runnable mRegisterListeners = new Runnable() {
@Override
public void run() {
registerListeners();
}
};
private final Runnable mRegisterListeners = () -> registerListeners();
}

View File

@@ -54,9 +54,11 @@ class TelephonyCallback extends android.telephony.TelephonyCallback
@Override
public void onActiveDataSubscriptionIdChanged(int subId) {
mActiveDataSubscriptionIdListeners.forEach(listener -> {
listener.onActiveDataSubscriptionIdChanged(subId);
});
List<ActiveDataSubscriptionIdListener> listeners;
synchronized (mActiveDataSubscriptionIdListeners) {
listeners = new ArrayList<>(mActiveDataSubscriptionIdListeners);
}
listeners.forEach(listener -> listener.onActiveDataSubscriptionIdChanged(subId));
}
void addActiveDataSubscriptionIdListener(ActiveDataSubscriptionIdListener listener) {
@@ -69,9 +71,11 @@ class TelephonyCallback extends android.telephony.TelephonyCallback
@Override
public void onCallStateChanged(int state) {
mCallStateListeners.forEach(listener -> {
listener.onCallStateChanged(state);
});
List<CallStateListener> listeners;
synchronized (mCallStateListeners) {
listeners = new ArrayList<>(mCallStateListeners);
}
listeners.forEach(listener -> listener.onCallStateChanged(state));
}
void addCallStateListener(CallStateListener listener) {
@@ -84,9 +88,11 @@ class TelephonyCallback extends android.telephony.TelephonyCallback
@Override
public void onServiceStateChanged(@NonNull ServiceState serviceState) {
mServiceStateListeners.forEach(listener -> {
listener.onServiceStateChanged(serviceState);
});
List<ServiceStateListener> listeners;
synchronized (mServiceStateListeners) {
listeners = new ArrayList<>(mServiceStateListeners);
}
listeners.forEach(listener -> listener.onServiceStateChanged(serviceState));
}
void addServiceStateListener(ServiceStateListener listener) {

View File

@@ -77,6 +77,8 @@ import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
import com.android.systemui.telephony.TelephonyListenerManager;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
import org.junit.After;
import org.junit.Before;
@@ -123,6 +125,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase {
protected DeviceProvisionedListener mUserCallback;
protected Instrumentation mInstrumentation;
protected DemoModeController mDemoModeController;
protected FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
protected int mSubId;
@@ -222,6 +225,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase {
mMockSm,
mConfig,
TestableLooper.get(this).getLooper(),
mFakeExecutor,
mCallbackHandler,
mock(AccessPointControllerImpl.class),
mock(DataUsageController.class),
@@ -291,7 +295,8 @@ public class NetworkControllerBaseTest extends SysuiTestCase {
NetworkControllerImpl networkControllerNoMobile =
new NetworkControllerImpl(mContext, mMockCm, mMockTm, mTelephonyListenerManager,
mMockWm, mMockNsm, mMockSm,
mConfig, TestableLooper.get(this).getLooper(), mCallbackHandler,
mConfig, TestableLooper.get(this).getLooper(), mFakeExecutor,
mCallbackHandler,
mock(AccessPointControllerImpl.class),
mock(DataUsageController.class), mMockSubDefaults,
mock(DeviceProvisionedController.class), mMockBd, mDemoModeController);

View File

@@ -108,7 +108,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest {
mConfig.show4gForLte = true;
mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm,
mTelephonyListenerManager, mMockWm,
mMockNsm, mMockSm, mConfig, Looper.getMainLooper(), mCallbackHandler,
mMockNsm, mMockSm, mConfig, Looper.getMainLooper(), mFakeExecutor, mCallbackHandler,
mock(AccessPointControllerImpl.class),
mock(DataUsageController.class), mMockSubDefaults,
mock(DeviceProvisionedController.class), mMockBd, mDemoModeController);

View File

@@ -63,7 +63,7 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest {
// Create a new NetworkController as this is currently handled in constructor.
mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm,
mTelephonyListenerManager, mMockWm, mMockNsm, mMockSm, mConfig,
Looper.getMainLooper(), mCallbackHandler,
Looper.getMainLooper(), mFakeExecutor, mCallbackHandler,
mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd,
mDemoModeController);
@@ -83,7 +83,7 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest {
mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm,
mTelephonyListenerManager, mMockWm, mMockNsm, mMockSm, mConfig,
Looper.getMainLooper(), mCallbackHandler,
Looper.getMainLooper(), mFakeExecutor, mCallbackHandler,
mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd,
mDemoModeController);
@@ -151,7 +151,7 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest {
// Create a new NetworkController as this is currently handled in constructor.
mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm,
mTelephonyListenerManager, mMockWm, mMockNsm, mMockSm, mConfig,
Looper.getMainLooper(), mCallbackHandler,
Looper.getMainLooper(), mFakeExecutor, mCallbackHandler,
mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd,
mDemoModeController);