Merge "Update UT cases for CarrierAppUtils" into main
diff --git a/src/java/com/android/internal/telephony/CarrierInfoManager.java b/src/java/com/android/internal/telephony/CarrierInfoManager.java
index 863db93..8364c0a 100644
--- a/src/java/com/android/internal/telephony/CarrierInfoManager.java
+++ b/src/java/com/android/internal/telephony/CarrierInfoManager.java
@@ -33,6 +33,7 @@
import android.util.Log;
import android.util.Pair;
+import com.android.internal.telephony.flags.Flags;
import com.android.internal.telephony.metrics.TelephonyMetrics;
import java.security.PublicKey;
@@ -297,7 +298,12 @@
final TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class)
.createForSubscriptionId(subId);
int carrierId = telephonyManager.getSimCarrierId();
- deleteCarrierInfoForImsiEncryption(context, subId, carrierId);
+ if (Flags.imsiKeyRetryDownloadOnPhoneUnlock()) {
+ String simOperator = telephonyManager.getSimOperator();
+ deleteCarrierInfoForImsiEncryption(context, subId, carrierId, simOperator);
+ } else {
+ deleteCarrierInfoForImsiEncryption(context, subId, carrierId);
+ }
Intent resetIntent = new Intent(TelephonyIntents.ACTION_CARRIER_CERTIFICATE_DOWNLOAD);
SubscriptionManager.putPhoneIdAndSubIdExtra(resetIntent, mPhoneId);
context.sendBroadcastAsUser(resetIntent, UserHandle.ALL);
@@ -312,13 +318,29 @@
*/
public static void deleteCarrierInfoForImsiEncryption(Context context, int subId,
int carrierId) {
+ deleteCarrierInfoForImsiEncryption(context, subId, carrierId, null);
+ }
+
+ /**
+ * Deletes all the keys for a given Carrier from the device keystore.
+ * @param context Context
+ * @param subId SubscriptionId
+ * @param carrierId delete the key which matches the carrierId
+ * @param simOperator delete the key which matches the MCCMNC
+ *
+ */
+ public static void deleteCarrierInfoForImsiEncryption(Context context, int subId,
+ int carrierId, String simOperator) {
Log.i(LOG_TAG, "deleting carrier key from db for subId=" + subId);
String mcc = "";
String mnc = "";
- final TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class)
- .createForSubscriptionId(subId);
- String simOperator = telephonyManager.getSimOperator();
+ if (TextUtils.isEmpty(simOperator)) {
+ final TelephonyManager telephonyManager = context.getSystemService(
+ TelephonyManager.class)
+ .createForSubscriptionId(subId);
+ simOperator = telephonyManager.getSimOperator();
+ }
if (!TextUtils.isEmpty(simOperator)) {
mcc = simOperator.substring(0, 3);
mnc = simOperator.substring(3);
diff --git a/src/java/com/android/internal/telephony/CarrierKeyDownloadManager.java b/src/java/com/android/internal/telephony/CarrierKeyDownloadManager.java
index 9143f21..10a3a32 100644
--- a/src/java/com/android/internal/telephony/CarrierKeyDownloadManager.java
+++ b/src/java/com/android/internal/telephony/CarrierKeyDownloadManager.java
@@ -18,6 +18,7 @@
import static java.nio.charset.StandardCharsets.UTF_8;
+import android.annotation.NonNull;
import android.app.AlarmManager;
import android.app.DownloadManager;
import android.app.KeyguardManager;
@@ -27,6 +28,8 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
+import android.net.ConnectivityManager;
+import android.net.Network;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
@@ -34,19 +37,22 @@
import android.os.UserManager;
import android.telephony.CarrierConfigManager;
import android.telephony.ImsiEncryptionInfo;
+import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
+
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.flags.FeatureFlags;
+import com.android.internal.telephony.flags.Flags;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
+
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
@@ -57,6 +63,7 @@
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Date;
+import java.util.List;
import java.util.Random;
import java.util.zip.GZIPInputStream;
import java.util.zip.ZipException;
@@ -99,6 +106,8 @@
private static final int EVENT_ALARM_OR_CONFIG_CHANGE = 0;
private static final int EVENT_DOWNLOAD_COMPLETE = 1;
+ private static final int EVENT_NETWORK_AVAILABLE = 2;
+ private static final int EVENT_SCREEN_UNLOCKED = 3;
private static final int[] CARRIER_KEY_TYPES = {TelephonyManager.KEY_TYPE_EPDG,
@@ -111,47 +120,77 @@
private boolean mAllowedOverMeteredNetwork = false;
private boolean mDeleteOldKeyAfterDownload = false;
private boolean mIsRequiredToHandleUnlock;
- private TelephonyManager mTelephonyManager;
+ private final TelephonyManager mTelephonyManager;
private UserManager mUserManager;
-
@VisibleForTesting
- public String mMccMncForDownload;
- public int mCarrierId;
+ public String mMccMncForDownload = "";
+ public int mCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
@VisibleForTesting
public long mDownloadId;
- private final FeatureFlags mFeatureFlags;
+ private DefaultNetworkCallback mDefaultNetworkCallback;
+ private ConnectivityManager mConnectivityManager;
+ private KeyguardManager mKeyguardManager;
- public CarrierKeyDownloadManager(Phone phone, FeatureFlags featureFlags) {
+ public CarrierKeyDownloadManager(Phone phone) {
mPhone = phone;
- mFeatureFlags = featureFlags;
mContext = phone.getContext();
IntentFilter filter = new IntentFilter();
filter.addAction(INTENT_KEY_RENEWAL_ALARM_PREFIX);
filter.addAction(TelephonyIntents.ACTION_CARRIER_CERTIFICATE_DOWNLOAD);
- filter.addAction(Intent.ACTION_USER_PRESENT);
+ if (Flags.imsiKeyRetryDownloadOnPhoneUnlock()) {
+ filter.addAction(Intent.ACTION_USER_UNLOCKED);
+ }
mContext.registerReceiver(mBroadcastReceiver, filter, null, phone);
mDownloadManager = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE);
mTelephonyManager = mContext.getSystemService(TelephonyManager.class)
.createForSubscriptionId(mPhone.getSubId());
- mUserManager = mContext.getSystemService(UserManager.class);
+ if (Flags.imsiKeyRetryDownloadOnPhoneUnlock()) {
+ mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
+ } else {
+ mUserManager = mContext.getSystemService(UserManager.class);
+ }
CarrierConfigManager carrierConfigManager = mContext.getSystemService(
CarrierConfigManager.class);
// Callback which directly handle config change should be executed on handler thread
carrierConfigManager.registerCarrierConfigChangeListener(this::post,
(slotIndex, subId, carrierId, specificCarrierId) -> {
- boolean isUserUnlocked = mUserManager.isUserUnlocked();
-
- if (isUserUnlocked && slotIndex == mPhone.getPhoneId()) {
- Log.d(LOG_TAG, "Carrier Config changed: slotIndex=" + slotIndex);
- handleAlarmOrConfigChange();
+ if (Flags.imsiKeyRetryDownloadOnPhoneUnlock()) {
+ logd("CarrierConfig changed slotIndex = " + slotIndex + " subId = " + subId
+ + " CarrierId = " + carrierId + " phoneId = "
+ + mPhone.getPhoneId());
+ // Below checks are necessary to optimise the logic.
+ if ((slotIndex == mPhone.getPhoneId()) && (carrierId > 0
+ || !TextUtils.isEmpty(
+ mMccMncForDownload))) {
+ mCarrierId = carrierId;
+ updateSimOperator();
+ // If device is screen locked do not proceed to handle
+ // EVENT_ALARM_OR_CONFIG_CHANGE
+ if (mKeyguardManager.isDeviceLocked()) {
+ logd("Device is Locked");
+ mIsRequiredToHandleUnlock = true;
+ } else {
+ logd("Carrier Config changed: slotIndex=" + slotIndex);
+ sendEmptyMessage(EVENT_ALARM_OR_CONFIG_CHANGE);
+ }
+ }
} else {
- Log.d(LOG_TAG, "User is locked");
- mContext.registerReceiver(mUserUnlockedReceiver, new IntentFilter(
- Intent.ACTION_USER_UNLOCKED));
+ boolean isUserUnlocked = mUserManager.isUserUnlocked();
+
+ if (isUserUnlocked && slotIndex == mPhone.getPhoneId()) {
+ Log.d(LOG_TAG, "Carrier Config changed: slotIndex=" + slotIndex);
+ handleAlarmOrConfigChange();
+ } else {
+ Log.d(LOG_TAG, "User is locked");
+ mContext.registerReceiver(mUserUnlockedReceiver, new IntentFilter(
+ Intent.ACTION_USER_UNLOCKED));
+ }
}
});
+ mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
}
+ // TODO remove this method upon imsiKeyRetryDownloadOnPhoneUnlock enabled.
private final BroadcastReceiver mUserUnlockedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -167,7 +206,7 @@
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
- Log.d(LOG_TAG, "Download Complete");
+ logd("Download Complete");
sendMessage(obtainMessage(EVENT_DOWNLOAD_COMPLETE,
intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0)));
}
@@ -180,27 +219,36 @@
String action = intent.getAction();
int slotIndex = SubscriptionManager.getSlotIndex(mPhone.getSubId());
int phoneId = mPhone.getPhoneId();
- if (action.equals(INTENT_KEY_RENEWAL_ALARM_PREFIX)) {
- int slotIndexExtra = intent.getIntExtra(SubscriptionManager.EXTRA_SLOT_INDEX, -1);
- if (slotIndexExtra == slotIndex) {
- Log.d(LOG_TAG, "Handling key renewal alarm: " + action);
- sendEmptyMessage(EVENT_ALARM_OR_CONFIG_CHANGE);
+ switch (action) {
+ case INTENT_KEY_RENEWAL_ALARM_PREFIX -> {
+ int slotIndexExtra = intent.getIntExtra(SubscriptionManager.EXTRA_SLOT_INDEX,
+ -1);
+ if (slotIndexExtra == slotIndex) {
+ logd("Handling key renewal alarm: " + action);
+ if (Flags.imsiKeyRetryDownloadOnPhoneUnlock()) {
+ updateSimOperator();
+ }
+ sendEmptyMessage(EVENT_ALARM_OR_CONFIG_CHANGE);
+ }
}
- } else if (action.equals(TelephonyIntents.ACTION_CARRIER_CERTIFICATE_DOWNLOAD)) {
- if (phoneId == intent.getIntExtra(PhoneConstants.PHONE_KEY,
- SubscriptionManager.INVALID_SIM_SLOT_INDEX)) {
- Log.d(LOG_TAG, "Handling reset intent: " + action);
- sendEmptyMessage(EVENT_ALARM_OR_CONFIG_CHANGE);
+ case TelephonyIntents.ACTION_CARRIER_CERTIFICATE_DOWNLOAD -> {
+ if (phoneId == intent.getIntExtra(PhoneConstants.PHONE_KEY,
+ SubscriptionManager.INVALID_SIM_SLOT_INDEX)) {
+ logd("Handling reset intent: " + action);
+ sendEmptyMessage(EVENT_ALARM_OR_CONFIG_CHANGE);
+ }
}
- } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
- // The Carrier key download fails when SIM is inserted while device is locked
- // hence adding a retry logic when device is unlocked.
- Log.d(LOG_TAG,
- "device unlocked, isRequiredToHandleUnlock = " + mIsRequiredToHandleUnlock
- + ", slotIndex = " + slotIndex);
- if (mIsRequiredToHandleUnlock) {
- mIsRequiredToHandleUnlock = false;
- sendEmptyMessage(EVENT_ALARM_OR_CONFIG_CHANGE);
+ case Intent.ACTION_USER_UNLOCKED -> {
+ // The Carrier key download fails when SIM is inserted while device is locked
+ // hence adding a retry logic when device is unlocked.
+ logd("device fully unlocked, isRequiredToHandleUnlock = "
+ + mIsRequiredToHandleUnlock
+ + ", slotIndex = " + slotIndex + " hasActiveDataNetwork = " + (
+ mConnectivityManager.getActiveNetwork() != null));
+ if (mIsRequiredToHandleUnlock) {
+ mIsRequiredToHandleUnlock = false;
+ sendEmptyMessage(EVENT_SCREEN_UNLOCKED);
+ }
}
}
}
@@ -209,76 +257,124 @@
@Override
public void handleMessage (Message msg) {
switch (msg.what) {
- case EVENT_ALARM_OR_CONFIG_CHANGE:
- handleAlarmOrConfigChange();
- break;
- case EVENT_DOWNLOAD_COMPLETE:
+ case EVENT_ALARM_OR_CONFIG_CHANGE, EVENT_NETWORK_AVAILABLE, EVENT_SCREEN_UNLOCKED ->
+ handleAlarmOrConfigChange();
+ case EVENT_DOWNLOAD_COMPLETE -> {
long carrierKeyDownloadIdentifier = (long) msg.obj;
- String currentMccMnc = getSimOperator();
- int carrierId = getSimCarrierId();
+ String currentMccMnc = Flags.imsiKeyRetryDownloadOnPhoneUnlock()
+ ? mTelephonyManager.getSimOperator(mPhone.getSubId()) : getSimOperator();
+ int carrierId = Flags.imsiKeyRetryDownloadOnPhoneUnlock()
+ ? mTelephonyManager.getSimCarrierId() : getSimCarrierId();
if (isValidDownload(currentMccMnc, carrierKeyDownloadIdentifier, carrierId)) {
onDownloadComplete(carrierKeyDownloadIdentifier, currentMccMnc, carrierId);
- onPostDownloadProcessing(carrierKeyDownloadIdentifier);
+ onPostDownloadProcessing();
}
- break;
+ }
}
}
- private void onPostDownloadProcessing(long carrierKeyDownloadIdentifier) {
+ private void onPostDownloadProcessing() {
resetRenewalAlarm();
- cleanupDownloadInfo();
-
+ if(Flags.imsiKeyRetryDownloadOnPhoneUnlock()) {
+ mDownloadId = -1;
+ } else {
+ cleanupDownloadInfo();
+ }
// unregister from DOWNLOAD_COMPLETE
mContext.unregisterReceiver(mDownloadReceiver);
}
private void handleAlarmOrConfigChange() {
- if (carrierUsesKeys()) {
- if (areCarrierKeysAbsentOrExpiring()) {
- boolean downloadStartedSuccessfully = downloadKey();
- // if the download was attempted, but not started successfully, and if carriers uses
- // keys, we'll still want to renew the alarms, and try downloading the key a day
- // later.
- if (!downloadStartedSuccessfully) {
- // If download fails due to the device lock, we will reattempt once the device
- // is unlocked.
- if (mFeatureFlags.imsiKeyRetryDownloadOnPhoneUnlock()) {
- KeyguardManager keyguardManager = mContext.getSystemService(
- KeyguardManager.class);
- if (keyguardManager.isKeyguardSecure()) {
- Log.e(LOG_TAG, "Key download failed in device lock state");
- mIsRequiredToHandleUnlock = true;
+ if (Flags.imsiKeyRetryDownloadOnPhoneUnlock()) {
+ if (carrierUsesKeys()) {
+ if (areCarrierKeysAbsentOrExpiring()) {
+ boolean hasActiveDataNetwork =
+ (mConnectivityManager.getActiveNetwork() != null);
+ boolean downloadStartedSuccessfully = hasActiveDataNetwork && downloadKey();
+ // if the download was attempted, but not started successfully, and if
+ // carriers uses keys, we'll still want to renew the alarms, and try
+ // downloading the key a day later.
+ int slotIndex = SubscriptionManager.getSlotIndex(mPhone.getSubId());
+ if (downloadStartedSuccessfully) {
+ unregisterDefaultNetworkCb(slotIndex);
+ } else {
+ // If download fails due to the device lock, we will reattempt once the
+ // device is unlocked.
+ mIsRequiredToHandleUnlock = mKeyguardManager.isDeviceLocked();
+ loge("hasActiveDataConnection = " + hasActiveDataNetwork
+ + " isDeviceLocked = " + mIsRequiredToHandleUnlock);
+ if (!hasActiveDataNetwork) {
+ registerDefaultNetworkCb(slotIndex);
}
+ resetRenewalAlarm();
}
- resetRenewalAlarm();
}
+ logd("handleAlarmOrConfigChange :: areCarrierKeysAbsentOrExpiring returned false");
} else {
- return;
+ cleanupRenewalAlarms();
+ if (!isOtherSlotHasCarrier()) {
+ // delete any existing alarms.
+ mPhone.deleteCarrierInfoForImsiEncryption(getSimCarrierId(), getSimOperator());
+ }
+ cleanupDownloadInfo();
}
} else {
- // delete any existing alarms.
- cleanupRenewalAlarms();
- mPhone.deleteCarrierInfoForImsiEncryption(getSimCarrierId());
-
+ if (carrierUsesKeys()) {
+ if (areCarrierKeysAbsentOrExpiring()) {
+ boolean downloadStartedSuccessfully = downloadKey();
+ // if the download was attempted, but not started successfully, and if
+ // carriers uses keys, we'll still want to renew the alarms, and try
+ // downloading the key a day later.
+ if (!downloadStartedSuccessfully) {
+ resetRenewalAlarm();
+ }
+ }
+ } else {
+ // delete any existing alarms.
+ cleanupRenewalAlarms();
+ mPhone.deleteCarrierInfoForImsiEncryption(getSimCarrierId());
+ }
}
}
+ private boolean isOtherSlotHasCarrier() {
+ SubscriptionManager subscriptionManager = mPhone.getContext().getSystemService(
+ SubscriptionManager.class);
+ List<SubscriptionInfo> subscriptionInfoList =
+ subscriptionManager.getActiveSubscriptionInfoList();
+ loge("handleAlarmOrConfigChange ActiveSubscriptionInfoList = " + (
+ (subscriptionInfoList != null) ? subscriptionInfoList.size() : null));
+ for (SubscriptionInfo subInfo : subscriptionInfoList) {
+ if (mPhone.getSubId() != subInfo.getSubscriptionId()
+ && subInfo.getCarrierId() == mPhone.getCarrierId()) {
+ // We do not proceed to remove the Key from the DB as another slot contains
+ // same operator sim which is in active state.
+ loge("handleAlarmOrConfigChange same operator sim in another slot");
+ return true;
+ }
+ }
+ return false;
+ }
+
private void cleanupDownloadInfo() {
- Log.d(LOG_TAG, "Cleaning up download info");
+ logd("Cleaning up download info");
mDownloadId = -1;
- mMccMncForDownload = null;
+ if (Flags.imsiKeyRetryDownloadOnPhoneUnlock()) {
+ mMccMncForDownload = "";
+ } else {
+ mMccMncForDownload = null;
+ }
mCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
}
private void cleanupRenewalAlarms() {
- Log.d(LOG_TAG, "Cleaning up existing renewal alarms");
+ logd("Cleaning up existing renewal alarms");
int slotIndex = SubscriptionManager.getSlotIndex(mPhone.getSubId());
Intent intent = new Intent(INTENT_KEY_RENEWAL_ALARM_PREFIX);
intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, slotIndex);
PendingIntent carrierKeyDownloadIntent = PendingIntent.getBroadcast(mContext, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
- AlarmManager alarmManager =
- (AlarmManager) mContext.getSystemService(mContext.ALARM_SERVICE);
+ AlarmManager alarmManager =mContext.getSystemService(AlarmManager.class);
alarmManager.cancel(carrierKeyDownloadIntent);
}
@@ -331,7 +427,7 @@
cleanupRenewalAlarms();
int slotIndex = SubscriptionManager.getSlotIndex(mPhone.getSubId());
long minExpirationDate = getExpirationDate();
- Log.d(LOG_TAG, "minExpirationDate: " + new Date(minExpirationDate));
+ logd("minExpirationDate: " + new Date(minExpirationDate));
final AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(
Context.ALARM_SERVICE);
Intent intent = new Intent(INTENT_KEY_RENEWAL_ALARM_PREFIX);
@@ -339,16 +435,35 @@
PendingIntent carrierKeyDownloadIntent = PendingIntent.getBroadcast(mContext, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
alarmManager.set(AlarmManager.RTC_WAKEUP, minExpirationDate, carrierKeyDownloadIntent);
- Log.d(LOG_TAG, "setRenewalAlarm: action=" + intent.getAction() + " time="
+ logd("setRenewalAlarm: action=" + intent.getAction() + " time="
+ new Date(minExpirationDate));
}
/**
+ * Read the store the sim operetor value and update the value in case of change in the sim
+ * operetor.
+ */
+ public void updateSimOperator() {
+ if (Flags.imsiKeyRetryDownloadOnPhoneUnlock()) {
+ String simOperator = mPhone.getOperatorNumeric();
+ if (!TextUtils.isEmpty(simOperator) && !simOperator.equals(mMccMncForDownload)) {
+ mMccMncForDownload = simOperator;
+ logd("updateSimOperator, Initialized mMccMncForDownload = " + mMccMncForDownload);
+ }
+ }
+ }
+
+ /**
* Returns the sim operator.
**/
@VisibleForTesting
public String getSimOperator() {
- return mTelephonyManager.getSimOperator(mPhone.getSubId());
+ if (Flags.imsiKeyRetryDownloadOnPhoneUnlock()) {
+ updateSimOperator();
+ return mMccMncForDownload;
+ } else {
+ return mTelephonyManager.getSimOperator(mPhone.getSubId());
+ }
}
/**
@@ -356,7 +471,11 @@
**/
@VisibleForTesting
public int getSimCarrierId() {
- return mTelephonyManager.getSimCarrierId();
+ if (Flags.imsiKeyRetryDownloadOnPhoneUnlock()) {
+ return (mCarrierId > 0) ? mCarrierId : mPhone.getCarrierId();
+ } else {
+ return mTelephonyManager.getSimCarrierId();
+ }
}
/**
@@ -367,7 +486,7 @@
@VisibleForTesting
public boolean isValidDownload(String currentMccMnc, long currentDownloadId, int carrierId) {
if (currentDownloadId != mDownloadId) {
- Log.e(LOG_TAG, "download ID=" + currentDownloadId
+ loge( "download ID=" + currentDownloadId
+ " for completed download does not match stored id=" + mDownloadId);
return false;
}
@@ -375,12 +494,12 @@
if (TextUtils.isEmpty(currentMccMnc) || TextUtils.isEmpty(mMccMncForDownload)
|| !TextUtils.equals(currentMccMnc, mMccMncForDownload)
|| mCarrierId != carrierId) {
- Log.e(LOG_TAG, "currentMccMnc=" + currentMccMnc + " storedMccMnc =" + mMccMncForDownload
+ loge( "currentMccMnc=" + currentMccMnc + " storedMccMnc =" + mMccMncForDownload
+ "currentCarrierId = " + carrierId + " storedCarrierId = " + mCarrierId);
return false;
}
- Log.d(LOG_TAG, "Matched MccMnc = " + currentMccMnc + ", carrierId = " + carrierId
+ logd("Matched MccMnc = " + currentMccMnc + ", carrierId = " + carrierId
+ ", downloadId: " + currentDownloadId);
return true;
}
@@ -390,7 +509,7 @@
**/
private void onDownloadComplete(long carrierKeyDownloadIdentifier, String mccMnc,
int carrierId) {
- Log.d(LOG_TAG, "onDownloadComplete: " + carrierKeyDownloadIdentifier);
+ logd("onDownloadComplete: " + carrierKeyDownloadIdentifier);
String jsonStr;
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(carrierKeyDownloadIdentifier);
@@ -405,22 +524,21 @@
try {
jsonStr = convertToString(mDownloadManager, carrierKeyDownloadIdentifier);
if (TextUtils.isEmpty(jsonStr)) {
- Log.d(LOG_TAG, "fallback to no gzip");
+ logd("fallback to no gzip");
jsonStr = convertToStringNoGZip(mDownloadManager,
carrierKeyDownloadIdentifier);
}
parseJsonAndPersistKey(jsonStr, mccMnc, carrierId);
} catch (Exception e) {
- Log.e(LOG_TAG, "Error in download:" + carrierKeyDownloadIdentifier
+ loge( "Error in download:" + carrierKeyDownloadIdentifier
+ ". " + e);
} finally {
mDownloadManager.remove(carrierKeyDownloadIdentifier);
}
}
- Log.d(LOG_TAG, "Completed downloading keys");
+ logd("Completed downloading keys");
}
cursor.close();
- return;
}
/**
@@ -442,7 +560,7 @@
CarrierConfigManager.IMSI_KEY_DOWNLOAD_URL_STRING,
CarrierConfigManager.KEY_ALLOW_METERED_NETWORK_FOR_CERT_DOWNLOAD_BOOL);
} catch (RuntimeException e) {
- Log.e(LOG_TAG, "CarrierConfigLoader is not available.");
+ loge( "CarrierConfigLoader is not available.");
}
if (b == null || b.isEmpty()) {
return false;
@@ -452,10 +570,10 @@
mURL = b.getString(CarrierConfigManager.IMSI_KEY_DOWNLOAD_URL_STRING);
mAllowedOverMeteredNetwork = b.getBoolean(
CarrierConfigManager.KEY_ALLOW_METERED_NETWORK_FOR_CERT_DOWNLOAD_BOOL);
+
if (mKeyAvailability == 0 || TextUtils.isEmpty(mURL)) {
- Log.d(LOG_TAG,
- "Carrier not enabled or invalid values. mKeyAvailability=" + mKeyAvailability
- + " mURL=" + mURL);
+ logd("Carrier not enabled or invalid values. mKeyAvailability=" + mKeyAvailability
+ + " mURL=" + mURL);
return false;
}
for (int key_type : CARRIER_KEY_TYPES) {
@@ -469,7 +587,7 @@
private static String convertToStringNoGZip(DownloadManager downloadManager, long downloadId) {
StringBuilder sb = new StringBuilder();
try (InputStream source = new FileInputStream(
- downloadManager.openDownloadedFile(downloadId).getFileDescriptor())) {
+ downloadManager.openDownloadedFile(downloadId).getFileDescriptor())) {
// If the carrier does not have the data gzipped, fallback to assuming it is not zipped.
// parseJsonAndPersistKey may still fail if the data is malformed, so we won't be
// persisting random bogus strings thinking it's the cert
@@ -488,8 +606,8 @@
private static String convertToString(DownloadManager downloadManager, long downloadId) {
try (InputStream source = new FileInputStream(
- downloadManager.openDownloadedFile(downloadId).getFileDescriptor());
- InputStream gzipIs = new GZIPInputStream(source)) {
+ downloadManager.openDownloadedFile(downloadId).getFileDescriptor());
+ InputStream gzipIs = new GZIPInputStream(source)) {
BufferedReader reader = new BufferedReader(new InputStreamReader(gzipIs, UTF_8));
StringBuilder sb = new StringBuilder();
@@ -523,7 +641,7 @@
public void parseJsonAndPersistKey(String jsonStr, String mccMnc, int carrierId) {
if (TextUtils.isEmpty(jsonStr) || TextUtils.isEmpty(mccMnc)
|| carrierId == TelephonyManager.UNKNOWN_CARRIER_ID) {
- Log.e(LOG_TAG, "jsonStr or mcc, mnc: is empty or carrierId is UNKNOWN_CARRIER_ID");
+ loge( "jsonStr or mcc, mnc: is empty or carrierId is UNKNOWN_CARRIER_ID");
return;
}
try {
@@ -548,22 +666,28 @@
if (typeString.equals(JSON_TYPE_VALUE_EPDG)) {
type = TelephonyManager.KEY_TYPE_EPDG;
} else if (!typeString.equals(JSON_TYPE_VALUE_WLAN)) {
- Log.e(LOG_TAG, "Invalid key-type specified: " + typeString);
+ loge( "Invalid key-type specified: " + typeString);
}
}
String identifier = key.getString(JSON_IDENTIFIER);
Pair<PublicKey, Long> keyInfo =
getKeyInformation(cleanCertString(cert).getBytes());
if (mDeleteOldKeyAfterDownload) {
- mPhone.deleteCarrierInfoForImsiEncryption(TelephonyManager.UNKNOWN_CARRIER_ID);
+ if (Flags.imsiKeyRetryDownloadOnPhoneUnlock()) {
+ mPhone.deleteCarrierInfoForImsiEncryption(
+ TelephonyManager.UNKNOWN_CARRIER_ID, null);
+ } else {
+ mPhone.deleteCarrierInfoForImsiEncryption(
+ TelephonyManager.UNKNOWN_CARRIER_ID);
+ }
mDeleteOldKeyAfterDownload = false;
}
savePublicKey(keyInfo.first, type, identifier, keyInfo.second, mcc, mnc, carrierId);
}
} catch (final JSONException e) {
- Log.e(LOG_TAG, "Json parsing error: " + e.getMessage());
+ loge( "Json parsing error: " + e.getMessage());
} catch (final Exception e) {
- Log.e(LOG_TAG, "Exception getting certificate: " + e);
+ loge( "Exception getting certificate: " + e);
}
}
@@ -584,7 +708,7 @@
public static boolean isKeyEnabled(int keyType, int keyAvailability) {
// since keytype has values of 1, 2.... we need to subtract 1 from the keytype.
int returnValue = (keyAvailability >> (keyType - 1)) & 1;
- return (returnValue == 1) ? true : false;
+ return returnValue == 1;
}
/**
@@ -603,31 +727,42 @@
ImsiEncryptionInfo imsiEncryptionInfo =
mPhone.getCarrierInfoForImsiEncryption(key_type, false);
if (imsiEncryptionInfo == null) {
- Log.d(LOG_TAG, "Key not found for: " + key_type);
+ logd("Key not found for: " + key_type);
return true;
} else if (imsiEncryptionInfo.getCarrierId() == TelephonyManager.UNKNOWN_CARRIER_ID) {
- Log.d(LOG_TAG, "carrier key is unknown carrier, so prefer to reDownload");
+ logd("carrier key is unknown carrier, so prefer to reDownload");
mDeleteOldKeyAfterDownload = true;
return true;
}
Date imsiDate = imsiEncryptionInfo.getExpirationTime();
long timeToExpire = imsiDate.getTime() - System.currentTimeMillis();
- return (timeToExpire < START_RENEWAL_WINDOW_DAYS * DAY_IN_MILLIS) ? true : false;
+ return timeToExpire < START_RENEWAL_WINDOW_DAYS * DAY_IN_MILLIS;
}
return false;
}
private boolean downloadKey() {
- Log.d(LOG_TAG, "starting download from: " + mURL);
- String mccMnc = getSimOperator();
- int carrierId = getSimCarrierId();
- if (!TextUtils.isEmpty(mccMnc) || carrierId != TelephonyManager.UNKNOWN_CARRIER_ID) {
- Log.d(LOG_TAG, "downloading key for mccmnc : " + mccMnc + ", carrierId : "
- + carrierId);
+ logd("starting download from: " + mURL);
+ String mccMnc = null;
+ int carrierId = -1;
+ if (Flags.imsiKeyRetryDownloadOnPhoneUnlock()) {
+ if (TextUtils.isEmpty(mMccMncForDownload)
+ || mCarrierId == TelephonyManager.UNKNOWN_CARRIER_ID) {
+ loge("mccmnc or carrierId is UnKnown");
+ return false;
+ }
} else {
- Log.e(LOG_TAG, "mccmnc or carrierId is UnKnown");
- return false;
+ mccMnc = getSimOperator();
+ carrierId = getSimCarrierId();
+ if (!TextUtils.isEmpty(mccMnc) || carrierId != TelephonyManager.UNKNOWN_CARRIER_ID) {
+ Log.d(LOG_TAG, "downloading key for mccmnc : " + mccMnc + ", carrierId : "
+ + carrierId);
+ } else {
+ Log.e(LOG_TAG, "mccmnc or carrierId is UnKnown");
+ return false;
+ }
}
+
try {
// register the broadcast receiver to listen for download complete
IntentFilter filter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
@@ -641,15 +776,16 @@
request.setAllowedOverMetered(mAllowedOverMeteredNetwork);
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN);
request.addRequestHeader("Accept-Encoding", "gzip");
- Long carrierKeyDownloadRequestId = mDownloadManager.enqueue(request);
-
- Log.d(LOG_TAG, "saving values mccmnc: " + mccMnc + ", downloadId: "
- + carrierKeyDownloadRequestId + ", carrierId: " + carrierId);
- mMccMncForDownload = mccMnc;
- mCarrierId = carrierId;
+ long carrierKeyDownloadRequestId = mDownloadManager.enqueue(request);
+ if (!Flags.imsiKeyRetryDownloadOnPhoneUnlock()) {
+ mMccMncForDownload = mccMnc;
+ mCarrierId = carrierId;
+ }
mDownloadId = carrierKeyDownloadRequestId;
+ logd("saving values mccmnc: " + mMccMncForDownload + ", downloadId: "
+ + carrierKeyDownloadRequestId + ", carrierId: " + mCarrierId);
} catch (Exception e) {
- Log.e(LOG_TAG, "exception trying to download key from url: " + mURL + ", Exception = "
+ loge( "exception trying to download key from url: " + mURL + ", Exception = "
+ e.getMessage());
return false;
}
@@ -667,7 +803,7 @@
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(inStream);
Pair<PublicKey, Long> keyInformation =
- new Pair(cert.getPublicKey(), cert.getNotAfter().getTime());
+ new Pair<>(cert.getPublicKey(), cert.getNotAfter().getTime());
return keyInformation;
}
@@ -699,4 +835,59 @@
cert.indexOf(CERT_BEGIN_STRING),
cert.indexOf(CERT_END_STRING) + CERT_END_STRING.length());
}
+
+ /**
+ * Registering the callback to listen on data connection availability.
+ *
+ * @param slotId Sim slotIndex that tries to download the key.
+ */
+ private void registerDefaultNetworkCb(int slotId) {
+ logd("RegisterDefaultNetworkCb for slotId = " + slotId);
+ if (mDefaultNetworkCallback == null
+ && slotId != SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+ mDefaultNetworkCallback = new DefaultNetworkCallback(slotId);
+ mConnectivityManager.registerDefaultNetworkCallback(mDefaultNetworkCallback, this);
+ }
+ }
+
+ /**
+ * Unregister the data connection monitor listener.
+ */
+ private void unregisterDefaultNetworkCb(int slotId) {
+ logd("unregisterDefaultNetworkCb for slotId = " + slotId);
+ if (mDefaultNetworkCallback != null) {
+ mConnectivityManager.unregisterNetworkCallback(mDefaultNetworkCallback);
+ mDefaultNetworkCallback = null;
+ }
+ }
+
+ final class DefaultNetworkCallback extends ConnectivityManager.NetworkCallback {
+ final int mSlotIndex;
+
+ public DefaultNetworkCallback(int slotId) {
+ mSlotIndex = slotId;
+ }
+
+ /** Called when the framework connects and has declared a new network ready for use. */
+ @Override
+ public void onAvailable(@NonNull Network network) {
+ logd("Data network connected, slotId = " + mSlotIndex);
+ if (mConnectivityManager.getActiveNetwork() != null && SubscriptionManager.getSlotIndex(
+ mPhone.getSubId()) == mSlotIndex) {
+ mIsRequiredToHandleUnlock = false;
+ unregisterDefaultNetworkCb(mSlotIndex);
+ sendEmptyMessage(EVENT_NETWORK_AVAILABLE);
+ }
+ }
+ }
+
+ private void loge(String logStr) {
+ String TAG = LOG_TAG + " [" + mPhone.getPhoneId() + "]";
+ Log.e(TAG, logStr);
+ }
+
+ private void logd(String logStr) {
+ String TAG = LOG_TAG + " [" + mPhone.getPhoneId() + "]";
+ Log.d(TAG, logStr);
+ }
}
diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
index d9352fb..eeba86b 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@@ -539,7 +539,7 @@
mContext.registerReceiver(mBroadcastReceiver, filter,
android.Manifest.permission.MODIFY_PHONE_STATE, null, Context.RECEIVER_EXPORTED);
- mCDM = new CarrierKeyDownloadManager(this, mFeatureFlags);
+ mCDM = new CarrierKeyDownloadManager(this);
mCIM = new CarrierInfoManager();
mCi.registerForImeiMappingChanged(this, EVENT_IMEI_MAPPING_CHANGED, null);
@@ -2124,8 +2124,13 @@
@Override
public void deleteCarrierInfoForImsiEncryption(int carrierId) {
+ CarrierInfoManager.deleteCarrierInfoForImsiEncryption(mContext, getSubId(), carrierId);
+ }
+
+ @Override
+ public void deleteCarrierInfoForImsiEncryption(int carrierId, String simOperator) {
CarrierInfoManager.deleteCarrierInfoForImsiEncryption(mContext, getSubId(),
- carrierId);
+ carrierId, simOperator);
}
@Override
@@ -3674,6 +3679,7 @@
case EVENT_SUBSCRIPTIONS_CHANGED:
logd("EVENT_SUBSCRIPTIONS_CHANGED");
updateUsageSetting();
+ updateNullCipherNotifier();
break;
case EVENT_SET_NULL_CIPHER_AND_INTEGRITY_DONE:
logd("EVENT_SET_NULL_CIPHER_AND_INTEGRITY_DONE");
@@ -3774,7 +3780,8 @@
&& mNullCipherNotifier != null) {
ar = (AsyncResult) msg.obj;
SecurityAlgorithmUpdate update = (SecurityAlgorithmUpdate) ar.result;
- mNullCipherNotifier.onSecurityAlgorithmUpdate(mContext, getSubId(), update);
+ mNullCipherNotifier.onSecurityAlgorithmUpdate(mContext, getPhoneId(),
+ getSubId(), update);
}
break;
@@ -5449,6 +5456,25 @@
obtainMessage(EVENT_SET_SECURITY_ALGORITHMS_UPDATED_ENABLED_DONE));
}
+ /**
+ * Update the phoneId -> subId mapping of the null cipher notifier.
+ */
+ @VisibleForTesting
+ public void updateNullCipherNotifier() {
+ if (!mFeatureFlags.enableModemCipherTransparencyUnsolEvents()) {
+ return;
+ }
+
+ SubscriptionInfoInternal subInfo = mSubscriptionManagerService
+ .getSubscriptionInfoInternal(getSubId());
+ boolean active = false;
+ if (subInfo != null) {
+ active = subInfo.isActive();
+ }
+ mNullCipherNotifier.setSubscriptionMapping(mContext, getPhoneId(),
+ active ? subInfo.getSubscriptionId() : -1);
+ }
+
@Override
public boolean isNullCipherAndIntegritySupported() {
return mIsNullCipherAndIntegritySupported;
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index ebf7cfd..6858533 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -4025,6 +4025,15 @@
return;
}
+ /**
+ * Deletes all the keys for a given Carrier from the device keystore.
+ * @param carrierId : the carrier ID which needs to be matched in the delete query
+ * @param simOperator : MccMnc which needs to be matched in the delete query.
+ */
+ public void deleteCarrierInfoForImsiEncryption(int carrierId, String simOperator) {
+
+ }
+
public int getCarrierId() {
return TelephonyManager.UNKNOWN_CARRIER_ID;
}
diff --git a/src/java/com/android/internal/telephony/security/CellularNetworkSecuritySafetySource.java b/src/java/com/android/internal/telephony/security/CellularNetworkSecuritySafetySource.java
index 34f26e3..605b197 100644
--- a/src/java/com/android/internal/telephony/security/CellularNetworkSecuritySafetySource.java
+++ b/src/java/com/android/internal/telephony/security/CellularNetworkSecuritySafetySource.java
@@ -25,6 +25,8 @@
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
+import android.content.res.Resources;
+import android.net.Uri;
import android.safetycenter.SafetyCenterManager;
import android.safetycenter.SafetyEvent;
import android.safetycenter.SafetySourceData;
@@ -62,10 +64,6 @@
private static final Intent CELLULAR_NETWORK_SECURITY_SETTINGS_INTENT =
new Intent("android.settings.CELLULAR_NETWORK_SECURITY");
- // TODO(b/321999913): direct to a help page URL e.g.
- // new Intent(Intent.ACTION_VIEW, Uri.parse("https://..."));
- private static final Intent LEARN_MORE_INTENT = new Intent();
-
static final int NULL_CIPHER_STATE_ENCRYPTED = 0;
static final int NULL_CIPHER_STATE_NOTIFY_ENCRYPTED = 1;
static final int NULL_CIPHER_STATE_NOTIFY_NON_ENCRYPTED = 2;
@@ -123,6 +121,13 @@
}
/**
+ * Clears issue state for the identified subscription
+ */
+ public synchronized void clearNullCipherState(Context context, int subId) {
+ mNullCipherStates.remove(subId);
+ updateSafetyCenter(context);
+ }
+ /**
* Enables or disables the identifier disclosure issue and clears any current issues if the
* enable state is changed.
*/
@@ -216,7 +221,8 @@
builder = new SafetySourceIssue.Builder(
NULL_CIPHER_ISSUE_NON_ENCRYPTED_ID + "_" + subId,
context.getString(
- R.string.scNullCipherIssueNonEncryptedTitle, subInfo.getDisplayName()),
+ R.string.scNullCipherIssueNonEncryptedTitle,
+ subInfo.getDisplayName()),
context.getString(R.string.scNullCipherIssueNonEncryptedSummary),
SEVERITY_LEVEL_RECOMMENDATION,
NULL_CIPHER_ISSUE_NON_ENCRYPTED_ID);
@@ -225,7 +231,7 @@
builder = new SafetySourceIssue.Builder(
NULL_CIPHER_ISSUE_NON_ENCRYPTED_ID + "_" + subId,
context.getString(
- R.string.scNullCipherIssueEncryptedTitle, subInfo.getDisplayName()),
+ R.string.scNullCipherIssueEncryptedTitle, subInfo.getDisplayName()),
context.getString(R.string.scNullCipherIssueEncryptedSummary),
SEVERITY_LEVEL_INFORMATION,
NULL_CIPHER_ISSUE_ENCRYPTED_ID);
@@ -233,26 +239,31 @@
default:
throw new AssertionError();
}
-
- return Optional.of(
- builder
- .setNotificationBehavior(SafetySourceIssue.NOTIFICATION_BEHAVIOR_IMMEDIATELY)
- .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_DEVICE)
- .addAction(
+ builder
+ .setNotificationBehavior(
+ SafetySourceIssue.NOTIFICATION_BEHAVIOR_IMMEDIATELY)
+ .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_DEVICE)
+ .addAction(
new SafetySourceIssue.Action.Builder(
NULL_CIPHER_ACTION_SETTINGS_ID,
context.getString(R.string.scNullCipherIssueActionSettings),
mSafetyCenterManagerWrapper.getActivityPendingIntent(
context, CELLULAR_NETWORK_SECURITY_SETTINGS_INTENT))
- .build())
- .addAction(
- new SafetySourceIssue.Action.Builder(
- NULL_CIPHER_ACTION_LEARN_MORE_ID,
- context.getString(R.string.scNullCipherIssueActionLearnMore),
- mSafetyCenterManagerWrapper.getActivityPendingIntent(
- context, LEARN_MORE_INTENT))
- .build())
- .build());
+ .build());
+
+ Intent learnMoreIntent = getLearnMoreIntent(context);
+ if (learnMoreIntent != null) {
+ builder.addAction(
+ new SafetySourceIssue.Action.Builder(
+ NULL_CIPHER_ACTION_LEARN_MORE_ID,
+ context.getString(
+ R.string.scNullCipherIssueActionLearnMore),
+ mSafetyCenterManagerWrapper.getActivityPendingIntent(
+ context, learnMoreIntent))
+ .build());
+ }
+
+ return Optional.of(builder.build());
}
/** Builds the identity disclosure issue if it's enabled and there are disclosures to report. */
@@ -264,7 +275,8 @@
SubscriptionInfoInternal subInfo =
mSubscriptionManagerService.getSubscriptionInfoInternal(subId);
- return Optional.of(
+
+ SafetySourceIssue.Builder builder =
new SafetySourceIssue.Builder(
IDENTIFIER_DISCLOSURE_ISSUE_ID + "_" + subId,
context.getString(R.string.scIdentifierDisclosureIssueTitle),
@@ -276,23 +288,51 @@
subInfo.getDisplayName()),
SEVERITY_LEVEL_RECOMMENDATION,
IDENTIFIER_DISCLOSURE_ISSUE_ID)
- .setNotificationBehavior(SafetySourceIssue.NOTIFICATION_BEHAVIOR_IMMEDIATELY)
- .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_DEVICE)
- .addAction(
- new SafetySourceIssue.Action.Builder(
- NULL_CIPHER_ACTION_SETTINGS_ID,
- context.getString(R.string.scNullCipherIssueActionSettings),
- mSafetyCenterManagerWrapper.getActivityPendingIntent(
- context, CELLULAR_NETWORK_SECURITY_SETTINGS_INTENT))
- .build())
- .addAction(
- new SafetySourceIssue.Action.Builder(
- NULL_CIPHER_ACTION_LEARN_MORE_ID,
- context.getString(R.string.scNullCipherIssueActionLearnMore),
- mSafetyCenterManagerWrapper.getActivityPendingIntent(
- context, LEARN_MORE_INTENT))
- .build())
- .build());
+ .setNotificationBehavior(
+ SafetySourceIssue.NOTIFICATION_BEHAVIOR_IMMEDIATELY)
+ .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_DEVICE)
+ .addAction(
+ new SafetySourceIssue.Action.Builder(
+ NULL_CIPHER_ACTION_SETTINGS_ID,
+ context.getString(
+ R.string.scNullCipherIssueActionSettings),
+ mSafetyCenterManagerWrapper.getActivityPendingIntent(
+ context,
+ CELLULAR_NETWORK_SECURITY_SETTINGS_INTENT))
+ .build());
+
+ Intent learnMoreIntent = getLearnMoreIntent(context);
+ if (learnMoreIntent != null) {
+ builder.addAction(
+ new SafetySourceIssue.Action.Builder(
+ NULL_CIPHER_ACTION_LEARN_MORE_ID,
+ context.getString(R.string.scNullCipherIssueActionLearnMore),
+ mSafetyCenterManagerWrapper.getActivityPendingIntent(
+ context, learnMoreIntent)).build()
+ );
+ }
+
+ return Optional.of(builder.build());
+ }
+
+ /**
+ * Return Intent for learn more action, or null if resource associated with the Intent
+ * uri is
+ * missing or empty.
+ */
+ private Intent getLearnMoreIntent(Context context) {
+ String learnMoreUri;
+ try {
+ learnMoreUri = context.getString(R.string.scCellularNetworkSecurityLearnMore);
+ } catch (Resources.NotFoundException e) {
+ return null;
+ }
+
+ if (learnMoreUri.isEmpty()) {
+ return null;
+ }
+
+ return new Intent(Intent.ACTION_VIEW, Uri.parse(learnMoreUri));
}
/** A wrapper around {@link SafetyCenterManager} that can be instrumented in tests. */
@@ -337,7 +377,7 @@
private IdentifierDisclosure(int count, Instant start, Instant end) {
mDisclosureCount = count;
mWindowStart = start;
- mWindowEnd = end;
+ mWindowEnd = end;
}
private int getDisclosureCount() {
diff --git a/src/java/com/android/internal/telephony/security/NullCipherNotifier.java b/src/java/com/android/internal/telephony/security/NullCipherNotifier.java
index 3ece701..e13c5b0 100644
--- a/src/java/com/android/internal/telephony/security/NullCipherNotifier.java
+++ b/src/java/com/android/internal/telephony/security/NullCipherNotifier.java
@@ -56,6 +56,7 @@
private final CellularNetworkSecuritySafetySource mSafetySource;
private final HashMap<Integer, SubscriptionState> mSubscriptionState = new HashMap<>();
+ private final HashMap<Integer, Integer> mActiveSubscriptions = new HashMap<>();
private final Object mEnabledLock = new Object();
@GuardedBy("mEnabledLock")
@@ -90,31 +91,78 @@
* Adds a security algorithm update. If appropriate, this will trigger a user notification.
*/
public void onSecurityAlgorithmUpdate(
- Context context, int subId, SecurityAlgorithmUpdate update) {
+ Context context, int phoneId, int subId, SecurityAlgorithmUpdate update) {
Rlog.d(TAG, "Security algorithm update: subId = " + subId + " " + update);
if (shouldIgnoreUpdate(update)) {
return;
}
+ if (!isEnabled()) {
+ Rlog.i(TAG, "Ignoring onSecurityAlgorithmUpdate. Notifier is disabled.");
+ return;
+ }
+
try {
mSerializedWorkQueue.execute(() -> {
- SubscriptionState subState = mSubscriptionState.get(subId);
- if (subState == null) {
- subState = new SubscriptionState();
- mSubscriptionState.put(subId, subState);
- }
+ try {
+ maybeUpdateSubscriptionMapping(context, phoneId, subId);
+ SubscriptionState subState = mSubscriptionState.get(subId);
+ if (subState == null) {
+ subState = new SubscriptionState();
+ mSubscriptionState.put(subId, subState);
+ }
- @CellularNetworkSecuritySafetySource.NullCipherState int nullCipherState =
- subState.update(update);
- mSafetySource.setNullCipherState(context, subId, nullCipherState);
+ @CellularNetworkSecuritySafetySource.NullCipherState int nullCipherState =
+ subState.update(update);
+ mSafetySource.setNullCipherState(context, subId, nullCipherState);
+ } catch (Throwable t) {
+ Rlog.e(TAG, "Failed to execute onSecurityAlgorithmUpdate " + t.getMessage());
+ }
});
} catch (RejectedExecutionException e) {
- Rlog.e(TAG, "Failed to schedule onEnableNotifier: " + e.getMessage());
+ Rlog.e(TAG, "Failed to schedule onSecurityAlgorithmUpdate: " + e.getMessage());
}
}
/**
+ * Set or update the current phoneId to subId mapping. When a new subId is mapped to a phoneId,
+ * we update the safety source to clear state of the old subId.
+ */
+ public void setSubscriptionMapping(Context context, int phoneId, int subId) {
+
+ if (!isEnabled()) {
+ Rlog.i(TAG, "Ignoring setSubscriptionMapping. Notifier is disabled.");
+ }
+
+ try {
+ mSerializedWorkQueue.execute(() -> {
+ try {
+ maybeUpdateSubscriptionMapping(context, phoneId, subId);
+ } catch (Throwable t) {
+ Rlog.e(TAG, "Failed to update subId mapping. phoneId: " + phoneId + " subId: "
+ + subId + ". " + t.getMessage());
+ }
+ });
+
+ } catch (RejectedExecutionException e) {
+ Rlog.e(TAG, "Failed to schedule setSubscriptionMapping: " + e.getMessage());
+ }
+ }
+
+ private void maybeUpdateSubscriptionMapping(Context context, int phoneId, int subId) {
+ final Integer oldSubId = mActiveSubscriptions.put(phoneId, subId);
+ if (oldSubId == null || oldSubId == subId) {
+ return;
+ }
+
+ // Our subId was updated for this phone, we should clear this subId's state.
+ mSubscriptionState.remove(oldSubId);
+ mSafetySource.clearNullCipherState(context, oldSubId);
+ }
+
+
+ /**
* Enables null cipher notification; {@code onSecurityAlgorithmUpdate} will start handling
* security algorithm updates and send notifications to the user when required.
*/
@@ -285,7 +333,7 @@
/** The state of security algorithms for a network connection. */
private static final class ConnectionState {
private static final ConnectionState UNKNOWN =
- new ConnectionState(SECURITY_ALGORITHM_UNKNOWN, SECURITY_ALGORITHM_UNKNOWN);
+ new ConnectionState(SECURITY_ALGORITHM_UNKNOWN, SECURITY_ALGORITHM_UNKNOWN);
private final @SecurityAlgorithm int mEncryption;
private final @SecurityAlgorithm int mIntegrity;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierKeyDownloadMgrTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierKeyDownloadMgrTest.java
index 07482e0..e60e95b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CarrierKeyDownloadMgrTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierKeyDownloadMgrTest.java
@@ -22,6 +22,7 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.times;
@@ -31,6 +32,8 @@
import android.app.DownloadManager;
import android.content.Context;
import android.content.Intent;
+import android.net.ConnectivityManager;
+import android.net.Network;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
import android.telephony.ImsiEncryptionInfo;
@@ -38,18 +41,18 @@
import android.telephony.TelephonyManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.text.TextUtils;
import android.util.Pair;
import androidx.test.filters.SmallTest;
-import com.android.internal.telephony.flags.FeatureFlags;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatchers;
+import org.mockito.Mock;
import org.mockito.Mockito;
import java.security.PublicKey;
@@ -91,7 +94,7 @@
+ "\"public-key\": \"" + CERT + "\"}]}";
private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener;
- private FeatureFlags mFeatureFlags;
+
@Before
public void setUp() throws Exception {
logd("CarrierActionAgentTest +Setup!");
@@ -99,15 +102,18 @@
mBundle = mContextFixture.getCarrierConfigBundle();
when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(mBundle);
when(mUserManager.isUserUnlocked()).thenReturn(true);
+ when(mKeyguardManager.isDeviceLocked()).thenReturn(false);
// Capture listener to emulate the carrier config change notification used later
ArgumentCaptor<CarrierConfigManager.CarrierConfigChangeListener> listenerArgumentCaptor =
ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class);
- mFeatureFlags = Mockito.mock(FeatureFlags.class);
- mCarrierKeyDM = new CarrierKeyDownloadManager(mPhone, mFeatureFlags);
+ mCarrierKeyDM = new CarrierKeyDownloadManager(mPhone);
verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(),
listenerArgumentCaptor.capture());
mCarrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(0);
-
+ mConnectivityManager = (ConnectivityManager) mPhone.getContext().getSystemService(
+ Context.CONNECTIVITY_SERVICE);
+ Network network = Mockito.mock(Network.class);
+ when(mConnectivityManager.getActiveNetwork()).thenReturn(network);
processAllMessages();
logd("CarrierActionAgentTest -Setup!");
}
@@ -331,8 +337,8 @@
expectedCal.add(Calendar.DATE, 1);
String dateExpected = dt.format(expectedCal.getTime());
- when(mTelephonyManager.getSimOperator(anyInt())).thenReturn("310260");
- when(mTelephonyManager.getSimCarrierId()).thenReturn(1);
+ when(mPhone.getOperatorNumeric()).thenReturn("310260");
+ when(mPhone.getCarrierId()).thenReturn(1);
Intent mIntent = new Intent(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
mIntent.putExtra(DownloadManager.EXTRA_DOWNLOAD_ID, downloadId);
mContext.sendBroadcast(mIntent);
@@ -355,11 +361,11 @@
bundle.putInt(CarrierConfigManager.IMSI_KEY_AVAILABILITY_INT, 3);
bundle.putString(CarrierConfigManager.IMSI_KEY_DOWNLOAD_URL_STRING, mURL);
- when(mTelephonyManager.getSimOperator(anyInt())).thenReturn("310260");
- when(mTelephonyManager.getSimCarrierId()).thenReturn(1);
+ when(mPhone.getOperatorNumeric()).thenReturn("310260");
+ when(mPhone.getCarrierId()).thenReturn(1);
mCarrierConfigChangeListener.onCarrierConfigChanged(0 /* slotIndex */,
SubscriptionManager.INVALID_SUBSCRIPTION_ID,
- TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID);
+ 1, TelephonyManager.UNKNOWN_CARRIER_ID);
processAllMessages();
assertEquals("310260", mCarrierKeyDM.mMccMncForDownload);
assertEquals(1, mCarrierKeyDM.mCarrierId);
@@ -369,6 +375,7 @@
@SmallTest
public void testCarrierConfigChangedWithUserLocked() {
when(mUserManager.isUserUnlocked()).thenReturn(false);
+ when(mKeyguardManager.isDeviceLocked()).thenReturn(true);
CarrierConfigManager carrierConfigManager = (CarrierConfigManager)
mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
int slotId = mPhone.getPhoneId();
@@ -376,14 +383,14 @@
bundle.putInt(CarrierConfigManager.IMSI_KEY_AVAILABILITY_INT, 3);
bundle.putString(CarrierConfigManager.IMSI_KEY_DOWNLOAD_URL_STRING, mURL);
- when(mTelephonyManager.getSimOperator(anyInt())).thenReturn("310260");
- when(mTelephonyManager.getSimCarrierId()).thenReturn(1);
+ when(mPhone.getOperatorNumeric()).thenReturn("310260");
+ when(mPhone.getCarrierId()).thenReturn(1);
mCarrierConfigChangeListener.onCarrierConfigChanged(0 /* slotIndex */,
SubscriptionManager.INVALID_SUBSCRIPTION_ID,
- TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID);
+ 1, TelephonyManager.UNKNOWN_CARRIER_ID);
processAllMessages();
- assertNull(mCarrierKeyDM.mMccMncForDownload);
- assertEquals(0, mCarrierKeyDM.mCarrierId);
+ assertEquals("310260", mCarrierKeyDM.mMccMncForDownload);
+ assertEquals(1, mCarrierKeyDM.mCarrierId);
}
@Test
@@ -391,6 +398,7 @@
public void testUserLockedAfterCarrierConfigChanged() {
// User is locked at beginning
when(mUserManager.isUserUnlocked()).thenReturn(false);
+ when(mKeyguardManager.isDeviceLocked()).thenReturn(true);
CarrierConfigManager carrierConfigManager = (CarrierConfigManager)
mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
int slotId = mPhone.getPhoneId();
@@ -399,17 +407,18 @@
bundle.putString(CarrierConfigManager.IMSI_KEY_DOWNLOAD_URL_STRING, mURL);
// Carrier config change received
- when(mTelephonyManager.getSimOperator(anyInt())).thenReturn("310260");
- when(mTelephonyManager.getSimCarrierId()).thenReturn(1);
+ when(mPhone.getOperatorNumeric()).thenReturn("310260");
+ when(mPhone.getCarrierId()).thenReturn(1);
mCarrierConfigChangeListener.onCarrierConfigChanged(0 /* slotIndex */,
SubscriptionManager.INVALID_SUBSCRIPTION_ID,
- TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID);
+ 1, TelephonyManager.UNKNOWN_CARRIER_ID);
processAllMessages();
// User unlocked event received
- Intent mIntent = new Intent(Intent.ACTION_USER_UNLOCKED);
+ Intent mIntent = new Intent(Intent.ACTION_USER_PRESENT);
mContext.sendBroadcast(mIntent);
when(mUserManager.isUserUnlocked()).thenReturn(true);
+ when(mKeyguardManager.isDeviceLocked()).thenReturn(false);
processAllMessages();
assertEquals("310260", mCarrierKeyDM.mMccMncForDownload);
@@ -432,11 +441,11 @@
mCarrierConfigChangeListener.onCarrierConfigChanged(0 /* slotIndex */,
SubscriptionManager.INVALID_SUBSCRIPTION_ID,
- TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID);
+ 1, TelephonyManager.UNKNOWN_CARRIER_ID);
processAllMessages();
- assertNull(mCarrierKeyDM.mMccMncForDownload);
+ assertTrue(TextUtils.isEmpty(mCarrierKeyDM.mMccMncForDownload));
- verify(mPhone).deleteCarrierInfoForImsiEncryption(0);
+ verify(mPhone).deleteCarrierInfoForImsiEncryption(1, "");
}
/**
@@ -453,8 +462,8 @@
bundle.putInt(CarrierConfigManager.IMSI_KEY_AVAILABILITY_INT, 3);
bundle.putString(CarrierConfigManager.IMSI_KEY_DOWNLOAD_URL_STRING, mURL);
- when(mTelephonyManager.getSimOperator(anyInt())).thenReturn("310260");
- when(mTelephonyManager.getSimCarrierId()).thenReturn(1);
+ when(mPhone.getOperatorNumeric()).thenReturn("310260");
+ when(mPhone.getCarrierId()).thenReturn(1);
Intent mIntent = new Intent("com.android.internal.telephony.carrier_key_download_alarm");
mIntent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, slotIndex);
mContext.sendBroadcast(mIntent);
@@ -493,4 +502,4 @@
assertEquals(CarrierKeyDownloadManager
.cleanCertString("Comments before" + CERT + "Comments after"), CERT);
}
-}
+}
\ No newline at end of file
diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
index 614846b..ba08f8b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
@@ -3019,7 +3019,63 @@
processAllMessages();
verify(mNullCipherNotifier, times(1))
- .onSecurityAlgorithmUpdate(eq(mContext), eq(0), eq(update));
+ .onSecurityAlgorithmUpdate(eq(mContext), eq(0), eq(0), eq(update));
+ }
+
+ @Test
+ public void testUpdateNullCipherNotifier_flagDisabled() {
+ when(mFeatureFlags.enableModemCipherTransparencyUnsolEvents()).thenReturn(false);
+ Phone phoneUT = makeNewPhoneUT();
+ phoneUT.sendMessage(
+ mPhoneUT.obtainMessage(
+ Phone.EVENT_SUBSCRIPTIONS_CHANGED,
+ new AsyncResult(null, null, null)));
+ processAllMessages();
+
+ verify(mNullCipherNotifier, never()).setSubscriptionMapping(any(), anyInt(), anyInt());
+ }
+
+ @Test
+ public void testUpdateNullCipherNotifier_activeSubscription() {
+ when(mFeatureFlags.enableModemCipherTransparencyUnsolEvents()).thenReturn(true);
+
+ int subId = 10;
+ SubscriptionInfoInternal subInfo = new SubscriptionInfoInternal.Builder().setSimSlotIndex(
+ 0).setId(subId).build();
+ when(mSubscriptionManagerService.getSubscriptionInfoInternal(subId)).thenReturn(
+ subInfo);
+ doReturn(subId).when(mSubscriptionManagerService)
+ .getSubId(anyInt());
+ Phone phoneUT = makeNewPhoneUT();
+
+ phoneUT.sendMessage(
+ mPhoneUT.obtainMessage(
+ Phone.EVENT_SUBSCRIPTIONS_CHANGED,
+ new AsyncResult(null, null, null)));
+ processAllMessages();
+
+ verify(mNullCipherNotifier, times(1)).setSubscriptionMapping(eq(mContext), eq(0), eq(10));
+ }
+
+ @Test
+ public void testUpdateNullCipherNotifier_inactiveSubscription() {
+ when(mFeatureFlags.enableModemCipherTransparencyUnsolEvents()).thenReturn(true);
+ int subId = 1;
+ SubscriptionInfoInternal subInfo = new SubscriptionInfoInternal.Builder().setSimSlotIndex(
+ -1).setId(subId).build();
+ when(mSubscriptionManagerService.getSubscriptionInfoInternal(subId)).thenReturn(
+ subInfo);
+ doReturn(subId).when(mSubscriptionManagerService)
+ .getSubId(anyInt());
+ Phone phoneUT = makeNewPhoneUT();
+
+ phoneUT.sendMessage(
+ mPhoneUT.obtainMessage(
+ Phone.EVENT_SUBSCRIPTIONS_CHANGED,
+ new AsyncResult(null, null, null)));
+ processAllMessages();
+
+ verify(mNullCipherNotifier, times(1)).setSubscriptionMapping(eq(mContext), eq(0), eq(-1));
}
@Test
diff --git a/tests/telephonytests/src/com/android/internal/telephony/security/CellularNetworkSecuritySafetySourceTest.java b/tests/telephonytests/src/com/android/internal/telephony/security/CellularNetworkSecuritySafetySourceTest.java
index 76118c4..77759a0 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/security/CellularNetworkSecuritySafetySourceTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/security/CellularNetworkSecuritySafetySourceTest.java
@@ -36,6 +36,7 @@
import android.content.Context;
import android.content.Intent;
import android.safetycenter.SafetySourceData;
+import android.safetycenter.SafetySourceIssue;
import android.util.Singleton;
import com.android.internal.R;
@@ -50,6 +51,7 @@
import org.mockito.ArgumentCaptor;
import java.time.Instant;
+import java.util.List;
public final class CellularNetworkSecuritySafetySourceTest extends TelephonyTest {
@@ -76,6 +78,8 @@
mContextFixture.putResource(R.string.scCellularNetworkSecurityTitle, "fake");
mContextFixture.putResource(R.string.scCellularNetworkSecuritySummary, "fake");
+ mContextFixture.putResource(R.string.scCellularNetworkSecurityLearnMore,
+ "https://support.google.com/android?p=cellular_security");
mContextFixture.putResource(R.string.scNullCipherIssueNonEncryptedTitle, "fake %1$s");
mContextFixture.putResource(R.string.scNullCipherIssueNonEncryptedSummary, "fake");
mContextFixture.putResource(R.string.scNullCipherIssueEncryptedTitle, "fake %1$s");
@@ -172,6 +176,26 @@
}
@Test
+ public void clearNullCipherState() {
+ ArgumentCaptor<SafetySourceData> data = ArgumentCaptor.forClass(SafetySourceData.class);
+
+ mSafetySource.setNullCipherIssueEnabled(mContext, true);
+ mSafetySource.setNullCipherState(mContext, 0, NULL_CIPHER_STATE_NOTIFY_ENCRYPTED);
+ mSafetySource.clearNullCipherState(mContext, 0);
+
+ // Once for enable, once for encrypted state, and once for clearing state
+ verify(mSafetyCenterManagerWrapper, times(3)).setSafetySourceData(data.capture());
+
+ // initial check that our encrypted state update created an issue
+ assertThat(data.getAllValues().get(1).getStatus()).isNotNull();
+ assertThat(data.getAllValues().get(1).getIssues()).hasSize(1);
+
+ // assert that our last call to clear state results in no issues sent to SC
+ assertThat(data.getAllValues().get(2).getStatus()).isNotNull();
+ assertThat(data.getAllValues().get(2).getIssues()).isEmpty();
+ }
+
+ @Test
public void disableIdentifierDisclosueIssue_nullData() {
// We must first enable before disabling, since a standalone call to disable may result in
// a no-op when the default for a new notifier is to be disabled.
@@ -245,4 +269,24 @@
assertThat(data.getAllValues().get(3).getStatus()).isNotNull();
assertThat(data.getAllValues().get(3).getIssues()).hasSize(2);
}
+
+ @Test
+ public void learnMoreLinkEmpty_learnMoreIsHidden() {
+ mContextFixture.putResource(R.string.scCellularNetworkSecurityLearnMore, "");
+
+ ArgumentCaptor<SafetySourceData> data = ArgumentCaptor.forClass(SafetySourceData.class);
+
+ mSafetySource.setNullCipherIssueEnabled(mContext, true);
+ mSafetySource.setNullCipherState(mContext, 0, NULL_CIPHER_STATE_NOTIFY_NON_ENCRYPTED);
+ mSafetySource.setIdentifierDisclosureIssueEnabled(mContext, true);
+ mSafetySource.setIdentifierDisclosure(mContext, 0, 12, Instant.now(), Instant.now());
+
+ verify(mSafetyCenterManagerWrapper, times(4)).setSafetySourceData(data.capture());
+ List<SafetySourceIssue.Action> actions = data.getAllValues().get(
+ 3).getIssues().getFirst().getActions();
+
+ // we only see the action that takes you to the settings page
+ assertThat(actions).hasSize(1);
+ assertThat(actions.getFirst().getId()).isEqualTo("cellular_security_settings");
+ }
}
\ No newline at end of file
diff --git a/tests/telephonytests/src/com/android/internal/telephony/security/NullCipherNotifierTest.java b/tests/telephonytests/src/com/android/internal/telephony/security/NullCipherNotifierTest.java
index 0bb7b76..6a4d2fb 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/security/NullCipherNotifierTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/security/NullCipherNotifierTest.java
@@ -45,6 +45,7 @@
public class NullCipherNotifierTest {
private static final int SUB_ID = 3425;
+ private static final int PHONE_ID = 999;
private static final List<Integer> NON_TRANSPORT_LAYER_EVENTS =
List.of(SecurityAlgorithmUpdate.CONNECTION_EVENT_VOLTE_SIP,
SecurityAlgorithmUpdate.CONNECTION_EVENT_VOLTE_SIP_SOS,
@@ -149,9 +150,11 @@
@Test
public void onSecurityAlgorithmUpdate_enabled_unprotectedEmergency_noSafetySourceUpdate() {
NullCipherNotifier notifier = new NullCipherNotifier(mExecutor, mSafetySource);
+ notifier.enable(mContext);
notifier.onSecurityAlgorithmUpdate(
mContext,
+ PHONE_ID,
SUB_ID,
new SecurityAlgorithmUpdate(
SecurityAlgorithmUpdate.CONNECTION_EVENT_AS_SIGNALLING_5G,
@@ -163,6 +166,24 @@
}
@Test
+ public void onSecurityAlgorithmUpdate_disabled_noSafetySourceUpdate() {
+ NullCipherNotifier notifier = new NullCipherNotifier(mExecutor, mSafetySource);
+ notifier.disable(mContext);
+
+ notifier.onSecurityAlgorithmUpdate(
+ mContext,
+ PHONE_ID,
+ SUB_ID,
+ new SecurityAlgorithmUpdate(
+ SecurityAlgorithmUpdate.CONNECTION_EVENT_AS_SIGNALLING_5G,
+ SecurityAlgorithmUpdate.SECURITY_ALGORITHM_EEA2,
+ SecurityAlgorithmUpdate.SECURITY_ALGORITHM_HMAC_SHA1_96,
+ /* isUnprotectedEmergency= */ false));
+
+ verify(mSafetySource, never()).setNullCipherState(any(), anyInt(), anyInt());
+ }
+
+ @Test
public void onSecurityAlgorithmUpdate_enabled_nonTransportLayerEvent_noSafetySourceUpdate() {
NullCipherNotifier notifier = new NullCipherNotifier(mExecutor, mSafetySource);
@@ -170,6 +191,7 @@
clearInvocations(mSafetySource);
notifier.onSecurityAlgorithmUpdate(
mContext,
+ PHONE_ID,
SUB_ID,
new SecurityAlgorithmUpdate(
connectionEvent,
@@ -185,12 +207,14 @@
@Test
public void onUpdate_enabled_transportLayerEvent_encryptionNullCipher_notifyNonEncrypted() {
NullCipherNotifier notifier = new NullCipherNotifier(mExecutor, mSafetySource);
+ notifier.enable(mContext);
for (int connectionEvent : TRANSPORT_LAYER_EVENTS) {
for (int encryptionAlgorithm : NULL_CIPHERS) {
clearInvocations(mSafetySource);
notifier.onSecurityAlgorithmUpdate(
mContext,
+ PHONE_ID,
SUB_ID,
new SecurityAlgorithmUpdate(
connectionEvent,
@@ -214,12 +238,14 @@
@Test
public void onUpdate_enabled_transportLayerEvent_integrityNullCipher_notifyNonEncrypted() {
NullCipherNotifier notifier = new NullCipherNotifier(mExecutor, mSafetySource);
+ notifier.enable(mContext);
for (int connectionEvent : TRANSPORT_LAYER_EVENTS) {
for (int integrityAlgorithm : NULL_CIPHERS) {
clearInvocations(mSafetySource);
notifier.onSecurityAlgorithmUpdate(
mContext,
+ PHONE_ID,
SUB_ID,
new SecurityAlgorithmUpdate(
connectionEvent,
@@ -243,12 +269,14 @@
@Test
public void onUpdate_enabled_transportLayerEvent_encryptionNonNullCipher_encrypted() {
NullCipherNotifier notifier = new NullCipherNotifier(mExecutor, mSafetySource);
+ notifier.enable(mContext);
for (int connectionEvent : TRANSPORT_LAYER_EVENTS) {
for (int encryptionAlgorithm : NON_NULL_CIPHERS) {
clearInvocations(mSafetySource);
notifier.onSecurityAlgorithmUpdate(
mContext,
+ PHONE_ID,
SUB_ID,
new SecurityAlgorithmUpdate(
connectionEvent,
@@ -272,12 +300,14 @@
@Test
public void onUpdate_enabled_transportLayerEvent_integrityNonNullCipher_encrypted() {
NullCipherNotifier notifier = new NullCipherNotifier(mExecutor, mSafetySource);
+ notifier.enable(mContext);
for (int connectionEvent : TRANSPORT_LAYER_EVENTS) {
for (int integrityAlgorithm : NON_NULL_CIPHERS) {
clearInvocations(mSafetySource);
notifier.onSecurityAlgorithmUpdate(
mContext,
+ PHONE_ID,
SUB_ID,
new SecurityAlgorithmUpdate(
connectionEvent,
@@ -301,11 +331,13 @@
@Test
public void onUpdate_enabled_transportLayerEvent_encryptionNonNullCipher_notifyEncrypted() {
NullCipherNotifier notifier = new NullCipherNotifier(mExecutor, mSafetySource);
+ notifier.enable(mContext);
for (int connectionEvent : TRANSPORT_LAYER_EVENTS) {
for (int encryptionAlgorithm : NON_NULL_CIPHERS) {
notifier.onSecurityAlgorithmUpdate(
mContext,
+ PHONE_ID,
SUB_ID,
new SecurityAlgorithmUpdate(
connectionEvent,
@@ -316,6 +348,7 @@
clearInvocations(mSafetySource);
notifier.onSecurityAlgorithmUpdate(
mContext,
+ PHONE_ID,
SUB_ID,
new SecurityAlgorithmUpdate(
connectionEvent,
@@ -345,6 +378,7 @@
for (int integrityAlgorithm : NON_NULL_CIPHERS) {
notifier.onSecurityAlgorithmUpdate(
mContext,
+ PHONE_ID,
SUB_ID,
new SecurityAlgorithmUpdate(
connectionEvent,
@@ -355,6 +389,7 @@
clearInvocations(mSafetySource);
notifier.onSecurityAlgorithmUpdate(
mContext,
+ PHONE_ID,
SUB_ID,
new SecurityAlgorithmUpdate(
connectionEvent,
@@ -374,4 +409,88 @@
}
}
}
+
+ @Test
+ public void onSecurityAlgorithmUpdate_updateSubscriptionId_clearsOldId() {
+ NullCipherNotifier notifier = new NullCipherNotifier(mExecutor, mSafetySource);
+ notifier.enable(mContext);
+
+ int connectionEvent = SecurityAlgorithmUpdate.CONNECTION_EVENT_AS_SIGNALLING_5G;
+ int encryptionAlgorithm = SecurityAlgorithmUpdate.SECURITY_ALGORITHM_EEA2;
+ int subId2 = 1337;
+
+ notifier.onSecurityAlgorithmUpdate(
+ mContext,
+ PHONE_ID,
+ SUB_ID,
+ getWellEncryptedUpdate());
+
+ notifier.setSubscriptionMapping(mContext, PHONE_ID, subId2);
+
+ verify(
+ mSafetySource,
+ times(1).description(
+ "Connection event: " + connectionEvent
+ + " Encryption algorithm: " + encryptionAlgorithm))
+ .setNullCipherState(
+ eq(mContext),
+ eq(SUB_ID),
+ eq(NULL_CIPHER_STATE_ENCRYPTED));
+
+ verify(mSafetySource, times(1)).clearNullCipherState(eq(mContext), eq(SUB_ID));
+ }
+
+ @Test
+ public void onSecurityAlgorithmUpdate_newSubIdOnAlgoUpdate_clearsOldId() {
+ NullCipherNotifier notifier = new NullCipherNotifier(mExecutor, mSafetySource);
+ notifier.enable(mContext);
+
+ int connectionEvent = SecurityAlgorithmUpdate.CONNECTION_EVENT_AS_SIGNALLING_5G;
+ int encryptionAlgorithm = SecurityAlgorithmUpdate.SECURITY_ALGORITHM_EEA2;
+ int subId2 = 1337;
+
+ notifier.onSecurityAlgorithmUpdate(
+ mContext,
+ PHONE_ID,
+ SUB_ID,
+ getWellEncryptedUpdate());
+
+ notifier.onSecurityAlgorithmUpdate(
+ mContext,
+ PHONE_ID,
+ subId2,
+ getWellEncryptedUpdate());
+
+ verify(
+ mSafetySource,
+ times(1).description(
+ "SubId: " + SUB_ID + "Connection event: " + connectionEvent
+ + " Encryption algorithm: " + encryptionAlgorithm))
+ .setNullCipherState(
+ eq(mContext),
+ eq(SUB_ID),
+ eq(NULL_CIPHER_STATE_ENCRYPTED));
+
+ // The update with subId2 should clear subId1 data since they have the same phone id
+ verify(mSafetySource, times(1)).clearNullCipherState(eq(mContext), eq(SUB_ID));
+
+ verify(
+ mSafetySource,
+ times(1).description(
+ "SubId: " + SUB_ID + "Connection event: " + connectionEvent
+ + " Encryption algorithm: " + encryptionAlgorithm))
+ .setNullCipherState(
+ eq(mContext),
+ eq(subId2),
+ eq(NULL_CIPHER_STATE_ENCRYPTED));
+
+ }
+
+ private SecurityAlgorithmUpdate getWellEncryptedUpdate() {
+ return new SecurityAlgorithmUpdate(
+ SecurityAlgorithmUpdate.CONNECTION_EVENT_AS_SIGNALLING_5G,
+ SecurityAlgorithmUpdate.SECURITY_ALGORITHM_EEA2,
+ SecurityAlgorithmUpdate.SECURITY_ALGORITHM_HMAC_SHA1_96,
+ /* isUnprotectedEmergency= */ false);
+ }
}