From 45066127b3c0d1a53b8dc237cde2b05acf7379e8 Mon Sep 17 00:00:00 2001 From: Hall Liu Date: Tue, 7 Apr 2020 15:37:44 -0700 Subject: [PATCH] Convert Telephony broadcasts to be non-sticky Convert ACTION_SERVICE_STATE_CHANGED and ACTION_ANY_DATA_CONNECTION_CHANGED to be non-sticky broadcasts that require the READ_PHONE_STATE permission to receive. As part of this, declare READ_PHONE_STATE to be split from READ_PRIVILEGED_PHONE_STATE, so that system apps holding READ_PRIVILEGED_PHONE_STATE can also receive these broadcasts. Also modify affected users to fetch the current value of the broadcast upon registration instead of relying on the sticky nature of the broadcast. Bug: 150155839 Test: manual Test: atest KeyguardUpdateMonitorTest Change-Id: I020b1554c4fc59c138d015e787526b4a66c74853 --- data/etc/platform.xml | 3 +++ .../keyguard/KeyguardUpdateMonitor.java | 9 +++++++ .../policy/NetworkControllerImpl.java | 15 +++++++++++- .../keyguard/KeyguardUpdateMonitorTest.java | 16 +++++++++++-- .../policy/NetworkControllerSignalTest.java | 24 +++++++++++++++++++ .../com/android/server/TelephonyRegistry.java | 5 ++-- .../DefaultPermissionGrantPolicy.java | 19 +++++++++++++++ 7 files changed, 86 insertions(+), 5 deletions(-) diff --git a/data/etc/platform.xml b/data/etc/platform.xml index 6af887d401f6b..9cd7cc6aedcf7 100644 --- a/data/etc/platform.xml +++ b/data/etc/platform.xml @@ -197,6 +197,9 @@ + + + diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index a96ef91850dff..b37400f691ae3 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -1664,6 +1664,15 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); mBroadcastDispatcher.registerReceiverWithHandler(mBroadcastReceiver, filter, mHandler); + // Since ACTION_SERVICE_STATE is being moved to a non-sticky broadcast, trigger the + // listener now with the service state from the default sub. + mBackgroundExecutor.execute(() -> { + int subId = SubscriptionManager.getDefaultSubscriptionId(); + ServiceState serviceState = mContext.getSystemService(TelephonyManager.class) + .getServiceStateForSubscriber(subId); + mHandler.sendMessage( + mHandler.obtainMessage(MSG_SERVICE_STATE_CHANGE, subId, 0, serviceState)); + }); mHandler.post(this::registerRingerTracker); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index a284335c972ea..f41a27cf4c647 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -329,7 +329,8 @@ public class NetworkControllerImpl extends BroadcastReceiver return mDataSaverController; } - private void registerListeners() { + @VisibleForTesting + void registerListeners() { for (int i = 0; i < mMobileSignalControllers.size(); i++) { MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i); mobileSignalController.registerListener(); @@ -364,6 +365,18 @@ public class NetworkControllerImpl extends BroadcastReceiver // Initial setup of WifiSignalController. Handled as if we had received a sticky broadcast // of WifiManager.WIFI_STATE_CHANGED_ACTION or WifiManager.NETWORK_STATE_CHANGED_ACTION mReceiverHandler.post(mWifiSignalController::fetchInitialState); + + // Initial setup of mLastServiceState. Only run if there is no service state yet. + // Each MobileSignalController will also get their corresponding + mReceiverHandler.post(() -> { + if (mLastServiceState == null) { + mLastServiceState = mPhone.getServiceState(); + if (mMobileSignalControllers.size() == 0) { + recalculateEmergency(); + } + } + }); + updateMobileControllers(); // Initial setup of emergency information. Handled as if we had received a sticky broadcast diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index 6c00ecacf97de..c3106bb2e3f2e 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -70,6 +70,7 @@ import android.testing.TestableLooper; import androidx.lifecycle.LiveData; import androidx.lifecycle.Observer; +import com.android.dx.mockito.inline.extended.ExtendedMockito; import com.android.internal.telephony.TelephonyIntents; import com.android.keyguard.KeyguardUpdateMonitor.BiometricAuthenticated; import com.android.systemui.SysuiTestCase; @@ -87,6 +88,7 @@ import org.mockito.ArgumentCaptor; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.mockito.MockitoSession; import java.util.ArrayList; import java.util.List; @@ -134,16 +136,17 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { @Mock private BroadcastDispatcher mBroadcastDispatcher; @Mock + private TelephonyManager mTelephonyManager; + @Mock private RingerModeTracker mRingerModeTracker; @Mock private LiveData mRingerModeLiveData; - @Mock - private TelephonyManager mTelephonyManager; // Direct executor private Executor mBackgroundExecutor = Runnable::run; private TestableLooper mTestableLooper; private TestableKeyguardUpdateMonitor mKeyguardUpdateMonitor; private TestableContext mSpiedContext; + private MockitoSession mMockitoSession; @Before public void setup() { @@ -165,6 +168,9 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { when(mStrongAuthTracker .isUnlockingWithBiometricAllowed(anyBoolean() /* isStrongBiometric */)) .thenReturn(true); + + when(mTelephonyManager.getServiceStateForSubscriber(anyInt())) + .thenReturn(new ServiceState()); mSpiedContext.addMockSystemService(TrustManager.class, mTrustManager); mSpiedContext.addMockSystemService(FingerprintManager.class, mFingerprintManager); mSpiedContext.addMockSystemService(BiometricManager.class, mBiometricManager); @@ -176,6 +182,11 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { when(mRingerModeTracker.getRingerMode()).thenReturn(mRingerModeLiveData); + mMockitoSession = ExtendedMockito.mockitoSession() + .spyStatic(SubscriptionManager.class).startMocking(); + ExtendedMockito.doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID) + .when(SubscriptionManager::getDefaultSubscriptionId); + mTestableLooper = TestableLooper.get(this); allowTestableLooperAsMainThread(); mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mSpiedContext); @@ -183,6 +194,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { @After public void tearDown() { + mMockitoSession.finishMocking(); mKeyguardUpdateMonitor.destroy(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java index 399b5c24431b3..3b27437757211 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java @@ -25,6 +25,7 @@ import static org.mockito.Mockito.when; import android.content.Intent; import android.net.ConnectivityManager; import android.net.NetworkCapabilities; +import android.os.Handler; import android.os.Looper; import android.telephony.CellSignalStrength; import android.telephony.ServiceState; @@ -46,6 +47,7 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import java.util.ArrayList; +import java.util.Collections; import java.util.List; @SmallTest @@ -67,6 +69,28 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { verifyLastMobileDataIndicators(false, -1, 0); } + @Test + public void testServiceStateInitialState() throws Exception { + // Verify that NetworkControllerImpl pulls the service state from Telephony upon + // initialization rather than relying on the sticky behavior of ACTION_SERVICE_STATE + + when(mServiceState.isEmergencyOnly()).thenReturn(true); + when(mMockTm.getServiceState()).thenReturn(mServiceState); + when(mMockSm.getCompleteActiveSubscriptionInfoList()).thenReturn(Collections.emptyList()); + + mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, + mMockNsm, mMockSm, mConfig, Looper.getMainLooper(), mCallbackHandler, + mock(AccessPointControllerImpl.class), mock(DataUsageController.class), + mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd); + mNetworkController.registerListeners(); + + // Wait for the main looper to execute the previous command + Handler mainThreadHandler = new Handler(Looper.getMainLooper()); + waitForIdleSync(mainThreadHandler); + + verifyEmergencyOnly(true); + } + @Test public void testNoSimsIconPresent() { // No Subscriptions. diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index 97a5cfe6006d1..1d40e2ee92f4f 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -23,6 +23,7 @@ import static android.telephony.TelephonyRegistryManager.SIM_ACTIVATION_TYPE_VOI import static java.util.Arrays.copyOf; +import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; @@ -2459,7 +2460,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId); intent.putExtra(PHONE_CONSTANTS_SLOT_KEY, phoneId); intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, phoneId); - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); + mContext.sendBroadcastAsUser(intent, UserHandle.ALL, Manifest.permission.READ_PHONE_STATE); } private void broadcastSignalStrengthChanged(SignalStrength signalStrength, int phoneId, @@ -2584,7 +2585,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { intent.putExtra(PHONE_CONSTANTS_DATA_APN_TYPE_KEY, ApnSetting.getApnTypesStringFromBitmask(apnType)); intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId); - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); + mContext.sendBroadcastAsUser(intent, UserHandle.ALL, Manifest.permission.READ_PHONE_STATE); } private void enforceNotifyPermissionOrCarrierPrivilege(String method) { diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java index 9051d85b21402..8f3bf39d4fc53 100644 --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java @@ -408,6 +408,25 @@ public final class DefaultPermissionGrantPolicy { } grantRuntimePermissionsForSystemPackage(pm, userId, pkg); } + + // Grant READ_PHONE_STATE to all system apps that have READ_PRIVILEGED_PHONE_STATE + for (PackageInfo pkg : packages) { + if (pkg == null + || !doesPackageSupportRuntimePermissions(pkg) + || ArrayUtils.isEmpty(pkg.requestedPermissions) + || !pkg.applicationInfo.isPrivilegedApp()) { + continue; + } + for (String permission : pkg.requestedPermissions) { + if (Manifest.permission.READ_PRIVILEGED_PHONE_STATE.equals(permission)) { + grantRuntimePermissions(pm, pkg, + Collections.singleton(Manifest.permission.READ_PHONE_STATE), + true, // systemFixed + userId); + } + } + } + } @SafeVarargs