Implement cellular cipher transparency APIs
This commit provides the service-side implementation to support
null cipher notifications exposed through the TelephonyManager APIs.
Bug: 316592273
Test: atest android.telephony.cts.TelephonyManagerTest
Change-Id: Ib8e12b642c68f6de1f54bed29b862e08307f6d95
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 8f3281c..29c0642 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -403,6 +403,8 @@
private static final int MIN_NULL_CIPHER_AND_INTEGRITY_VERSION = 201;
// Cellular identifier disclosure transparency was added in IRadioNetwork 2.2
private static final int MIN_IDENTIFIER_DISCLOSURE_VERSION = 202;
+ // Null cipher notification support was added in IRadioNetwork 2.2
+ private static final int MIN_NULL_CIPHER_NOTIFICATION_VERSION = 202;
/** The singleton instance. */
private static PhoneInterfaceManager sInstance;
@@ -12022,6 +12024,17 @@
}
}
+ private void checkForNullCipherNotificationSupport() {
+ if (getHalVersion(HAL_SERVICE_NETWORK) < MIN_NULL_CIPHER_NOTIFICATION_VERSION) {
+ throw new UnsupportedOperationException(
+ "Null cipher notification operations require HAL 2.2 or above");
+ }
+ if (!getDefaultPhone().isNullCipherNotificationSupported()) {
+ throw new UnsupportedOperationException(
+ "Null cipher notification operations unsupported by modem");
+ }
+ }
+
/**
* Get the SIM state for the slot index.
* For Remote-SIMs, this method returns {@link IccCardConstants.State#UNKNOWN}
@@ -12901,6 +12914,49 @@
}
/**
+ * Enables or disables notifications sent when cellular null cipher or integrity algorithms
+ * are in use by the cellular modem.
+ *
+ * @throws IllegalStateException if the Telephony process is not currently available
+ * @throws SecurityException if the caller does not have the required privileges
+ * @throws UnsupportedOperationException if the modem does not support reporting on ciphering
+ * and integrity algorithms in use
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+ public void setEnableNullCipherNotifications(boolean enable) {
+ enforceModifyPermission();
+ checkForNullCipherNotificationSupport();
+
+ SharedPreferences.Editor editor = mTelephonySharedPreferences.edit();
+ editor.putBoolean(Phone.PREF_NULL_CIPHER_NOTIFICATIONS_ENABLED, enable);
+ editor.apply();
+
+ // Each phone instance is responsible for updating its respective modem immediately
+ // after a preference change.
+ for (Phone phone : PhoneFactory.getPhones()) {
+ phone.handleNullCipherNotificationPreferenceChanged();
+ }
+ }
+
+ /**
+ * Get whether notifications are enabled for null cipher or integrity algorithms in use by the
+ * cellular modem.
+ *
+ * @throws IllegalStateException if the Telephony process is not currently available
+ * @throws SecurityException if the caller does not have the required privileges
+ * @throws UnsupportedOperationException if the modem does not support reporting on ciphering
+ * and integrity algorithms in use
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public boolean isNullCipherNotificationsEnabled() {
+ enforceReadPrivilegedPermission("isNullCipherNotificationsEnabled");
+ checkForNullCipherNotificationSupport();
+ return getDefaultPhone().getNullCipherNotificationsPreferenceEnabled();
+ }
+
+ /**
* Check whether the caller (or self, if not processing an IPC) can read device identifiers.
*
* <p>This method behaves in one of the following ways:
diff --git a/tests/src/com/android/phone/PhoneInterfaceManagerTest.java b/tests/src/com/android/phone/PhoneInterfaceManagerTest.java
index 150703d..f5c2a6f 100644
--- a/tests/src/com/android/phone/PhoneInterfaceManagerTest.java
+++ b/tests/src/com/android/phone/PhoneInterfaceManagerTest.java
@@ -92,6 +92,7 @@
TelephonyManager.setupISubForTest(mSubscriptionManagerService);
mSharedPreferences = mPhoneInterfaceManager.getSharedPreferences();
mSharedPreferences.edit().remove(Phone.PREF_NULL_CIPHER_AND_INTEGRITY_ENABLED).commit();
+ mSharedPreferences.edit().remove(Phone.PREF_NULL_CIPHER_NOTIFICATIONS_ENABLED).commit();
mIIntegerConsumer = mock(IIntegerConsumer.class);
}
@@ -269,6 +270,108 @@
mPhoneInterfaceManager).getDefaultPhone();
}
+ @Test
+ public void setEnableNullCipherNotifications_allReqsMet_successfullyEnabled() {
+ setModemSupportsNullCipherNotification(true);
+ doNothing().when(mPhoneInterfaceManager).enforceModifyPermission();
+ doReturn(202).when(mPhoneInterfaceManager).getHalVersion(anyInt());
+ assertFalse(mSharedPreferences.contains(Phone.PREF_NULL_CIPHER_NOTIFICATIONS_ENABLED));
+
+ mPhoneInterfaceManager.setEnableNullCipherNotifications(true);
+
+ assertTrue(
+ mSharedPreferences.getBoolean(Phone.PREF_NULL_CIPHER_NOTIFICATIONS_ENABLED, false));
+ }
+
+ @Test
+ public void setEnableNullCipherNotifications_allReqsMet_successfullyDisabled() {
+ setModemSupportsNullCipherNotification(true);
+ doNothing().when(mPhoneInterfaceManager).enforceModifyPermission();
+ doReturn(202).when(mPhoneInterfaceManager).getHalVersion(anyInt());
+ assertFalse(mSharedPreferences.contains(Phone.PREF_NULL_CIPHER_NOTIFICATIONS_ENABLED));
+
+ mPhoneInterfaceManager.setEnableNullCipherNotifications(false);
+
+ assertFalse(
+ mSharedPreferences.getBoolean(Phone.PREF_NULL_CIPHER_NOTIFICATIONS_ENABLED, true));
+ }
+
+ @Test
+ public void setEnableNullCipherNotifications_lackingNecessaryHal_throwsException() {
+ setModemSupportsNullCipherNotification(true);
+ doNothing().when(mPhoneInterfaceManager).enforceModifyPermission();
+ doReturn(102).when(mPhoneInterfaceManager).getHalVersion(anyInt());
+
+ assertThrows(UnsupportedOperationException.class,
+ () -> mPhoneInterfaceManager.setEnableNullCipherNotifications(true));
+ }
+
+ @Test
+ public void setEnableNullCipherNotifications_lackingModemSupport_throwsException() {
+ setModemSupportsNullCipherNotification(false);
+ doNothing().when(mPhoneInterfaceManager).enforceModifyPermission();
+ doReturn(202).when(mPhoneInterfaceManager).getHalVersion(anyInt());
+
+ assertThrows(UnsupportedOperationException.class,
+ () -> mPhoneInterfaceManager.setEnableNullCipherNotifications(true));
+ }
+
+ @Test
+ public void setEnableNullCipherNotifications_lackingPermissions_throwsException() {
+ setModemSupportsNullCipherNotification(true);
+ doReturn(202).when(mPhoneInterfaceManager).getHalVersion(anyInt());
+ doThrow(SecurityException.class).when(mPhoneInterfaceManager).enforceModifyPermission();
+
+ assertThrows(SecurityException.class, () ->
+ mPhoneInterfaceManager.setEnableNullCipherNotifications(true));
+ }
+
+ @Test
+ public void isNullCipherNotificationsEnabled_allReqsMet_returnsTrue() {
+ setModemSupportsNullCipherNotification(true);
+ doReturn(202).when(mPhoneInterfaceManager).getHalVersion(anyInt());
+ doNothing().when(mPhoneInterfaceManager).enforceReadPrivilegedPermission(anyString());
+ doReturn(true).when(mPhone).getNullCipherNotificationsPreferenceEnabled();
+
+ assertTrue(mPhoneInterfaceManager.isNullCipherNotificationsEnabled());
+ }
+
+ @Test
+ public void isNullCipherNotificationsEnabled_lackingNecessaryHal_throwsException() {
+ setModemSupportsNullCipherNotification(true);
+ doReturn(102).when(mPhoneInterfaceManager).getHalVersion(anyInt());
+ doNothing().when(mPhoneInterfaceManager).enforceReadPrivilegedPermission(anyString());
+
+ assertThrows(UnsupportedOperationException.class, () ->
+ mPhoneInterfaceManager.isNullCipherNotificationsEnabled());
+ }
+
+ @Test
+ public void isNullCipherNotificationsEnabled_lackingModemSupport_throwsException() {
+ setModemSupportsNullCipherNotification(false);
+ doReturn(202).when(mPhoneInterfaceManager).getHalVersion(anyInt());
+ doNothing().when(mPhoneInterfaceManager).enforceReadPrivilegedPermission(anyString());
+
+ assertThrows(UnsupportedOperationException.class, () ->
+ mPhoneInterfaceManager.isNullCipherNotificationsEnabled());
+ }
+
+ @Test
+ public void isNullCipherNotificationsEnabled_lackingPermissions_throwsException() {
+ setModemSupportsNullCipherNotification(true);
+ doReturn(202).when(mPhoneInterfaceManager).getHalVersion(anyInt());
+ doThrow(SecurityException.class).when(
+ mPhoneInterfaceManager).enforceReadPrivilegedPermission(anyString());
+
+ assertThrows(SecurityException.class, () ->
+ mPhoneInterfaceManager.isNullCipherNotificationsEnabled());
+ }
+
+ private void setModemSupportsNullCipherNotification(boolean enable) {
+ doReturn(enable).when(mPhone).isNullCipherNotificationSupported();
+ doReturn(mPhone).when(mPhoneInterfaceManager).getDefaultPhone();
+ }
+
/**
* Verify getCarrierRestrictionStatus throws exception for invalid caller package name.
*/