[automerger skipped] [automerged blank] Import translations. DO NOT MERGE ANYWHERE 2p: d82596210d am: 19084309b2 -s ours
am skip reason: subject contains skip directive
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/services/Telephony/+/16982731
Change-Id: I1c4cf150bdc0de315346515654e2a111f26ead2c
diff --git a/src/com/android/phone/CallForwardEditPreference.java b/src/com/android/phone/CallForwardEditPreference.java
index bf296f9..45121f7 100644
--- a/src/com/android/phone/CallForwardEditPreference.java
+++ b/src/com/android/phone/CallForwardEditPreference.java
@@ -58,6 +58,7 @@
CarrierXmlParser.SsEntry.SSAction.UNKNOWN;
private int mAction;
private HashMap<String, String> mCfInfo;
+ private long mDelayMillisAfterUssdSet = 1000;
public CallForwardEditPreference(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -488,8 +489,9 @@
mPhone.getCallForwardingOption(reason, mServiceClass,
obtainMessage(MESSAGE_GET_CF, msg.arg1, MESSAGE_SET_CF, ar.exception));
} else {
- mHandler.sendMessage(mHandler.obtainMessage(mHandler.MESSAGE_GET_CF_USSD,
- msg.arg1, MyHandler.MESSAGE_SET_CF, ar.exception));
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(mHandler.MESSAGE_GET_CF_USSD,
+ msg.arg1, MyHandler.MESSAGE_SET_CF, ar.exception),
+ mDelayMillisAfterUssdSet);
}
}
diff --git a/src/com/android/phone/CallWaitingSwitchPreference.java b/src/com/android/phone/CallWaitingSwitchPreference.java
index 01dd3b2..609488c 100644
--- a/src/com/android/phone/CallWaitingSwitchPreference.java
+++ b/src/com/android/phone/CallWaitingSwitchPreference.java
@@ -6,28 +6,34 @@
import android.content.Context;
import android.os.Handler;
import android.os.Message;
+import android.os.PersistableBundle;
import android.preference.SwitchPreference;
+import android.telephony.CarrierConfigManager;
import android.telephony.TelephonyManager;
import android.util.AttributeSet;
import android.util.Log;
import com.android.internal.telephony.Phone;
-import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
public class CallWaitingSwitchPreference extends SwitchPreference {
private static final String LOG_TAG = "CallWaitingSwitchPreference";
+ private static final int DELAY_MILLIS_FOR_USSD = 1000;
private final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
private final MyHandler mHandler = new MyHandler();
private Phone mPhone;
private TimeConsumingPreferenceListener mTcpListener;
- private Executor mExecutor;
+ private ScheduledExecutorService mExecutor;
private TelephonyManager mTelephonyManager;
private boolean mIsDuringUpdateProcess = false;
private int mUpdateStatus = TelephonyManager.CALL_WAITING_STATUS_UNKNOWN_ERROR;
private int mQueryStatus = TelephonyManager.CALL_WAITING_STATUS_UNKNOWN_ERROR;
+ private boolean mUssdMode = false;
public CallWaitingSwitchPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
@@ -45,9 +51,14 @@
TimeConsumingPreferenceListener listener, boolean skipReading, Phone phone) {
mPhone = phone;
mTcpListener = listener;
- mExecutor = Executors.newSingleThreadExecutor();
+ mExecutor = Executors.newSingleThreadScheduledExecutor();
mTelephonyManager = getContext().getSystemService(
TelephonyManager.class).createForSubscriptionId(phone.getSubId());
+ CarrierConfigManager configManager = getContext().getSystemService(
+ CarrierConfigManager.class);
+ PersistableBundle bundle = configManager.getConfigForSubId(phone.getSubId());
+ mUssdMode = (bundle != null) ? bundle.getBoolean(
+ CarrierConfigManager.KEY_USE_CALL_WAITING_USSD_BOOL, false) : false;
if (!skipReading) {
Log.d(LOG_TAG, "init getCallWaitingStatus");
@@ -67,7 +78,23 @@
private void updateStatusCallBack(int result) {
Log.d(LOG_TAG, "updateStatusCallBack: CW state " + result + ", and re get");
mUpdateStatus = result;
- mTelephonyManager.getCallWaitingStatus(mExecutor, this::queryStatusCallBack);
+ if (mUssdMode) {
+ Log.d(LOG_TAG, "updateStatusCallBack: USSD mode needs to wait 1s since Framework"
+ + " has the limitation");
+ Consumer<Integer> resultListener = this::queryStatusCallBack;
+ try {
+ mExecutor.schedule(new Runnable() {
+ @Override
+ public void run() {
+ mTelephonyManager.getCallWaitingStatus(mExecutor, resultListener);
+ }
+ }, DELAY_MILLIS_FOR_USSD, TimeUnit.MILLISECONDS);
+ } catch (Exception e) {
+ Log.d(LOG_TAG, "Exception while waiting: " + e);
+ }
+ } else {
+ mTelephonyManager.getCallWaitingStatus(mExecutor, this::queryStatusCallBack);
+ }
}
@Override
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index a463243..45ca974 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -65,6 +65,7 @@
import com.android.internal.telephony.TelephonyPermissions;
import com.android.internal.telephony.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.telephony.Rlog;
import java.io.File;
import java.io.FileDescriptor;
@@ -1064,6 +1065,7 @@
}
String fileName;
+ String iccid = null;
if (isNoSimConfig) {
fileName = getFilenameForNoSimConfig(packageName);
} else {
@@ -1073,7 +1075,7 @@
return null;
}
- final String iccid = getIccIdForPhoneId(phoneId);
+ iccid = getIccIdForPhoneId(phoneId);
final int cid = getSpecificCarrierIdForPhoneId(phoneId);
if (iccid == null) {
loge("Cannot restore config with null iccid.");
@@ -1102,7 +1104,15 @@
} catch (FileNotFoundException e) {
// Missing file is normal occurrence that might occur with a new sim or when restoring
// an override file during boot and should not be treated as an error.
- if (file != null) logd("File not found: " + file.getPath());
+ if (file != null) {
+ if (isNoSimConfig) {
+ logd("File not found: " + file.getPath());
+ } else {
+ String filePath = file.getPath();
+ filePath = getFilePathForLogging(filePath, iccid);
+ logd("File not found : " + filePath);
+ }
+ }
} catch (IOException e) {
loge(e.toString());
}
@@ -1110,6 +1120,22 @@
return restoredBundle;
}
+ /**
+ * This method will mask most part of iccid in the filepath for logging on userbuild
+ */
+ private String getFilePathForLogging(String filePath, String iccid) {
+ // If loggable then return with actual file path
+ if (Rlog.isLoggable(LOG_TAG, Log.VERBOSE)) {
+ return filePath;
+ }
+ String path = filePath;
+ int length = (iccid != null) ? iccid.length() : 0;
+ if (length > 5 && filePath != null) {
+ path = filePath.replace(iccid.substring(5), "***************");
+ }
+ return path;
+ }
+
private PersistableBundle restoreConfigFromXml(String packageName, @NonNull String extraString,
int phoneId) {
return restoreConfigFromXml(packageName, extraString, phoneId, false);
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 03b0be9..d96c0c5 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -22,6 +22,7 @@
import static com.android.internal.telephony.PhoneConstants.PHONE_TYPE_GSM;
import static com.android.internal.telephony.PhoneConstants.PHONE_TYPE_IMS;
import static com.android.internal.telephony.PhoneConstants.SUBSCRIPTION_KEY;
+import static com.android.internal.telephony.TelephonyStatsLog.RCS_CLIENT_PROVISIONING_STATS__EVENT__CLIENT_PARAMS_SENT;
import android.Manifest;
import android.Manifest.permission;
@@ -180,6 +181,7 @@
import com.android.internal.telephony.ims.ImsResolver;
import com.android.internal.telephony.imsphone.ImsPhone;
import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
+import com.android.internal.telephony.metrics.RcsStats;
import com.android.internal.telephony.metrics.TelephonyMetrics;
import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
import com.android.internal.telephony.uicc.IccIoResult;
@@ -2055,7 +2057,8 @@
case CMD_PREPARE_UNATTENDED_REBOOT:
request = (MainThreadRequest) msg.obj;
request.result =
- UiccController.getInstance().getPinStorage().prepareUnattendedReboot();
+ UiccController.getInstance().getPinStorage()
+ .prepareUnattendedReboot(request.workSource);
notifyRequester(request);
break;
@@ -5511,11 +5514,9 @@
*/
public int setForbiddenPlmns(int subId, int appType, List<String> fplmns, String callingPackage,
String callingFeatureId) {
- if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mApp, subId, callingPackage,
- callingFeatureId, "setForbiddenPlmns")) {
- if (DBG) logv("no permissions for setForbiddenplmns");
- throw new IllegalStateException("No Permissions for setForbiddenPlmns");
- }
+ TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
+ mApp, subId, "setForbiddenPlmns");
+
if (appType != TelephonyManager.APPTYPE_USIM && appType != TelephonyManager.APPTYPE_SIM) {
loge("setForbiddenPlmnList(): App Type must be USIM or SIM");
throw new IllegalArgumentException("Invalid appType: App Type must be USIM or SIM");
@@ -6921,7 +6922,9 @@
for (int p = packages.size() - 1; p >= 0; p--) {
PackageInfo pkgInfo = packages.get(p);
if (pkgInfo != null && pkgInfo.packageName != null
- && card.getCarrierPrivilegeStatus(pkgInfo)
+ && getCarrierPrivilegeStatusFromCarrierConfigRules(
+ card.getCarrierPrivilegeStatus(pkgInfo),
+ getPhone(phoneId), pkgInfo.packageName)
== TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
privilegedPackages.add(pkgInfo.packageName);
}
@@ -8321,6 +8324,16 @@
int result = (int) sendRequest(CMD_ENABLE_VONR, enabled, subId,
workSource);
if (DBG) log("setVoNrEnabled result: " + result);
+
+ if (result == TelephonyManager.ENABLE_VONR_SUCCESS) {
+ if (DBG) {
+ log("Set VoNR settings in siminfo db; subId=" + subId + ", value:" + enabled);
+ }
+ SubscriptionManager.setSubscriptionProperty(
+ subId, SubscriptionManager.NR_ADVANCED_CALLING_ENABLED,
+ (enabled ? "1" : "0"));
+ }
+
return result;
} finally {
Binder.restoreCallingIdentity(identity);
@@ -10389,6 +10402,9 @@
} else {
configBinder.setRcsClientConfiguration(rcc);
}
+
+ RcsStats.getInstance().onRcsClientProvisioningStats(subId,
+ RCS_CLIENT_PROVISIONING_STATS__EVENT__CLIENT_PARAMS_SENT);
} catch (RemoteException e) {
Rlog.e(LOG_TAG, "fail to setRcsClientConfiguration " + e.getMessage());
throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
@@ -10894,11 +10910,12 @@
@Override
@TelephonyManager.PrepareUnattendedRebootResult
public int prepareForUnattendedReboot() {
+ WorkSource workSource = getWorkSource(Binder.getCallingUid());
enforceRebootPermission();
final long identity = Binder.clearCallingIdentity();
try {
- return (int) sendRequest(CMD_PREPARE_UNATTENDED_REBOOT, null);
+ return (int) sendRequest(CMD_PREPARE_UNATTENDED_REBOOT, null, workSource);
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/src/com/android/phone/RcsProvisioningMonitor.java b/src/com/android/phone/RcsProvisioningMonitor.java
index 6d2bd6f..e819afc 100644
--- a/src/com/android/phone/RcsProvisioningMonitor.java
+++ b/src/com/android/phone/RcsProvisioningMonitor.java
@@ -16,6 +16,10 @@
package com.android.phone;
+import static com.android.internal.telephony.TelephonyStatsLog.RCS_ACS_PROVISIONING_STATS__RESPONSE_TYPE__PROVISIONING_XML;
+import static com.android.internal.telephony.TelephonyStatsLog.RCS_CLIENT_PROVISIONING_STATS__EVENT__DMA_CHANGED;
+import static com.android.internal.telephony.TelephonyStatsLog.RCS_CLIENT_PROVISIONING_STATS__EVENT__TRIGGER_RCS_RECONFIGURATION;
+
import android.Manifest;
import android.app.role.OnRoleHoldersChangedListener;
import android.app.role.RoleManager;
@@ -47,6 +51,8 @@
import com.android.ims.FeatureUpdates;
import com.android.ims.RcsFeatureManager;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.metrics.RcsStats;
+import com.android.internal.telephony.metrics.RcsStats.RcsProvisioningCallback;
import com.android.internal.telephony.util.HandlerExecutor;
import com.android.internal.util.CollectionUtils;
import com.android.telephony.Rlog;
@@ -100,6 +106,8 @@
private final RoleManagerAdapter mRoleManager;
private FeatureConnectorFactory<RcsFeatureManager> mFeatureFactory;
+ private RcsStats mRcsStats;
+
private static RcsProvisioningMonitor sInstance;
private final SubscriptionManager.OnSubscriptionsChangedListener mSubChangedListener =
@@ -227,6 +235,10 @@
if (mSingleRegistrationCapability != singleRegistrationCapability) {
mSingleRegistrationCapability = singleRegistrationCapability;
notifyDma();
+
+ // update whether single registration supported.
+ mRcsStats.setEnableSingleRegistration(mSubId,
+ mSingleRegistrationCapability == ProvisioningManager.STATUS_CAPABLE);
}
}
@@ -338,6 +350,9 @@
} else {
notifyRcsAutoConfigurationReceived();
}
+
+ // check callback for metrics if not registered, register callback
+ registerMetricsCallback();
} else {
// clear callbacks if rcs disconnected
clearCallbacks();
@@ -397,6 +412,18 @@
}
}
}
+
+ private void registerMetricsCallback() {
+ RcsProvisioningCallback rcsProvisioningCallback = mRcsStats.getRcsProvisioningCallback(
+ mSubId, mSingleRegistrationCapability == ProvisioningManager.STATUS_CAPABLE);
+
+ // if not yet registered, register callback and set registered value
+ if (rcsProvisioningCallback != null && !rcsProvisioningCallback.getRegistered()) {
+ if (addRcsConfigCallback(rcsProvisioningCallback)) {
+ rcsProvisioningCallback.setRegistered(true);
+ }
+ }
+ }
}
@VisibleForTesting
@@ -454,7 +481,7 @@
@VisibleForTesting
public RcsProvisioningMonitor(PhoneGlobals app, Looper looper, RoleManagerAdapter roleManager,
- FeatureConnectorFactory<RcsFeatureManager> factory) {
+ FeatureConnectorFactory<RcsFeatureManager> factory, RcsStats rcsStats) {
mPhone = app;
mHandler = new MyHandler(looper);
mCarrierConfigManager = mPhone.getSystemService(CarrierConfigManager.class);
@@ -465,6 +492,7 @@
logv("DMA is " + mDmaPackageName);
mDmaChangedListener = new DmaChangedListener();
mFeatureFactory = factory;
+ mRcsStats = rcsStats;
init();
}
@@ -477,7 +505,8 @@
HandlerThread handlerThread = new HandlerThread(TAG);
handlerThread.start();
sInstance = new RcsProvisioningMonitor(app, handlerThread.getLooper(),
- new RoleManagerAdapterImpl(app), RcsFeatureManager::getConnector);
+ new RoleManagerAdapterImpl(app), RcsFeatureManager::getConnector,
+ RcsStats.getInstance());
}
return sInstance;
}
@@ -704,6 +733,10 @@
logv("acs not used, set cached config and notify.");
v.setConfig(cachedConfig);
}
+
+ // store RCS metrics - DMA changed event
+ mRcsStats.onRcsClientProvisioningStats(k,
+ RCS_CLIENT_PROVISIONING_STATS__EVENT__DMA_CHANGED);
});
}
}
@@ -803,6 +836,14 @@
}
info.setConfig(isCompressed ? RcsConfig.decompressGzip(config) : config);
updateConfigForSub(subId, config, isCompressed);
+
+ // Supporting ACS means config data comes from ACS
+ // store RCS metrics - received provisioning event
+ if (isAcsUsed(subId)) {
+ mRcsStats.onRcsAcsProvisioningStats(subId, 200,
+ RCS_ACS_PROVISIONING_STATS__RESPONSE_TYPE__PROVISIONING_XML,
+ isRcsVolteSingleRegistrationEnabled(subId));
+ }
}
private void onReconfigRequest(int subId) {
@@ -814,6 +855,10 @@
updateConfigForSub(subId, null, true);
info.triggerRcsReconfiguration();
}
+
+ // store RCS metrics - reconfig event
+ mRcsStats.onRcsClientProvisioningStats(subId,
+ RCS_CLIENT_PROVISIONING_STATS__EVENT__TRIGGER_RCS_RECONFIGURATION);
}
private void notifyDmaForSub(int subId, int capability) {
diff --git a/src/com/android/services/telephony/ImsConference.java b/src/com/android/services/telephony/ImsConference.java
index 7f088f7..c62b4fa 100644
--- a/src/com/android/services/telephony/ImsConference.java
+++ b/src/com/android/services/telephony/ImsConference.java
@@ -534,6 +534,10 @@
(properties & Connection.PROPERTY_IS_ADHOC_CONFERENCE) != 0);
Log.i(this, "applyHostProperties: confProp=%s", conferenceProperties);
+ conferenceProperties = changeBitmask(conferenceProperties,
+ Connection.PROPERTY_CROSS_SIM,
+ (properties & Connection.PROPERTY_CROSS_SIM) != 0);
+
return conferenceProperties;
}
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 4f6acc8..8c5fb66 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -498,7 +498,8 @@
IntentFilter intentFilter = new IntentFilter(
TelecomManager.ACTION_TTY_PREFERRED_MODE_CHANGED);
- registerReceiver(mTtyBroadcastReceiver, intentFilter);
+ registerReceiver(mTtyBroadcastReceiver, intentFilter,
+ android.Manifest.permission.MODIFY_PHONE_STATE, null);
}
@Override
diff --git a/src/com/android/services/telephony/rcs/DelegateStateTracker.java b/src/com/android/services/telephony/rcs/DelegateStateTracker.java
index 321c7ba..18aab88 100644
--- a/src/com/android/services/telephony/rcs/DelegateStateTracker.java
+++ b/src/com/android/services/telephony/rcs/DelegateStateTracker.java
@@ -24,9 +24,12 @@
import android.telephony.ims.aidl.ISipDelegate;
import android.telephony.ims.aidl.ISipDelegateConnectionStateCallback;
import android.telephony.ims.stub.DelegateConnectionStateCallback;
+import android.util.ArraySet;
import android.util.LocalLog;
import android.util.Log;
+import com.android.internal.telephony.metrics.RcsStats;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
@@ -50,11 +53,15 @@
private boolean mCreatedCalled = false;
private int mRegistrationStateOverride = -1;
+ private Set<String> mDelegateSupportedTags;
+ private final RcsStats mRcsStats;
+
public DelegateStateTracker(int subId, ISipDelegateConnectionStateCallback appStateCallback,
- ISipDelegate localDelegateImpl) {
+ ISipDelegate localDelegateImpl, RcsStats rcsStats) {
mSubId = subId;
mAppStateCallback = appStateCallback;
mLocalDelegateImpl = localDelegateImpl;
+ mRcsStats = rcsStats;
}
/**
@@ -63,10 +70,13 @@
* Registration and state updates will be send via the
* {@link SipDelegateBinderConnection.StateCallback} callback implemented by this class as they
* arrive.
+ * @param supportedTags the tags supported by the SipTransportController and ImsService creating
+ * the SipDelegate. These tags will be used as a key for SipDelegate
+ * metrics.
* @param deniedTags The tags denied by the SipTransportController and ImsService creating the
* SipDelegate. These tags will need to be notified back to the IMS application.
*/
- public void sipDelegateConnected(Set<FeatureTagState> deniedTags) {
+ public void sipDelegateConnected(Set<String> supportedTags, Set<FeatureTagState> deniedTags) {
logi("SipDelegate connected with denied tags:" + deniedTags);
// From the IMS application perspective, we only call onCreated/onDestroyed once and
// provide the local implementation of ISipDelegate, which doesn't change, even though
@@ -74,6 +84,8 @@
if (!mCreatedCalled) {
mCreatedCalled = true;
notifySipDelegateCreated();
+ mDelegateSupportedTags = supportedTags;
+ mRcsStats.createSipDelegateStats(mSubId, mDelegateSupportedTags);
}
mRegistrationStateOverride = -1;
mDelegateDeniedTags = new ArrayList<>(deniedTags);
@@ -84,8 +96,8 @@
*
* This will trigger an override of the IMS application's registration state. All feature tags
* in the REGISTERED state will be overridden to move to the deregistering state specified until
- * a new SipDelegate was successfully created and {@link #sipDelegateConnected(Set)} was called
- * or it was destroyed and {@link #sipDelegateDestroyed(int)} was called.
+ * a new SipDelegate was successfully created and {@link #sipDelegateConnected(Set, Set)} was
+ * called or it was destroyed and {@link #sipDelegateDestroyed(int)} was called.
* @param deregisteringReason The new deregistering reason that all feature tags in the
* registered state should now report.
*/
@@ -115,6 +127,7 @@
mRegistrationStateOverride = -1;
try {
mAppStateCallback.onDestroyed(reason);
+ mRcsStats.onSipDelegateStats(mSubId, mDelegateSupportedTags, reason);
} catch (RemoteException e) {
logw("sipDelegateDestroyed: IMS application is dead: " + e);
}
@@ -141,6 +154,11 @@
logi("onRegistrationStateChanged: sending reg state " + registrationState);
try {
mAppStateCallback.onFeatureTagStatusChanged(registrationState, mDelegateDeniedTags);
+ Set<String> registeredFeatureTags = registrationState.getRegisteredFeatureTags();
+ mRcsStats.onSipTransportFeatureTagStats(mSubId,
+ new ArraySet<FeatureTagState>(mDelegateDeniedTags),
+ registrationState.getDeregisteredFeatureTags(),
+ registeredFeatureTags);
} catch (RemoteException e) {
logw("onRegistrationStateChanged: IMS application is dead: " + e);
}
diff --git a/src/com/android/services/telephony/rcs/SipDelegateController.java b/src/com/android/services/telephony/rcs/SipDelegateController.java
index 8cc70a4..c728141 100644
--- a/src/com/android/services/telephony/rcs/SipDelegateController.java
+++ b/src/com/android/services/telephony/rcs/SipDelegateController.java
@@ -34,6 +34,7 @@
import android.util.Pair;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.metrics.RcsStats;
import com.android.internal.util.IndentingPrintWriter;
import java.io.PrintWriter;
@@ -102,7 +103,7 @@
mMessageTransportWrapper = new MessageTransportWrapper(mSubId, executorService,
messageCallback);
mDelegateStateTracker = new DelegateStateTracker(mSubId, stateCallback,
- mMessageTransportWrapper.getDelegateConnection());
+ mMessageTransportWrapper.getDelegateConnection(), RcsStats.getInstance());
}
/**
@@ -191,7 +192,7 @@
.collect(Collectors.toSet()));
mMessageTransportWrapper.openTransport(resultPair.first, allowedTags,
resultPair.second);
- mDelegateStateTracker.sipDelegateConnected(resultPair.second);
+ mDelegateStateTracker.sipDelegateConnected(allowedTags, resultPair.second);
return true;
});
}
diff --git a/src/com/android/services/telephony/rcs/SipSessionTracker.java b/src/com/android/services/telephony/rcs/SipSessionTracker.java
index 5ab482f..68e3065 100644
--- a/src/com/android/services/telephony/rcs/SipSessionTracker.java
+++ b/src/com/android/services/telephony/rcs/SipSessionTracker.java
@@ -24,6 +24,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.SipMessageParsingUtils;
+import com.android.internal.telephony.metrics.RcsStats;
import com.android.internal.util.IndentingPrintWriter;
import java.io.PrintWriter;
@@ -66,6 +67,14 @@
// associated pending operation.
private final ArrayMap<String, Runnable> mPendingAck = new ArrayMap<>();
+ private final RcsStats mRcsStats;
+ int mSubId;
+
+ public SipSessionTracker(int subId, RcsStats rcsStats) {
+ mSubId = subId;
+ mRcsStats = rcsStats;
+ }
+
/**
* Filter a SIP message to determine if it will result in a new SIP dialog. This will need to be
* successfully acknowledged by the remote IMS stack using
@@ -73,10 +82,10 @@
*
* @param message The Incoming SIP message.
*/
- public void filterSipMessage(SipMessage message) {
+ public void filterSipMessage(int direction, SipMessage message) {
final Runnable r;
if (startsEarlyDialog(message)) {
- r = getCreateDialogRunnable(message);
+ r = getCreateDialogRunnable(direction, message);
} else if (closesDialog(message)) {
r = getCloseDialogRunnable(message);
} else if (SipMessageParsingUtils.isSipResponse(message.getStartLine())) {
@@ -137,6 +146,8 @@
if (dialogsToCleanup.isEmpty()) return;
logi("Cleanup dialogs associated with call id: " + callId);
for (SipDialog d : dialogsToCleanup) {
+ mRcsStats.onSipTransportSessionClosed(mSubId, callId, 0,
+ d.getState() == d.STATE_CLOSED);
d.close();
logi("Dialog closed: " + d);
}
@@ -197,6 +208,9 @@
* Clears all tracked sessions.
*/
public void clearAllSessions() {
+ for (SipDialog d : mTrackedDialogs) {
+ mRcsStats.onSipTransportSessionClosed(mSubId, d.getCallId(), 0, false);
+ }
mTrackedDialogs.clear();
mPendingAck.clear();
}
@@ -262,7 +276,7 @@
return SIP_CLOSE_DIALOG_REQUEST_METHOD.equalsIgnoreCase(startLineSegments[0]);
}
- private Runnable getCreateDialogRunnable(SipMessage m) {
+ private Runnable getCreateDialogRunnable(int direction, SipMessage m) {
return () -> {
List<SipDialog> duplicateDialogs = mTrackedDialogs.stream()
.filter(d -> d.getCallId().equals(m.getCallIdParameter()))
@@ -273,6 +287,10 @@
return;
}
SipDialog dialog = SipDialog.fromSipMessage(m);
+ String[] startLineSegments =
+ SipMessageParsingUtils.splitStartLineAndVerify(m.getStartLine());
+ mRcsStats.earlySipTransportSession(startLineSegments[0], dialog.getCallId(),
+ direction);
logi("Starting new SipDialog: " + dialog);
mTrackedDialogs.add(dialog);
};
@@ -285,6 +303,7 @@
.collect(Collectors.toList());
if (dialogsToClose.isEmpty()) return;
logi("Closing dialogs associated with: " + m);
+ mRcsStats.onSipTransportSessionClosed(mSubId, m.getCallIdParameter(), 0, true);
for (SipDialog d : dialogsToClose) {
d.close();
logi("Dialog closed: " + d);
@@ -344,11 +363,13 @@
if (statusCode <= 100) return;
// If 300+, then this dialog has received an error response and should move to closed state.
if (statusCode >= 300) {
+ mRcsStats.onSipTransportSessionClosed(mSubId, m.getCallIdParameter(), statusCode, true);
d.close();
return;
}
if (toTag == null) logw("updateSipDialogState: No to tag for message: " + m);
if (statusCode >= 200) {
+ mRcsStats.confirmedSipTransportSession(m.getCallIdParameter(), statusCode);
d.confirm(toTag);
return;
}
diff --git a/src/com/android/services/telephony/rcs/TelephonyRcsService.java b/src/com/android/services/telephony/rcs/TelephonyRcsService.java
index 034382c..046910c 100644
--- a/src/com/android/services/telephony/rcs/TelephonyRcsService.java
+++ b/src/com/android/services/telephony/rcs/TelephonyRcsService.java
@@ -32,6 +32,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.PhoneConfigurationManager;
+import com.android.internal.telephony.metrics.RcsStats;
import com.android.internal.util.IndentingPrintWriter;
import com.android.phone.R;
@@ -163,6 +164,7 @@
mFeatureControllers = new SparseArray<>(numSlots);
mSlotToAssociatedSubIds = new SparseArray<>(numSlots);
mRcsUceEnabled = sResourceProxy.getDeviceUceEnabled(mContext);
+ RcsStats.getInstance().registerUceCallback();
}
@VisibleForTesting
@@ -173,6 +175,7 @@
mSlotToAssociatedSubIds = new SparseArray<>(numSlots);
sResourceProxy = resourceProxy;
mRcsUceEnabled = sResourceProxy.getDeviceUceEnabled(mContext);
+ RcsStats.getInstance().registerUceCallback();
}
/**
diff --git a/src/com/android/services/telephony/rcs/TransportSipMessageValidator.java b/src/com/android/services/telephony/rcs/TransportSipMessageValidator.java
index 777026c..3b1b26d 100644
--- a/src/com/android/services/telephony/rcs/TransportSipMessageValidator.java
+++ b/src/com/android/services/telephony/rcs/TransportSipMessageValidator.java
@@ -16,6 +16,9 @@
package com.android.services.telephony.rcs;
+import static com.android.internal.telephony.TelephonyStatsLog.SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__INCOMING;
+import static com.android.internal.telephony.TelephonyStatsLog.SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__OUTGOING;
+
import android.telephony.ims.DelegateRegistrationState;
import android.telephony.ims.FeatureTagState;
import android.telephony.ims.SipDelegateConfiguration;
@@ -26,6 +29,8 @@
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.SipMessageParsingUtils;
+import com.android.internal.telephony.metrics.RcsStats;
import com.android.internal.util.IndentingPrintWriter;
import com.android.services.telephony.rcs.validator.IncomingTransportStateValidator;
import com.android.services.telephony.rcs.validator.MalformedSipMessageValidator;
@@ -145,11 +150,13 @@
private PendingTask mPendingClose;
private PendingRegCleanupTask mPendingRegCleanup;
private Consumer<Set<String>> mRegistrationAppliedConsumer;
+ private final RcsStats mRcsStats;
public TransportSipMessageValidator(int subId, ScheduledExecutorService executor) {
mSubId = subId;
mExecutor = executor;
- mSipSessionTracker = new SipSessionTracker();
+ mRcsStats = RcsStats.getInstance();
+ mSipSessionTracker = new SipSessionTracker(subId, mRcsStats);
mOutgoingTransportStateValidator = new OutgoingTransportStateValidator(mSipSessionTracker);
mIncomingTransportStateValidator = new IncomingTransportStateValidator();
mOutgoingMessageValidator = new MalformedSipMessageValidator().andThen(
@@ -163,7 +170,7 @@
public TransportSipMessageValidator(int subId, ScheduledExecutorService executor,
SipSessionTracker sipSessionTracker,
OutgoingTransportStateValidator outgoingStateValidator,
- IncomingTransportStateValidator incomingStateValidator) {
+ IncomingTransportStateValidator incomingStateValidator, RcsStats rcsStats) {
mSubId = subId;
mExecutor = executor;
mSipSessionTracker = sipSessionTracker;
@@ -171,6 +178,7 @@
mIncomingTransportStateValidator = incomingStateValidator;
mOutgoingMessageValidator = mOutgoingTransportStateValidator;
mIncomingMessageValidator = mIncomingTransportStateValidator;
+ mRcsStats = rcsStats;
}
/**
@@ -365,7 +373,11 @@
}
ValidationResult result = mOutgoingMessageValidator.validate(message);
logi("verifyOutgoingMessage: " + result + ", message=" + message);
- if (result.isValidated) mSipSessionTracker.filterSipMessage(message);
+ if (result.isValidated) {
+ mSipSessionTracker.filterSipMessage(
+ SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__OUTGOING, message);
+ }
+ updateForMetrics(SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__OUTGOING, message, result);
return result;
}
@@ -378,7 +390,11 @@
public ValidationResult verifyIncomingMessage(SipMessage message) {
ValidationResult result = mIncomingMessageValidator.validate(message);
logi("verifyIncomingMessage: " + result + ", message=" + message);
- if (result.isValidated) mSipSessionTracker.filterSipMessage(message);
+ if (result.isValidated) {
+ mSipSessionTracker.filterSipMessage(
+ SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__INCOMING, message);
+ }
+ updateForMetrics(SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__INCOMING, message, result);
return result;
}
@@ -539,6 +555,28 @@
.collect(Collectors.toSet());
}
+ private void updateForMetrics(int direction, SipMessage m, ValidationResult result) {
+ String[] startLineSegments = SipMessageParsingUtils
+ .splitStartLineAndVerify(m.getStartLine());
+ if (SipMessageParsingUtils.isSipRequest(m.getStartLine())) {
+ if (result.isValidated) {
+ // SipMessage add to list for Metrics stats
+ mRcsStats.onSipMessageRequest(m.getCallIdParameter(), startLineSegments[0],
+ direction);
+ } else {
+ //Message sending fail and there is no response.
+ mRcsStats.invalidatedMessageResult(mSubId, startLineSegments[0], direction,
+ result.restrictedReason);
+ }
+ } else if (SipMessageParsingUtils.isSipResponse(m.getStartLine())) {
+ int statusCode = Integer.parseInt(startLineSegments[1]);
+ mRcsStats.onSipMessageResponse(mSubId, m.getCallIdParameter(), statusCode,
+ result.restrictedReason);
+ } else {
+ logw("Message is Restricted");
+ }
+ }
+
private void logi(String log) {
Log.i(SipTransportController.LOG_TAG, LOG_TAG + "[" + mSubId + "] " + log);
mLocalLog.log("[I] " + log);
diff --git a/tests/src/com/android/phone/RcsProvisioningMonitorTest.java b/tests/src/com/android/phone/RcsProvisioningMonitorTest.java
index 8e5e073..8873402 100644
--- a/tests/src/com/android/phone/RcsProvisioningMonitorTest.java
+++ b/tests/src/com/android/phone/RcsProvisioningMonitorTest.java
@@ -16,6 +16,10 @@
package com.android.phone;
+import static com.android.internal.telephony.TelephonyStatsLog.RCS_ACS_PROVISIONING_STATS__RESPONSE_TYPE__PROVISIONING_XML;
+import static com.android.internal.telephony.TelephonyStatsLog.RCS_CLIENT_PROVISIONING_STATS__EVENT__DMA_CHANGED;
+import static com.android.internal.telephony.TelephonyStatsLog.RCS_CLIENT_PROVISIONING_STATS__EVENT__TRIGGER_RCS_RECONFIGURATION;
+
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNull;
@@ -64,6 +68,7 @@
import com.android.ims.FeatureConnector;
import com.android.ims.RcsFeatureManager;
import com.android.internal.telephony.ITelephony;
+import com.android.internal.telephony.metrics.RcsStats;
import org.junit.After;
import org.junit.Before;
@@ -179,6 +184,10 @@
private IRcsConfigCallback mCallback;
@Mock
private PackageManager mPackageManager;
+ @Mock
+ private RcsStats mRcsStats;
+ @Mock
+ private RcsStats.RcsProvisioningCallback mRcsProvisioningCallback;
private Executor mExecutor = new Executor() {
@Override
@@ -768,6 +777,66 @@
assertNull(mRcsProvisioningMonitor.getImsFeatureValidationOverride(FAKE_SUB_ID_BASE));
}
+ @Test
+ @SmallTest
+ public void testMetricsAcsNotUsed() throws Exception {
+ createMonitor(1);
+
+ // Not used ACS
+ mBundle.putBoolean(CarrierConfigManager.KEY_USE_ACS_FOR_RCS_BOOL, false);
+ broadcastCarrierConfigChange(FAKE_SUB_ID_BASE);
+ processAllMessages();
+ mRcsProvisioningMonitor.updateConfig(FAKE_SUB_ID_BASE, CONFIG_DEFAULT.getBytes(), false);
+ processAllMessages();
+ verify(mRcsStats, never()).onRcsAcsProvisioningStats(anyInt(), anyInt(),
+ anyInt(), anyBoolean());
+ }
+
+ @Test
+ @SmallTest
+ public void testMetricsAcsUsed() throws Exception {
+ when(mRcsStats.getRcsProvisioningCallback(anyInt(), anyBoolean()))
+ .thenReturn(mRcsProvisioningCallback);
+ createMonitor(1);
+
+ verify(mIImsConfig, times(1))
+ .notifyRcsAutoConfigurationReceived(any(), anyBoolean());
+ // verify RcsStats.getRcsProvisioningCallback() is called
+ verify(mRcsStats, times(1)).getRcsProvisioningCallback(
+ eq(FAKE_SUB_ID_BASE), anyBoolean());
+ // verify registered callback obj which comes from RcsStats.getRcsProvisioningCallback()
+ verify(mIImsConfig, times(1))
+ .addRcsConfigCallback(eq(mRcsProvisioningCallback));
+
+ // Config data received and ACS used
+ int errorCode = 200;
+ mBundle.putBoolean(CarrierConfigManager.KEY_USE_ACS_FOR_RCS_BOOL, true);
+ broadcastCarrierConfigChange(FAKE_SUB_ID_BASE);
+ processAllMessages();
+ mRcsProvisioningMonitor.updateConfig(FAKE_SUB_ID_BASE, CONFIG_DEFAULT.getBytes(), false);
+ processAllMessages();
+ verify(mRcsStats, times(1)).onRcsAcsProvisioningStats(eq(FAKE_SUB_ID_BASE), eq(errorCode),
+ eq(RCS_ACS_PROVISIONING_STATS__RESPONSE_TYPE__PROVISIONING_XML), anyBoolean());
+ }
+
+ @Test
+ @SmallTest
+ public void testMetricsClientProvisioningStats() throws Exception {
+ createMonitor(1);
+
+ // reconfig trigger
+ mRcsProvisioningMonitor.requestReconfig(FAKE_SUB_ID_BASE);
+ processAllMessages();
+ verify(mRcsStats, times(1)).onRcsClientProvisioningStats(eq(FAKE_SUB_ID_BASE),
+ eq(RCS_CLIENT_PROVISIONING_STATS__EVENT__TRIGGER_RCS_RECONFIGURATION));
+
+ // DMA changed
+ updateDefaultMessageApplication(DEFAULT_MESSAGING_APP2);
+ processAllMessages();
+ verify(mRcsStats, times(1)).onRcsClientProvisioningStats(eq(FAKE_SUB_ID_BASE),
+ eq(RCS_CLIENT_PROVISIONING_STATS__EVENT__DMA_CHANGED));
+ }
+
private void createMonitor(int subCount) throws Exception {
if (Looper.myLooper() == null) {
Looper.prepare();
@@ -777,7 +846,7 @@
.thenReturn(mFeatureConnector);
when(mFeatureManager.getConfig()).thenReturn(mIImsConfig);
mRcsProvisioningMonitor = new RcsProvisioningMonitor(mPhone, mHandlerThread.getLooper(),
- mRoleManager, mFeatureFactory);
+ mRoleManager, mFeatureFactory, mRcsStats);
mHandler = mRcsProvisioningMonitor.getHandler();
try {
mLooper = new TestableLooper(mHandler.getLooper());
diff --git a/tests/src/com/android/services/telephony/rcs/DelegateStateTrackerTest.java b/tests/src/com/android/services/telephony/rcs/DelegateStateTrackerTest.java
index 8236f44..25b5339 100644
--- a/tests/src/com/android/services/telephony/rcs/DelegateStateTrackerTest.java
+++ b/tests/src/com/android/services/telephony/rcs/DelegateStateTrackerTest.java
@@ -37,6 +37,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.TelephonyTestBase;
+import com.android.internal.telephony.metrics.RcsStats;
import org.junit.After;
import org.junit.Before;
@@ -56,6 +57,7 @@
@Mock private ISipDelegate mSipDelegate;
@Mock private ISipDelegateConnectionStateCallback mAppCallback;
+ @Mock private RcsStats mRcsStats;
@Before
public void setUp() throws Exception {
@@ -76,12 +78,14 @@
@Test
public void testDelegateCreated() throws Exception {
DelegateStateTracker stateTracker = new DelegateStateTracker(TEST_SUB_ID, mAppCallback,
- mSipDelegate);
+ mSipDelegate, mRcsStats);
Set<FeatureTagState> deniedTags = getMmTelDeniedTag();
- stateTracker.sipDelegateConnected(deniedTags);
+ Set<String> supportedTags = getSupportedTags();
+ stateTracker.sipDelegateConnected(supportedTags, deniedTags);
// Calling connected multiple times should not generate multiple onCreated events.
- stateTracker.sipDelegateConnected(deniedTags);
+ stateTracker.sipDelegateConnected(supportedTags, deniedTags);
verify(mAppCallback).onCreated(mSipDelegate);
+ verify(mRcsStats).createSipDelegateStats(TEST_SUB_ID, supportedTags);
// Ensure status updates are sent to app as expected.
DelegateRegistrationState regState = new DelegateRegistrationState.Builder()
@@ -97,8 +101,10 @@
stateTracker.onConfigurationChanged(c);
verify(mAppCallback).onFeatureTagStatusChanged(eq(regState),
eq(new ArrayList<>(deniedTags)));
+ verify(mRcsStats).onSipTransportFeatureTagStats(TEST_SUB_ID, deniedTags,
+ regState.getDeregisteredFeatureTags(),
+ regState.getRegisteredFeatureTags());
verify(mAppCallback).onConfigurationChanged(c);
-
verify(mAppCallback, never()).onDestroyed(anyInt());
}
@@ -109,14 +115,18 @@
@Test
public void testDelegateDestroyed() throws Exception {
DelegateStateTracker stateTracker = new DelegateStateTracker(TEST_SUB_ID, mAppCallback,
- mSipDelegate);
+ mSipDelegate, mRcsStats);
Set<FeatureTagState> deniedTags = getMmTelDeniedTag();
- stateTracker.sipDelegateConnected(deniedTags);
+ Set<String> supportedTags = getSupportedTags();
+ stateTracker.sipDelegateConnected(supportedTags, deniedTags);
+ verify(mRcsStats).createSipDelegateStats(eq(TEST_SUB_ID), eq(supportedTags));
stateTracker.sipDelegateDestroyed(
SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
verify(mAppCallback).onDestroyed(
SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+ verify(mRcsStats).onSipDelegateStats(eq(TEST_SUB_ID), eq(supportedTags),
+ eq(SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP));
}
/**
@@ -130,9 +140,10 @@
@Test
public void testDelegateChangingRegisteredTagsOverride() throws Exception {
DelegateStateTracker stateTracker = new DelegateStateTracker(TEST_SUB_ID, mAppCallback,
- mSipDelegate);
+ mSipDelegate, mRcsStats);
Set<FeatureTagState> deniedTags = getMmTelDeniedTag();
- stateTracker.sipDelegateConnected(deniedTags);
+ Set<String> supportedTags = getSupportedTags();
+ stateTracker.sipDelegateConnected(supportedTags, deniedTags);
// SipDelegate created
verify(mAppCallback).onCreated(mSipDelegate);
DelegateRegistrationState regState = new DelegateRegistrationState.Builder()
@@ -158,7 +169,7 @@
DelegateRegistrationState.DEREGISTERED_REASON_NOT_PROVISIONED)
.build();
// new underlying SipDelegate created
- stateTracker.sipDelegateConnected(deniedTags);
+ stateTracker.sipDelegateConnected(supportedTags, deniedTags);
stateTracker.onRegistrationStateChanged(regState);
// Verify registration state through the process:
@@ -187,9 +198,10 @@
@Test
public void testDelegateChangingDeniedTagsChanged() throws Exception {
DelegateStateTracker stateTracker = new DelegateStateTracker(TEST_SUB_ID, mAppCallback,
- mSipDelegate);
+ mSipDelegate, mRcsStats);
Set<FeatureTagState> deniedTags = getMmTelDeniedTag();
- stateTracker.sipDelegateConnected(deniedTags);
+ Set<String> supportedTags = getSupportedTags();
+ stateTracker.sipDelegateConnected(supportedTags, deniedTags);
// SipDelegate created
verify(mAppCallback).onCreated(mSipDelegate);
DelegateRegistrationState regState = new DelegateRegistrationState.Builder()
@@ -220,7 +232,7 @@
// new underlying SipDelegate created, but SipDelegate denied one to one chat
deniedTags.add(new FeatureTagState(ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG,
SipDelegateManager.DENIED_REASON_NOT_ALLOWED));
- stateTracker.sipDelegateConnected(deniedTags);
+ stateTracker.sipDelegateConnected(supportedTags, deniedTags);
DelegateRegistrationState fullyDeniedRegState = new DelegateRegistrationState.Builder()
.build();
// In this special case, it will be the SipDelegateConnectionBase that will trigger
@@ -244,9 +256,10 @@
@Test
public void testDelegateChangingDeniedTagsChangingToDestroy() throws Exception {
DelegateStateTracker stateTracker = new DelegateStateTracker(TEST_SUB_ID, mAppCallback,
- mSipDelegate);
+ mSipDelegate, mRcsStats);
Set<FeatureTagState> deniedTags = getMmTelDeniedTag();
- stateTracker.sipDelegateConnected(deniedTags);
+ Set<String> supportedTags = getSupportedTags();
+ stateTracker.sipDelegateConnected(supportedTags, deniedTags);
// SipDelegate created
verify(mAppCallback).onCreated(mSipDelegate);
DelegateRegistrationState regState = new DelegateRegistrationState.Builder()
@@ -296,4 +309,11 @@
SipDelegateManager.DENIED_REASON_NOT_ALLOWED));
return deniedTags;
}
+
+ private Set<String> getSupportedTags() {
+ Set<String> supportedTags = new ArraySet<>();
+ supportedTags.add(ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG);
+ supportedTags.add(ImsSignallingUtils.GROUP_CHAT_TAG);
+ return supportedTags;
+ }
}
diff --git a/tests/src/com/android/services/telephony/rcs/SipDelegateControllerTest.java b/tests/src/com/android/services/telephony/rcs/SipDelegateControllerTest.java
index 5b0e7c5..78f6894 100644
--- a/tests/src/com/android/services/telephony/rcs/SipDelegateControllerTest.java
+++ b/tests/src/com/android/services/telephony/rcs/SipDelegateControllerTest.java
@@ -107,7 +107,8 @@
assertTrue(future.get());
verify(mMockMessageTracker).openTransport(mMockSipDelegate, request.getFeatureTags(),
Collections.emptySet());
- verify(mMockDelegateStateTracker).sipDelegateConnected(Collections.emptySet());
+ verify(mMockDelegateStateTracker).sipDelegateConnected(request.getFeatureTags(),
+ Collections.emptySet());
}
@SmallTest
@@ -138,7 +139,7 @@
allowedTags.removeAll(deniedTags.stream().map(FeatureTagState::getFeatureTag)
.collect(Collectors.toSet()));
verify(mMockMessageTracker).openTransport(mMockSipDelegate, allowedTags, deniedTags);
- verify(mMockDelegateStateTracker).sipDelegateConnected(deniedTags);
+ verify(mMockDelegateStateTracker).sipDelegateConnected(allowedTags, deniedTags);
}
@SmallTest
@@ -249,7 +250,9 @@
Collections.emptySet());
verify(mMockMessageTracker).openTransport(mMockSipDelegate, newFts,
Collections.emptySet());
- verify(mMockDelegateStateTracker, times(2)).sipDelegateConnected(Collections.emptySet());
+ verify(mMockDelegateStateTracker).sipDelegateConnected(
+ request.getFeatureTags(), Collections.emptySet());
+ verify(mMockDelegateStateTracker).sipDelegateConnected(newFts, Collections.emptySet());
}
private void createSipDelegate(DelegateRequest request, SipDelegateController controller)
diff --git a/tests/src/com/android/services/telephony/rcs/SipSessionTrackerTest.java b/tests/src/com/android/services/telephony/rcs/SipSessionTrackerTest.java
index 823a8be..37abb83 100644
--- a/tests/src/com/android/services/telephony/rcs/SipSessionTrackerTest.java
+++ b/tests/src/com/android/services/telephony/rcs/SipSessionTrackerTest.java
@@ -16,19 +16,28 @@
package com.android.services.telephony.rcs;
+import static com.android.internal.telephony.TelephonyStatsLog.SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__OUTGOING;
+
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.verify;
+
import android.net.Uri;
import android.telephony.ims.SipMessage;
import android.util.Base64;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import com.android.internal.telephony.metrics.RcsStats;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import java.nio.ByteBuffer;
import java.util.Arrays;
@@ -90,11 +99,104 @@
// Keep track of the string entry so we can generate unique strings.
private int mStringEntryCounter = 0;
private SipSessionTracker mTrackerUT;
+ private static final int TEST_SUB_ID = 1;
+ private static final String TEST_INVITE_SIP_METHOD = "INVITE";
+ private static final int TEST_SIP_RESPONSE_CODE = 200;
+ private static final int TEST_SIP_CLOSE_RESPONSE_CODE = 0;
+ @Mock
+ private RcsStats mRcsStats;
@Before
public void setUp() {
mStringEntryCounter = 0;
- mTrackerUT = new SipSessionTracker();
+ MockitoAnnotations.initMocks(this);
+ mTrackerUT = new SipSessionTracker(TEST_SUB_ID, mRcsStats);
+ }
+
+ @Test
+ public void testMetricsEndedGracefullyBye() {
+ DialogAttributes attr = new DialogAttributes();
+ // INVITE
+ SipMessage inviteRequest = generateSipRequest(SipMessageUtils.INVITE_SIP_METHOD, attr);
+ filterMessage(inviteRequest, attr);
+ assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
+ verifyContainsCallIds(mTrackerUT.getEarlyDialogs(), attr);
+
+ // confirmed dialog
+ attr.setToTag();
+ SipMessage inviteConfirm = generateSipResponse("200", "OK", attr);
+ filterMessage(inviteConfirm, attr);
+ assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
+ verifyContainsCallIds(mTrackerUT.getConfirmedDialogs(), attr);
+
+ // Gracefully Ended
+ SipMessage inviteClose = generateSipRequest(SipMessageUtils.BYE_SIP_METHOD, attr);
+ filterMessage(inviteClose, attr);
+
+ assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
+ assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
+ verifyContainsCallIds(mTrackerUT.getClosedDialogs(), attr);
+
+ // verify Metrics information
+ verify(mRcsStats).onSipTransportSessionClosed(eq(TEST_SUB_ID), eq(attr.callId),
+ eq(TEST_SIP_CLOSE_RESPONSE_CODE), eq(true));
+ }
+
+ @Test
+ public void testMetricsCloseCleanupSession() {
+ //mTrackerUT.setRcsStats(mRcsStats);
+ DialogAttributes attr = new DialogAttributes();
+ // INVITE A -> B
+ SipMessage inviteRequest = generateSipRequest(SipMessageUtils.INVITE_SIP_METHOD, attr);
+ filterMessage(inviteRequest, attr);
+ assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
+ verifyContainsCallIds(mTrackerUT.getEarlyDialogs(), attr);
+
+ // confirmed dialog
+ attr.setToTag();
+ SipMessage inviteConfirm = generateSipResponse("200", "OK", attr);
+ filterMessage(inviteConfirm, attr);
+ assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
+ verifyContainsCallIds(mTrackerUT.getConfirmedDialogs(), attr);
+
+ //forcefully close session
+ mTrackerUT.cleanupSession(attr.callId);
+ assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
+ assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
+ assertTrue(mTrackerUT.getClosedDialogs().isEmpty());
+
+ // verify Metrics information
+ verify(mRcsStats).onSipTransportSessionClosed(eq(TEST_SUB_ID), eq(attr.callId),
+ eq(TEST_SIP_CLOSE_RESPONSE_CODE), eq(false));
+ }
+
+ @Test
+ public void testMetricsCloseClearAllSessions() {
+ //mTrackerUT.setRcsStats(mRcsStats);
+ DialogAttributes attr = new DialogAttributes();
+
+ // INVITE
+ SipMessage inviteRequest = generateSipRequest(SipMessageUtils.INVITE_SIP_METHOD, attr);
+ filterMessage(inviteRequest, attr);
+ assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
+ verifyContainsCallIds(mTrackerUT.getEarlyDialogs(), attr);
+
+ // confirmed dialog
+ attr.setToTag();
+ SipMessage inviteConfirm = generateSipResponse("200", "OK", attr);
+ filterMessage(inviteConfirm, attr);
+ assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
+ verifyContainsCallIds(mTrackerUT.getConfirmedDialogs(), attr);
+
+ //forcefully close session
+ mTrackerUT.clearAllSessions();
+ assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
+ assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
+ assertTrue(mTrackerUT.getClosedDialogs().isEmpty());
+
+ // verify Metrics information
+ verify(mRcsStats).onSipTransportSessionClosed(eq(TEST_SUB_ID), eq(attr.callId),
+ eq(TEST_SIP_CLOSE_RESPONSE_CODE), eq(false));
}
@Test
@@ -291,7 +393,8 @@
public void testAcknowledgeMessageFailed() {
DialogAttributes attr = new DialogAttributes();
SipMessage inviteRequest = generateSipRequest(SipMessageUtils.INVITE_SIP_METHOD, attr);
- mTrackerUT.filterSipMessage(inviteRequest);
+ mTrackerUT.filterSipMessage(
+ SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__OUTGOING, inviteRequest);
// Do not acknowledge the request and ensure that the operation has not been applied yet.
assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
@@ -310,8 +413,10 @@
// We unexpectedly received two filter requests for the same branchId without
// acknowledgePendingMessage being called in between. Ensure that when it is called, it
// applies both operations.
- mTrackerUT.filterSipMessage(inviteRequest);
- mTrackerUT.filterSipMessage(inviteConfirm);
+ mTrackerUT.filterSipMessage(
+ SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__OUTGOING, inviteRequest);
+ mTrackerUT.filterSipMessage(
+ SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__OUTGOING, inviteConfirm);
assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
// we should skip right to confirmed as both operations run back-to-back
@@ -321,7 +426,8 @@
}
private void filterMessage(SipMessage m, DialogAttributes attr) {
- mTrackerUT.filterSipMessage(m);
+ mTrackerUT.filterSipMessage(
+ SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__OUTGOING, m);
mTrackerUT.acknowledgePendingMessage(attr.branchId);
}
private void verifyContainsCallIds(Set<SipDialog> callIdSet, DialogAttributes... attrs) {
diff --git a/tests/src/com/android/services/telephony/rcs/TransportSipMessageValidatorTest.java b/tests/src/com/android/services/telephony/rcs/TransportSipMessageValidatorTest.java
index 4d222e3..0fe897f 100644
--- a/tests/src/com/android/services/telephony/rcs/TransportSipMessageValidatorTest.java
+++ b/tests/src/com/android/services/telephony/rcs/TransportSipMessageValidatorTest.java
@@ -16,6 +16,9 @@
package com.android.services.telephony.rcs;
+import static com.android.internal.telephony.TelephonyStatsLog.SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__INCOMING;
+import static com.android.internal.telephony.TelephonyStatsLog.SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__OUTGOING;
+
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
@@ -23,6 +26,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -37,6 +41,7 @@
import com.android.TelephonyTestBase;
import com.android.TestExecutorService;
+import com.android.internal.telephony.metrics.RcsStats;
import com.android.services.telephony.rcs.validator.IncomingTransportStateValidator;
import com.android.services.telephony.rcs.validator.OutgoingTransportStateValidator;
import com.android.services.telephony.rcs.validator.ValidationResult;
@@ -76,6 +81,8 @@
private IncomingTransportStateValidator mIncomingStateValidator;
@Mock
private OutgoingTransportStateValidator mOutgoingStateValidator;
+ @Mock
+ private RcsStats mRcsStats;
@Before
public void setUp() throws Exception {
@@ -117,12 +124,50 @@
}
@Test
+ public void testMetricsResponse() {
+ String testSipInviteMethod = "INVITE";
+ String testSipMessageMethod = "MESSAGE";
+ int testSipResponseCode = 200;
+ int testMessageError = 0;
+
+ TestExecutorService executor = new TestExecutorService();
+ TransportSipMessageValidator tracker = openTransport(executor);
+ // Since the incoming/outgoing messages were verified, there should have been two calls
+ // to filter the message.
+ verify(mSipSessionTracker).filterSipMessage(
+ SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__OUTGOING, TEST_MESSAGE);
+ verify(mSipSessionTracker).filterSipMessage(
+ SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__INCOMING, TEST_MESSAGE);
+
+ assertTrue(tracker.verifyOutgoingMessage(generateSipRequest("INVITE",
+ "testId1"), TEST_CONFIG_VERSION).isValidated);
+ verify(mRcsStats).onSipMessageRequest(eq("testId1"),
+ eq(testSipInviteMethod),
+ eq(SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__OUTGOING));
+
+ assertTrue(tracker.verifyOutgoingMessage(generateSipRequest("MESSAGE",
+ "testId2"), TEST_CONFIG_VERSION).isValidated);
+ verify(mRcsStats).onSipMessageRequest(eq("testId2"),
+ eq(testSipMessageMethod),
+ eq(SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__OUTGOING));
+
+ assertTrue(tracker.verifyIncomingMessage(
+ generateSipResponse("200", "OK", "testId2"))
+ .isValidated);
+ verify(mRcsStats).onSipMessageResponse(eq(TEST_SUB_ID), eq("testId2"),
+ eq(testSipResponseCode), eq(testMessageError));
+ }
+
+ @Test
public void testSessionTrackerFiltering() {
TestExecutorService executor = new TestExecutorService();
TransportSipMessageValidator tracker = openTransport(executor);
// Since the incoming/outgoing messages were verified, there should have been two calls
// to filter the message.
- verify(mSipSessionTracker, times(2)).filterSipMessage(TEST_MESSAGE);
+ verify(mSipSessionTracker).filterSipMessage(
+ SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__OUTGOING, TEST_MESSAGE);
+ verify(mSipSessionTracker).filterSipMessage(
+ SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__INCOMING, TEST_MESSAGE);
// ensure pass through methods are working
tracker.acknowledgePendingMessage("abc");
verify(mSipSessionTracker).acknowledgePendingMessage("abc");
@@ -140,7 +185,10 @@
assertFalse(tracker.verifyOutgoingMessage(TEST_MESSAGE, TEST_CONFIG_VERSION).isValidated);
// The number of times the filter method was called should still only be two after these
// messages were not validated.
- verify(mSipSessionTracker, times(2)).filterSipMessage(TEST_MESSAGE);
+ verify(mSipSessionTracker).filterSipMessage(
+ SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__OUTGOING, TEST_MESSAGE);
+ verify(mSipSessionTracker).filterSipMessage(
+ SIP_TRANSPORT_SESSION__SIP_MESSAGE_DIRECTION__INCOMING, TEST_MESSAGE);
}
@@ -482,6 +530,27 @@
doReturn(ValidationResult.SUCCESS).when(mIncomingStateValidator).validate(any());
doReturn(mIncomingStateValidator).when(mIncomingStateValidator).andThen(any());
return new TransportSipMessageValidator(TEST_SUB_ID, executor, mSipSessionTracker,
- mOutgoingStateValidator, mIncomingStateValidator);
+ mOutgoingStateValidator, mIncomingStateValidator, mRcsStats);
+ }
+
+ private SipMessage generateSipResponse(String statusCode, String statusString, String callId) {
+ String fromHeader = "Alice <sip:alice@atlanta.com>;tag=1928301774";
+ String toHeader = "Bob <sip:bob@biloxi.com>";
+ String branchId = "AAAA";
+ String fromTag = "tag=1928301774";
+ String toTag = "";
+ return SipMessageUtils.generateSipResponse(statusCode, statusString, fromHeader,
+ toHeader, branchId, callId, fromTag, toTag);
+ }
+
+ private SipMessage generateSipRequest(String requestMethod, String callId) {
+ String fromHeader = "Alice <sip:alice@atlanta.com>;tag=1928301774";
+ String toHeader = "Bob <sip:bob@biloxi.com>";
+ String branchId = "AAAA";
+ String fromTag = "tag=1928301774";
+ String toTag = "";
+ String toUri = "sip:bob@biloxi.com";
+ return SipMessageUtils.generateSipRequest(requestMethod, fromHeader, toHeader,
+ toUri, branchId, callId, fromTag, toTag);
}
}