Merge "Flagging requirement for notifyDataActivityChanged based on Slot." into main
diff --git a/flags/Android.bp b/flags/Android.bp
index 99c99c5..3c0deee 100644
--- a/flags/Android.bp
+++ b/flags/Android.bp
@@ -23,6 +23,7 @@
package: "com.android.internal.telephony.flags",
srcs: [
"data.aconfig",
+ "domainselection.aconfig",
"ims.aconfig",
"messaging.aconfig",
"misc.aconfig",
diff --git a/flags/data.aconfig b/flags/data.aconfig
index 52cd486..e65f8e4 100644
--- a/flags/data.aconfig
+++ b/flags/data.aconfig
@@ -1,6 +1,20 @@
package: "com.android.internal.telephony.flags"
flag {
+ name: "use_alarm_callback"
+ namespace: "telephony"
+ description: "Use alarm callback instead of broadcast."
+ bug: "311476875"
+}
+
+flag {
+ name: "refine_preferred_data_profile_selection"
+ namespace: "telephony"
+ description: "Upon internet network connect, refine selection of preferred data profile."
+ bug: "311476883"
+}
+
+flag {
name: "unthrottle_check_transport"
namespace: "telephony"
description: "Check transport when unthrottle."
diff --git a/flags/domainselection.aconfig b/flags/domainselection.aconfig
new file mode 100644
index 0000000..2e1dfc8
--- /dev/null
+++ b/flags/domainselection.aconfig
@@ -0,0 +1,29 @@
+package: "com.android.internal.telephony.flags"
+
+flag {
+ name: "ap_domain_selection_enabled"
+ namespace: "telephony"
+ description: "This flag controls AP domain selection feature."
+ bug:"258112541"
+}
+
+flag {
+ name: "use_aosp_domain_selection_service"
+ namespace: "telephony"
+ description: "This flag controls AOSP's domain selection service supported."
+ bug:"258112541"
+}
+
+flag {
+ name: "use_oem_domain_selection_service"
+ namespace: "telephony"
+ description: "This flag controls OEMs' domain selection service supported."
+ bug:"258112541"
+}
+
+flag {
+ name: "domain_selection_metrics_enabled"
+ namespace: "telephony"
+ description: "This flag controls domain selection metrics."
+ bug:"258112541"
+}
diff --git a/flags/iwlan.aconfig b/flags/iwlan.aconfig
index efd43e4..0dc9f8d 100644
--- a/flags/iwlan.aconfig
+++ b/flags/iwlan.aconfig
@@ -6,3 +6,9 @@
description: "Add AEAD algorithms AES-GCM-8, AES-GCM-12 and AES-GCM-16 to IWLAN"
bug:"306119890"
}
+flag {
+ name: "enable_multiple_sa_proposals"
+ namespace: "telephony"
+ description: "Add multiple proposals of cipher suites in IKE SA and Child SA"
+ bug:"287296642"
+}
diff --git a/flags/misc.aconfig b/flags/misc.aconfig
index deda579..159d462 100644
--- a/flags/misc.aconfig
+++ b/flags/misc.aconfig
@@ -56,3 +56,10 @@
description: "Load default data subid on create in PhoneGlobals."
bug: "310591561"
}
+
+flag {
+ name: "enable_telephony_analytics"
+ namespace: "telephony"
+ description: "Enable Telephony Analytics information of Service State , Sms and Call scenarios"
+ bug: "309896524"
+}
diff --git a/proto/src/persist_atoms.proto b/proto/src/persist_atoms.proto
index 537f824..6d1008b 100644
--- a/proto/src/persist_atoms.proto
+++ b/proto/src/persist_atoms.proto
@@ -277,6 +277,9 @@
optional int32 fold_state = 34;
optional int64 rat_switch_count_after_connected = 35;
optional bool handover_in_progress = 36;
+ optional bool is_iwlan_cross_sim_at_start = 37;
+ optional bool is_iwlan_cross_sim_at_end = 38;
+ optional bool is_iwlan_cross_sim_at_connected = 39;
// Internal use only
optional int64 setup_begin_millis = 10001;
@@ -365,6 +368,7 @@
repeated int32 handover_failure_causes = 20;
repeated int32 handover_failure_rat = 21;
optional bool is_non_dds = 22;
+ optional bool is_iwlan_cross_sim = 23;
}
message CellularServiceState {
@@ -382,6 +386,7 @@
optional int32 fold_state = 12;
optional bool override_voice_service = 13;
optional bool isDataEnabled = 14;
+ optional bool is_iwlan_cross_sim = 15;
// Internal use only
optional int64 last_used_millis = 10001;
@@ -408,6 +413,7 @@
optional int32 extra_code = 6;
optional string extra_message = 7;
optional int32 count = 8;
+ optional bool is_iwlan_cross_sim = 9;
// Internal use only
optional int64 last_used_millis = 10001;
@@ -429,6 +435,7 @@
optional int64 ut_available_millis = 12;
optional int64 registering_millis = 13;
optional int64 unregistered_millis = 14;
+ optional bool is_iwlan_cross_sim = 15;
// Internal use only
optional int64 last_used_millis = 10001;
diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java
index 4b977ff..6b40040 100644
--- a/src/java/com/android/internal/telephony/CommandsInterface.java
+++ b/src/java/com/android/internal/telephony/CommandsInterface.java
@@ -2912,4 +2912,19 @@
* @param result Callback message to receive the result.
*/
default void isCellularIdentifierTransparencyEnabled(Message result) {}
-}
\ No newline at end of file
+
+ /**
+ * Enables or disables security algorithm update reports.
+ *
+ * @param enable {@code true} to enable, {@code false} to disable.
+ * @param result Callback message to receive the result.
+ */
+ default void setSecurityAlgorithmsUpdatedEnabled(boolean enable, Message result) {}
+
+ /**
+ * Check whether security algorithm update reports are enabled.
+ *
+ * @param result Callback message to receive the result.
+ */
+ default void isSecurityAlgorithmsUpdatedEnabled(Message result) {}
+}
diff --git a/src/java/com/android/internal/telephony/MultiSimSettingController.java b/src/java/com/android/internal/telephony/MultiSimSettingController.java
index d6b0930..d07e731 100644
--- a/src/java/com/android/internal/telephony/MultiSimSettingController.java
+++ b/src/java/com/android/internal/telephony/MultiSimSettingController.java
@@ -541,7 +541,7 @@
boolean setDefaultData = true;
List<SubscriptionInfo> activeSubList = mSubscriptionManagerService
.getActiveSubscriptionInfoList(mContext.getOpPackageName(),
- mContext.getAttributionTag());
+ mContext.getAttributionTag(), true/*isForAllProfile*/);
for (SubscriptionInfo activeInfo : activeSubList) {
if (!(groupUuid.equals(activeInfo.getGroupUuid()))) {
// Do not set refSubId as defaultDataSubId if there are other active
@@ -588,7 +588,7 @@
List<SubscriptionInfo> activeSubInfos = mSubscriptionManagerService
.getActiveSubscriptionInfoList(mContext.getOpPackageName(),
- mContext.getAttributionTag());
+ mContext.getAttributionTag(), true/*isForAllProfile*/);
if (ArrayUtils.isEmpty(activeSubInfos)) {
mPrimarySubList.clear();
diff --git a/src/java/com/android/internal/telephony/NetworkIndication.java b/src/java/com/android/internal/telephony/NetworkIndication.java
index dc3fbf1..3f345e0 100644
--- a/src/java/com/android/internal/telephony/NetworkIndication.java
+++ b/src/java/com/android/internal/telephony/NetworkIndication.java
@@ -30,6 +30,7 @@
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED;
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED;
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESTRICTED_STATE_CHANGED;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SECURITY_ALGORITHMS_UPDATED;
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SIGNAL_STRENGTH;
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SUPP_SVC_NOTIFICATION;
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_VOICE_RADIO_TECH_CHANGED;
@@ -438,6 +439,20 @@
// TODO (b/276752426) notify registrants of identifier disclosure
}
+ /**
+ * Security algorithm update events
+ * @param indicationType Type of radio indication
+ * @param securityAlgorithmUpdate details of what changed
+ */
+ public void securityAlgorithmsUpdated(int indicationType,
+ android.hardware.radio.network.SecurityAlgorithmUpdate securityAlgorithmUpdate) {
+ mRil.processIndication(HAL_SERVICE_NETWORK, indicationType);
+
+ if (mRil.isLogOrTrace()) {
+ mRil.unsljLogRet(RIL_UNSOL_SECURITY_ALGORITHMS_UPDATED, securityAlgorithmUpdate);
+ }
+ }
+
@Override
public String getInterfaceHash() {
return IRadioNetworkIndication.HASH;
diff --git a/src/java/com/android/internal/telephony/NetworkResponse.java b/src/java/com/android/internal/telephony/NetworkResponse.java
index e4e2b1b..eb2cd16 100644
--- a/src/java/com/android/internal/telephony/NetworkResponse.java
+++ b/src/java/com/android/internal/telephony/NetworkResponse.java
@@ -528,6 +528,29 @@
}
}
+ /**
+ * @param responseInfo Response info struct containing response type, serial no. and error
+ */
+ public void setSecurityAlgorithmsUpdatedEnabledResponse(RadioResponseInfo responseInfo) {
+ RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo);
+ }
+
+ /**
+ * @param responseInfo Response info struct containing response type, serial no. and error.
+ * @param isEnabled Indicates whether security algorithm updates from the modem are enabled.
+ */
+ public void isSecurityAlgorithmsUpdatedEnabledResponse(RadioResponseInfo responseInfo,
+ boolean isEnabled) {
+ RILRequest rr = mRil.processResponse(HAL_SERVICE_NETWORK, responseInfo);
+
+ if (rr != null) {
+ if (responseInfo.error == RadioError.NONE) {
+ RadioResponse.sendMessageResponse(rr.mResult, isEnabled);
+ }
+ mRil.processResponseDone(rr, responseInfo, isEnabled);
+ }
+ }
+
@Override
public String getInterfaceHash() {
return IRadioNetworkResponse.HASH;
diff --git a/src/java/com/android/internal/telephony/NetworkTypeController.java b/src/java/com/android/internal/telephony/NetworkTypeController.java
index d1c8359..e6fb84e 100644
--- a/src/java/com/android/internal/telephony/NetworkTypeController.java
+++ b/src/java/com/android/internal/telephony/NetworkTypeController.java
@@ -594,9 +594,6 @@
log("Reset timers since physical channel config indications are off.");
}
resetAllTimers();
- mRatchetedNrBands.clear();
- mRatchetedNrBandwidths = 0;
- mLastAnchorNrCellId = PhysicalChannelConfig.PHYSICAL_CELL_ID_UNKNOWN;
}
transitionToCurrentState();
break;
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index 72d0622..b991b8e 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -660,7 +660,7 @@
mCi.registerForSrvccStateChanged(this, EVENT_SRVCC_STATE_CHANGED, null);
}
//Initialize Telephony Analytics
- if (isTelephonyAnalyticsEnabled()) {
+ if (mFeatureFlags.enableTelephonyAnalytics()) {
mTelephonyAnalytics = new TelephonyAnalytics(this);
}
}
@@ -4780,11 +4780,6 @@
return mTelephonyAnalytics;
}
- public boolean isTelephonyAnalyticsEnabled() {
- return mContext.getResources().getBoolean(
- com.android.internal.R.bool.telephony_analytics_switch);
- }
-
/** @hide */
public CarrierPrivilegesTracker getCarrierPrivilegesTracker() {
return null;
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index 56cb808..7ed7dcb 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -5134,6 +5134,61 @@
});
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setSecurityAlgorithmsUpdatedEnabled(boolean enable, Message result) {
+ RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class);
+ if (!canMakeRequest(
+ "setSecurityAlgorithmsUpdatedEnabled",
+ networkProxy,
+ result,
+ RADIO_HAL_VERSION_2_2)) {
+ return;
+ }
+
+ RILRequest rr = obtainRequest(RIL_REQUEST_SET_SECURITY_ALGORITHMS_UPDATED_ENABLED, result,
+ mRILDefaultWorkSource);
+
+ if (RILJ_LOGD) {
+ riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)
+ + " enable=" + enable);
+ }
+
+ radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "setSecurityAlgorithmsUpdatedEnabled",
+ () -> {
+ networkProxy.setSecurityAlgorithmsUpdatedEnabled(rr.mSerial, enable);
+ });
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void isSecurityAlgorithmsUpdatedEnabled(Message result) {
+ RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class);
+ if (!canMakeRequest(
+ "isSecurityAlgorithmsUpdatedEnabled",
+ networkProxy,
+ result,
+ RADIO_HAL_VERSION_2_2)) {
+ return;
+ }
+
+ RILRequest rr = obtainRequest(RIL_REQUEST_IS_SECURITY_ALGORITHMS_UPDATED_ENABLED, result,
+ mRILDefaultWorkSource);
+
+ if (RILJ_LOGD) {
+ riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest));
+ }
+
+ radioServiceInvokeHelper(
+ HAL_SERVICE_NETWORK, rr, "isSecurityAlgorithmsUpdatedEnabled", () -> {
+ networkProxy.isSecurityAlgorithmsUpdatedEnabled(rr.mSerial);
+ });
+ }
+
//***** Private Methods
/**
* This is a helper function to be called when an indication callback is called for any radio
@@ -6015,4 +6070,4 @@
return "UNKNOWN:" + service;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/java/com/android/internal/telephony/RadioNetworkProxy.java b/src/java/com/android/internal/telephony/RadioNetworkProxy.java
index fc308ca..4acc71a 100644
--- a/src/java/com/android/internal/telephony/RadioNetworkProxy.java
+++ b/src/java/com/android/internal/telephony/RadioNetworkProxy.java
@@ -949,4 +949,34 @@
}
// Only supported on AIDL.
}
+
+ /**
+ * Checks security algorithm update reports are enabled.
+ *
+ * @param serial Serial number of the request.
+ * @throws RemoteException
+ */
+ public void isSecurityAlgorithmsUpdatedEnabled(int serial) throws RemoteException {
+ if (isEmpty()) return;
+ if (isAidl()) {
+ mNetworkProxy.isSecurityAlgorithmsUpdatedEnabled(serial);
+ }
+ // Only supported on AIDL.
+ }
+
+ /**
+ * Enables or disables security algorithm update reports.
+ *
+ * @param serial Serial number of request.
+ * @param enable Indicates whether to enable or disable security algorithm update reports.
+ * @throws RemoteException
+ */
+ public void setSecurityAlgorithmsUpdatedEnabled(int serial,
+ boolean enable) throws RemoteException {
+ if (isEmpty()) return;
+ if (isAidl()) {
+ mNetworkProxy.setSecurityAlgorithmsUpdatedEnabled(serial, enable);
+ }
+ // Only supported on AIDL.
+ }
}
diff --git a/src/java/com/android/internal/telephony/SignalStrengthController.java b/src/java/com/android/internal/telephony/SignalStrengthController.java
index 383ffcd..387c501 100644
--- a/src/java/com/android/internal/telephony/SignalStrengthController.java
+++ b/src/java/com/android/internal/telephony/SignalStrengthController.java
@@ -353,7 +353,7 @@
List<SubscriptionInfo> subInfoList = SubscriptionManagerService.getInstance()
.getActiveSubscriptionInfoList(mPhone.getContext().getOpPackageName(),
- mPhone.getContext().getAttributionTag());
+ mPhone.getContext().getAttributionTag(), true/*isForAllProfile*/);
if (!ArrayUtils.isEmpty(subInfoList)) {
for (SubscriptionInfo info : subInfoList) {
diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java
index 48a18ee..bba0f19 100644
--- a/src/java/com/android/internal/telephony/data/DataNetwork.java
+++ b/src/java/com/android/internal/telephony/data/DataNetwork.java
@@ -406,6 +406,10 @@
/** Data network tear down due to preferred data switched to another phone. */
public static final int TEAR_DOWN_REASON_PREFERRED_DATA_SWITCHED = 30;
+ //********************************************************************************************//
+ // WHENEVER ADD A NEW TEAR DOWN REASON, PLEASE UPDATE DataDeactivateReasonEnum in enums.proto //
+ //********************************************************************************************//
+
@IntDef(prefix = {"BANDWIDTH_SOURCE_"},
value = {
BANDWIDTH_SOURCE_UNKNOWN,
diff --git a/src/java/com/android/internal/telephony/data/DataProfileManager.java b/src/java/com/android/internal/telephony/data/DataProfileManager.java
index df1fc92..b4055a3 100644
--- a/src/java/com/android/internal/telephony/data/DataProfileManager.java
+++ b/src/java/com/android/internal/telephony/data/DataProfileManager.java
@@ -419,18 +419,36 @@
* @param internetNetworks The connected internet data networks.
*/
private void onInternetDataNetworkConnected(@NonNull Set<DataNetwork> internetNetworks) {
- // Most of the cases there should be only one.
- // but in case there are multiple, find the default internet network, and choose the
- // one which has longest life cycle.
- DataProfile defaultProfile = internetNetworks.stream()
- .filter(network -> mPreferredDataProfile == null
- // Find the one most resembles the current preferred profile,
- // avoiding e.g. DUN default network.
- || canPreferredDataProfileSatisfy(
- network.getAttachedNetworkRequestList()))
- .map(DataNetwork::getDataProfile)
- .min(Comparator.comparingLong(DataProfile::getLastSetupTimestamp))
- .orElse(null);
+ DataProfile defaultProfile = null;
+ if (mFeatureFlags.refinePreferredDataProfileSelection()) {
+ // Most of the cases there should be only one.
+ // but in case there are multiple, find the default internet network, and choose the
+ // one which has longest life cycle.
+ defaultProfile = internetNetworks.stream()
+ .filter(network -> mPreferredDataProfile == null
+ // Find the one most resembles the current preferred profile,
+ // avoiding e.g. DUN default network.
+ || canPreferredDataProfileSatisfy(
+ network.getAttachedNetworkRequestList()))
+ .map(DataNetwork::getDataProfile)
+ .min(Comparator.comparingLong(DataProfile::getLastSetupTimestamp))
+ .orElse(null);
+ } else {
+ if (internetNetworks.size() == 1) {
+ // Most of the cases there should be only one.
+ defaultProfile = internetNetworks.stream().findFirst().get().getDataProfile();
+ } else if (internetNetworks.size() > 1) {
+ // but in case there are multiple, find the default internet network, and choose the
+ // one which has longest life cycle.
+ defaultProfile = internetNetworks.stream()
+ .filter(network -> mPreferredDataProfile == null
+ || canPreferredDataProfileSatisfy(
+ network.getAttachedNetworkRequestList()))
+ .map(DataNetwork::getDataProfile)
+ .min(Comparator.comparingLong(DataProfile::getLastSetupTimestamp))
+ .orElse(null);
+ }
+ }
// Update a working internet data profile as a future candidate for preferred data profile
// after APNs are reset to default
diff --git a/src/java/com/android/internal/telephony/data/DataRetryManager.java b/src/java/com/android/internal/telephony/data/DataRetryManager.java
index 754400e..5933463 100644
--- a/src/java/com/android/internal/telephony/data/DataRetryManager.java
+++ b/src/java/com/android/internal/telephony/data/DataRetryManager.java
@@ -22,6 +22,11 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.net.NetworkCapabilities;
import android.os.AsyncResult;
import android.os.Handler;
@@ -74,6 +79,11 @@
public class DataRetryManager extends Handler {
private static final boolean VDBG = false;
+ /** Intent of Alarm Manager for long retry timer. */
+ private static final String ACTION_RETRY = "com.android.internal.telephony.data.ACTION_RETRY";
+ /** The extra key for the hashcode of the retry entry for Alarm Manager. */
+ private static final String ACTION_RETRY_EXTRA_HASHCODE = "extra_retry_hashcode";
+
/** Event for data setup retry. */
private static final int EVENT_DATA_SETUP_RETRY = 3;
@@ -1014,6 +1024,22 @@
mRil.registerForOn(this, EVENT_RADIO_ON, null);
mRil.registerForModemReset(this, EVENT_MODEM_RESET, null);
+ if (!mFlags.useAlarmCallback()) {
+ // Register intent of alarm manager for long retry timer
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(ACTION_RETRY);
+ mPhone.getContext().registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (ACTION_RETRY.equals(intent.getAction())) {
+ DataRetryManager.this.onAlarmIntentRetry(
+ intent.getIntExtra(ACTION_RETRY_EXTRA_HASHCODE,
+ -1 /*Bad hashcode*/));
+ }
+ }
+ }, intentFilter);
+ }
+
if (mDataConfigManager.shouldResetDataThrottlingWhenTacChanges()) {
mPhone.getServiceStateTracker().registerForAreaCodeChanged(this, EVENT_TAC_CHANGED,
null);
@@ -1449,19 +1475,48 @@
? EVENT_DATA_SETUP_RETRY : EVENT_DATA_HANDOVER_RETRY, dataRetryEntry),
dataRetryEntry.retryDelayMillis);
} else {
- // No need to wake up the device, the retry can wait util next time the device wake up
- // to save power.
- mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME,
- dataRetryEntry.retryElapsedTime,
- "dataRetryHash-" + dataRetryEntry.hashCode() /*debug tag*/,
- Runnable::run,
- null /*worksource*/,
- () -> {
- logl("onAlarm retry " + dataRetryEntry);
- sendMessage(obtainMessage(dataRetryEntry instanceof DataSetupRetryEntry
- ? EVENT_DATA_SETUP_RETRY : EVENT_DATA_HANDOVER_RETRY,
- dataRetryEntry));
- });
+ if (mFlags.useAlarmCallback()) {
+ // No need to wake up the device, the retry can wait util next time the device wake
+ // up to save power.
+ mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME,
+ dataRetryEntry.retryElapsedTime,
+ "dataRetryHash-" + dataRetryEntry.hashCode() /*debug tag*/,
+ Runnable::run,
+ null /*worksource*/,
+ () -> {
+ logl("onAlarm retry " + dataRetryEntry);
+ sendMessage(obtainMessage(dataRetryEntry instanceof DataSetupRetryEntry
+ ? EVENT_DATA_SETUP_RETRY : EVENT_DATA_HANDOVER_RETRY,
+ dataRetryEntry));
+ });
+ } else {
+ Intent intent = new Intent(ACTION_RETRY);
+ intent.putExtra(ACTION_RETRY_EXTRA_HASHCODE, dataRetryEntry.hashCode());
+ // No need to wake up the device, the retry can wait util next time the device wake
+ // up to save power.
+ mAlarmManager.setAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME,
+ dataRetryEntry.retryElapsedTime,
+ PendingIntent.getBroadcast(mPhone.getContext(),
+ dataRetryEntry.hashCode()/*Unique identifier of the retry attempt*/,
+ intent,
+ PendingIntent.FLAG_IMMUTABLE));
+ }
+ }
+ }
+
+ /**
+ * Called when it's time to retry scheduled by Alarm Manager.
+ * @param retryHashcode The hashcode is the unique identifier of which retry entry to retry.
+ */
+ private void onAlarmIntentRetry(int retryHashcode) {
+ DataRetryEntry dataRetryEntry = mDataRetryEntries.stream()
+ .filter(entry -> entry.hashCode() == retryHashcode)
+ .findAny()
+ .orElse(null);
+ logl("onAlarmIntentRetry: found " + dataRetryEntry + " with hashcode " + retryHashcode);
+ if (dataRetryEntry != null) {
+ sendMessage(obtainMessage(dataRetryEntry instanceof DataSetupRetryEntry
+ ? EVENT_DATA_SETUP_RETRY : EVENT_DATA_HANDOVER_RETRY, dataRetryEntry));
}
}
diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java
index 6773dca..3023501 100644
--- a/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java
+++ b/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java
@@ -39,14 +39,18 @@
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.sysprop.TelephonyProperties;
+import android.telephony.AccessNetworkConstants;
import android.telephony.Annotation.DisconnectCauses;
import android.telephony.CarrierConfigManager;
import android.telephony.DisconnectCause;
import android.telephony.EmergencyRegResult;
import android.telephony.NetworkRegistrationInfo;
+import android.telephony.PreciseDataConnectionState;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
+import android.telephony.data.ApnSetting;
import android.util.ArraySet;
import com.android.internal.annotations.VisibleForTesting;
@@ -57,6 +61,7 @@
import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.telephony.data.PhoneSwitcher;
+import com.android.internal.telephony.satellite.SatelliteController;
import com.android.telephony.Rlog;
import java.lang.annotation.Retention;
@@ -65,6 +70,7 @@
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executor;
import java.util.function.Consumer;
/**
@@ -83,6 +89,7 @@
private static final boolean DEFAULT_EMERGENCY_CALLBACK_MODE_SUPPORTED = true;
/** Default Emergency Callback Mode exit timeout value. */
private static final long DEFAULT_ECM_EXIT_TIMEOUT_MS = 300000;
+ private static final int DEFAULT_EPDN_DISCONNECTION_TIMEOUT_MS = 500;
/** The emergency types used when setting the emergency mode on modem. */
@Retention(RetentionPolicy.SOURCE)
@@ -120,6 +127,9 @@
private final Runnable mExitEcmRunnable = this::exitEmergencyCallbackMode;
// Tracks emergency calls by callId that have reached {@link Call.State#ACTIVE}.
private final Set<String> mActiveEmergencyCalls = new ArraySet<>();
+ private Phone mPhoneToExit;
+ private int mPdnDisconnectionTimeoutMs = DEFAULT_EPDN_DISCONNECTION_TIMEOUT_MS;
+ private final Object mLock = new Object();
private Phone mPhone;
// Tracks ongoing emergency callId to handle a second emergency call
private String mOngoingCallId;
@@ -165,6 +175,29 @@
}
};
+ /**
+ * TelephonyCallback used to monitor whether ePDN on cellular network is disconnected or not.
+ */
+ private final class PreciseDataConnectionStateListener extends TelephonyCallback implements
+ TelephonyCallback.PreciseDataConnectionStateListener {
+ @Override
+ public void onPreciseDataConnectionStateChanged(
+ @NonNull PreciseDataConnectionState dataConnectionState) {
+ ApnSetting apnSetting = dataConnectionState.getApnSetting();
+ if ((apnSetting == null)
+ || ((apnSetting.getApnTypeBitmask() | ApnSetting.TYPE_EMERGENCY) == 0)
+ || (dataConnectionState.getTransportType()
+ != AccessNetworkConstants.TRANSPORT_TYPE_WWAN)) {
+ return;
+ }
+ int state = dataConnectionState.getState();
+ Rlog.d(TAG, "onPreciseDataConnectionStateChanged ePDN state=" + state);
+ if (state == TelephonyManager.DATA_DISCONNECTED) exitEmergencyModeIfDelayed();
+ }
+ }
+
+ private PreciseDataConnectionStateListener mDataConnectionStateListener;
+
/** PhoneFactory Dependencies for testing. */
@VisibleForTesting
public interface PhoneFactoryProxy {
@@ -188,6 +221,8 @@
@VisibleForTesting
public interface TelephonyManagerProxy {
int getPhoneCount();
+ void registerTelephonyCallback(int subId, Executor executor, TelephonyCallback callback);
+ void unregisterTelephonyCallback(TelephonyCallback callback);
}
private final TelephonyManagerProxy mTelephonyManagerProxy;
@@ -195,7 +230,6 @@
private static class TelephonyManagerProxyImpl implements TelephonyManagerProxy {
private final TelephonyManager mTelephonyManager;
-
TelephonyManagerProxyImpl(Context context) {
mTelephonyManager = new TelephonyManager(context);
}
@@ -204,6 +238,18 @@
public int getPhoneCount() {
return mTelephonyManager.getActiveModemCount();
}
+
+ @Override
+ public void registerTelephonyCallback(int subId,
+ Executor executor, TelephonyCallback callback) {
+ TelephonyManager tm = mTelephonyManager.createForSubscriptionId(subId);
+ tm.registerTelephonyCallback(executor, callback);
+ }
+
+ @Override
+ public void unregisterTelephonyCallback(TelephonyCallback callback) {
+ mTelephonyManager.unregisterTelephonyCallback(callback);
+ }
}
/**
@@ -215,11 +261,15 @@
}
@VisibleForTesting
- public static final int MSG_SET_EMERGENCY_MODE_DONE = 1;
+ public static final int MSG_SET_EMERGENCY_MODE = 1;
@VisibleForTesting
- public static final int MSG_EXIT_EMERGENCY_MODE_DONE = 2;
+ public static final int MSG_EXIT_EMERGENCY_MODE = 2;
@VisibleForTesting
- public static final int MSG_SET_EMERGENCY_CALLBACK_MODE_DONE = 3;
+ public static final int MSG_SET_EMERGENCY_MODE_DONE = 3;
+ @VisibleForTesting
+ public static final int MSG_EXIT_EMERGENCY_MODE_DONE = 4;
+ @VisibleForTesting
+ public static final int MSG_SET_EMERGENCY_CALLBACK_MODE_DONE = 5;
private class MyHandler extends Handler {
@@ -263,7 +313,7 @@
if (mIsEmergencyCallStartedDuringEmergencySms) {
Phone phone = mPhone;
mPhone = null;
- exitEmergencyMode(mSmsPhone, emergencyType);
+ exitEmergencyMode(mSmsPhone, emergencyType, false);
// Restore call phone for further use.
mPhone = phone;
@@ -322,6 +372,27 @@
}
break;
}
+ case MSG_EXIT_EMERGENCY_MODE: {
+ Rlog.v(TAG, "MSG_EXIT_EMERGENCY_MODE");
+ exitEmergencyModeIfDelayed();
+ break;
+ }
+ case MSG_SET_EMERGENCY_MODE: {
+ AsyncResult ar = (AsyncResult) msg.obj;
+ Integer emergencyType = (Integer) ar.userObj;
+ Rlog.v(TAG, "MSG_SET_EMERGENCY_MODE for "
+ + emergencyTypeToString(emergencyType) + ", " + mEmergencyMode);
+ // Should be reached here only when starting a new emergency service
+ // while exiting emergency callback mode on the other slot.
+ if (mEmergencyMode != MODE_EMERGENCY_WWAN) return;
+ final Phone phone = (mPhone != null) ? mPhone : mSmsPhone;
+ if (phone != null) {
+ mWasEmergencyModeSetOnModem = true;
+ phone.setEmergencyMode(MODE_EMERGENCY_WWAN,
+ mHandler.obtainMessage(MSG_SET_EMERGENCY_MODE_DONE, emergencyType));
+ }
+ break;
+ }
default:
break;
}
@@ -459,7 +530,7 @@
// exit the emergency mode when receiving the result of setting the emergency mode and
// the emergency mode for this call will be restarted after the exit complete.
if (isInEmergencyMode() && !isEmergencyModeInProgress()) {
- exitEmergencyMode(mSmsPhone, EMERGENCY_TYPE_SMS);
+ exitEmergencyMode(mSmsPhone, EMERGENCY_TYPE_SMS, false);
}
mPhone = phone;
@@ -511,7 +582,7 @@
MSG_SET_EMERGENCY_CALLBACK_MODE_DONE);
}
} else {
- exitEmergencyMode(mPhone, EMERGENCY_TYPE_CALL);
+ exitEmergencyMode(mPhone, EMERGENCY_TYPE_CALL, false);
clearEmergencyCallInfo();
}
}
@@ -576,8 +647,27 @@
return;
}
- mWasEmergencyModeSetOnModem = true;
- phone.setEmergencyMode(mode, m);
+ synchronized (mLock) {
+ unregisterForDataConnectionStateChanges();
+ if (mPhoneToExit != null) {
+ if (emergencyType != EMERGENCY_TYPE_CALL) {
+ setIsInEmergencyCall(false);
+ }
+ mOnEcmExitCompleteRunnable = null;
+ if (mPhoneToExit != phone) {
+ // Exit emergency mode on the other phone first,
+ // then set emergency mode on the given phone.
+ mPhoneToExit.exitEmergencyMode(
+ mHandler.obtainMessage(MSG_SET_EMERGENCY_MODE,
+ Integer.valueOf(emergencyType)));
+ mPhoneToExit = null;
+ return;
+ }
+ mPhoneToExit = null;
+ }
+ mWasEmergencyModeSetOnModem = true;
+ phone.setEmergencyMode(mode, m);
+ }
}
private void completeEmergencyMode(@EmergencyType int emergencyType) {
@@ -650,8 +740,10 @@
*
* @param phone the {@code Phone} to exit the emergency mode.
* @param emergencyType the emergency type to identify an emergency call or SMS.
+ * @param waitForPdnDisconnect indicates whether it shall wait for the disconnection of ePDN.
*/
- private void exitEmergencyMode(Phone phone, @EmergencyType int emergencyType) {
+ private void exitEmergencyMode(Phone phone, @EmergencyType int emergencyType,
+ boolean waitForPdnDisconnect) {
Rlog.i(TAG, "exitEmergencyMode for " + emergencyTypeToString(emergencyType));
if (emergencyType == EMERGENCY_TYPE_CALL) {
@@ -687,8 +779,23 @@
return;
}
- mWasEmergencyModeSetOnModem = false;
- phone.exitEmergencyMode(m);
+ synchronized (mLock) {
+ mWasEmergencyModeSetOnModem = false;
+ if (waitForPdnDisconnect) {
+ registerForDataConnectionStateChanges(phone);
+ mPhoneToExit = phone;
+ if (mPdnDisconnectionTimeoutMs > 0) {
+ // To avoid waiting for the disconnection indefinitely.
+ mHandler.sendEmptyMessageDelayed(MSG_EXIT_EMERGENCY_MODE,
+ mPdnDisconnectionTimeoutMs);
+ }
+ return;
+ } else {
+ unregisterForDataConnectionStateChanges();
+ mPhoneToExit = null;
+ }
+ phone.exitEmergencyMode(m);
+ }
}
/** Returns last {@link EmergencyRegResult} as set by {@code setEmergencyMode()}. */
@@ -887,7 +994,9 @@
gsmCdmaPhone.notifyEmergencyCallRegistrants(false);
// Exit emergency mode on modem.
- exitEmergencyMode(gsmCdmaPhone, EMERGENCY_TYPE_CALL);
+ // b/299866883: Wait for the disconnection of ePDN before calling exitEmergencyMode.
+ exitEmergencyMode(gsmCdmaPhone, EMERGENCY_TYPE_CALL,
+ mEmergencyCallDomain == NetworkRegistrationInfo.DOMAIN_PS);
}
mEmergencyCallDomain = NetworkRegistrationInfo.DOMAIN_UNKNOWN;
@@ -1026,7 +1135,7 @@
MSG_SET_EMERGENCY_CALLBACK_MODE_DONE);
}
} else {
- exitEmergencyMode(mSmsPhone, EMERGENCY_TYPE_SMS);
+ exitEmergencyMode(mSmsPhone, EMERGENCY_TYPE_SMS, false);
}
clearEmergencySmsInfo();
@@ -1078,8 +1187,10 @@
boolean isTestEmergencyNumber) {
final boolean isAirplaneModeOn = isAirplaneModeOn(mContext);
boolean needToTurnOnRadio = !isRadioOn() || isAirplaneModeOn;
+ final SatelliteController satelliteController = SatelliteController.getInstance();
+ boolean needToTurnOffSatellite = satelliteController.isSatelliteEnabled();
- if (needToTurnOnRadio) {
+ if (needToTurnOnRadio || needToTurnOffSatellite) {
Rlog.i(TAG, "turnOnRadioAndSwitchDds: phoneId=" + phone.getPhoneId() + " for "
+ emergencyTypeToString(emergencyType));
if (mRadioOnHelper == null) {
@@ -1090,9 +1201,15 @@
@Override
public void onComplete(RadioOnStateListener listener, boolean isRadioReady) {
if (!isRadioReady) {
- // Could not turn radio on
- Rlog.e(TAG, "Failed to turn on radio.");
- completeEmergencyMode(emergencyType, DisconnectCause.POWER_OFF);
+ if (satelliteController.isSatelliteEnabled()) {
+ // Could not turn satellite off
+ Rlog.e(TAG, "Failed to turn off satellite modem.");
+ completeEmergencyMode(emergencyType, DisconnectCause.SATELLITE_ENABLED);
+ } else {
+ // Could not turn radio on
+ Rlog.e(TAG, "Failed to turn on radio.");
+ completeEmergencyMode(emergencyType, DisconnectCause.POWER_OFF);
+ }
} else {
switchDdsAndSetEmergencyMode(phone, emergencyType);
}
@@ -1104,7 +1221,8 @@
// should be able to make emergency calls at any time after the radio has been
// powered on and isn't in the UNAVAILABLE state, even if it is reporting the
// OUT_OF_SERVICE state.
- return phone.getServiceStateTracker().isRadioOn();
+ return phone.getServiceStateTracker().isRadioOn()
+ && !satelliteController.isSatelliteEnabled();
}
@Override
@@ -1334,4 +1452,49 @@
Rlog.i(TAG, "updateNoSimEcbmSupported preference updated slotIndex=" + slotIndex
+ ", supported=" + carrierConfig);
}
+
+ /** For test purpose only */
+ @VisibleForTesting
+ public void setPdnDisconnectionTimeoutMs(int timeout) {
+ mPdnDisconnectionTimeoutMs = timeout;
+ }
+
+ private void exitEmergencyModeIfDelayed() {
+ synchronized (mLock) {
+ if (mPhoneToExit != null) {
+ unregisterForDataConnectionStateChanges();
+ mPhoneToExit.exitEmergencyMode(
+ mHandler.obtainMessage(MSG_EXIT_EMERGENCY_MODE_DONE,
+ Integer.valueOf(EMERGENCY_TYPE_CALL)));
+ mPhoneToExit = null;
+ }
+ }
+ }
+
+ /**
+ * Registers for changes to data connection state.
+ */
+ private void registerForDataConnectionStateChanges(Phone phone) {
+ if ((mDataConnectionStateListener != null) || (phone == null)) {
+ return;
+ }
+ Rlog.i(TAG, "registerForDataConnectionStateChanges");
+
+ mDataConnectionStateListener = new PreciseDataConnectionStateListener();
+ mTelephonyManagerProxy.registerTelephonyCallback(phone.getSubId(),
+ mHandler::post, mDataConnectionStateListener);
+ }
+
+ /**
+ * Unregisters for changes to data connection state.
+ */
+ private void unregisterForDataConnectionStateChanges() {
+ if (mDataConnectionStateListener == null) {
+ return;
+ }
+ Rlog.i(TAG, "unregisterForDataConnectionStateChanges");
+
+ mTelephonyManagerProxy.unregisterTelephonyCallback(mDataConnectionStateListener);
+ mDataConnectionStateListener = null;
+ }
}
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
index 1ee8447..4943ba3 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
@@ -2481,7 +2481,7 @@
setServiceState(ServiceState.STATE_IN_SERVICE);
getDefaultPhone().setImsRegistrationState(true);
mMetrics.writeOnImsConnectionState(mPhoneId, ImsConnectionState.State.CONNECTED, null);
- mImsStats.onImsRegistered(imsRadioTech);
+ mImsStats.onImsRegistered(attributes);
mImsNrSaModeHandler.onImsRegistered(
attributes.getRegistrationTechnology(), attributes.getFeatureTags());
updateImsRegistrationInfo(REGISTRATION_STATE_REGISTERED,
diff --git a/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java b/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java
index afb87dd..2b3ed82 100644
--- a/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java
+++ b/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java
@@ -18,7 +18,13 @@
import static com.android.internal.telephony.TelephonyStatsLog.DATA_CALL_SESSION__IP_TYPE__APN_PROTOCOL_IPV4;
+import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.os.Handler;
+import android.os.HandlerThread;
import android.os.SystemClock;
import android.telephony.Annotation.ApnType;
import android.telephony.Annotation.DataFailureCause;
@@ -55,6 +61,8 @@
private long mStartTime;
@Nullable private DataCallSession mDataCallSession;
+ private Network mSystemDefaultNetwork;
+ private boolean mIsSystemDefaultNetworkMobile;
private final PersistAtomsStorage mAtomsStorage =
PhoneFactory.getMetricsCollector().getAtomsStorage();
@@ -62,8 +70,47 @@
public static final int SIZE_LIMIT_HANDOVER_FAILURES = 15;
+ final class DefaultNetworkCallback extends ConnectivityManager.NetworkCallback {
+ @Override
+ public void onAvailable(@NonNull Network network) {
+ mSystemDefaultNetwork = network;
+ }
+
+ @Override
+ public void onCapabilitiesChanged(@NonNull Network network,
+ @NonNull NetworkCapabilities nc) {
+ if (network == mSystemDefaultNetwork) {
+ mIsSystemDefaultNetworkMobile = nc.hasTransport(
+ NetworkCapabilities.TRANSPORT_CELLULAR);
+ }
+ }
+
+ @Override
+ public void onLost(@NonNull Network network) {
+ mIsSystemDefaultNetworkMobile = false;
+ mSystemDefaultNetwork = null;
+ }
+ }
+
public DataCallSessionStats(Phone phone) {
mPhone = phone;
+ registerSystemDefaultNetworkCallback(phone);
+ }
+
+ private void registerSystemDefaultNetworkCallback(@NonNull Phone phone) {
+ ConnectivityManager connectivityManager = phone.getContext()
+ .getSystemService(ConnectivityManager.class);
+ if (connectivityManager != null) {
+ HandlerThread handlerThread = new HandlerThread(
+ DataCallSessionStats.class.getSimpleName());
+ handlerThread.start();
+ Handler callbackHandler = new Handler(handlerThread.getLooper());
+ DefaultNetworkCallback mDefaultNetworkCallback = new DefaultNetworkCallback();
+ connectivityManager.registerSystemDefaultNetworkCallback(
+ mDefaultNetworkCallback, callbackHandler);
+ } else {
+ loge("registerSystemDefaultNetworkCallback: ConnectivityManager is null!");
+ }
}
/** Creates a new ongoing atom when data call is set up. */
@@ -101,6 +148,9 @@
(currentRat == TelephonyManager.NETWORK_TYPE_IWLAN)
? 0
: ServiceStateStats.getBand(mPhone);
+ // Limitation: Will not capture IKE mobility between Backup Calling <-> WiFi Calling.
+ mDataCallSession.isIwlanCrossSim = currentRat == TelephonyManager.NETWORK_TYPE_IWLAN
+ && mIsSystemDefaultNetworkMobile;
}
// only set if apn hasn't been set during setup
@@ -199,6 +249,8 @@
if (mDataCallSession.ratAtEnd != currentRat) {
mDataCallSession.ratSwitchCount++;
mDataCallSession.ratAtEnd = currentRat;
+ mDataCallSession.isIwlanCrossSim = currentRat == TelephonyManager.NETWORK_TYPE_IWLAN
+ && mIsSystemDefaultNetworkMobile;
}
// band may have changed even if RAT was the same
mDataCallSession.bandAtEnd =
@@ -288,6 +340,7 @@
copy.handoverFailureRat = Arrays.copyOf(call.handoverFailureRat,
call.handoverFailureRat.length);
copy.isNonDds = call.isNonDds;
+ copy.isIwlanCrossSim = call.isIwlanCrossSim;
return copy;
}
@@ -313,6 +366,7 @@
proto.handoverFailureCauses = new int[0];
proto.handoverFailureRat = new int[0];
proto.isNonDds = false;
+ proto.isIwlanCrossSim = false;
return proto;
}
diff --git a/src/java/com/android/internal/telephony/metrics/ImsStats.java b/src/java/com/android/internal/telephony/metrics/ImsStats.java
index 2420602..04c9677 100644
--- a/src/java/com/android/internal/telephony/metrics/ImsStats.java
+++ b/src/java/com/android/internal/telephony/metrics/ImsStats.java
@@ -23,6 +23,7 @@
import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT;
import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO;
import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE;
+import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM;
import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN;
import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_LTE;
import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_NONE;
@@ -39,6 +40,7 @@
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.telephony.ims.ImsReasonInfo;
+import android.telephony.ims.ImsRegistrationAttributes;
import android.telephony.ims.ProvisioningManager;
import android.telephony.ims.RegistrationManager.ImsRegistrationState;
import android.telephony.ims.feature.MmTelFeature.MmTelCapabilities;
@@ -231,6 +233,12 @@
} else {
ImsRegistrationStats stats = copyOfDimensionsOnly(mLastRegistrationStats);
+ if (stats.rat == TelephonyManager.NETWORK_TYPE_UNKNOWN) {
+ logw("conclude: discarding UNKNOWN RAT, duration=%d", duration);
+ mLastTimestamp = now;
+ return;
+ }
+
switch (mLastRegistrationState) {
case REGISTRATION_STATE_REGISTERED:
stats.registeredMillis = duration;
@@ -285,6 +293,7 @@
mLastRegistrationStats.rat = newRat;
ratChanged = true;
}
+ mLastRegistrationStats.isIwlanCrossSim = radioTech == REGISTRATION_TECH_CROSS_SIM;
boolean voiceAvailableNow = capabilities.isCapable(CAPABILITY_TYPE_VOICE);
boolean voiceAvailabilityChanged =
@@ -324,15 +333,18 @@
}
/** Updates the stats when IMS registration succeeds. */
- public synchronized void onImsRegistered(@TransportType int imsRadioTech) {
+ public synchronized void onImsRegistered(ImsRegistrationAttributes attributes) {
conclude();
- mLastTransportType = imsRadioTech;
+ mLastTransportType = attributes.getTransportType();
// NOTE: status can be unregistered (no registering phase)
if (mLastRegistrationState == REGISTRATION_STATE_NOT_REGISTERED) {
updateImsRegistrationStats();
}
- mLastRegistrationStats.rat = convertTransportTypeToNetworkType(imsRadioTech);
+ mLastRegistrationStats.rat =
+ convertTransportTypeToNetworkType(attributes.getTransportType());
+ mLastRegistrationStats.isIwlanCrossSim = attributes.getRegistrationTechnology()
+ == REGISTRATION_TECH_CROSS_SIM;
mLastRegistrationState = REGISTRATION_STATE_REGISTERED;
}
@@ -344,6 +356,8 @@
ImsRegistrationTermination termination = new ImsRegistrationTermination();
if (mLastRegistrationState != REGISTRATION_STATE_NOT_REGISTERED) {
termination.carrierId = mLastRegistrationStats.carrierId;
+ termination.ratAtEnd = getRatAtEnd(mLastRegistrationStats.rat);
+ termination.isIwlanCrossSim = mLastRegistrationStats.isIwlanCrossSim;
} else {
// if the registration state is from unregistered to unregistered.
termination.carrierId = mPhone.getDefaultPhone().getCarrierId();
@@ -359,16 +373,20 @@
// Reset state to unregistered.
mLastRegistrationState = REGISTRATION_STATE_NOT_REGISTERED;
- mLastRegistrationStats.rat = TelephonyManager.NETWORK_TYPE_UNKNOWN;
mLastAvailableFeatures = new MmTelCapabilities();
}
/** Updates the RAT when service state changes. */
public synchronized void onServiceStateChanged(ServiceState state) {
- if (mLastTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN
- && mLastRegistrationState != REGISTRATION_STATE_NOT_REGISTERED) {
- mLastRegistrationStats.rat =
- ServiceStateStats.getRat(state, NetworkRegistrationInfo.DOMAIN_PS);
+ conclude();
+
+ @NetworkType int newRat = state.getDataNetworkType();
+ MmTelCapabilities lastCapableFeatures = getLastCapableFeaturesForNetworkType(newRat);
+
+ if (lastCapableFeatures != null) {
+ mLastRegistrationStats.rat = newRat;
+ } else {
+ mLastRegistrationStats.rat = TelephonyManager.NETWORK_TYPE_UNKNOWN;
}
}
@@ -428,6 +446,19 @@
case REGISTRATION_TECH_NONE:
return null;
case REGISTRATION_TECH_IWLAN:
+ case REGISTRATION_TECH_CROSS_SIM:
+ return mLastWlanCapableFeatures;
+ default:
+ return mLastWwanCapableFeatures;
+ }
+ }
+
+ @Nullable
+ private MmTelCapabilities getLastCapableFeaturesForNetworkType(@NetworkType int netType) {
+ switch (netType) {
+ case TelephonyManager.NETWORK_TYPE_UNKNOWN:
+ return null;
+ case TelephonyManager.NETWORK_TYPE_IWLAN:
return mLastWlanCapableFeatures;
default:
return mLastWwanCapableFeatures;
@@ -442,6 +473,7 @@
case REGISTRATION_TECH_LTE:
return TelephonyManager.NETWORK_TYPE_LTE;
case REGISTRATION_TECH_IWLAN:
+ case REGISTRATION_TECH_CROSS_SIM:
return TelephonyManager.NETWORK_TYPE_IWLAN;
case REGISTRATION_TECH_NR:
return TelephonyManager.NETWORK_TYPE_NR;
@@ -457,6 +489,7 @@
dest.carrierId = source.carrierId;
dest.simSlotIndex = source.simSlotIndex;
dest.rat = source.rat;
+ dest.isIwlanCrossSim = source.isIwlanCrossSim;
return dest;
}
diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
index 8c1aae3..9866c74 100644
--- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
+++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
@@ -786,7 +786,8 @@
perSimStatus.minimumVoltageClass, // simVoltageClass
perSimStatus.userModifiedApnTypes, // userModifiedApnTypeBitmask
perSimStatus.unmeteredNetworks, // unmeteredNetworks
- perSimStatus.vonrEnabled); // vonrEnabled
+ perSimStatus.vonrEnabled, // vonrEnabled
+ perSimStatus.crossSimCallingEnabled); // crossSimCallingEnabled
data.add(statsEvent);
result = StatsManager.PULL_SUCCESS;
}
@@ -934,7 +935,8 @@
state.isInternetPdnUp,
state.foldState,
state.overrideVoiceService,
- state.isDataEnabled);
+ state.isDataEnabled,
+ state.isIwlanCrossSim);
}
private static StatsEvent buildStatsEvent(VoiceCallRatUsage usage) {
@@ -988,7 +990,10 @@
session.lastKnownRat,
session.foldState,
session.ratSwitchCountAfterConnected,
- session.handoverInProgress);
+ session.handoverInProgress,
+ session.isIwlanCrossSimAtStart,
+ session.isIwlanCrossSimAtEnd,
+ session.isIwlanCrossSimAtConnected);
}
private static StatsEvent buildStatsEvent(IncomingSms sms) {
@@ -1060,7 +1065,8 @@
dataCallSession.bandAtEnd,
dataCallSession.handoverFailureCauses,
dataCallSession.handoverFailureRat,
- dataCallSession.isNonDds);
+ dataCallSession.isNonDds,
+ dataCallSession.isIwlanCrossSim);
}
private static StatsEvent buildStatsEvent(ImsRegistrationStats stats) {
@@ -1079,7 +1085,8 @@
roundAndConvertMillisToSeconds(stats.utCapableMillis),
roundAndConvertMillisToSeconds(stats.utAvailableMillis),
roundAndConvertMillisToSeconds(stats.registeringMillis),
- roundAndConvertMillisToSeconds(stats.unregisteredMillis));
+ roundAndConvertMillisToSeconds(stats.unregisteredMillis),
+ stats.isIwlanCrossSim);
}
private static StatsEvent buildStatsEvent(ImsRegistrationTermination termination) {
@@ -1092,7 +1099,8 @@
termination.reasonCode,
termination.extraCode,
termination.extraMessage,
- termination.count);
+ termination.count,
+ termination.isIwlanCrossSim);
}
private static StatsEvent buildStatsEvent(NetworkRequestsV2 networkRequests) {
diff --git a/src/java/com/android/internal/telephony/metrics/PerSimStatus.java b/src/java/com/android/internal/telephony/metrics/PerSimStatus.java
index bc1edc3..a8c7421 100644
--- a/src/java/com/android/internal/telephony/metrics/PerSimStatus.java
+++ b/src/java/com/android/internal/telephony/metrics/PerSimStatus.java
@@ -32,6 +32,7 @@
import android.database.Cursor;
import android.net.Uri;
import android.provider.Telephony;
+import android.telephony.AnomalyReporter;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
@@ -46,9 +47,14 @@
import com.android.internal.telephony.subscription.SubscriptionManagerService;
import com.android.internal.telephony.uicc.UiccController;
import com.android.internal.telephony.uicc.UiccSlot;
+import com.android.telephony.Rlog;
+
+import java.util.UUID;
/** Stores the per SIM status. */
public class PerSimStatus {
+ private static final String TAG = "PerSimStatus";
+
private static final long BITMASK_2G =
TelephonyManager.NETWORK_TYPE_BITMASK_GSM
| TelephonyManager.NETWORK_TYPE_BITMASK_GPRS
@@ -56,6 +62,9 @@
| TelephonyManager.NETWORK_TYPE_BITMASK_CDMA
| TelephonyManager.NETWORK_TYPE_BITMASK_1xRTT;
+ private static final UUID CROSS_SIM_CALLING_STATUS_ANOMALY_UUID =
+ UUID.fromString("377e1a33-d4ac-4039-9cc0-f0d8396757f3");
+
public final int carrierId;
public final int phoneNumberSourceUicc;
public final int phoneNumberSourceCarrier;
@@ -74,6 +83,8 @@
public final long unmeteredNetworks;
public final boolean vonrEnabled;
+ public final boolean crossSimCallingEnabled;
+
/** Returns the current sim status of the given {@link Phone}. */
@Nullable
public static PerSimStatus getCurrentState(Phone phone) {
@@ -105,7 +116,8 @@
getMinimumVoltageClass(phone),
getUserModifiedApnTypes(phone),
persistAtomsStorage.getUnmeteredNetworks(phone.getPhoneId(), carrierId),
- isVonrEnabled(phone));
+ isVonrEnabled(phone),
+ isCrossSimCallingEnabled(imsMmTelManager));
}
private PerSimStatus(
@@ -125,7 +137,8 @@
int minimumVoltageClass,
int userModifiedApnTypes,
long unmeteredNetworks,
- boolean vonrEnabled) {
+ boolean vonrEnabled,
+ boolean crossSimCallingEnabled) {
this.carrierId = carrierId;
this.phoneNumberSourceUicc = phoneNumberSourceUicc;
this.phoneNumberSourceCarrier = phoneNumberSourceCarrier;
@@ -143,6 +156,18 @@
this.userModifiedApnTypes = userModifiedApnTypes;
this.unmeteredNetworks = unmeteredNetworks;
this.vonrEnabled = vonrEnabled;
+ this.crossSimCallingEnabled = crossSimCallingEnabled;
+ }
+
+ private static boolean isCrossSimCallingEnabled(ImsMmTelManager imsMmTelManager) {
+ try {
+ return imsMmTelManager != null && imsMmTelManager.isCrossSimCallingEnabled();
+ } catch (Exception e) {
+ AnomalyReporter.reportAnomaly(CROSS_SIM_CALLING_STATUS_ANOMALY_UUID,
+ "Failed to query ImsMmTelManager for cross-SIM calling status!");
+ Rlog.e(TAG, e.getMessage());
+ }
+ return false;
}
@Nullable
diff --git a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
index d5d041a..101df0d 100644
--- a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
+++ b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
@@ -1713,7 +1713,8 @@
&& state.isInternetPdnUp == key.isInternetPdnUp
&& state.foldState == key.foldState
&& state.overrideVoiceService == key.overrideVoiceService
- && state.isDataEnabled == key.isDataEnabled) {
+ && state.isDataEnabled == key.isDataEnabled
+ && state.isIwlanCrossSim == key.isIwlanCrossSim) {
return state;
}
}
@@ -1761,7 +1762,8 @@
for (ImsRegistrationStats stats : mAtoms.imsRegistrationStats) {
if (stats.carrierId == key.carrierId
&& stats.simSlotIndex == key.simSlotIndex
- && stats.rat == key.rat) {
+ && stats.rat == key.rat
+ && stats.isIwlanCrossSim == key.isIwlanCrossSim) {
return stats;
}
}
@@ -1777,6 +1779,7 @@
if (termination.carrierId == key.carrierId
&& termination.isMultiSim == key.isMultiSim
&& termination.ratAtEnd == key.ratAtEnd
+ && termination.isIwlanCrossSim == key.isIwlanCrossSim
&& termination.setupFailed == key.setupFailed
&& termination.reasonCode == key.reasonCode
&& termination.extraCode == key.extraCode
diff --git a/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java b/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java
index 14ce2cc..d400c22 100644
--- a/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java
+++ b/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java
@@ -32,6 +32,7 @@
import android.telephony.ServiceState;
import android.telephony.ServiceState.RoamingType;
import android.telephony.TelephonyManager;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.Phone;
@@ -89,6 +90,7 @@
CellularServiceState newServiceState = copyOf(state.mServiceState);
newServiceState.voiceRat =
getVoiceRat(mPhone, getServiceStateForPhone(mPhone));
+ newServiceState.isIwlanCrossSim = isCrossSimCallingRegistered(mPhone);
return new TimestampedServiceState(newServiceState, now);
});
addServiceState(lastState, now);
@@ -132,6 +134,7 @@
newState.foldState = mDeviceStateHelper.getFoldState();
newState.overrideVoiceService = mOverrideVoiceService.get();
newState.isDataEnabled = mPhone.getDataSettingsManager().isDataEnabled();
+ newState.isIwlanCrossSim = isCrossSimCallingRegistered(mPhone);
TimestampedServiceState prevState =
mLastState.getAndSet(new TimestampedServiceState(newState, now));
addServiceStateAndSwitch(
@@ -302,6 +305,7 @@
copy.foldState = state.foldState;
copy.overrideVoiceService = state.overrideVoiceService;
copy.isDataEnabled = state.isDataEnabled;
+ copy.isIwlanCrossSim = state.isIwlanCrossSim;
return copy;
}
@@ -360,6 +364,14 @@
}
}
+ private boolean isCrossSimCallingRegistered(Phone phone) {
+ if (phone.getImsPhone() != null) {
+ return phone.getImsPhone().getImsRegistrationTech()
+ == ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM;
+ }
+ return false;
+ }
+
/** Returns RAT used by WWAN if WWAN is in service. */
public static @NetworkType int getRat(
ServiceState state, @NetworkRegistrationInfo.Domain int domain) {
diff --git a/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java b/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java
index 5de9902..5dbf645 100644
--- a/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java
+++ b/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java
@@ -53,6 +53,7 @@
import android.telephony.data.ApnSetting;
import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.ImsStreamMediaProfile;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.util.LongSparseArray;
import android.util.SparseArray;
import android.util.SparseIntArray;
@@ -484,6 +485,11 @@
proto.videoEnabled = videoState != VideoProfile.STATE_AUDIO_ONLY ? true : false;
proto.handoverInProgress = isHandoverInProgress(bearer, proto.isEmergency);
+ boolean isCrossSimCall = isCrossSimCall(conn);
+ proto.isIwlanCrossSimAtStart = isCrossSimCall;
+ proto.isIwlanCrossSimAtEnd = isCrossSimCall;
+ proto.isIwlanCrossSimAtConnected = isCrossSimCall;
+
// internal fields for tracking
if (getDirection(conn) == VOICE_CALL_SESSION__DIRECTION__CALL_DIRECTION_MT) {
// MT call setup hasn't begun hence set to 0
@@ -609,7 +615,9 @@
proto.setupFailed = false;
// Track RAT when voice call is connected.
ServiceState serviceState = getServiceState();
- proto.ratAtConnected = getVoiceRatWithVoNRFix(mPhone, serviceState, proto.bearerAtEnd);
+ @NetworkType int rat = getVoiceRatWithVoNRFix(mPhone, serviceState, proto.bearerAtEnd);
+ proto.ratAtConnected = rat;
+ proto.isIwlanCrossSimAtConnected = isCrossSimCall(conn);
// Reset list of codecs with the last codec at the present time. In this way, we
// track codec quality only after call is connected and not while ringing.
resetCodecList(conn);
@@ -646,6 +654,7 @@
proto.lastKnownRat = rat;
}
}
+ proto.isIwlanCrossSimAtEnd = isCrossSimCall(mPhone);
}
private void finishImsCall(int id, ImsReasonInfo reasonInfo, long durationMillis) {
@@ -905,6 +914,21 @@
return conn == null ? 0 : (int) conn.getCreateTime();
}
+ private boolean isCrossSimCall(Connection conn) {
+ if (conn instanceof ImsPhoneConnection) {
+ return ((ImsPhoneConnection) conn).isCrossSimCall();
+ }
+ return false;
+ }
+
+ private boolean isCrossSimCall(Phone phone) {
+ if (phone.getImsPhone() != null) {
+ return phone.getImsPhone().getImsRegistrationTech()
+ == ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM;
+ }
+ return false;
+ }
+
@VisibleForTesting
protected long getTimeMillis() {
return SystemClock.elapsedRealtime();
diff --git a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java
index ddd0a69..e4d16e7 100644
--- a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java
+++ b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java
@@ -344,6 +344,10 @@
SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING,
getPendingDatagramCount(), SatelliteManager.SATELLITE_RESULT_SUCCESS);
sendRequestAsync(CMD_SEND_SATELLITE_DATAGRAM, datagramArgs, phone);
+ } else {
+ logd("sendSatelliteDatagram: mSendingDatagramInProgress="
+ + mSendingDatagramInProgress + ", isPollingInIdleState="
+ + mDatagramController.isPollingInIdleState());
}
}
}
diff --git a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java
index 695a563..3ac1bbd 100644
--- a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java
+++ b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java
@@ -392,6 +392,10 @@
case EVENT_RECEIVED_ACK: {
DatagramRetryArgument argument = (DatagramRetryArgument) msg.obj;
+ if (!sInstance.mPendingAckCountHashMap.containsKey(argument.datagramId)) {
+ logd("The datagram " + argument.datagramId + " should have been deleted.");
+ return;
+ }
int pendingAckCount = sInstance.mPendingAckCountHashMap
.get(argument.datagramId);
pendingAckCount -= 1;
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
index 00e3189..b29cf26 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
@@ -1735,6 +1735,7 @@
if (!mSatelliteModemInterface.isSatelliteServiceSupported()) {
return SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED;
}
+ logd("registerForSatelliteDatagram: callback=" + callback);
return mDatagramController.registerForSatelliteDatagram(subId, callback);
}
@@ -1755,6 +1756,7 @@
if (!mSatelliteModemInterface.isSatelliteServiceSupported()) {
return;
}
+ logd("unregisterForSatelliteDatagram: callback=" + callback);
mDatagramController.unregisterForSatelliteDatagram(subId, callback);
}
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java
index 3d629db..03481c6 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java
@@ -103,12 +103,14 @@
@Override
public void onSatelliteDatagramReceived(
android.telephony.satellite.stub.SatelliteDatagram datagram, int pendingCount) {
+ logd("onSatelliteDatagramReceived: pendingCount=" + pendingCount);
mSatelliteDatagramsReceivedRegistrants.notifyResult(new Pair<>(
SatelliteServiceUtils.fromSatelliteDatagram(datagram), pendingCount));
}
@Override
public void onPendingDatagrams() {
+ logd("onPendingDatagrams");
mPendingDatagramsRegistrants.notifyResult(null);
}
diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
index 1bf866b..62cb452 100644
--- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
+++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
@@ -1879,6 +1879,8 @@
*
* @param callingPackage The package making the call.
* @param callingFeatureId The feature in the package.
+ * @param isForAllProfiles whether the caller intends to see all subscriptions regardless
+ * association.
*
* @return Sorted list of the currently {@link SubscriptionInfo} records available on the
* device.
@@ -1891,7 +1893,7 @@
"carrier privileges",
})
public List<SubscriptionInfo> getActiveSubscriptionInfoList(@NonNull String callingPackage,
- @Nullable String callingFeatureId) {
+ @Nullable String callingFeatureId, boolean isForAllProfiles) {
// Check if the caller has READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or carrier
// privilege on any active subscription. The carrier app will get full subscription infos
// on the subs it has carrier privilege.
@@ -1905,7 +1907,13 @@
+ "permission. Returning empty list here.");
return Collections.emptyList();
}
- return getSubscriptionInfoStreamAsUser(BINDER_WRAPPER.getCallingUserHandle())
+ if (isForAllProfiles && !hasAcrossAllUsersPermission()) {
+ //TODO(b/308809058 to determine whether the permission enforcement is needed)
+ loge("getActiveSubscriptionInfoList: "
+ + callingPackage + " has no appropriate permission.");
+ }
+ return getSubscriptionInfoStreamAsUser(isForAllProfiles
+ ? UserHandle.ALL : BINDER_WRAPPER.getCallingUserHandle())
.filter(SubscriptionInfoInternal::isActive)
// Remove the identifier if the caller does not have sufficient permission.
// carrier apps will get full subscription info on the subscriptions associated
@@ -1922,6 +1930,8 @@
*
* @param callingPackage The package making the call.
* @param callingFeatureId The feature in the package.
+ * @param isForAllProfiles whether the caller intends to see all subscriptions regardless
+ * association.
*
* @return the number of active subscriptions.
*
@@ -1934,14 +1944,27 @@
"carrier privileges",
})
public int getActiveSubInfoCount(@NonNull String callingPackage,
- @Nullable String callingFeatureId) {
+ @Nullable String callingFeatureId, boolean isForAllProfiles) {
if (!TelephonyPermissions.checkReadPhoneStateOnAnyActiveSub(mContext,
Binder.getCallingPid(), Binder.getCallingUid(), callingPackage, callingFeatureId,
"getAllSubInfoList")) {
throw new SecurityException("Need READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or "
+ "carrier privilege");
}
- return getActiveSubIdListAsUser(false, BINDER_WRAPPER.getCallingUserHandle()).length;
+ if (isForAllProfiles && !hasAcrossAllUsersPermission()) {
+ //TODO(b/308809058 to determine whether the permission enforcement is needed)
+ loge("getActiveSubInfoCount: "
+ + callingPackage + " has no appropriate permission.");
+ }
+ return getActiveSubIdListAsUser(false, isForAllProfiles
+ ? UserHandle.ALL : BINDER_WRAPPER.getCallingUserHandle()).length;
+ }
+
+ /**@return {@code true} if the caller is permitted to see all subscriptions. */
+ private boolean hasAcrossAllUsersPermission() {
+ return hasPermissions(Manifest.permission.INTERACT_ACROSS_USERS,
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ Manifest.permission.INTERACT_ACROSS_PROFILES);
}
/**
@@ -3885,16 +3908,6 @@
}
/**
- * @return All active subscriptions.
- */
- @NonNull
- private List<SubscriptionInfoInternal> getActiveSubscriptionInfoListAllUser() {
- return mSubscriptionDatabaseManager.getAllSubscriptions().stream()
- .filter(SubscriptionInfoInternal::isActive)
- .collect(Collectors.toList());
- }
-
- /**
* Get subscriptions accessible to the caller user.
*
* @param user The user to check.
@@ -4136,7 +4149,10 @@
*/
@VisibleForTesting
public void updateGroupDisabled() {
- List<SubscriptionInfoInternal> activeSubscriptions = getActiveSubscriptionInfoListAllUser();
+ List<SubscriptionInfoInternal> activeSubscriptions = mSubscriptionDatabaseManager
+ .getAllSubscriptions().stream()
+ .filter(SubscriptionInfoInternal::isActive)
+ .collect(Collectors.toList());
for (SubscriptionInfo oppSubInfo : getOpportunisticSubscriptions(
mContext.getOpPackageName(), mContext.getFeatureId())) {
boolean groupDisabled = activeSubscriptions.stream()
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CellBroadcastConfigTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/CellBroadcastConfigTrackerTest.java
index 21a14b2..722f6ac 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CellBroadcastConfigTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CellBroadcastConfigTrackerTest.java
@@ -51,6 +51,7 @@
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
+import org.mockito.Mockito;
import java.util.ArrayList;
import java.util.Arrays;
@@ -67,6 +68,7 @@
@Before
public void setUp() throws Exception {
super.setUp(getClass().getSimpleName());
+ mFeatureFlags = Mockito.mock(FeatureFlags.class);
mSpyCi = spy(mSimulatedCommands);
mPhone = new GsmCdmaPhone(mContext, mSpyCi, mNotifier, true, 0,
PhoneConstants.PHONE_TYPE_GSM, mTelephonyComponentFactory, (c, p) -> mImsManager,
diff --git a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java
index a41dbe1..7893e78 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java
@@ -198,7 +198,7 @@
}
return subscriptionInfoList;
}).when(mSubscriptionManagerService).getActiveSubscriptionInfoList(
- anyString(), nullable(String.class));
+ anyString(), nullable(String.class), anyBoolean());
doAnswer(invocation -> {
final boolean visibleOnly = (boolean) invocation.getArguments()[0];
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java
index f8d22cd..ff14f9a 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java
@@ -54,7 +54,6 @@
import com.android.internal.telephony.data.DataConfigManager.DataConfigManagerCallback;
import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback;
import com.android.internal.telephony.data.DataProfileManager.DataProfileManagerCallback;
-import com.android.internal.telephony.flags.FeatureFlags;
import org.junit.After;
import org.junit.Before;
@@ -100,8 +99,6 @@
private DataProfileManager mDataProfileManagerUT;
- private FeatureFlags mFeatureFlags;
-
private final ApnSettingContentProvider mApnSettingContentProvider =
new ApnSettingContentProvider();
@@ -835,7 +832,6 @@
logd("DataProfileManagerTest +Setup!");
super.setUp(getClass().getSimpleName());
mDataProfileManagerCallback = Mockito.mock(DataProfileManagerCallback.class);
- mFeatureFlags = Mockito.mock(FeatureFlags.class);
((MockContentResolver) mContext.getContentResolver()).addProvider(
Telephony.Carriers.CONTENT_URI.getAuthority(), mApnSettingContentProvider);
@@ -1035,6 +1031,7 @@
@Test
public void testSetPreferredDataProfile() {
+ doReturn(true).when(mFeatureFlags).refinePreferredDataProfileSelection();
TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(
new NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java
index dd95ff0..2541bd1 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java
@@ -786,6 +786,7 @@
@Test
public void testDataRetryLongTimer() {
+ doReturn(true).when(mFeatureFlags).useAlarmCallback();
// Rule requires a long timer
DataSetupRetryRule retryRule = new DataSetupRetryRule(
"capabilities=internet, retry_interval=120000, maximum_retries=2");
diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java
index 7da79a6..1eff979 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java
@@ -57,6 +57,7 @@
import android.telephony.EmergencyRegResult;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
@@ -206,6 +207,83 @@
}
/**
+ * Test that the EmergencyStateTracker turns off satellite modem, performs a DDS switch and
+ * sets emergency mode switch when we are not roaming and the carrier only supports SUPL over
+ * the data plane.
+ */
+ @Test
+ @SmallTest
+ public void startEmergencyCall_satelliteEnabled_turnOnRadioSwitchDdsAndSetEmergencyMode() {
+ EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker(
+ true /* isSuplDdsSwitchRequiredForEmergencyCall */);
+ // Create test Phones and set radio on
+ Phone testPhone = setupTestPhoneForEmergencyCall(false /* isRoaming */,
+ true /* isRadioOn */);
+ when(mSST.isRadioOn()).thenReturn(true);
+ // Satellite enabled
+ when(mSatelliteController.isSatelliteEnabled()).thenReturn(true);
+
+ setConfigForDdsSwitch(testPhone, null,
+ CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_DP_ONLY, "150");
+ // Spy is used to capture consumer in delayDialForDdsSwitch
+ EmergencyStateTracker spyEst = spy(emergencyStateTracker);
+ CompletableFuture<Integer> unused = spyEst.startEmergencyCall(testPhone, TEST_CALL_ID,
+ false);
+
+ // startEmergencyCall should trigger radio on
+ ArgumentCaptor<RadioOnStateListener.Callback> callback = ArgumentCaptor
+ .forClass(RadioOnStateListener.Callback.class);
+ verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true), eq(testPhone),
+ eq(false), eq(0));
+ // isOkToCall() should return true once satellite modem is off
+ assertFalse(callback.getValue()
+ .isOkToCall(testPhone, ServiceState.STATE_IN_SERVICE, false));
+ when(mSatelliteController.isSatelliteEnabled()).thenReturn(false);
+ assertTrue(callback.getValue()
+ .isOkToCall(testPhone, ServiceState.STATE_IN_SERVICE, false));
+ // Once radio on is complete, trigger delay dial
+ callback.getValue().onComplete(null, true);
+ ArgumentCaptor<Consumer<Boolean>> completeConsumer = ArgumentCaptor
+ .forClass(Consumer.class);
+ verify(spyEst).switchDdsDelayed(eq(testPhone), completeConsumer.capture());
+ verify(mPhoneSwitcher).overrideDefaultDataForEmergency(eq(testPhone.getPhoneId()),
+ eq(150) /* extensionTime */, any());
+ // After dds switch completes successfully, set emergency mode
+ completeConsumer.getValue().accept(true);
+ verify(testPhone).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any());
+ }
+
+ /**
+ * Test that if startEmergencyCall fails to turn off satellite modem, then it's future completes
+ * with {@link DisconnectCause#SATELLITE_ENABLED}.
+ */
+ @Test
+ @SmallTest
+ public void startEmergencyCall_satelliteOffFails_returnsDisconnectCauseSatelliteEnabled() {
+ EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker(
+ true /* isSuplDdsSwitchRequiredForEmergencyCall */);
+ // Create test Phones and set radio on
+ Phone testPhone = setupTestPhoneForEmergencyCall(false /* isRoaming */,
+ true /* isRadioOn */);
+ // Satellite enabled
+ when(mSatelliteController.isSatelliteEnabled()).thenReturn(true);
+
+ CompletableFuture<Integer> future = emergencyStateTracker.startEmergencyCall(testPhone,
+ TEST_CALL_ID, false);
+
+ // startEmergencyCall should trigger satellite modem off
+ ArgumentCaptor<RadioOnStateListener.Callback> callback = ArgumentCaptor
+ .forClass(RadioOnStateListener.Callback.class);
+ verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true), eq(testPhone),
+ eq(false), eq(0));
+ // Verify future completes with DisconnectCause.POWER_OFF if radio not ready
+ CompletableFuture<Void> unused = future.thenAccept((result) -> {
+ assertEquals((Integer) result, (Integer) DisconnectCause.SATELLITE_ENABLED);
+ });
+ callback.getValue().onComplete(null, false /* isRadioReady */);
+ }
+
+ /**
* Test that the EmergencyStateTracker does not perform a DDS switch when the carrier supports
* control-plane fallback. Radio is set to on so RadioOnHelper not triggered.
*/
@@ -598,6 +676,216 @@
}
/**
+ * Test that once endCall() for IMS call is called and we enter ECM, then we exit ECM
+ * after the specified timeout.
+ */
+ @Test
+ @SmallTest
+ public void endCall_entersEcm_thenExitsEcmAfterTimeoutImsCall() throws Exception {
+ // Setup EmergencyStateTracker
+ EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker(
+ /* isSuplDdsSwitchRequiredForEmergencyCall= */ true);
+ // Create test Phone
+ Phone testPhone = setupTestPhoneForEmergencyCall(/* isRoaming= */ true,
+ /* isRadioOn= */ true);
+ setUpAsyncResultForSetEmergencyMode(testPhone, E_REG_RESULT);
+ setUpAsyncResultForExitEmergencyMode(testPhone);
+ CompletableFuture<Integer> unused = emergencyStateTracker.startEmergencyCall(testPhone,
+ TEST_CALL_ID, false);
+ // Set call to ACTIVE
+ emergencyStateTracker.onEmergencyCallStateChanged(Call.State.ACTIVE, TEST_CALL_ID);
+ emergencyStateTracker.onEmergencyCallDomainUpdated(
+ PhoneConstants.PHONE_TYPE_IMS, TEST_CALL_ID);
+ // Set ecm as supported
+ setEcmSupportedConfig(testPhone, /* ecmSupported= */ true);
+
+ processAllMessages();
+
+ emergencyStateTracker.endCall(TEST_CALL_ID);
+
+ assertTrue(emergencyStateTracker.isInEcm());
+
+ Context mockContext = mock(Context.class);
+ replaceInstance(EmergencyStateTracker.class, "mContext",
+ emergencyStateTracker, mockContext);
+ processAllFutureMessages();
+
+ ArgumentCaptor<TelephonyCallback> callbackCaptor =
+ ArgumentCaptor.forClass(TelephonyCallback.class);
+
+ verify(mTelephonyManagerProxy).registerTelephonyCallback(eq(testPhone.getSubId()),
+ any(), callbackCaptor.capture());
+
+ TelephonyCallback callback = callbackCaptor.getValue();
+
+ assertNotNull(callback);
+
+ // Verify exitEmergencyMode() is called after timeout
+ verify(testPhone).exitEmergencyMode(any(Message.class));
+ assertFalse(emergencyStateTracker.isInEmergencyMode());
+ assertFalse(emergencyStateTracker.isInEcm());
+ verify(mTelephonyManagerProxy).unregisterTelephonyCallback(eq(callback));
+ }
+
+ /**
+ * Test that startEmergencyCall() is called right after exiting ECM on the same slot.
+ */
+ @Test
+ @SmallTest
+ public void exitEcm_thenDialEmergencyCallOnTheSameSlotRightAfter() throws Exception {
+ // Setup EmergencyStateTracker
+ EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker(
+ /* isSuplDdsSwitchRequiredForEmergencyCall= */ true);
+ emergencyStateTracker.setPdnDisconnectionTimeoutMs(0);
+ // Create test Phone
+ Phone testPhone = setupTestPhoneForEmergencyCall(/* isRoaming= */ true,
+ /* isRadioOn= */ true);
+ setUpAsyncResultForSetEmergencyMode(testPhone, E_REG_RESULT);
+ setUpAsyncResultForExitEmergencyMode(testPhone);
+
+ verify(testPhone, times(0)).setEmergencyMode(anyInt(), any(Message.class));
+ verify(testPhone, times(0)).exitEmergencyMode(any(Message.class));
+
+ CompletableFuture<Integer> unused = emergencyStateTracker.startEmergencyCall(testPhone,
+ TEST_CALL_ID, false);
+ processAllMessages();
+
+ verify(testPhone, times(1)).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class));
+ verify(testPhone, times(0)).exitEmergencyMode(any(Message.class));
+
+ // Set call to ACTIVE
+ emergencyStateTracker.onEmergencyCallStateChanged(Call.State.ACTIVE, TEST_CALL_ID);
+ emergencyStateTracker.onEmergencyCallDomainUpdated(
+ PhoneConstants.PHONE_TYPE_IMS, TEST_CALL_ID);
+ // Set ecm as supported
+ setEcmSupportedConfig(testPhone, /* ecmSupported= */ true);
+
+ processAllMessages();
+
+ emergencyStateTracker.endCall(TEST_CALL_ID);
+
+ assertTrue(emergencyStateTracker.isInEcm());
+
+ Context mockContext = mock(Context.class);
+ replaceInstance(EmergencyStateTracker.class, "mContext",
+ emergencyStateTracker, mockContext);
+ processAllFutureMessages();
+
+ ArgumentCaptor<TelephonyCallback> callbackCaptor =
+ ArgumentCaptor.forClass(TelephonyCallback.class);
+
+ verify(mTelephonyManagerProxy).registerTelephonyCallback(eq(testPhone.getSubId()),
+ any(), callbackCaptor.capture());
+
+ TelephonyCallback callback = callbackCaptor.getValue();
+
+ assertNotNull(callback);
+ assertFalse(emergencyStateTracker.isInEmergencyMode());
+ assertFalse(emergencyStateTracker.isInEcm());
+ verify(mTelephonyManagerProxy, times(0)).unregisterTelephonyCallback(eq(callback));
+ verify(testPhone, times(1)).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class));
+ verify(testPhone, times(1)).setEmergencyMode(eq(MODE_EMERGENCY_CALLBACK),
+ any(Message.class));
+ verify(testPhone, times(0)).exitEmergencyMode(any(Message.class));
+
+ replaceInstance(EmergencyStateTracker.class, "mContext", emergencyStateTracker, mContext);
+
+ // dial on the same slot
+ unused = emergencyStateTracker.startEmergencyCall(testPhone, TEST_CALL_ID, false);
+ processAllMessages();
+
+ assertTrue(emergencyStateTracker.isInEmergencyMode());
+ assertFalse(emergencyStateTracker.isInEcm());
+ verify(mTelephonyManagerProxy, times(1)).unregisterTelephonyCallback(eq(callback));
+ verify(testPhone, times(2)).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class));
+ verify(testPhone, times(1)).setEmergencyMode(eq(MODE_EMERGENCY_CALLBACK),
+ any(Message.class));
+ verify(testPhone, times(0)).exitEmergencyMode(any(Message.class));
+ }
+
+ /**
+ * Test that startEmergencyCall() is called right after exiting ECM on the other slot.
+ */
+ @Test
+ @SmallTest
+ public void exitEcm_thenDialEmergencyCallOnTheOtherSlotRightAfter() throws Exception {
+ // Setup EmergencyStateTracker
+ EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker(
+ /* isSuplDdsSwitchRequiredForEmergencyCall= */ true);
+ emergencyStateTracker.setPdnDisconnectionTimeoutMs(0);
+ // Create test Phone
+ Phone testPhone = setupTestPhoneForEmergencyCall(/* isRoaming= */ true,
+ /* isRadioOn= */ true);
+ setUpAsyncResultForSetEmergencyMode(testPhone, E_REG_RESULT);
+ setUpAsyncResultForExitEmergencyMode(testPhone);
+
+ verify(testPhone, times(0)).setEmergencyMode(anyInt(), any(Message.class));
+ verify(testPhone, times(0)).exitEmergencyMode(any(Message.class));
+
+ CompletableFuture<Integer> unused = emergencyStateTracker.startEmergencyCall(testPhone,
+ TEST_CALL_ID, false);
+ processAllMessages();
+
+ verify(testPhone, times(1)).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class));
+ verify(testPhone, times(0)).exitEmergencyMode(any(Message.class));
+
+ // Set call to ACTIVE
+ emergencyStateTracker.onEmergencyCallStateChanged(Call.State.ACTIVE, TEST_CALL_ID);
+ emergencyStateTracker.onEmergencyCallDomainUpdated(
+ PhoneConstants.PHONE_TYPE_IMS, TEST_CALL_ID);
+ // Set ecm as supported
+ setEcmSupportedConfig(testPhone, /* ecmSupported= */ true);
+
+ processAllMessages();
+
+ emergencyStateTracker.endCall(TEST_CALL_ID);
+
+ assertTrue(emergencyStateTracker.isInEcm());
+
+ Context mockContext = mock(Context.class);
+ replaceInstance(EmergencyStateTracker.class, "mContext",
+ emergencyStateTracker, mockContext);
+ processAllFutureMessages();
+
+ ArgumentCaptor<TelephonyCallback> callbackCaptor =
+ ArgumentCaptor.forClass(TelephonyCallback.class);
+
+ verify(mTelephonyManagerProxy).registerTelephonyCallback(eq(testPhone.getSubId()),
+ any(), callbackCaptor.capture());
+
+ TelephonyCallback callback = callbackCaptor.getValue();
+
+ assertNotNull(callback);
+ assertFalse(emergencyStateTracker.isInEmergencyMode());
+ assertFalse(emergencyStateTracker.isInEcm());
+ verify(mTelephonyManagerProxy, times(0)).unregisterTelephonyCallback(eq(callback));
+ verify(testPhone, times(1)).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class));
+ verify(testPhone, times(1)).setEmergencyMode(eq(MODE_EMERGENCY_CALLBACK),
+ any(Message.class));
+ verify(testPhone, times(0)).exitEmergencyMode(any(Message.class));
+
+ Phone phone1 = getPhone(1);
+ verify(phone1, times(0)).setEmergencyMode(anyInt(), any(Message.class));
+ verify(phone1, times(0)).exitEmergencyMode(any(Message.class));
+
+ replaceInstance(EmergencyStateTracker.class, "mContext", emergencyStateTracker, mContext);
+
+ // dial on the other slot
+ unused = emergencyStateTracker.startEmergencyCall(phone1, TEST_CALL_ID, false);
+ processAllMessages();
+
+ assertTrue(emergencyStateTracker.isInEmergencyMode());
+ assertFalse(emergencyStateTracker.isInEcm());
+ verify(mTelephonyManagerProxy, times(1)).unregisterTelephonyCallback(eq(callback));
+ verify(testPhone, times(1)).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class));
+ verify(testPhone, times(1)).setEmergencyMode(eq(MODE_EMERGENCY_CALLBACK),
+ any(Message.class));
+ verify(testPhone, times(1)).exitEmergencyMode(any(Message.class));
+ verify(phone1, times(1)).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class));
+ verify(phone1, times(0)).exitEmergencyMode(any(Message.class));
+ }
+
+ /**
* Test that after exitEmergencyCallbackMode() is called, the correct intents are sent and
* emergency mode is exited on the modem.
*/
diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmMmiCodeTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmMmiCodeTest.java
index 1f2cb15..17a428b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmMmiCodeTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmMmiCodeTest.java
@@ -43,6 +43,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
+import org.mockito.Mockito;
import java.util.ArrayList;
import java.util.concurrent.Executor;
@@ -65,6 +66,7 @@
@Before
public void setUp() throws Exception {
super.setUp(getClass().getSimpleName());
+ mFeatureFlags = Mockito.mock(FeatureFlags.class);
doReturn(mExecutor).when(mContext).getMainExecutor();
mGsmCdmaPhoneUT = new GsmCdmaPhone(mContext, mSimulatedCommands, mNotifier, true, 0,
PhoneConstants.PHONE_TYPE_GSM, mTelephonyComponentFactory, (c, p) -> mImsManager,
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/DataCallSessionStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/DataCallSessionStatsTest.java
new file mode 100644
index 0000000..700b4cf
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/DataCallSessionStatsTest.java
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.metrics;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.telephony.DataFailCause;
+import android.telephony.ServiceState;
+import android.telephony.TelephonyManager;
+import android.telephony.data.ApnSetting;
+import android.telephony.data.DataCallResponse;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.TelephonyTest;
+import com.android.internal.telephony.nano.PersistAtomsProto.DataCallSession;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+public class DataCallSessionStatsTest extends TelephonyTest {
+
+ private ArgumentCaptor<NetworkCallback> mNetworkCallbackCaptor =
+ ArgumentCaptor.forClass(NetworkCallback.class);
+ private DataCallResponse mDefaultImsResponse = buildDataCallResponse("ims", 0);
+ private Network mMockNetwork;
+ private NetworkCapabilities mCellularNetworkCapabilities = new NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR).build();
+
+ private static class TestableDataCallSessionStats extends DataCallSessionStats {
+ private long mTimeMillis = 0L;
+
+ TestableDataCallSessionStats(Phone phone) {
+ super(phone);
+ }
+
+ @Override
+ protected long getTimeMillis() {
+ return mTimeMillis;
+ }
+
+ private void setTimeMillis(long timeMillis) {
+ mTimeMillis = timeMillis;
+ }
+ }
+
+ private TestableDataCallSessionStats mDataCallSessionStats;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp(getClass().getSimpleName());
+ doNothing().when(mConnectivityManager).registerSystemDefaultNetworkCallback(
+ mNetworkCallbackCaptor.capture(), any());
+ mMockNetwork = mock(Network.class);
+ when(mServiceState.getDataRegistrationState()).thenReturn(ServiceState.STATE_IN_SERVICE);
+ mDataCallSessionStats = new TestableDataCallSessionStats(mPhone);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mDataCallSessionStats = null;
+ super.tearDown();
+ }
+
+ private NetworkCallback getNetworkMonitorCallback() {
+ return mNetworkCallbackCaptor.getValue();
+ }
+
+ private DataCallResponse buildDataCallResponse(String apn, long retryDurationMillis) {
+ return new DataCallResponse.Builder()
+ .setId(apn.hashCode())
+ .setRetryDurationMillis(retryDurationMillis)
+ .build();
+ }
+
+ @Test
+ @SmallTest
+ public void testSetupDataCallOnCellularIms_success() {
+ mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS);
+ mDataCallSessionStats.onSetupDataCallResponse(
+ mDefaultImsResponse,
+ TelephonyManager.NETWORK_TYPE_LTE,
+ ApnSetting.TYPE_IMS,
+ ApnSetting.PROTOCOL_IP,
+ DataFailCause.NONE);
+
+ mDataCallSessionStats.setTimeMillis(60000L);
+ mDataCallSessionStats.conclude();
+
+ ArgumentCaptor<DataCallSession> callCaptor =
+ ArgumentCaptor.forClass(DataCallSession.class);
+ verify(mPersistAtomsStorage, times(1)).addDataCallSession(
+ callCaptor.capture());
+ DataCallSession stats = callCaptor.getValue();
+
+ assertEquals(ApnSetting.TYPE_IMS, stats.apnTypeBitmask);
+ assertEquals(1, stats.durationMinutes);
+ assertEquals(TelephonyManager.NETWORK_TYPE_LTE, stats.ratAtEnd);
+ assertTrue(stats.ongoing);
+ }
+
+ @Test
+ @SmallTest
+ public void testSetupDataCallOnIwlan_success() {
+ mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS);
+ mDataCallSessionStats.onSetupDataCallResponse(
+ mDefaultImsResponse,
+ TelephonyManager.NETWORK_TYPE_IWLAN,
+ ApnSetting.TYPE_IMS,
+ ApnSetting.PROTOCOL_IP,
+ DataFailCause.NONE);
+
+ mDataCallSessionStats.setTimeMillis(120000L);
+ mDataCallSessionStats.conclude();
+
+ ArgumentCaptor<DataCallSession> callCaptor =
+ ArgumentCaptor.forClass(DataCallSession.class);
+ verify(mPersistAtomsStorage, times(1)).addDataCallSession(
+ callCaptor.capture());
+ DataCallSession stats = callCaptor.getValue();
+
+ assertEquals(ApnSetting.TYPE_IMS, stats.apnTypeBitmask);
+ assertEquals(2, stats.durationMinutes);
+ assertEquals(TelephonyManager.NETWORK_TYPE_IWLAN, stats.ratAtEnd);
+ assertFalse(stats.isIwlanCrossSim);
+ assertTrue(stats.ongoing);
+ }
+
+ @Test
+ @SmallTest
+ public void testSetupDataCallOnCrossSimCalling_success() {
+ getNetworkMonitorCallback().onAvailable(mMockNetwork);
+ getNetworkMonitorCallback().onCapabilitiesChanged(
+ mMockNetwork, mCellularNetworkCapabilities);
+ mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS);
+ mDataCallSessionStats.onSetupDataCallResponse(
+ mDefaultImsResponse,
+ TelephonyManager.NETWORK_TYPE_IWLAN,
+ ApnSetting.TYPE_IMS,
+ ApnSetting.PROTOCOL_IP,
+ DataFailCause.NONE);
+
+ mDataCallSessionStats.setTimeMillis(60000L);
+ mDataCallSessionStats.conclude();
+
+ ArgumentCaptor<DataCallSession> callCaptor =
+ ArgumentCaptor.forClass(DataCallSession.class);
+ verify(mPersistAtomsStorage, times(1)).addDataCallSession(
+ callCaptor.capture());
+ DataCallSession stats = callCaptor.getValue();
+
+ assertEquals(ApnSetting.TYPE_IMS, stats.apnTypeBitmask);
+ assertEquals(1, stats.durationMinutes);
+ assertEquals(TelephonyManager.NETWORK_TYPE_IWLAN, stats.ratAtEnd);
+ assertTrue(stats.isIwlanCrossSim);
+ assertTrue(stats.ongoing);
+ }
+
+ @Test
+ @SmallTest
+ public void testSetupDataCallOnCellularIms_failure() {
+ mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS);
+ mDataCallSessionStats.onSetupDataCallResponse(
+ mDefaultImsResponse,
+ TelephonyManager.NETWORK_TYPE_LTE,
+ ApnSetting.TYPE_IMS,
+ ApnSetting.PROTOCOL_IP,
+ DataFailCause.NETWORK_FAILURE);
+
+ ArgumentCaptor<DataCallSession> callCaptor =
+ ArgumentCaptor.forClass(DataCallSession.class);
+ verify(mPersistAtomsStorage, times(1)).addDataCallSession(
+ callCaptor.capture());
+ DataCallSession stats = callCaptor.getValue();
+
+ assertEquals(ApnSetting.TYPE_IMS, stats.apnTypeBitmask);
+ assertEquals(0, stats.durationMinutes);
+ assertEquals(TelephonyManager.NETWORK_TYPE_LTE, stats.ratAtEnd);
+ assertFalse(stats.ongoing);
+ }
+
+ @Test
+ @SmallTest
+ public void testHandoverFromCellularToIwlan_success() {
+ mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS);
+ mDataCallSessionStats.onSetupDataCallResponse(
+ mDefaultImsResponse,
+ TelephonyManager.NETWORK_TYPE_LTE,
+ ApnSetting.TYPE_IMS,
+ ApnSetting.PROTOCOL_IP,
+ DataFailCause.NONE);
+
+ mDataCallSessionStats.onDrsOrRatChanged(TelephonyManager.NETWORK_TYPE_IWLAN);
+ mDataCallSessionStats.conclude();
+
+ ArgumentCaptor<DataCallSession> callCaptor =
+ ArgumentCaptor.forClass(DataCallSession.class);
+ verify(mPersistAtomsStorage, times(1)).addDataCallSession(
+ callCaptor.capture());
+ DataCallSession stats = callCaptor.getValue();
+
+ assertEquals(ApnSetting.TYPE_IMS, stats.apnTypeBitmask);
+ assertEquals(TelephonyManager.NETWORK_TYPE_IWLAN, stats.ratAtEnd);
+ assertEquals(1, stats.ratSwitchCount);
+ assertTrue(stats.ongoing);
+ }
+
+ @Test
+ @SmallTest
+ public void testHandoverFromCellularToCrossSimCalling_success() {
+ mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS);
+ mDataCallSessionStats.onSetupDataCallResponse(
+ mDefaultImsResponse,
+ TelephonyManager.NETWORK_TYPE_LTE,
+ ApnSetting.TYPE_IMS,
+ ApnSetting.PROTOCOL_IP,
+ DataFailCause.NONE);
+
+ getNetworkMonitorCallback().onAvailable(mMockNetwork);
+ getNetworkMonitorCallback().onCapabilitiesChanged(
+ mMockNetwork, mCellularNetworkCapabilities);
+ mDataCallSessionStats.onDrsOrRatChanged(TelephonyManager.NETWORK_TYPE_IWLAN);
+ mDataCallSessionStats.conclude();
+
+ ArgumentCaptor<DataCallSession> callCaptor =
+ ArgumentCaptor.forClass(DataCallSession.class);
+ verify(mPersistAtomsStorage, times(1)).addDataCallSession(
+ callCaptor.capture());
+ DataCallSession stats = callCaptor.getValue();
+
+ assertEquals(ApnSetting.TYPE_IMS, stats.apnTypeBitmask);
+ assertEquals(TelephonyManager.NETWORK_TYPE_IWLAN, stats.ratAtEnd);
+ assertEquals(1, stats.ratSwitchCount);
+ assertTrue(stats.isIwlanCrossSim);
+ assertTrue(stats.ongoing);
+ }
+
+ @Test
+ @SmallTest
+ public void testHandoverFromCellularToIwlan_failure() {
+ mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS);
+ mDataCallSessionStats.onSetupDataCallResponse(
+ mDefaultImsResponse,
+ TelephonyManager.NETWORK_TYPE_LTE,
+ ApnSetting.TYPE_IMS,
+ ApnSetting.PROTOCOL_IP,
+ DataFailCause.NONE);
+
+ mDataCallSessionStats.onHandoverFailure(DataFailCause.IWLAN_DNS_RESOLUTION_TIMEOUT,
+ TelephonyManager.NETWORK_TYPE_LTE, TelephonyManager.NETWORK_TYPE_IWLAN);
+ mDataCallSessionStats.conclude();
+
+ ArgumentCaptor<DataCallSession> callCaptor =
+ ArgumentCaptor.forClass(DataCallSession.class);
+ verify(mPersistAtomsStorage, times(1)).addDataCallSession(
+ callCaptor.capture());
+ DataCallSession stats = callCaptor.getValue();
+
+ assertEquals(ApnSetting.TYPE_IMS, stats.apnTypeBitmask);
+ assertEquals(TelephonyManager.NETWORK_TYPE_LTE, stats.ratAtEnd);
+ assertTrue(stats.ongoing);
+ assertEquals(DataFailCause.IWLAN_DNS_RESOLUTION_TIMEOUT,
+ stats.handoverFailureCauses[0]);
+
+ int cellularToIwlanFailureDirection = TelephonyManager.NETWORK_TYPE_LTE
+ | (TelephonyManager.NETWORK_TYPE_IWLAN << 16);
+ assertEquals(cellularToIwlanFailureDirection, stats.handoverFailureRat[0]);
+ }
+
+ @Test
+ @SmallTest
+ public void testSetupDataCallOnIwlan_success_thenOOS() {
+ mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS);
+ mDataCallSessionStats.onSetupDataCallResponse(
+ mDefaultImsResponse,
+ TelephonyManager.NETWORK_TYPE_IWLAN,
+ ApnSetting.TYPE_IMS,
+ ApnSetting.PROTOCOL_IP,
+ DataFailCause.NONE);
+ when(mServiceState.getDataRegistrationState())
+ .thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
+ mDataCallSessionStats.onDataCallDisconnected(DataFailCause.IWLAN_IKE_DPD_TIMEOUT);
+
+ ArgumentCaptor<DataCallSession> callCaptor =
+ ArgumentCaptor.forClass(DataCallSession.class);
+ verify(mPersistAtomsStorage, times(1)).addDataCallSession(
+ callCaptor.capture());
+ DataCallSession stats = callCaptor.getValue();
+
+ assertEquals(ApnSetting.TYPE_IMS, stats.apnTypeBitmask);
+ assertEquals(TelephonyManager.NETWORK_TYPE_IWLAN, stats.ratAtEnd);
+ assertTrue(stats.oosAtEnd);
+ assertFalse(stats.ongoing);
+ }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/ImsStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/ImsStatsTest.java
index 7c7c5b2..df8bd85 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/ImsStatsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/ImsStatsTest.java
@@ -23,6 +23,7 @@
import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT;
import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO;
import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE;
+import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM;
import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN;
import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_LTE;
import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_NR;
@@ -40,6 +41,7 @@
import android.telephony.NetworkRegistrationInfo;
import android.telephony.TelephonyManager;
import android.telephony.ims.ImsReasonInfo;
+import android.telephony.ims.ImsRegistrationAttributes;
import android.telephony.ims.ProvisioningManager;
import android.telephony.ims.feature.MmTelFeature.MmTelCapabilities;
import android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability;
@@ -67,6 +69,13 @@
private static final int CARRIER1_ID = 1;
private static final int CARRIER2_ID = 1187;
+ private ImsRegistrationAttributes mWwanAttributes =
+ new ImsRegistrationAttributes.Builder(REGISTRATION_TECH_LTE).build();
+ private ImsRegistrationAttributes mIwlanAttributes =
+ new ImsRegistrationAttributes.Builder(REGISTRATION_TECH_IWLAN).build();
+ private ImsRegistrationAttributes mCrossSimAttributes =
+ new ImsRegistrationAttributes.Builder(REGISTRATION_TECH_CROSS_SIM).build();
+
@MmTelCapability
private static final int CAPABILITY_TYPE_ALL =
MmTelCapabilities.CAPABILITY_TYPE_VOICE
@@ -164,7 +173,7 @@
CAPABILITY_TYPE_SMS,
REGISTRATION_TECH_LTE,
ProvisioningManager.PROVISIONING_VALUE_ENABLED);
- mImsStats.onImsRegistered(TRANSPORT_TYPE_WWAN);
+ mImsStats.onImsRegistered(mWwanAttributes);
mImsStats.onImsCapabilitiesChanged(
REGISTRATION_TECH_LTE, new MmTelCapabilities(CAPABILITY_TYPE_ALL));
@@ -211,7 +220,7 @@
CAPABILITY_TYPE_SMS,
REGISTRATION_TECH_LTE,
ProvisioningManager.PROVISIONING_VALUE_ENABLED);
- mImsStats.onImsRegistered(TRANSPORT_TYPE_WWAN);
+ mImsStats.onImsRegistered(mWwanAttributes);
mImsStats.onImsCapabilitiesChanged(
REGISTRATION_TECH_LTE, new MmTelCapabilities(CAPABILITY_TYPE_VOICE));
@@ -258,7 +267,7 @@
CAPABILITY_TYPE_UT,
REGISTRATION_TECH_LTE,
ProvisioningManager.PROVISIONING_VALUE_ENABLED);
- mImsStats.onImsRegistered(TRANSPORT_TYPE_WLAN);
+ mImsStats.onImsRegistered(mIwlanAttributes);
mImsStats.onImsCapabilitiesChanged(
REGISTRATION_TECH_IWLAN, new MmTelCapabilities(CAPABILITY_TYPE_VOICE));
@@ -287,6 +296,35 @@
@Test
@SmallTest
+ public void conclude_registeredVoiceOnly_crossSimCalling() throws Exception {
+ mImsStats.onSetFeatureResponse(
+ CAPABILITY_TYPE_VOICE,
+ REGISTRATION_TECH_CROSS_SIM,
+ ProvisioningManager.PROVISIONING_VALUE_ENABLED);
+ mImsStats.onImsRegistered(mCrossSimAttributes);
+ mImsStats.onImsCapabilitiesChanged(
+ REGISTRATION_TECH_CROSS_SIM, new MmTelCapabilities(CAPABILITY_TYPE_VOICE));
+
+ mImsStats.incTimeMillis(2000L);
+ mImsStats.conclude();
+
+ // Duration should be counted
+ ArgumentCaptor<ImsRegistrationStats> captor =
+ ArgumentCaptor.forClass(ImsRegistrationStats.class);
+ verify(mPersistAtomsStorage).addImsRegistrationStats(captor.capture());
+ ImsRegistrationStats stats = captor.getValue();
+ assertEquals(CARRIER1_ID, stats.carrierId);
+ assertEquals(0, stats.simSlotIndex);
+ assertEquals(TelephonyManager.NETWORK_TYPE_IWLAN, stats.rat);
+ assertEquals(true, stats.isIwlanCrossSim);
+ assertEquals(2000L, stats.registeredMillis);
+ assertEquals(2000L, stats.voiceCapableMillis);
+ assertEquals(2000L, stats.voiceAvailableMillis);
+ verifyNoMoreInteractions(mPersistAtomsStorage);
+ }
+
+ @Test
+ @SmallTest
public void conclude_notRegistered() throws Exception {
// IMS over LTE
mImsStats.onSetFeatureResponse(
@@ -333,7 +371,7 @@
ImsRegistrationStats stats = statsCaptor.getValue();
assertEquals(CARRIER1_ID, stats.carrierId);
assertEquals(0, stats.simSlotIndex);
- assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, stats.rat);
+ assertEquals(TelephonyManager.NETWORK_TYPE_LTE, stats.rat);
assertEquals(2000L, stats.unregisteredMillis);
verifyNoMoreInteractions(mPersistAtomsStorage);
}
@@ -380,12 +418,129 @@
@Test
@SmallTest
+ public void conclude_serviceStateChanged_afterRatUnknown() throws Exception {
+ // IMS over LTE
+ mImsStats.onSetFeatureResponse(
+ CAPABILITY_TYPE_VOICE,
+ REGISTRATION_TECH_LTE,
+ ProvisioningManager.PROVISIONING_VALUE_ENABLED);
+ mImsStats.onSetFeatureResponse(
+ CAPABILITY_TYPE_VIDEO,
+ REGISTRATION_TECH_LTE,
+ ProvisioningManager.PROVISIONING_VALUE_ENABLED);
+ mImsStats.onSetFeatureResponse(
+ CAPABILITY_TYPE_UT,
+ REGISTRATION_TECH_LTE,
+ ProvisioningManager.PROVISIONING_VALUE_ENABLED);
+ mImsStats.onSetFeatureResponse(
+ CAPABILITY_TYPE_SMS,
+ REGISTRATION_TECH_LTE,
+ ProvisioningManager.PROVISIONING_VALUE_ENABLED);
+ mImsStats.onImsCapabilitiesChanged(
+ REGISTRATION_TECH_LTE, new MmTelCapabilities(CAPABILITY_TYPE_ALL));
+
+ mImsStats.onImsUnregistered(
+ new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR, 999, "Timeout"));
+
+ doReturn(TelephonyManager.NETWORK_TYPE_UNKNOWN)
+ .when(mServiceState)
+ .getDataNetworkType();
+ mImsStats.onServiceStateChanged(mServiceState);
+
+ mImsStats.incTimeMillis(2000L);
+
+ doReturn(TelephonyManager.NETWORK_TYPE_LTE)
+ .when(mServiceState)
+ .getDataNetworkType();
+ mImsStats.onServiceStateChanged(mServiceState);
+ mImsStats.conclude();
+
+ // Atom with termination info should be generated
+ ArgumentCaptor<ImsRegistrationTermination> terminationCaptor =
+ ArgumentCaptor.forClass(ImsRegistrationTermination.class);
+ verify(mPersistAtomsStorage).addImsRegistrationTermination(terminationCaptor.capture());
+ ImsRegistrationTermination termination = terminationCaptor.getValue();
+ assertEquals(CARRIER1_ID, termination.carrierId);
+ assertFalse(termination.isMultiSim);
+ assertEquals(TelephonyManager.NETWORK_TYPE_LTE, termination.ratAtEnd);
+ assertTrue(termination.setupFailed);
+ assertEquals(ImsReasonInfo.CODE_REGISTRATION_ERROR, termination.reasonCode);
+ assertEquals(999, termination.extraCode);
+ assertEquals("Timeout", termination.extraMessage);
+ verifyNoMoreInteractions(mPersistAtomsStorage);
+ }
+
+ @Test
+ @SmallTest
+ public void conclude_serviceStateChanged_afterRatLte() throws Exception {
+ // IMS over LTE
+ mImsStats.onSetFeatureResponse(
+ CAPABILITY_TYPE_VOICE,
+ REGISTRATION_TECH_LTE,
+ ProvisioningManager.PROVISIONING_VALUE_ENABLED);
+ mImsStats.onSetFeatureResponse(
+ CAPABILITY_TYPE_VIDEO,
+ REGISTRATION_TECH_LTE,
+ ProvisioningManager.PROVISIONING_VALUE_ENABLED);
+ mImsStats.onSetFeatureResponse(
+ CAPABILITY_TYPE_UT,
+ REGISTRATION_TECH_LTE,
+ ProvisioningManager.PROVISIONING_VALUE_ENABLED);
+ mImsStats.onSetFeatureResponse(
+ CAPABILITY_TYPE_SMS,
+ REGISTRATION_TECH_LTE,
+ ProvisioningManager.PROVISIONING_VALUE_ENABLED);
+ mImsStats.onImsCapabilitiesChanged(
+ REGISTRATION_TECH_LTE, new MmTelCapabilities(CAPABILITY_TYPE_ALL));
+
+ mImsStats.onImsUnregistered(
+ new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR, 999, "Timeout"));
+
+ doReturn(TelephonyManager.NETWORK_TYPE_LTE)
+ .when(mServiceState)
+ .getDataNetworkType();
+ mImsStats.onServiceStateChanged(mServiceState);
+
+ mImsStats.incTimeMillis(2000L);
+
+ doReturn(TelephonyManager.NETWORK_TYPE_UNKNOWN)
+ .when(mServiceState)
+ .getDataNetworkType();
+ mImsStats.onServiceStateChanged(mServiceState);
+ mImsStats.conclude();
+
+ // Atom with termination info and durations should be generated
+ ArgumentCaptor<ImsRegistrationTermination> terminationCaptor =
+ ArgumentCaptor.forClass(ImsRegistrationTermination.class);
+ verify(mPersistAtomsStorage).addImsRegistrationTermination(terminationCaptor.capture());
+ ImsRegistrationTermination termination = terminationCaptor.getValue();
+ assertEquals(CARRIER1_ID, termination.carrierId);
+ assertFalse(termination.isMultiSim);
+ assertEquals(TelephonyManager.NETWORK_TYPE_LTE, termination.ratAtEnd);
+ assertTrue(termination.setupFailed);
+ assertEquals(ImsReasonInfo.CODE_REGISTRATION_ERROR, termination.reasonCode);
+ assertEquals(999, termination.extraCode);
+ assertEquals("Timeout", termination.extraMessage);
+
+ ArgumentCaptor<ImsRegistrationStats> statsCaptor =
+ ArgumentCaptor.forClass(ImsRegistrationStats.class);
+ verify(mPersistAtomsStorage).addImsRegistrationStats(statsCaptor.capture());
+ ImsRegistrationStats stats = statsCaptor.getValue();
+ assertEquals(CARRIER1_ID, stats.carrierId);
+ assertEquals(0, stats.simSlotIndex);
+ assertEquals(TelephonyManager.NETWORK_TYPE_LTE, stats.rat);
+ assertEquals(2000L, stats.unregisteredMillis);
+ verifyNoMoreInteractions(mPersistAtomsStorage);
+ }
+
+ @Test
+ @SmallTest
public void onImsCapabilitiesChanged_sameTech() throws Exception {
mImsStats.onSetFeatureResponse(
CAPABILITY_TYPE_VOICE,
REGISTRATION_TECH_LTE,
ProvisioningManager.PROVISIONING_VALUE_ENABLED);
- mImsStats.onImsRegistered(TRANSPORT_TYPE_WWAN);
+ mImsStats.onImsRegistered(mWwanAttributes);
mImsStats.incTimeMillis(2000L);
mImsStats.onImsCapabilitiesChanged(
@@ -420,7 +575,7 @@
CAPABILITY_TYPE_VOICE,
REGISTRATION_TECH_LTE,
ProvisioningManager.PROVISIONING_VALUE_ENABLED);
- mImsStats.onImsRegistered(TRANSPORT_TYPE_WWAN);
+ mImsStats.onImsRegistered(mWwanAttributes);
mImsStats.onImsCapabilitiesChanged(
REGISTRATION_TECH_LTE, new MmTelCapabilities(CAPABILITY_TYPE_VOICE));
@@ -459,7 +614,7 @@
CAPABILITY_TYPE_SMS,
REGISTRATION_TECH_LTE,
ProvisioningManager.PROVISIONING_VALUE_ENABLED);
- mImsStats.onImsRegistered(TRANSPORT_TYPE_WWAN);
+ mImsStats.onImsRegistered(mWwanAttributes);
mImsStats.onImsCapabilitiesChanged(
REGISTRATION_TECH_LTE, new MmTelCapabilities(CAPABILITY_TYPE_SMS));
@@ -498,7 +653,7 @@
CAPABILITY_TYPE_VOICE,
REGISTRATION_TECH_LTE,
ProvisioningManager.PROVISIONING_VALUE_ENABLED);
- mImsStats.onImsRegistered(TRANSPORT_TYPE_WWAN);
+ mImsStats.onImsRegistered(mWwanAttributes);
mImsStats.incTimeMillis(2000L);
mImsStats.onSetFeatureResponse(
@@ -529,11 +684,11 @@
@Test
@SmallTest
public void onImsRegistered_differentTech() throws Exception {
- mImsStats.onImsRegistered(TRANSPORT_TYPE_WWAN);
+ mImsStats.onImsRegistered(mWwanAttributes);
mImsStats.incTimeMillis(2000L);
- mImsStats.onImsRegistered(TRANSPORT_TYPE_WLAN);
+ mImsStats.onImsRegistered(mIwlanAttributes);
mImsStats.incTimeMillis(2000L);
- mImsStats.onImsRegistered(TRANSPORT_TYPE_WWAN);
+ mImsStats.onImsRegistered(mWwanAttributes);
// At this point, the first 2 registrations should have their durations counted
ArgumentCaptor<ImsRegistrationStats> captor =
@@ -574,7 +729,7 @@
public void onImsRegistered_afterImsRegistering() throws Exception {
mImsStats.onImsRegistering(TRANSPORT_TYPE_WWAN);
mImsStats.incTimeMillis(2000L);
- mImsStats.onImsRegistered(TRANSPORT_TYPE_WWAN);
+ mImsStats.onImsRegistered(mWwanAttributes);
// Registering duration should be counted
ArgumentCaptor<ImsRegistrationStats> captor =
@@ -591,6 +746,11 @@
@Test
@SmallTest
public void onImsRegistering_afterImsUnregistered() throws Exception {
+ doReturn(TelephonyManager.NETWORK_TYPE_LTE)
+ .when(mServiceState)
+ .getDataNetworkType();
+ mImsStats.onServiceStateChanged(mServiceState);
+
mImsStats.onImsUnregistered(
new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR, 999, "Timeout"));
mImsStats.incTimeMillis(2000L);
@@ -615,7 +775,7 @@
ImsRegistrationStats stats = statsCaptor.getValue();
assertEquals(CARRIER1_ID, stats.carrierId);
assertEquals(0, stats.simSlotIndex);
- assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, stats.rat);
+ assertEquals(TelephonyManager.NETWORK_TYPE_LTE, stats.rat);
assertEquals(2000L, stats.unregisteredMillis);
verifyNoMoreInteractions(mPersistAtomsStorage);
}
@@ -649,7 +809,7 @@
mImsStats.onImsUnregistered(
new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR, 999, "Timeout"));
- // Atom with termination info should be generated
+ // Atom with termination info and durations should be generated
ArgumentCaptor<ImsRegistrationStats> statsCaptor =
ArgumentCaptor.forClass(ImsRegistrationStats.class);
verify(mPersistAtomsStorage).addImsRegistrationStats(statsCaptor.capture());
@@ -677,7 +837,7 @@
@Test
@SmallTest
public void onImsUnregistered_afterRegistered() throws Exception {
- mImsStats.onImsRegistered(TRANSPORT_TYPE_WWAN);
+ mImsStats.onImsRegistered(mWwanAttributes);
mImsStats.incTimeMillis(2000L);
mImsStats.onImsUnregistered(
new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR, 999, "Timeout"));
@@ -879,9 +1039,7 @@
}
}
- @Test
- @SmallTest
- public void onImsUnregistered_multiSim() throws Exception {
+ void secondSimMockSetup() {
doReturn(mSecondImsPhone).when(mSecondPhone).getImsPhone();
doReturn(mSecondPhone).when(mSecondImsPhone).getDefaultPhone();
doReturn(1).when(mSecondPhone).getPhoneId();
@@ -898,8 +1056,14 @@
// Reusing service state tracker from phone 0 for simplicity
doReturn(mSST).when(mSecondPhone).getServiceStateTracker();
doReturn(mSST).when(mSecondImsPhone).getServiceStateTracker();
+ }
+
+ @Test
+ @SmallTest
+ public void onImsUnregistered_multiSim() throws Exception {
+ secondSimMockSetup();
mImsStats = new TestableImsStats(mSecondImsPhone);
- mImsStats.onImsRegistered(TRANSPORT_TYPE_WWAN);
+ mImsStats.onImsRegistered(mWwanAttributes);
mImsStats.incTimeMillis(2000L);
mImsStats.onImsUnregistered(
new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR, 999, "Timeout"));
@@ -937,6 +1101,42 @@
@Test
@SmallTest
+ public void onImsUnregistered_crossSim() throws Exception {
+ secondSimMockSetup();
+ mImsStats = new TestableImsStats(mSecondImsPhone);
+ mImsStats.onImsRegistered(mCrossSimAttributes);
+ mImsStats.incTimeMillis(2000L);
+ mImsStats.onImsUnregistered(
+ new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR, 999, "Timeout"));
+
+ // Atom with termination info and durations should be generated
+ ArgumentCaptor<ImsRegistrationStats> statsCaptor =
+ ArgumentCaptor.forClass(ImsRegistrationStats.class);
+ verify(mPersistAtomsStorage).addImsRegistrationStats(statsCaptor.capture());
+ ImsRegistrationStats stats = statsCaptor.getValue();
+ assertEquals(CARRIER2_ID, stats.carrierId);
+ assertEquals(1, stats.simSlotIndex);
+ assertEquals(TelephonyManager.NETWORK_TYPE_IWLAN, stats.rat);
+ assertEquals(true, stats.isIwlanCrossSim);
+ assertEquals(2000L, stats.registeredMillis);
+
+ ArgumentCaptor<ImsRegistrationTermination> terminationCaptor =
+ ArgumentCaptor.forClass(ImsRegistrationTermination.class);
+ verify(mPersistAtomsStorage).addImsRegistrationTermination(terminationCaptor.capture());
+ ImsRegistrationTermination termination = terminationCaptor.getValue();
+ assertEquals(CARRIER2_ID, termination.carrierId);
+ assertTrue(termination.isMultiSim);
+ assertEquals(TelephonyManager.NETWORK_TYPE_IWLAN, termination.ratAtEnd);
+ assertEquals(true, termination.isIwlanCrossSim);
+ assertFalse(termination.setupFailed);
+ assertEquals(ImsReasonInfo.CODE_REGISTRATION_ERROR, termination.reasonCode);
+ assertEquals(999, termination.extraCode);
+ assertEquals("Timeout", termination.extraMessage);
+ verifyNoMoreInteractions(mPersistAtomsStorage);
+ }
+
+ @Test
+ @SmallTest
public void getImsVoiceRadioTech_noRegistration() throws Exception {
// Do nothing
@@ -946,7 +1146,7 @@
@Test
@SmallTest
public void getImsVoiceRadioTech_noVoiceRegistration() throws Exception {
- mImsStats.onImsRegistered(TRANSPORT_TYPE_WWAN);
+ mImsStats.onImsRegistered(mWwanAttributes);
mImsStats.onImsCapabilitiesChanged(
REGISTRATION_TECH_LTE, new MmTelCapabilities(CAPABILITY_TYPE_SMS));
@@ -956,7 +1156,7 @@
@Test
@SmallTest
public void getImsVoiceRadioTech_cellularRegistration() throws Exception {
- mImsStats.onImsRegistered(TRANSPORT_TYPE_WWAN);
+ mImsStats.onImsRegistered(mWwanAttributes);
mImsStats.onImsCapabilitiesChanged(
REGISTRATION_TECH_LTE, new MmTelCapabilities(CAPABILITY_TYPE_VOICE));
@@ -966,7 +1166,7 @@
@Test
@SmallTest
public void getImsVoiceRadioTech_wifiRegistration() throws Exception {
- mImsStats.onImsRegistered(TRANSPORT_TYPE_WLAN);
+ mImsStats.onImsRegistered(mIwlanAttributes);
mImsStats.onImsCapabilitiesChanged(
REGISTRATION_TECH_IWLAN, new MmTelCapabilities(CAPABILITY_TYPE_VOICE));
@@ -975,8 +1175,18 @@
@Test
@SmallTest
+ public void getImsVoiceRadioTech_crossSimRegistration() throws Exception {
+ mImsStats.onImsRegistered(mCrossSimAttributes);
+ mImsStats.onImsCapabilitiesChanged(
+ REGISTRATION_TECH_CROSS_SIM, new MmTelCapabilities(CAPABILITY_TYPE_VOICE));
+
+ assertEquals(TelephonyManager.NETWORK_TYPE_IWLAN, mImsStats.getImsVoiceRadioTech());
+ }
+
+ @Test
+ @SmallTest
public void getImsVoiceRadioTech_unregistered() throws Exception {
- mImsStats.onImsRegistered(TRANSPORT_TYPE_WWAN);
+ mImsStats.onImsRegistered(mWwanAttributes);
mImsStats.onImsCapabilitiesChanged(
REGISTRATION_TECH_LTE, new MmTelCapabilities(CAPABILITY_TYPE_VOICE));
mImsStats.onImsUnregistered(
@@ -995,17 +1205,14 @@
@Test
@SmallTest
public void getImsVoiceRadioTech_serviceStateChanged() throws Exception {
- mImsStats.onImsRegistered(TRANSPORT_TYPE_WWAN);
+ mImsStats.onImsRegistered(mWwanAttributes);
mImsStats.onImsCapabilitiesChanged(
REGISTRATION_TECH_LTE, new MmTelCapabilities(CAPABILITY_TYPE_VOICE));
- doReturn(
- new NetworkRegistrationInfo.Builder()
- .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_NR)
- .setRegistrationState(
- NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
- .build())
+
+ doReturn(TelephonyManager.NETWORK_TYPE_NR)
.when(mServiceState)
- .getNetworkRegistrationInfo(DOMAIN_PS, TRANSPORT_TYPE_WWAN);
+ .getDataNetworkType();
+
mImsStats.onServiceStateChanged(mServiceState);
assertEquals(TelephonyManager.NETWORK_TYPE_NR, mImsStats.getImsVoiceRadioTech());
}
@@ -1013,17 +1220,14 @@
@Test
@SmallTest
public void getImsVoiceRadioTech_serviceStateChanged_wlan() throws Exception {
- mImsStats.onImsRegistered(TRANSPORT_TYPE_WWAN);
+ mImsStats.onImsRegistered(mWwanAttributes);
mImsStats.onImsCapabilitiesChanged(
REGISTRATION_TECH_IWLAN, new MmTelCapabilities(CAPABILITY_TYPE_VOICE));
- doReturn(
- new NetworkRegistrationInfo.Builder()
- .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_NR)
- .setRegistrationState(
- NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
- .build())
+
+ doReturn(TelephonyManager.NETWORK_TYPE_IWLAN)
.when(mServiceState)
- .getNetworkRegistrationInfo(DOMAIN_PS, TRANSPORT_TYPE_WWAN);
+ .getDataNetworkType();
+
mImsStats.onServiceStateChanged(mServiceState);
assertEquals(TelephonyManager.NETWORK_TYPE_IWLAN, mImsStats.getImsVoiceRadioTech());
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/PerSimStatusTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/PerSimStatusTest.java
index dc9be1c..e03dfe4 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/PerSimStatusTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/PerSimStatusTest.java
@@ -107,6 +107,7 @@
.when(imsMmTelManager1)
.getVoWiFiRoamingModeSetting();
doReturn(false).when(imsMmTelManager1).isVtSettingEnabled();
+ doReturn(true).when(imsMmTelManager1).isCrossSimCallingEnabled();
doReturn(false).when(mPhone).getDataRoamingEnabled();
doReturn(1L)
.when(mPhone)
@@ -152,6 +153,7 @@
.when(imsMmTelManager2)
.getVoWiFiRoamingModeSetting();
doReturn(true).when(imsMmTelManager2).isVtSettingEnabled();
+ doReturn(false).when(imsMmTelManager2).isCrossSimCallingEnabled();
doReturn(false).when(mSecondPhone).getDataRoamingEnabled();
doReturn(1L)
.when(mSecondPhone)
@@ -191,6 +193,8 @@
perSimStatus1.minimumVoltageClass);
assertEquals(NETWORK_TYPE_BITMASK_GSM, perSimStatus1.unmeteredNetworks);
assertEquals(false, perSimStatus1.vonrEnabled);
+ assertEquals(true, perSimStatus1.crossSimCallingEnabled);
+
assertEquals(101, perSimStatus2.carrierId);
assertEquals(1, perSimStatus2.phoneNumberSourceUicc);
assertEquals(2, perSimStatus2.phoneNumberSourceCarrier);
@@ -210,6 +214,7 @@
perSimStatus2.minimumVoltageClass);
assertEquals(NETWORK_TYPE_BITMASK_GSM, perSimStatus2.unmeteredNetworks);
assertEquals(false, perSimStatus2.vonrEnabled);
+ assertEquals(false, perSimStatus2.crossSimCallingEnabled);
}
@Test
@@ -279,6 +284,7 @@
perSimStatus.minimumVoltageClass);
assertEquals(NETWORK_TYPE_BITMASK_GSM, perSimStatus.unmeteredNetworks);
assertEquals(true, perSimStatus.vonrEnabled);
+ assertEquals(false, perSimStatus.crossSimCallingEnabled);
}
@Test
@@ -340,6 +346,7 @@
perSimStatus.minimumVoltageClass);
assertEquals(NETWORK_TYPE_BITMASK_GSM, perSimStatus.unmeteredNetworks);
assertEquals(true, perSimStatus.vonrEnabled);
+ assertEquals(false, perSimStatus.crossSimCallingEnabled);
}
@Test
@@ -397,5 +404,6 @@
perSimStatus.minimumVoltageClass);
assertEquals(NETWORK_TYPE_BITMASK_GSM, perSimStatus.unmeteredNetworks);
assertEquals(true, perSimStatus.vonrEnabled);
+ assertEquals(false, perSimStatus.crossSimCallingEnabled);
}
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java
index 2509b8c..c66cfa7 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java
@@ -44,6 +44,7 @@
import android.telephony.NetworkRegistrationInfo;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.test.suitebuilder.annotation.SmallTest;
import com.android.internal.telephony.Phone;
@@ -401,6 +402,30 @@
@Test
@SmallTest
+ public void onImsVoiceRegistrationChanged_crossSimCalling() throws Exception {
+ mServiceStateStats.onServiceStateChanged(mServiceState);
+ mockWwanPsRat(TelephonyManager.NETWORK_TYPE_UNKNOWN);
+ doReturn(TelephonyManager.NETWORK_TYPE_IWLAN).when(mImsStats).getImsVoiceRadioTech();
+ doReturn(ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM).when(mImsPhone)
+ .getImsRegistrationTech();
+ mServiceStateStats.incTimeMillis(100L);
+ mServiceStateStats.onImsVoiceRegistrationChanged();
+ mServiceStateStats.incTimeMillis(200L);
+ mServiceStateStats.conclude();
+
+ ArgumentCaptor<CellularServiceState> captor =
+ ArgumentCaptor.forClass(CellularServiceState.class);
+ verify(mPersistAtomsStorage, times(2))
+ .addCellularServiceStateAndCellularDataServiceSwitch(captor.capture(), eq(null));
+ CellularServiceState state = captor.getAllValues().get(1);
+
+ assertEquals(200L, state.totalTimeMillis);
+ assertEquals(TelephonyManager.NETWORK_TYPE_IWLAN, state.voiceRat);
+ assertTrue(state.isIwlanCrossSim);
+ }
+
+ @Test
+ @SmallTest
public void onInternetDataNetworkDisconnected() throws Exception {
// Using default service state for LTE
mServiceStateStats.onServiceStateChanged(mServiceState);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/VoiceCallSessionStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/VoiceCallSessionStatsTest.java
index 5412992..00ba0f8 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/VoiceCallSessionStatsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/VoiceCallSessionStatsTest.java
@@ -56,6 +56,7 @@
import android.telephony.data.ApnSetting;
import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.ImsStreamMediaProfile;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.test.suitebuilder.annotation.SmallTest;
import com.android.internal.telephony.Call;
@@ -196,6 +197,7 @@
doReturn(PhoneConstants.PHONE_TYPE_IMS).when(mImsConnection0).getPhoneType();
doReturn(false).when(mImsConnection0).isEmergencyCall();
+ doReturn(false).when(mImsConnection0).isCrossSimCall();
doReturn(PhoneConstants.PHONE_TYPE_IMS).when(mImsConnection1).getPhoneType();
doReturn(false).when(mImsConnection1).isEmergencyCall();
doReturn(PhoneConstants.PHONE_TYPE_GSM).when(mGsmConnection0).getPhoneType();
@@ -203,6 +205,9 @@
doReturn(PhoneConstants.PHONE_TYPE_GSM).when(mGsmConnection1).getPhoneType();
doReturn(false).when(mGsmConnection1).isEmergencyCall();
+ doReturn(ImsRegistrationImplBase.REGISTRATION_TECH_LTE).when(mImsPhone)
+ .getImsRegistrationTech();
+
if (Looper.myLooper() == null) {
Looper.prepare();
}
@@ -241,7 +246,6 @@
ImsReasonInfo.CODE_REMOTE_CALL_DECLINE);
expectedCall.setupDurationMillis = 200;
expectedCall.setupFailed = true;
- expectedCall.ratAtConnected = TelephonyManager.NETWORK_TYPE_UNKNOWN;
expectedCall.codecBitmask = 1L << AudioCodec.AUDIO_CODEC_EVS_SWB;
expectedCall.mainCodecQuality =
VOICE_CALL_SESSION__MAIN_CODEC_QUALITY__CODEC_QUALITY_SUPER_WIDEBAND;
@@ -1519,6 +1523,75 @@
@Test
@SmallTest
+ public void singleCrossSimCall_moAccepted() {
+ setServiceStateWithWifiCalling(mServiceState, TelephonyManager.NETWORK_TYPE_LTE);
+ doReturn(mImsPhone).when(mPhone).getImsPhone();
+ doReturn(ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM).when(mImsPhone)
+ .getImsRegistrationTech();
+ doReturn(TelephonyManager.NETWORK_TYPE_IWLAN).when(mImsStats).getImsVoiceRadioTech();
+ doReturn(false).when(mImsConnection0).isIncoming();
+ doReturn(true).when(mImsConnection0).isCrossSimCall();
+ doReturn(2000L).when(mImsConnection0).getCreateTime();
+ doReturn(1000L).when(mImsConnection0).getDurationMillis();
+ doReturn(mImsCall0).when(mImsConnection0).getCall();
+ doReturn(new ArrayList(List.of(mImsConnection0))).when(mImsCall0).getConnections();
+ VoiceCallSession expectedCall =
+ makeSlot0CallProto(
+ VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_IMS,
+ VOICE_CALL_SESSION__DIRECTION__CALL_DIRECTION_MO,
+ TelephonyManager.NETWORK_TYPE_IWLAN,
+ ImsReasonInfo.CODE_USER_TERMINATED_BY_REMOTE);
+ expectedCall.isIwlanCrossSimAtStart = true;
+ expectedCall.isIwlanCrossSimAtEnd = true;
+ expectedCall.isIwlanCrossSimAtConnected = true;
+
+ expectedCall.bandAtEnd = 0; // not configured for IWLAN
+ expectedCall.setupDurationMillis = 200;
+ expectedCall.setupFailed = false;
+ expectedCall.codecBitmask = 1L << AudioCodec.AUDIO_CODEC_EVS_SWB;
+ expectedCall.mainCodecQuality =
+ VOICE_CALL_SESSION__MAIN_CODEC_QUALITY__CODEC_QUALITY_SUPER_WIDEBAND;
+ expectedCall.disconnectExtraMessage = "normal call clearing";
+ expectedCall.callDuration =
+ VOICE_CALL_SESSION__CALL_DURATION__CALL_DURATION_LESS_THAN_ONE_MINUTE;
+ VoiceCallRatUsage expectedRatUsage =
+ makeRatUsageProto(
+ CARRIER_ID_SLOT_0, TelephonyManager.NETWORK_TYPE_IWLAN, 2000L, 100000L, 1L);
+ final AtomicReference<VoiceCallRatUsage[]> ratUsage = setupRatUsageCapture();
+
+ mVoiceCallSessionStats0.setTimeMillis(2000L);
+ doReturn(Call.State.DIALING).when(mImsCall0).getState();
+ doReturn(Call.State.DIALING).when(mImsConnection0).getState();
+ mVoiceCallSessionStats0.onImsDial(mImsConnection0);
+ mVoiceCallSessionStats0.setTimeMillis(2100L);
+ mVoiceCallSessionStats0.onAudioCodecChanged(
+ mImsConnection0, ImsStreamMediaProfile.AUDIO_QUALITY_EVS_SWB);
+ mVoiceCallSessionStats0.setTimeMillis(2200L);
+ doReturn(Call.State.ALERTING).when(mImsCall0).getState();
+ doReturn(Call.State.ALERTING).when(mImsConnection0).getState();
+ mVoiceCallSessionStats0.onCallStateChanged(mImsCall0);
+ mVoiceCallSessionStats0.setTimeMillis(12000L);
+ doReturn(Call.State.ACTIVE).when(mImsCall0).getState();
+ doReturn(Call.State.ACTIVE).when(mImsConnection0).getState();
+ mVoiceCallSessionStats0.onCallStateChanged(mImsCall0);
+ mVoiceCallSessionStats0.setTimeMillis(100000L);
+ mVoiceCallSessionStats0.onImsCallTerminated(
+ mImsConnection0,
+ new ImsReasonInfo(
+ ImsReasonInfo.CODE_USER_TERMINATED_BY_REMOTE, 0, "normal call clearing"));
+
+ ArgumentCaptor<VoiceCallSession> callCaptor =
+ ArgumentCaptor.forClass(VoiceCallSession.class);
+ verify(mPersistAtomsStorage, times(1)).addVoiceCallSession(callCaptor.capture());
+ verify(mPersistAtomsStorage, times(1)).addVoiceCallRatUsage(any());
+ verifyNoMoreInteractions(mPersistAtomsStorage);
+ assertProtoEquals(expectedCall, callCaptor.getValue());
+ assertThat(ratUsage.get()).hasLength(1);
+ assertProtoEquals(expectedRatUsage, ratUsage.get()[0]);
+ }
+
+ @Test
+ @SmallTest
public void singleCsCall_moRejected() {
doReturn(false).when(mGsmConnection0).isIncoming();
doReturn(2000L).when(mGsmConnection0).getCreateTime();
@@ -2518,6 +2591,8 @@
public void singleWifiCall_preferred() {
setServiceStateWithWifiCalling(mServiceState, TelephonyManager.NETWORK_TYPE_LTE);
doReturn(mImsPhone).when(mPhone).getImsPhone();
+ doReturn(ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN).when(mImsPhone)
+ .getImsRegistrationTech();
doReturn(TelephonyManager.NETWORK_TYPE_IWLAN).when(mImsStats).getImsVoiceRadioTech();
doReturn(true).when(mImsConnection0).isIncoming();
doReturn(2000L).when(mImsConnection0).getCreateTime();
@@ -2566,6 +2641,8 @@
public void singleWifiCall_airPlaneMode() {
setServiceStateWithWifiCalling(mServiceState, TelephonyManager.NETWORK_TYPE_UNKNOWN);
doReturn(mImsPhone).when(mPhone).getImsPhone();
+ doReturn(ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN).when(mImsPhone)
+ .getImsRegistrationTech();
doReturn(TelephonyManager.NETWORK_TYPE_IWLAN).when(mImsStats).getImsVoiceRadioTech();
doReturn(true).when(mImsConnection0).isIncoming();
doReturn(2000L).when(mImsConnection0).getCreateTime();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java
index 0a1ab02..fd5f6ab 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java
@@ -428,7 +428,7 @@
processAllMessages();
// As modem is busy receiving datagrams, sending datagram did not proceed further.
mInOrder.verify(mMockDatagramController).needsWaitingForSatelliteConnected();
- mInOrder.verify(mMockDatagramController).isPollingInIdleState();
+ mInOrder.verify(mMockDatagramController, times(2)).isPollingInIdleState();
verifyNoMoreInteractions(mMockDatagramController);
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java
index 94f56b4..0e16e25 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java
@@ -23,6 +23,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.anyInt;
@@ -38,6 +39,7 @@
import static org.mockito.Mockito.when;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.os.AsyncResult;
import android.os.IBinder;
@@ -66,6 +68,7 @@
import org.mockito.MockitoAnnotations;
import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
@RunWith(AndroidTestingRunner.class)
@@ -272,10 +275,13 @@
@Test
public void testSatelliteDatagramReceived_success_zeroPendingCount() {
+ TestSatelliteDatagramCallback testSatelliteDatagramCallback =
+ new TestSatelliteDatagramCallback();
+
+ mSatelliteDatagramListenerHandler.addListener(testSatelliteDatagramCallback);
mSatelliteDatagramListenerHandler.obtainMessage(1 /*EVENT_SATELLITE_DATAGRAM_RECEIVED*/,
new AsyncResult(null, new Pair<>(mDatagram, 0), null))
.sendToTarget();
-
processAllMessages();
mInOrder.verify(mMockDatagramController)
@@ -286,6 +292,14 @@
.updateReceiveStatus(eq(SUB_ID),
eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE),
eq(0), eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
+ assertTrue(testSatelliteDatagramCallback.waitForOnSatelliteDatagramReceived());
+
+ assertTrue(testSatelliteDatagramCallback.sendInternalAck());
+ try {
+ processAllFutureMessages();
+ } catch (Exception e) {
+ fail("Unexpected exception e=" + e);
+ }
}
@Test
@@ -475,4 +489,57 @@
mLong = duration;
}
}
+
+ private static class TestSatelliteDatagramCallback extends ISatelliteDatagramCallback.Stub {
+ @Nullable private IVoidConsumer mInternalAck;
+ private final Semaphore mSemaphore = new Semaphore(0);
+
+ @Override
+ public void onSatelliteDatagramReceived(long datagramId,
+ @NonNull SatelliteDatagram datagram, int pendingCount,
+ @NonNull IVoidConsumer internalAck) {
+ logd("onSatelliteDatagramReceived");
+ mInternalAck = internalAck;
+ try {
+ internalAck.accept();
+ } catch (RemoteException e) {
+ logd("onSatelliteDatagramReceived: accept e=" + e);
+ return;
+ }
+
+ try {
+ mSemaphore.release();
+ } catch (Exception e) {
+ logd("onSatelliteDatagramReceived: release e=" + e);
+ }
+ }
+
+ public boolean waitForOnSatelliteDatagramReceived() {
+ logd("waitForOnSatelliteDatagramReceived");
+ try {
+ if (!mSemaphore.tryAcquire(1000, TimeUnit.MILLISECONDS)) {
+ logd("Timed out to receive onSatelliteDatagramReceived");
+ return false;
+ }
+ } catch (InterruptedException e) {
+ logd("waitForOnSatelliteDatagramReceived: e=" + e);
+ return false;
+ }
+ return true;
+ }
+
+ public boolean sendInternalAck() {
+ if (mInternalAck == null) {
+ logd("sendInternalAck: mInternalAck is null");
+ return false;
+ }
+ try {
+ mInternalAck.accept();
+ } catch (RemoteException e) {
+ logd("sendInternalAck: accept e=" + e);
+ return false;
+ }
+ return true;
+ }
+ }
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java
index e4e2434..eecaf90 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java
@@ -766,13 +766,13 @@
// Should get an empty list without READ_PHONE_STATE.
assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoList(
- CALLING_PACKAGE, CALLING_FEATURE)).isEmpty();
+ CALLING_PACKAGE, CALLING_FEATURE, true)).isEmpty();
// Grant READ_PHONE_STATE permission for insertion.
mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE);
List<SubscriptionInfo> subInfos = mSubscriptionManagerServiceUT
- .getActiveSubscriptionInfoList(CALLING_PACKAGE, CALLING_FEATURE);
+ .getActiveSubscriptionInfoList(CALLING_PACKAGE, CALLING_FEATURE, true);
assertThat(subInfos).hasSize(1);
assertThat(subInfos.get(0).getIccId()).isEmpty();
assertThat(subInfos.get(0).getCardString()).isEmpty();
@@ -783,7 +783,7 @@
setCarrierPrivilegesForSubId(true, 1);
subInfos = mSubscriptionManagerServiceUT
- .getActiveSubscriptionInfoList(CALLING_PACKAGE, CALLING_FEATURE);
+ .getActiveSubscriptionInfoList(CALLING_PACKAGE, CALLING_FEATURE, true);
assertThat(subInfos).hasSize(1);
assertThat(subInfos.get(0)).isEqualTo(FAKE_SUBSCRIPTION_INFO1.toSubscriptionInfo());
}
@@ -963,11 +963,11 @@
// Should fail without READ_PHONE_STATE
assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT
- .getActiveSubInfoCount(CALLING_PACKAGE, CALLING_FEATURE));
+ .getActiveSubInfoCount(CALLING_PACKAGE, CALLING_FEATURE, true));
mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
assertThat(mSubscriptionManagerServiceUT.getActiveSubInfoCount(
- CALLING_PACKAGE, CALLING_FEATURE)).isEqualTo(2);
+ CALLING_PACKAGE, CALLING_FEATURE, true)).isEqualTo(2);
}
@Test
@@ -1252,7 +1252,7 @@
.isEqualTo(new int[]{subId1, subId2});
// Test get getActiveSubInfoCount
assertThat(mSubscriptionManagerServiceUT.getActiveSubInfoCount(
- CALLING_PACKAGE, CALLING_FEATURE)).isEqualTo(1);
+ CALLING_PACKAGE, CALLING_FEATURE, false)).isEqualTo(1);
// Test getActiveSubscriptionInfo
assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfo(
subId1, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId()).isEqualTo(subId1);
@@ -1274,7 +1274,8 @@
.isEqualTo(subId2);
// Test getActiveSubscriptionInfoList
assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoList(
- CALLING_PACKAGE, CALLING_FEATURE).stream().map(SubscriptionInfo::getSubscriptionId)
+ CALLING_PACKAGE, CALLING_FEATURE, false)
+ .stream().map(SubscriptionInfo::getSubscriptionId)
.toList()).isEqualTo(List.of(subId1));
// Test getAllSubInfoList
assertThat(mSubscriptionManagerServiceUT.getAllSubInfoList(CALLING_PACKAGE,
@@ -1368,7 +1369,7 @@
.isEqualTo(new int[]{subId1, subId2});
// Test get getActiveSubInfoCount
assertThat(mSubscriptionManagerServiceUT.getActiveSubInfoCount(
- CALLING_PACKAGE, CALLING_FEATURE)).isEqualTo(1);
+ CALLING_PACKAGE, CALLING_FEATURE, false)).isEqualTo(1);
// Test getActiveSubscriptionInfo
assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfo(
subId1, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId()).isEqualTo(subId1);
@@ -1390,7 +1391,7 @@
.isEqualTo(subId2);
// Test getActiveSubscriptionInfoList
assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoList(
- CALLING_PACKAGE, CALLING_FEATURE).stream()
+ CALLING_PACKAGE, CALLING_FEATURE, false).stream()
.map(SubscriptionInfo::getSubscriptionId)
.toList()).isEqualTo(List.of(subId1));
// Test getAllSubInfoList
@@ -2151,7 +2152,7 @@
assertThat(mSubscriptionManagerServiceUT.getAllSubInfoList(
CALLING_PACKAGE, CALLING_FEATURE).isEmpty()).isTrue();
assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoList(
- CALLING_PACKAGE, CALLING_FEATURE)).isEmpty();
+ CALLING_PACKAGE, CALLING_FEATURE, true)).isEmpty();
}
@Test
@@ -2357,7 +2358,7 @@
verify(mEuiccController).blockingGetEuiccProfileInfoList(eq(1));
List<SubscriptionInfo> subInfoList = mSubscriptionManagerServiceUT
- .getActiveSubscriptionInfoList(CALLING_PACKAGE, CALLING_FEATURE);
+ .getActiveSubscriptionInfoList(CALLING_PACKAGE, CALLING_FEATURE, true);
assertThat(subInfoList).hasSize(1);
assertThat(subInfoList.get(0).getSimSlotIndex()).isEqualTo(1);
assertThat(subInfoList.get(0).getSubscriptionId()).isEqualTo(1);
@@ -2475,7 +2476,7 @@
processAllMessages();
List<SubscriptionInfo> subInfoList = mSubscriptionManagerServiceUT
- .getActiveSubscriptionInfoList(CALLING_PACKAGE, CALLING_FEATURE);
+ .getActiveSubscriptionInfoList(CALLING_PACKAGE, CALLING_FEATURE, true);
assertThat(subInfoList).hasSize(1);
assertThat(subInfoList.get(0).isActive()).isTrue();
@@ -2595,16 +2596,17 @@
CALLING_PACKAGE, CALLING_FEATURE)).isEmpty();
assertThat(mSubscriptionManagerServiceUT.getActiveSubIdList(false)).isEmpty();
assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoList(
- CALLING_PACKAGE, CALLING_FEATURE)).isEmpty();
+ CALLING_PACKAGE, CALLING_FEATURE, true)).isEmpty();
setIdentifierAccess(true);
mSubscriptionManagerServiceUT.addSubInfo(FAKE_MAC_ADDRESS2, FAKE_CARRIER_NAME2,
0, SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM);
assertThat(mSubscriptionManagerServiceUT.getActiveSubIdList(false)).isNotEmpty();
assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoList(
- CALLING_PACKAGE, CALLING_FEATURE)).isNotEmpty();
+ CALLING_PACKAGE, CALLING_FEATURE, true)).isNotEmpty();
assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoList(
- CALLING_PACKAGE, CALLING_FEATURE).get(0).getIccId()).isEqualTo(FAKE_MAC_ADDRESS2);
+ CALLING_PACKAGE, CALLING_FEATURE, true).get(0).getIccId())
+ .isEqualTo(FAKE_MAC_ADDRESS2);
}
@Test