Fix synchronization in SystemStateHelper
Properly acquire the big telecom lock before doing anything after
receiving a broadcast.
Bug: 181057509
Test: atest CarModeInCallServiceTest
Change-Id: Ie4c2311278c7c27560c16c87d1eeed282470f9e8
diff --git a/src/com/android/server/telecom/SystemStateHelper.java b/src/com/android/server/telecom/SystemStateHelper.java
index 8fb6bc5..0c14d5e 100644
--- a/src/com/android/server/telecom/SystemStateHelper.java
+++ b/src/com/android/server/telecom/SystemStateHelper.java
@@ -77,35 +77,39 @@
public void onReceive(Context context, Intent intent) {
Log.startSession("SSP.oR");
try {
- String action = intent.getAction();
- if (UiModeManager.ACTION_ENTER_CAR_MODE_PRIORITIZED.equals(action)) {
- int priority = intent.getIntExtra(UiModeManager.EXTRA_PRIORITY,
- UiModeManager.DEFAULT_PRIORITY);
- String callingPackage = intent.getStringExtra(
- UiModeManager.EXTRA_CALLING_PACKAGE);
- Log.i(SystemStateHelper.this, "ENTER_CAR_MODE_PRIORITIZED; priority=%d, pkg=%s",
- priority, callingPackage);
- onEnterCarMode(priority, callingPackage);
- } else if (UiModeManager.ACTION_EXIT_CAR_MODE_PRIORITIZED.equals(action)) {
- int priority = intent.getIntExtra(UiModeManager.EXTRA_PRIORITY,
- UiModeManager.DEFAULT_PRIORITY);
- String callingPackage = intent.getStringExtra(
- UiModeManager.EXTRA_CALLING_PACKAGE);
- Log.i(SystemStateHelper.this, "EXIT_CAR_MODE_PRIORITIZED; priority=%d, pkg=%s",
- priority, callingPackage);
- onExitCarMode(priority, callingPackage);
- } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
- Uri data = intent.getData();
- if (data == null) {
+ synchronized (mLock) {
+ String action = intent.getAction();
+ if (UiModeManager.ACTION_ENTER_CAR_MODE_PRIORITIZED.equals(action)) {
+ int priority = intent.getIntExtra(UiModeManager.EXTRA_PRIORITY,
+ UiModeManager.DEFAULT_PRIORITY);
+ String callingPackage = intent.getStringExtra(
+ UiModeManager.EXTRA_CALLING_PACKAGE);
+ Log.i(SystemStateHelper.this,
+ "ENTER_CAR_MODE_PRIORITIZED; priority=%d, pkg=%s",
+ priority, callingPackage);
+ onEnterCarMode(priority, callingPackage);
+ } else if (UiModeManager.ACTION_EXIT_CAR_MODE_PRIORITIZED.equals(action)) {
+ int priority = intent.getIntExtra(UiModeManager.EXTRA_PRIORITY,
+ UiModeManager.DEFAULT_PRIORITY);
+ String callingPackage = intent.getStringExtra(
+ UiModeManager.EXTRA_CALLING_PACKAGE);
+ Log.i(SystemStateHelper.this,
+ "EXIT_CAR_MODE_PRIORITIZED; priority=%d, pkg=%s",
+ priority, callingPackage);
+ onExitCarMode(priority, callingPackage);
+ } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+ Uri data = intent.getData();
+ if (data == null) {
+ Log.w(SystemStateHelper.this,
+ "Got null data for package removed, ignoring");
+ return;
+ }
+ mListeners.forEach(
+ l -> l.onPackageUninstalled(data.getEncodedSchemeSpecificPart()));
+ } else {
Log.w(SystemStateHelper.this,
- "Got null data for package removed, ignoring");
- return;
+ "Unexpected intent received: %s", intent.getAction());
}
- mListeners.forEach(
- l -> l.onPackageUninstalled(data.getEncodedSchemeSpecificPart()));
- } else {
- Log.w(SystemStateHelper.this,
- "Unexpected intent received: %s", intent.getAction());
}
} finally {
Log.endSession();
@@ -125,9 +129,11 @@
private Set<SystemStateListener> mListeners = new CopyOnWriteArraySet<>();
private boolean mIsCarModeOrProjectionActive;
+ private final TelecomSystem.SyncRoot mLock;
- public SystemStateHelper(Context context) {
+ public SystemStateHelper(Context context, TelecomSystem.SyncRoot lock) {
mContext = context;
+ mLock = lock;
IntentFilter intentFilter1 = new IntentFilter(
UiModeManager.ACTION_ENTER_CAR_MODE_PRIORITIZED);
diff --git a/src/com/android/server/telecom/TelecomSystem.java b/src/com/android/server/telecom/TelecomSystem.java
index 8928e76..112390e 100644
--- a/src/com/android/server/telecom/TelecomSystem.java
+++ b/src/com/android/server/telecom/TelecomSystem.java
@@ -233,7 +233,7 @@
mContext.registerReceiver(bluetoothStateReceiver, BluetoothStateReceiver.INTENT_FILTER);
WiredHeadsetManager wiredHeadsetManager = new WiredHeadsetManager(mContext);
- SystemStateHelper systemStateHelper = new SystemStateHelper(mContext);
+ SystemStateHelper systemStateHelper = new SystemStateHelper(mContext, mLock);
mMissedCallNotifier = missedCallNotifierImplFactory
.makeMissedCallNotifierImpl(mContext, mPhoneAccountRegistrar, defaultDialerCache,
diff --git a/tests/src/com/android/server/telecom/tests/SystemStateHelperTest.java b/tests/src/com/android/server/telecom/tests/SystemStateHelperTest.java
index ad52625..94b8463 100644
--- a/tests/src/com/android/server/telecom/tests/SystemStateHelperTest.java
+++ b/tests/src/com/android/server/telecom/tests/SystemStateHelperTest.java
@@ -48,6 +48,7 @@
import com.android.server.telecom.SystemStateHelper;
import com.android.server.telecom.SystemStateHelper.SystemStateListener;
+import com.android.server.telecom.TelecomSystem;
import org.junit.After;
import org.junit.Before;
@@ -78,6 +79,7 @@
@Mock SensorManager mSensorManager;
@Mock Intent mIntentEnter;
@Mock Intent mIntentExit;
+ TelecomSystem.SyncRoot mLock = new TelecomSystem.SyncRoot() { };
@Override
@Before
@@ -109,7 +111,7 @@
@SmallTest
@Test
public void testListeners() throws Exception {
- SystemStateHelper systemStateHelper = new SystemStateHelper(mContext);
+ SystemStateHelper systemStateHelper = new SystemStateHelper(mContext, mLock);
assertFalse(systemStateHelper.removeListener(mSystemStateListener));
systemStateHelper.addListener(mSystemStateListener);
@@ -121,14 +123,14 @@
@Test
public void testQuerySystemForCarMode_True() {
when(mUiModeManager.getCurrentModeType()).thenReturn(Configuration.UI_MODE_TYPE_CAR);
- assertTrue(new SystemStateHelper(mContext).isCarModeOrProjectionActive());
+ assertTrue(new SystemStateHelper(mContext, mLock).isCarModeOrProjectionActive());
}
@SmallTest
@Test
public void testQuerySystemForCarMode_False() {
when(mUiModeManager.getCurrentModeType()).thenReturn(Configuration.UI_MODE_TYPE_NORMAL);
- assertFalse(new SystemStateHelper(mContext).isCarModeOrProjectionActive());
+ assertFalse(new SystemStateHelper(mContext, mLock).isCarModeOrProjectionActive());
}
@SmallTest
@@ -136,11 +138,11 @@
public void testQuerySystemForAutomotiveProjection_True() {
when(mUiModeManager.getActiveProjectionTypes())
.thenReturn(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE);
- assertTrue(new SystemStateHelper(mContext).isCarModeOrProjectionActive());
+ assertTrue(new SystemStateHelper(mContext, mLock).isCarModeOrProjectionActive());
when(mUiModeManager.getActiveProjectionTypes())
.thenReturn(UiModeManager.PROJECTION_TYPE_ALL);
- assertTrue(new SystemStateHelper(mContext).isCarModeOrProjectionActive());
+ assertTrue(new SystemStateHelper(mContext, mLock).isCarModeOrProjectionActive());
}
@SmallTest
@@ -148,7 +150,7 @@
public void testQuerySystemForAutomotiveProjection_False() {
when(mUiModeManager.getActiveProjectionTypes())
.thenReturn(UiModeManager.PROJECTION_TYPE_NONE);
- assertFalse(new SystemStateHelper(mContext).isCarModeOrProjectionActive());
+ assertFalse(new SystemStateHelper(mContext, mLock).isCarModeOrProjectionActive());
}
@SmallTest
@@ -157,7 +159,7 @@
when(mUiModeManager.getCurrentModeType()).thenReturn(Configuration.UI_MODE_TYPE_CAR);
when(mUiModeManager.getActiveProjectionTypes())
.thenReturn(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE);
- assertTrue(new SystemStateHelper(mContext).isCarModeOrProjectionActive());
+ assertTrue(new SystemStateHelper(mContext, mLock).isCarModeOrProjectionActive());
}
@SmallTest
@@ -166,7 +168,7 @@
when(mContext.getSystemService(UiModeManager.class))
.thenReturn(mUiModeManager) // Without this, class construction will throw NPE.
.thenReturn(null);
- assertFalse(new SystemStateHelper(mContext).isCarModeOrProjectionActive());
+ assertFalse(new SystemStateHelper(mContext, mLock).isCarModeOrProjectionActive());
}
@SmallTest
@@ -174,7 +176,7 @@
public void testPackageRemoved() {
ArgumentCaptor<BroadcastReceiver> receiver =
ArgumentCaptor.forClass(BroadcastReceiver.class);
- new SystemStateHelper(mContext).addListener(mSystemStateListener);
+ new SystemStateHelper(mContext, mLock).addListener(mSystemStateListener);
verify(mContext, atLeastOnce())
.registerReceiver(receiver.capture(), any(IntentFilter.class));
Intent packageRemovedIntent = new Intent(Intent.ACTION_PACKAGE_REMOVED);
@@ -188,7 +190,7 @@
public void testReceiverAndIntentFilter() {
ArgumentCaptor<IntentFilter> intentFilterCaptor =
ArgumentCaptor.forClass(IntentFilter.class);
- new SystemStateHelper(mContext);
+ new SystemStateHelper(mContext, mLock);
verify(mContext, times(2)).registerReceiver(
any(BroadcastReceiver.class), intentFilterCaptor.capture());
@@ -225,7 +227,7 @@
public void testOnEnterExitCarMode() {
ArgumentCaptor<BroadcastReceiver> receiver =
ArgumentCaptor.forClass(BroadcastReceiver.class);
- new SystemStateHelper(mContext).addListener(mSystemStateListener);
+ new SystemStateHelper(mContext, mLock).addListener(mSystemStateListener);
verify(mContext, atLeastOnce())
.registerReceiver(receiver.capture(), any(IntentFilter.class));
@@ -244,7 +246,7 @@
@SmallTest
@Test
public void testOnSetReleaseAutomotiveProjection() {
- SystemStateHelper systemStateHelper = new SystemStateHelper(mContext);
+ SystemStateHelper systemStateHelper = new SystemStateHelper(mContext, mLock);
// We don't care what listener is registered, that's an implementation detail, but we need
// to call methods on whatever it is.
ArgumentCaptor<UiModeManager.OnProjectionStateChangeListener> listenerCaptor =