diff options
author | Hakjun Choi <hakjunc@google.com> | 2021-11-25 01:05:22 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2021-11-25 01:05:22 +0000 |
commit | af94eeb0a2e2d2835281f7e9d31a684e8d50d781 (patch) | |
tree | 400819c1ad0d554d77b5a4e707e4b216251fe803 | |
parent | b6cf253315e975af81f9f874943dd1abf9dd1430 (diff) | |
parent | be5550dc2f7afb5aa732f1cf8238890924ed873e (diff) | |
download | ims-android12L-dev.tar.gz |
Merge changes from topic "RCS single registration metrics" into sc-v2-devandroid-12.1.0_r9android-12.1.0_r8android-12.1.0_r7android-12.1.0_r22android-12.1.0_r21android-12.1.0_r20android-12.1.0_r19android-12.1.0_r11android-12.1.0_r10android12L-devandroid12-qpr3-s7-releaseandroid12-qpr3-s6-releaseandroid12-qpr3-s5-releaseandroid12-qpr3-s4-releaseandroid12-qpr3-s3-releaseandroid12-qpr3-s2-releaseandroid12-qpr3-s1-releaseandroid12-qpr3-release
* changes:
Add metrics for UCE event about Publish, Subscribe, Options and metrics for RCS registration features
[UCE] Reset the retry count and times related publish when the publish status changed to not_published
Create UceStatsWriter for RCS metrics
15 files changed, 856 insertions, 24 deletions
diff --git a/src/java/com/android/ims/rcs/uce/UceStatsWriter.java b/src/java/com/android/ims/rcs/uce/UceStatsWriter.java new file mode 100644 index 00000000..1db9040c --- /dev/null +++ b/src/java/com/android/ims/rcs/uce/UceStatsWriter.java @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2021 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.ims.rcs.uce; + +import android.annotation.IntDef; +import android.telephony.ims.stub.ImsRegistrationImplBase; +import android.telephony.ims.stub.RcsCapabilityExchangeImplBase; +import android.telephony.ims.RcsContactPresenceTuple; +import android.telephony.ims.RcsContactUceCapability; +import com.android.internal.annotations.VisibleForTesting; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; + +/** + * The UceStatsWriter should be a singleton class for storing atoms in RcsStats. + * ims-common provides an interface for setting atoms to telephony-common. + **/ +public class UceStatsWriter { + private static UceStatsWriter sInstance = null; + private UceStatsCallback mCallBack; + + /** + * @hide + */ + // Defines which UCE event occurred. + @IntDef(value = { + PUBLISH_EVENT, + SUBSCRIBE_EVENT, + INCOMING_OPTION_EVENT, + OUTGOING_OPTION_EVENT + }) + @Retention(RetentionPolicy.SOURCE) + public @interface UceEventType {} + /** + * UCE events related to Publish Method. + */ + public static final int PUBLISH_EVENT = 0; + /** + * UCE events related to Subscribe Method. + */ + public static final int SUBSCRIBE_EVENT = 1; + /** + * UCE events related to incoming Options Method. + */ + public static final int INCOMING_OPTION_EVENT = 2; + /** + * UCE events related to outgoing Options Method. + */ + public static final int OUTGOING_OPTION_EVENT = 3; + + /** + * The callback interface is called by the Metrics data creator to receive information from + * others controllers. + */ + public interface UceStatsCallback { + /** + * Notify the callback listener that the feature tag associated with + * IMS registration of this device have changed. + */ + public void onImsRegistrationFeatureTagStats(int subId, List<String> featureTagList, + int registrationTech); + + /** + * Notify that the active IMS registration to the carrier network has been terminated. + */ + public void onStoreCompleteImsRegistrationFeatureTagStats(int subId); + + /** + * Notify the callback listener that the PIDF ServiceDescriptions associated with + * the UCE presence of this device have changed. + */ + void onImsRegistrationServiceDescStats(int subId, List<String> serviceIdList, + List<String> serviceIdVersionList, int registrationTech); + + /** + * Notify the callback listener that a subscribe response received. + */ + void onSubscribeResponse(int subId, long taskId, int networkResponse); + + /** + * Notify the callback listener that a UCE Network Event has occurred. + */ + void onUceEvent(int subId, int type, boolean successful, int commandCode, + int networkResponse); + + /** + * Notify the callback listener that a subscribe has ended. + */ + void onSubscribeTerminated(int subId, long taskId, String reason); + + /** + * Notify that the Presence Notify Event has changed. + */ + void onPresenceNotifyEvent(int subId, long taskId, + List<RcsContactUceCapability> updatedCapList); + + /** + * Notify that the active UCE PUBLISH to the carrier network has been terminated. + */ + void onStoreCompleteImsRegistrationServiceDescStats(int subId); + } + + /** + * create an instance of UceStatsWriter + */ + public static UceStatsWriter init(UceStatsCallback callback) { + synchronized (UceStatsWriter.class) { + if (sInstance == null) { + sInstance = new UceStatsWriter(callback); + } + return sInstance; + } + } + + /** + * get the current instance of UceStatsWriter + */ + public static UceStatsWriter getInstance() { + synchronized (UceStatsWriter.class) { + return sInstance; + } + } + + /** + * Stats about each Feature tag that was included in IMS registration received from + * the network during register. + * @param subId The subId associated with the event. + * @param featureTagList Ims Feature tag list. + * @param registrationTech The registration tech associated with the feature tag. + */ + public void setImsRegistrationFeatureTagStats(int subId, List<String> featureTagList, + @ImsRegistrationImplBase.ImsRegistrationTech int registrationTech) { + if (mCallBack == null) { + return; + } + mCallBack.onImsRegistrationFeatureTagStats(subId, featureTagList, registrationTech); + } + + /** + * Update time of stats for each stored feature tag. + * @param subId The subId associated with the event. + */ + public void setStoreCompleteImsRegistrationFeatureTagStats(int subId) { + if (mCallBack == null) { + return; + } + mCallBack.onStoreCompleteImsRegistrationFeatureTagStats(subId); + } + + /** + * Stats about each ServiceDescription that was included in the PIDF XML sent to + * the network during publish + * @param subId The subId associated with the event. + * @param tupleList Tuple information set in PIDF. + * @param registrationTech The registration tech associated with the feature tag. + */ + public void setImsRegistrationServiceDescStats(int subId, + List<RcsContactPresenceTuple> tupleList, + @ImsRegistrationImplBase.ImsRegistrationTech int registrationTech) { + if (mCallBack == null) { + return; + } + ArrayList<String> svcId = new ArrayList<>(); + ArrayList<String> svcVersion = new ArrayList<>(); + + for (RcsContactPresenceTuple tuple : tupleList) { + svcId.add(tuple.getServiceId()); + svcVersion.add(tuple.getServiceVersion()); + } + mCallBack.onImsRegistrationServiceDescStats(subId, svcId, svcVersion, registrationTech); + } + + /** + * Stats related to UCE queries to the network + * @param subId The subId associated with the event. + * @param taskId The taskId associate with the event. + * @param networkResponse The network response code for the Uce event + */ + public void setSubscribeResponse(int subId, long taskId, int networkResponse) { + if (mCallBack != null) { + mCallBack.onSubscribeResponse(subId, taskId, networkResponse); + } + } + + /** + * Stats related to UCE queries to the network + * @param subId The subId associated with the event. + * @param type Used to identify the message type. + * @param successful Whether the UCE event is successfully finished. + * @param commandCode The command error code for the Uce event + * @param networkResponse The network response code for the Uce event + */ + public void setUceEvent(int subId, @UceEventType int type, boolean successful, + @RcsCapabilityExchangeImplBase.CommandCode int commandCode, int networkResponse) { + if (mCallBack != null) { + mCallBack.onUceEvent(subId, type, successful, commandCode, networkResponse); + } + } + + /** + * The result of processing received notify messages. + * @param subId The subId associated with the event. + * @param taskId The taskId associate with the event. + * @param updatedCapList Capability information of the user contained in Presence Notify. + */ + public void setPresenceNotifyEvent(int subId, long taskId, + List<RcsContactUceCapability> updatedCapList) { + if (mCallBack == null || updatedCapList == null || updatedCapList.isEmpty()) { + return; + } + mCallBack.onPresenceNotifyEvent(subId, taskId, updatedCapList); + } + + /** + * Indicates that the subscription request has become a terminated state. + * @param subId The subId associated with the event. + * @param taskId The taskId associate with the event. + * @param reason The terminated reason associated with the subscription state. + */ + public void setSubscribeTerminated(int subId, long taskId, String reason) { + if (mCallBack != null) { + mCallBack.onSubscribeTerminated(subId, taskId, reason); + } + } + + /** + * indicates that the device has removed an existing PUBLISH from the carrier's network + * containing the device's RCS capabilities state. + * The registered time of publication must be set in ImsRegistrationServiceDescStats, + * which is the life time of publication, so it can be set only when publication is over. + * @param subId The subId associated with the event. + */ + public void setUnPublish(int subId) { + if (mCallBack != null) { + mCallBack.onStoreCompleteImsRegistrationServiceDescStats(subId); + } + } + + @VisibleForTesting + protected UceStatsWriter(UceStatsCallback callback) { + mCallBack = callback; + } +} diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java index e881ae0c..872d35dc 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java @@ -46,6 +46,7 @@ import android.util.IndentingPrintWriter; import android.util.LocalLog; import android.util.Log; +import com.android.ims.rcs.uce.UceStatsWriter; import com.android.ims.rcs.uce.presence.publish.PublishController.PublishControllerCallback; import com.android.ims.rcs.uce.presence.publish.PublishController.PublishTriggerType; import com.android.ims.rcs.uce.util.UceUtils; @@ -53,7 +54,12 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.util.HandlerExecutor; import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; import java.util.Objects; +import java.util.Set; /** * Listen to the device changes and notify the PublishController to publish the device's @@ -65,6 +71,8 @@ public class DeviceCapabilityListener { private static final long REGISTER_IMS_CHANGED_DELAY = 15000L; // 15 seconds + private final UceStatsWriter mUceStatsWriter; + /** * Used to inject ImsMmTelManager instances for testing. */ @@ -180,7 +188,7 @@ public class DeviceCapabilityListener { private final Object mLock = new Object(); public DeviceCapabilityListener(Context context, int subId, DeviceCapabilityInfo info, - PublishControllerCallback callback) { + PublishControllerCallback callback, UceStatsWriter uceStatsWriter) { mSubId = subId; logi("create"); @@ -188,6 +196,7 @@ public class DeviceCapabilityListener { mCallback = callback; mCapabilityInfo = info; mInitialized = false; + mUceStatsWriter = uceStatsWriter; mHandlerThread = new HandlerThread("DeviceCapListenerThread"); mHandlerThread.start(); @@ -447,6 +456,12 @@ public class DeviceCapabilityListener { synchronized (mLock) { logi("onRcsRegistered: " + attributes); if (!mIsImsCallbackRegistered) return; + + List<String> featureTagList = new ArrayList<>(attributes.getFeatureTags()); + int registrationTech = attributes.getRegistrationTechnology(); + + mUceStatsWriter.setImsRegistrationFeatureTagStats( + mSubId, featureTagList, registrationTech); handleImsRcsRegistered(attributes); } } @@ -456,6 +471,7 @@ public class DeviceCapabilityListener { synchronized (mLock) { logi("onRcsUnregistered: " + info); if (!mIsImsCallbackRegistered) return; + mUceStatsWriter.setStoreCompleteImsRegistrationFeatureTagStats(mSubId); handleImsRcsUnregistered(); } } diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/PublishControllerImpl.java b/src/java/com/android/ims/rcs/uce/presence/publish/PublishControllerImpl.java index e2340ff5..0ff48856 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/PublishControllerImpl.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/PublishControllerImpl.java @@ -44,6 +44,7 @@ import com.android.ims.rcs.uce.UceController; import com.android.ims.rcs.uce.UceController.UceControllerCallback; import com.android.ims.rcs.uce.UceDeviceState; import com.android.ims.rcs.uce.UceDeviceState.DeviceStateResult; +import com.android.ims.rcs.uce.UceStatsWriter; import com.android.ims.rcs.uce.util.UceUtils; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.SomeArgs; @@ -79,7 +80,8 @@ public class PublishControllerImpl implements PublishController { @VisibleForTesting public interface DeviceCapListenerFactory { DeviceCapabilityListener createDeviceCapListener(Context context, int subId, - DeviceCapabilityInfo capInfo, PublishControllerCallback callback); + DeviceCapabilityInfo capInfo, PublishControllerCallback callback, + UceStatsWriter uceStatsWriter); } private final int mSubId; @@ -90,6 +92,7 @@ public class PublishControllerImpl implements PublishController { private volatile boolean mReceivePublishFromService; private volatile RcsFeatureManager mRcsFeatureManager; private final UceControllerCallback mUceCtrlCallback; + private final UceStatsWriter mUceStatsWriter; // The capability type that the device is using. private @RcsImsCapabilityFlag int mCapabilityType; @@ -115,8 +118,9 @@ public class PublishControllerImpl implements PublishController { // The listener to listen to the device's capabilities changed. private DeviceCapabilityListener mDeviceCapListener; - private DeviceCapListenerFactory mDeviceCapListenerFactory = (context, subId, capInfo, callback) - -> new DeviceCapabilityListener(context, subId, capInfo, callback); + private DeviceCapListenerFactory mDeviceCapListenerFactory = (context, subId, capInfo, callback, + uceStatsWriter) + -> new DeviceCapabilityListener(context, subId, capInfo, callback, uceStatsWriter); // Listen to the RCS availability status changed. private final IImsCapabilityCallback mRcsCapabilitiesCallback = @@ -141,6 +145,7 @@ public class PublishControllerImpl implements PublishController { mSubId = subId; mContext = context; mUceCtrlCallback = callback; + mUceStatsWriter = UceStatsWriter.getInstance(); logi("create"); initPublishController(looper); } @@ -148,12 +153,13 @@ public class PublishControllerImpl implements PublishController { @VisibleForTesting public PublishControllerImpl(Context context, int subId, UceControllerCallback c, Looper looper, DeviceCapListenerFactory deviceCapFactory, - PublishProcessorFactory processorFactory) { + PublishProcessorFactory processorFactory, UceStatsWriter instance) { mSubId = subId; mContext = context; mUceCtrlCallback = c; mDeviceCapListenerFactory = deviceCapFactory; mPublishProcessorFactory = processorFactory; + mUceStatsWriter = instance; initPublishController(looper); } @@ -200,7 +206,7 @@ public class PublishControllerImpl implements PublishController { private void initDeviceCapabilitiesListener() { mDeviceCapListener = mDeviceCapListenerFactory.createDeviceCapListener(mContext, mSubId, - mDeviceCapabilityInfo, mPublishControllerCallback); + mDeviceCapabilityInfo, mPublishControllerCallback, mUceStatsWriter); } @Override @@ -330,8 +336,7 @@ public class PublishControllerImpl implements PublishController { public void onUnpublish() { logd("onUnpublish"); if (mIsDestroyedFlag) return; - mPublishHandler.sendPublishStateChangedMessage(RcsUceAdapter.PUBLISH_STATE_NOT_PUBLISHED, - Instant.now(), null /*pidfXml*/); + mPublishHandler.sendUnpublishedMessage(RcsUceAdapter.PUBLISH_STATE_NOT_PUBLISHED); } @Override @@ -416,6 +421,7 @@ public class PublishControllerImpl implements PublishController { private static final int MSG_REQUEST_NETWORK_RESPONSE = 10; private static final int MSG_REQUEST_CANCELED = 11; private static final int MSG_RESET_DEVICE_STATE = 12; + private static final int MSG_UNPUBLISHED = 13; private final WeakReference<PublishControllerImpl> mPublishControllerRef; @@ -496,6 +502,14 @@ public class PublishControllerImpl implements PublishController { publishCtrl.handleResetDeviceStateMessage(); break; + case MSG_UNPUBLISHED: { + SomeArgs args = (SomeArgs) message.obj; + int newPublishState = (Integer) args.arg1; + Instant updatedTimestamp = (Instant) args.arg2; + args.recycle(); + publishCtrl.handleUnpublishedMessage(newPublishState, updatedTimestamp); + break; + } default: publishCtrl.logd("invalid message: " + message.what); break; @@ -584,6 +598,22 @@ public class PublishControllerImpl implements PublishController { } /** + * Send the message to notify the publish state is changed. + */ + public void sendUnpublishedMessage(@PublishState int publishState) { + PublishControllerImpl publishCtrl = mPublishControllerRef.get(); + if (publishCtrl == null) return; + if (publishCtrl.mIsDestroyedFlag) return; + + SomeArgs args = SomeArgs.obtain(); + args.arg1 = publishState; + args.arg2 = Instant.now(); + Message message = obtainMessage(); + message.what = MSG_UNPUBLISHED; + message.obj = args; + sendMessage(message); + } + /** * Send the message to notify the new added callback of the latest publish state. */ public void sendNotifyCurrentPublishStateMessage( @@ -703,6 +733,7 @@ public class PublishControllerImpl implements PublishController { EVENT_DESCRIPTION.put(MSG_REQUEST_NETWORK_RESPONSE, "REQUEST_NETWORK_RESPONSE"); EVENT_DESCRIPTION.put(MSG_REQUEST_CANCELED, "REQUEST_CANCELED"); EVENT_DESCRIPTION.put(MSG_RESET_DEVICE_STATE, "RESET_DEVICE_STATE"); + EVENT_DESCRIPTION.put(MSG_UNPUBLISHED, "MSG_UNPUBLISHED"); } } @@ -909,6 +940,9 @@ public class PublishControllerImpl implements PublishController { if (mPublishState == newPublishState) return; mPublishState = newPublishState; } + if (newPublishState == RcsUceAdapter.PUBLISH_STATE_NOT_PUBLISHED) { + mUceStatsWriter.setUnPublish(mSubId); + } // Trigger the publish state changed in handler thread since it may take time. logd("Notify publish state changed: " + mPublishState); @@ -988,6 +1022,13 @@ public class PublishControllerImpl implements PublishController { mUceCtrlCallback.resetDeviceState(); } + private void handleUnpublishedMessage(@PublishState int newPublishState, + Instant updatedTimestamp) { + if (mIsDestroyedFlag) return; + mPublishProcessor.resetState(); + handlePublishStateChangedMessage(newPublishState, updatedTimestamp, null); + } + @VisibleForTesting public void setCapabilityType(int type) { mCapabilityType = type; diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/PublishProcessor.java b/src/java/com/android/ims/rcs/uce/presence/publish/PublishProcessor.java index 68aeaa8f..01aa22b9 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/PublishProcessor.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/PublishProcessor.java @@ -22,6 +22,8 @@ import android.annotation.NonNull; import android.content.Context; import android.os.RemoteException; import android.telephony.ims.RcsContactUceCapability; +import android.telephony.ims.stub.ImsRegistrationImplBase; +import android.telephony.ims.stub.RcsCapabilityExchangeImplBase; import android.text.TextUtils; import android.util.IndentingPrintWriter; import android.util.LocalLog; @@ -31,6 +33,7 @@ import com.android.ims.RcsFeatureManager; import com.android.ims.rcs.uce.presence.pidfparser.PidfParser; import com.android.ims.rcs.uce.presence.publish.PublishController.PublishControllerCallback; import com.android.ims.rcs.uce.presence.publish.PublishController.PublishTriggerType; +import com.android.ims.rcs.uce.UceStatsWriter; import com.android.ims.rcs.uce.util.UceUtils; import com.android.internal.annotations.VisibleForTesting; @@ -53,6 +56,8 @@ public class PublishProcessor { private volatile boolean mIsDestroyed; private volatile RcsFeatureManager mRcsFeatureManager; + private final UceStatsWriter mUceStatsWriter; + // Manage the state of the publish processor. private PublishProcessorState mProcessorState; @@ -74,6 +79,18 @@ public class PublishProcessor { mDeviceCapabilities = capabilityInfo; mPublishCtrlCallback = publishCtrlCallback; mProcessorState = new PublishProcessorState(subId); + mUceStatsWriter = UceStatsWriter.getInstance(); + } + + @VisibleForTesting + public PublishProcessor(Context context, int subId, DeviceCapabilityInfo capabilityInfo, + PublishControllerCallback publishCtrlCallback, UceStatsWriter instance) { + mSubId = subId; + mContext = context; + mDeviceCapabilities = capabilityInfo; + mPublishCtrlCallback = publishCtrlCallback; + mProcessorState = new PublishProcessorState(subId); + mUceStatsWriter = instance; } /** @@ -158,6 +175,13 @@ public class PublishProcessor { return false; } + featureManager.getImsRegistrationTech((tech) -> { + int registrationTech = (tech == null) + ? ImsRegistrationImplBase.REGISTRATION_TECH_NONE : tech; + mUceStatsWriter.setImsRegistrationServiceDescStats(mSubId, + deviceCapability.getCapabilityTuples(), registrationTech); + }); + // Publish to the Presence server. return publishCapabilities(featureManager, pidfXml); } @@ -244,6 +268,13 @@ public class PublishProcessor { mLocalLog.log("Receive command error code=" + requestResponse.getCmdErrorCode()); logd("onCommandError: " + requestResponse.toString()); + int cmdError = requestResponse.getCmdErrorCode().orElse(0); + boolean successful = false; + if (cmdError == RcsCapabilityExchangeImplBase.COMMAND_CODE_NO_CHANGE) { + successful = true; + } + mUceStatsWriter.setUceEvent(mSubId, UceStatsWriter.PUBLISH_EVENT, successful, cmdError, 0); + if (requestResponse.needRetry() && !mProcessorState.isReachMaximumRetries()) { handleRequestRespWithRetry(requestResponse); } else { @@ -267,6 +298,10 @@ public class PublishProcessor { mLocalLog.log("Receive network response code=" + requestResponse.getNetworkRespSipCode()); logd("onNetworkResponse: " + requestResponse.toString()); + int responseCode = requestResponse.getNetworkRespSipCode().orElse(0); + mUceStatsWriter.setUceEvent(mSubId, UceStatsWriter.PUBLISH_EVENT, true, 0, + responseCode); + if (requestResponse.needRetry() && !mProcessorState.isReachMaximumRetries()) { handleRequestRespWithRetry(requestResponse); } else { @@ -445,6 +480,12 @@ public class PublishProcessor { return mProcessorState.isPublishingNow(); } + /** + * Reset the retry count and time related publish. + */ + public void resetState() { + mProcessorState.resetState(); + } @VisibleForTesting public void setProcessorState(PublishProcessorState processorState) { mProcessorState = processorState; diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/PublishProcessorState.java b/src/java/com/android/ims/rcs/uce/presence/publish/PublishProcessorState.java index 40d901f6..0e9adfad 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/PublishProcessorState.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/PublishProcessorState.java @@ -348,6 +348,16 @@ public class PublishProcessorState { } } + /** + * Reset the retry count and related time when the publication status has + * changed to not_published. + */ + public void resetState() { + synchronized (mLock) { + mPublishThrottle.resetState(); + } + } + /* * Check if it has reached the maximum retry count. */ diff --git a/src/java/com/android/ims/rcs/uce/request/OptionsRequestCoordinator.java b/src/java/com/android/ims/rcs/uce/request/OptionsRequestCoordinator.java index a150dd6d..a2660931 100644 --- a/src/java/com/android/ims/rcs/uce/request/OptionsRequestCoordinator.java +++ b/src/java/com/android/ims/rcs/uce/request/OptionsRequestCoordinator.java @@ -24,6 +24,7 @@ import android.telephony.ims.RcsUceAdapter; import android.telephony.ims.aidl.IRcsUceControllerCallback; import com.android.ims.rcs.uce.request.UceRequestManager.RequestManagerCallback; +import com.android.ims.rcs.uce.UceStatsWriter; import com.android.internal.annotations.VisibleForTesting; import java.util.Collection; @@ -44,7 +45,14 @@ public class OptionsRequestCoordinator extends UceRequestCoordinator { public Builder(int subId, Collection<UceRequest> requests, RequestManagerCallback callback) { - mRequestCoordinator = new OptionsRequestCoordinator(subId, requests, callback); + mRequestCoordinator = new OptionsRequestCoordinator(subId, requests, callback, + UceStatsWriter.getInstance()); + } + @VisibleForTesting + public Builder(int subId, Collection<UceRequest> requests, + RequestManagerCallback callback, UceStatsWriter instance) { + mRequestCoordinator = new OptionsRequestCoordinator(subId, requests, callback, + instance); } public Builder setCapabilitiesCallback(IRcsUceControllerCallback callback) { @@ -105,9 +113,12 @@ public class OptionsRequestCoordinator extends UceRequestCoordinator { // The callback to notify the result of the capabilities request. private IRcsUceControllerCallback mCapabilitiesCallback; + private final UceStatsWriter mUceStatsWriter; + private OptionsRequestCoordinator(int subId, Collection<UceRequest> requests, - RequestManagerCallback requestMgrCallback) { + RequestManagerCallback requestMgrCallback, UceStatsWriter instance) { super(subId, requests, requestMgrCallback); + mUceStatsWriter = instance; logd("OptionsRequestCoordinator: created"); } @@ -189,6 +200,11 @@ public class OptionsRequestCoordinator extends UceRequestCoordinator { // Finish this request. request.onFinish(); + int commandErrorCode = response.getCommandError().orElse(0); + mUceStatsWriter.setUceEvent(mSubId, UceStatsWriter.OUTGOING_OPTION_EVENT, + false, commandErrorCode, 0); + + // Remove this request from the activated collection and notify RequestManager. Long taskId = request.getTaskId(); RequestResult requestResult = sCommandErrorCreator.createRequestResult(taskId, response); @@ -203,6 +219,11 @@ public class OptionsRequestCoordinator extends UceRequestCoordinator { CapabilityRequestResponse response = request.getRequestResponse(); logd("handleNetworkResponse: " + response.toString()); + int responseCode = response.getNetworkRespSipCode().orElse(0); + mUceStatsWriter.setUceEvent(mSubId, UceStatsWriter.OUTGOING_OPTION_EVENT, true, + 0, responseCode); + + List<RcsContactUceCapability> updatedCapList = response.getUpdatedContactCapability(); if (!updatedCapList.isEmpty()) { // Save the capabilities and trigger the capabilities callback diff --git a/src/java/com/android/ims/rcs/uce/request/RemoteOptionsCoordinator.java b/src/java/com/android/ims/rcs/uce/request/RemoteOptionsCoordinator.java index c8aa3f77..5a3e33bb 100644 --- a/src/java/com/android/ims/rcs/uce/request/RemoteOptionsCoordinator.java +++ b/src/java/com/android/ims/rcs/uce/request/RemoteOptionsCoordinator.java @@ -25,6 +25,7 @@ import android.telephony.ims.aidl.IOptionsRequestCallback; import com.android.ims.rcs.uce.request.RemoteOptionsRequest.RemoteOptResponse; import com.android.ims.rcs.uce.request.UceRequestManager.RequestManagerCallback; +import com.android.ims.rcs.uce.UceStatsWriter; import com.android.internal.annotations.VisibleForTesting; import java.util.Collection; @@ -41,7 +42,13 @@ public class RemoteOptionsCoordinator extends UceRequestCoordinator { RemoteOptionsCoordinator mRemoteOptionsCoordinator; public Builder(int subId, Collection<UceRequest> requests, RequestManagerCallback c) { - mRemoteOptionsCoordinator = new RemoteOptionsCoordinator(subId, requests, c); + mRemoteOptionsCoordinator = new RemoteOptionsCoordinator(subId, requests, c, + UceStatsWriter.getInstance()); + } + @VisibleForTesting + public Builder(int subId, Collection<UceRequest> requests, RequestManagerCallback c, + UceStatsWriter instance) { + mRemoteOptionsCoordinator = new RemoteOptionsCoordinator(subId, requests, c, instance); } public Builder setOptionsRequestCallback(IOptionsRequestCallback callback) { @@ -78,9 +85,12 @@ public class RemoteOptionsCoordinator extends UceRequestCoordinator { // The callback to notify the result of the remote options request. private IOptionsRequestCallback mOptionsReqCallback; + private final UceStatsWriter mUceStatsWriter; + private RemoteOptionsCoordinator(int subId, Collection<UceRequest> requests, - RequestManagerCallback requestMgrCallback) { + RequestManagerCallback requestMgrCallback, UceStatsWriter instance) { super(subId, requests, requestMgrCallback); + mUceStatsWriter = instance; logd("RemoteOptionsCoordinator: created"); } @@ -144,6 +154,9 @@ public class RemoteOptionsCoordinator extends UceRequestCoordinator { boolean isRemoteNumberBlocked) { try { logd("triggerOptionsReqCallback: start"); + mUceStatsWriter.setUceEvent(mSubId, UceStatsWriter.INCOMING_OPTION_EVENT, true, 0, + 200); + mOptionsReqCallback.respondToCapabilityRequest(deviceCaps, isRemoteNumberBlocked); } catch (RemoteException e) { logw("triggerOptionsReqCallback exception: " + e); @@ -155,6 +168,9 @@ public class RemoteOptionsCoordinator extends UceRequestCoordinator { private void triggerOptionsReqWithErrorCallback(int errorCode, String reason) { try { logd("triggerOptionsReqWithErrorCallback: start"); + mUceStatsWriter.setUceEvent(mSubId, UceStatsWriter.INCOMING_OPTION_EVENT, true, 0, + errorCode); + mOptionsReqCallback.respondToCapabilityRequestWithError(errorCode, reason); } catch (RemoteException e) { logw("triggerOptionsReqWithErrorCallback exception: " + e); diff --git a/src/java/com/android/ims/rcs/uce/request/SubscribeRequestCoordinator.java b/src/java/com/android/ims/rcs/uce/request/SubscribeRequestCoordinator.java index b3cc781b..f44686ac 100644 --- a/src/java/com/android/ims/rcs/uce/request/SubscribeRequestCoordinator.java +++ b/src/java/com/android/ims/rcs/uce/request/SubscribeRequestCoordinator.java @@ -29,6 +29,7 @@ import com.android.ims.rcs.uce.eab.EabCapabilityResult; import com.android.ims.rcs.uce.presence.pidfparser.PidfParserUtils; import com.android.ims.rcs.uce.request.SubscriptionTerminatedHelper.TerminatedResult; import com.android.ims.rcs.uce.request.UceRequestManager.RequestManagerCallback; +import com.android.ims.rcs.uce.UceStatsWriter; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; @@ -53,7 +54,13 @@ public class SubscribeRequestCoordinator extends UceRequestCoordinator { * The builder of the SubscribeRequestCoordinator class. */ public Builder(int subId, Collection<UceRequest> requests, RequestManagerCallback c) { - mRequestCoordinator = new SubscribeRequestCoordinator(subId, requests, c); + mRequestCoordinator = new SubscribeRequestCoordinator(subId, requests, c, + UceStatsWriter.getInstance()); + } + @VisibleForTesting + public Builder(int subId, Collection<UceRequest> requests, RequestManagerCallback c, + UceStatsWriter instance) { + mRequestCoordinator = new SubscribeRequestCoordinator(subId, requests, c, instance); } /** @@ -154,9 +161,12 @@ public class SubscribeRequestCoordinator extends UceRequestCoordinator { // The callback to notify the result of the capabilities request. private volatile IRcsUceControllerCallback mCapabilitiesCallback; + private final UceStatsWriter mUceStatsWriter; + private SubscribeRequestCoordinator(int subId, Collection<UceRequest> requests, - RequestManagerCallback requestMgrCallback) { + RequestManagerCallback requestMgrCallback, UceStatsWriter instance) { super(subId, requests, requestMgrCallback); + mUceStatsWriter = instance; logd("SubscribeRequestCoordinator: created"); } @@ -248,6 +258,10 @@ public class SubscribeRequestCoordinator extends UceRequestCoordinator { // Finish this request. request.onFinish(); + int commandErrorCode = response.getCommandError().orElse(0); + mUceStatsWriter.setUceEvent(mSubId, UceStatsWriter.SUBSCRIBE_EVENT, + false, commandErrorCode, 0); + // Remove this request from the activated collection and notify RequestManager. Long taskId = request.getTaskId(); RequestResult requestResult = sCommandErrorCreator.createRequestResult(taskId, response, @@ -263,6 +277,9 @@ public class SubscribeRequestCoordinator extends UceRequestCoordinator { CapabilityRequestResponse response = request.getRequestResponse(); logd("handleNetworkResponse: " + response.toString()); + int respCode = response.getNetworkRespSipCode().orElse(0); + mUceStatsWriter.setSubscribeResponse(mSubId, request.getTaskId(), respCode); + // Refresh the device state with the request result. response.getResponseSipCode().ifPresent(sipCode -> { String reason = response.getResponseReason().orElse(""); @@ -379,6 +396,7 @@ public class SubscribeRequestCoordinator extends UceRequestCoordinator { return; } + mUceStatsWriter.setPresenceNotifyEvent(mSubId, taskId, updatedCapList); // Save the updated capabilities to the cache. mRequestManagerCallback.saveCapabilities(updatedCapList); @@ -402,6 +420,8 @@ public class SubscribeRequestCoordinator extends UceRequestCoordinator { return; } + mUceStatsWriter.setPresenceNotifyEvent(mSubId, taskId, terminatedResources); + // Save the terminated capabilities to the cache. mRequestManagerCallback.saveCapabilities(terminatedResources); @@ -442,6 +462,7 @@ public class SubscribeRequestCoordinator extends UceRequestCoordinator { // Remove this request from the activated collection and notify RequestManager. Long taskId = request.getTaskId(); + mUceStatsWriter.setSubscribeTerminated(mSubId, taskId, response.getTerminatedReason()); RequestResult requestResult = sTerminatedCreator.createRequestResult(taskId, response, mRequestManagerCallback); moveRequestToFinishedCollection(taskId, requestResult); diff --git a/tests/src/com/android/ims/rcs/uce/UceStatsWriterTest.java b/tests/src/com/android/ims/rcs/uce/UceStatsWriterTest.java new file mode 100644 index 00000000..49edf198 --- /dev/null +++ b/tests/src/com/android/ims/rcs/uce/UceStatsWriterTest.java @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2021 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.ims.rcs.uce; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; + +import android.telephony.ims.RcsContactPresenceTuple; +import android.telephony.ims.RcsContactUceCapability; + +import com.android.ims.rcs.uce.UceStatsWriter; +import com.android.ims.rcs.uce.UceStatsWriter.UceStatsCallback; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; + +@RunWith(AndroidJUnit4.class) +public class UceStatsWriterTest { + private int mSubId = 3; + private long mTaskId = 5; + private int mRegistrationTech = 3; + private int mType = 2; + private boolean mSuccessful = true; + private int mCommandCode = 4; + private int mNetworkResponse = 200; + private String mReason = "noresource"; + + private Callback mCallback; + private TestableUceStatsWriter mWrite; + + class Callback implements UceStatsCallback { + int subId; + List<String> featureTagList; + List<String> serviceIdList; + List<String> versions; + int registrationTech; + int type; + boolean successful; + int commandCode; + int networkResponse; + long taskId; + List<RcsContactUceCapability> updatedCapList; + String reason; + + Callback() { + } + + public void onImsRegistrationFeatureTagStats(int subId, List<String> featureTagList, + int registrationTech) { + this.subId = subId; + this.featureTagList = featureTagList; + this.registrationTech = registrationTech; + } + + public void onStoreCompleteImsRegistrationFeatureTagStats(int subId) {} + + public void onImsRegistrationServiceDescStats(int subId, List<String> serviceIdList, + List<String> serviceIdVersionList, int registrationTech) { + this.subId = subId; + this.serviceIdList = serviceIdList; + this.versions = serviceIdVersionList; + this.registrationTech = registrationTech; + } + + public void onSubscribeResponse(int subId, long taskId, int networkResponse) { + this.subId = subId; + this.taskId = taskId; + this.successful = true; + this.commandCode = 0; + this.networkResponse = networkResponse; + } + + public void onUceEvent(int subId, int type, boolean successful, int commandCode, + int networkResponse) { + this.subId = subId; + this.type = type; + this.successful = successful; + this.commandCode = commandCode; + this.networkResponse = networkResponse; + } + + public void onSubscribeTerminated(int subId, long taskId, String reason) { + this.subId = subId; + this.taskId = taskId; + this.reason = reason; + } + + public void onPresenceNotifyEvent(int subId, long taskId, + List<RcsContactUceCapability> updatedCapList) { + this.subId = subId; + this.taskId = taskId; + this.updatedCapList = updatedCapList; + } + + public void onStoreCompleteImsRegistrationServiceDescStats(int subId) { + this.subId = subId; + } + } + + private class TestableUceStatsWriter extends UceStatsWriter { + public TestableUceStatsWriter(UceStatsCallback callback) { + super(callback); + } + } + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mCallback = new Callback(); + mWrite = new TestableUceStatsWriter(mCallback); + } + + @After + public void tearDown() throws Exception { + } + + @Test + @SmallTest + public void setImsRegistrationFeatureTagStats() throws Exception { + List<String> featureTags = new ArrayList<>(); + featureTags.add("+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcse.im\""); + featureTags.add("+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.session\""); + featureTags.add("+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.ftsms\""); + mWrite.setImsRegistrationFeatureTagStats(mSubId, featureTags, mRegistrationTech); + assertEquals(mSubId, mCallback.subId); + for (int index = 0; index < featureTags.size(); index++) { + assertEquals(featureTags.get(index), mCallback.featureTagList.get(index)); + } + assertEquals(mRegistrationTech, mCallback.registrationTech); + } + + @Test + @SmallTest + public void setImsRegistrationServiceDescStats() throws Exception { + List<RcsContactPresenceTuple> tupleList = new ArrayList<>(); + tupleList.add(getContactChatTuple()); + tupleList.add(getContactFtTuple()); + tupleList.add(getContactUnknown1Tuple()); + tupleList.add(getContactUnknown2Tuple()); + mWrite.setImsRegistrationServiceDescStats(mSubId, tupleList, mRegistrationTech); + assertEquals(mSubId, mCallback.subId); + for (int index = 0; index < tupleList.size(); index++) { + assertEquals(tupleList.get(index).getServiceId(), mCallback.serviceIdList.get(index)); + assertEquals(tupleList.get(index).getServiceVersion(), mCallback.versions.get(index)); + } + assertEquals(mRegistrationTech, mCallback.registrationTech); + } + + @Test + @SmallTest + public void setSubscribeEvent() throws Exception { + mWrite.setSubscribeResponse(mSubId, mTaskId, mNetworkResponse); + assertEquals(mSubId, mCallback.subId); + assertEquals(mTaskId, mCallback.taskId); + assertTrue(mCallback.successful); + assertEquals(0, mCallback.commandCode); + assertEquals(mNetworkResponse, mCallback.networkResponse); + } + + @Test + @SmallTest + public void setSubscribeTerminated() throws Exception { + mWrite.setSubscribeResponse(mSubId, mTaskId, mNetworkResponse); + mWrite.setSubscribeTerminated(mSubId, mTaskId, mReason); + assertEquals(mSubId, mCallback.subId); + assertEquals(mTaskId, mCallback.taskId); + assertEquals(mReason, mCallback.reason); + } + + @Test + @SmallTest + public void setUceEvent() throws Exception { + mWrite.setUceEvent(mSubId, mType, mSuccessful, mCommandCode, mNetworkResponse); + assertEquals(mSubId, mCallback.subId); + assertEquals(mType, mCallback.type); + assertEquals(mSuccessful, mCallback.successful); + assertEquals(mCommandCode, mCallback.commandCode); + assertEquals(mNetworkResponse, mCallback.networkResponse); + } + + @Test + @SmallTest + public void setPresenceNotifyEvent() throws Exception { + List<RcsContactUceCapability> updatedCapList = new ArrayList<>(); + RcsContactUceCapability.PresenceBuilder builder = + new RcsContactUceCapability.PresenceBuilder(null, 0, 2); + builder.addCapabilityTuple(getContactChatTuple()); + builder.addCapabilityTuple(getContactCallComposer2Tuple()); + builder.addCapabilityTuple(getContactUnknown1Tuple()); + updatedCapList.add(builder.build()); + + mWrite.setPresenceNotifyEvent(mSubId, mTaskId, updatedCapList); + assertEquals(mSubId, mCallback.subId); + assertEquals(mTaskId, mCallback.taskId); + assertEquals(updatedCapList.size(), mCallback.updatedCapList.size()); + for (int index = 0; index < updatedCapList.size(); index++) { + RcsContactUceCapability input = updatedCapList.get(index); + RcsContactUceCapability output = mCallback.updatedCapList.get(index); + assertEquals(input.getCapabilityTuples().size(), output.getCapabilityTuples().size()); + } + } + + @Test + @SmallTest + public void setPresenceNotifyEvent_withCallComposer2Caps() throws Exception { + RcsContactPresenceTuple tuple = getContactCallComposer2Tuple(); + List<RcsContactUceCapability> updatedCapList = new ArrayList<>(); + RcsContactUceCapability.PresenceBuilder builder = + new RcsContactUceCapability.PresenceBuilder(null, 0, 2); + builder.addCapabilityTuple(getContactCallComposer2Tuple()); + updatedCapList.add(builder.build()); + + mWrite.setPresenceNotifyEvent(mSubId, mTaskId, updatedCapList); + assertEquals(mSubId, mCallback.subId); + assertEquals(mTaskId, mCallback.taskId); + assertEquals(updatedCapList.size(), mCallback.updatedCapList.size()); + } + + @Test + @SmallTest + public void setUnPublish() throws Exception { + mWrite.setUnPublish(mSubId); + assertEquals(mSubId, mCallback.subId); + } + + private RcsContactPresenceTuple getContactChatTuple() { + RcsContactPresenceTuple.Builder builder = + new RcsContactPresenceTuple.Builder("open", RcsContactPresenceTuple.SERVICE_ID_CHAT_V1, + "1.0"); + return builder.build(); + } + + private RcsContactPresenceTuple getContactMmtelTuple() { + RcsContactPresenceTuple.Builder builder = + new RcsContactPresenceTuple.Builder("open", RcsContactPresenceTuple.SERVICE_ID_MMTEL, + "1.0"); + return builder.build(); + } + + private RcsContactPresenceTuple getContactFtTuple() { + RcsContactPresenceTuple.Builder builder = + new RcsContactPresenceTuple.Builder("open", RcsContactPresenceTuple.SERVICE_ID_FT, + "1.0"); + return builder.build(); + } + + private RcsContactPresenceTuple getContactCallComposer2Tuple() { + RcsContactPresenceTuple.Builder builder = + new RcsContactPresenceTuple.Builder("open", + RcsContactPresenceTuple.SERVICE_ID_CALL_COMPOSER, + "2.0"); + return builder.build(); + } + + private RcsContactPresenceTuple getContactUnknown1Tuple() { + RcsContactPresenceTuple.Builder builder = + new RcsContactPresenceTuple.Builder("open", "Unknown1", + "8.0"); + return builder.build(); + } + + private RcsContactPresenceTuple getContactUnknown2Tuple() { + RcsContactPresenceTuple.Builder builder = + new RcsContactPresenceTuple.Builder("open", "Unknown2", + "9.0"); + return builder.build(); + } +} diff --git a/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java b/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java index bf33103f..1959dd0d 100644 --- a/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java +++ b/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java @@ -19,7 +19,11 @@ package com.android.ims.rcs.uce.presence.publish; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.refEq; import static org.mockito.Mockito.verify; import android.content.BroadcastReceiver; @@ -39,12 +43,18 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.ims.ImsTestBase; +import com.android.ims.rcs.uce.UceStatsWriter; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.Mockito; @RunWith(AndroidJUnit4.class) public class DeviceCapabilityListenerTest extends ImsTestBase { @@ -60,6 +70,7 @@ public class DeviceCapabilityListenerTest extends ImsTestBase { @Mock DeviceCapabilityListener.ImsMmTelManagerFactory mImsMmTelMgrFactory; @Mock DeviceCapabilityListener.ImsRcsManagerFactory mImsRcsMgrFactory; @Mock DeviceCapabilityListener.ProvisioningManagerFactory mProvisioningMgrFactory; + @Mock UceStatsWriter mUceStatsWriter; int mSubId = 1; @@ -77,6 +88,10 @@ public class DeviceCapabilityListenerTest extends ImsTestBase { doReturn(true).when(mDeviceCapability).updateVtSetting(anyBoolean()); doReturn(true).when(mDeviceCapability).updateVtSetting(anyBoolean()); doReturn(true).when(mDeviceCapability).updateMmtelCapabilitiesChanged(any()); + + doNothing().when(mUceStatsWriter).setImsRegistrationFeatureTagStats( + anyInt(), anyList(), anyInt()); + doNothing().when(mUceStatsWriter).setStoreCompleteImsRegistrationFeatureTagStats(anyInt()); } @After @@ -183,8 +198,18 @@ public class DeviceCapabilityListenerTest extends ImsTestBase { DeviceCapabilityListener deviceCapListener = createDeviceCapabilityListener(); deviceCapListener.setImsCallbackRegistered(true); RegistrationCallback registrationCallback = deviceCapListener.mRcsRegistrationCallback; + + List<String> list = new ArrayList<>(); + list.add("+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcse.im\""); + list.add("+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.session\""); + list.add("+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.ftsms\""); + Set<String> featureTags = new HashSet<String>(list); + ImsRegistrationAttributes attr = new ImsRegistrationAttributes.Builder( - ImsRegistrationImplBase.REGISTRATION_TECH_LTE).build(); + ImsRegistrationImplBase.REGISTRATION_TECH_LTE) + .setFeatureTags(featureTags) + .build(); + // Notify DeviceCapabilityListener that registered has caused a change and requires publish doReturn(true).when(mDeviceCapability).updateImsRcsRegistered(attr); @@ -195,6 +220,8 @@ public class DeviceCapabilityListenerTest extends ImsTestBase { verify(mDeviceCapability).updateImsRcsRegistered(attr); verify(mCallback).requestPublishFromInternal( PublishController.PUBLISH_TRIGGER_RCS_REGISTERED); + verify(mUceStatsWriter).setImsRegistrationFeatureTagStats(anyInt(), + refEq(list), eq(ImsRegistrationImplBase.REGISTRATION_TECH_LTE)); } @Test @@ -216,6 +243,7 @@ public class DeviceCapabilityListenerTest extends ImsTestBase { verify(mDeviceCapability).updateImsRcsUnregistered(); verify(mCallback).requestPublishFromInternal( PublishController.PUBLISH_TRIGGER_RCS_UNREGISTERED); + verify(mUceStatsWriter).setStoreCompleteImsRegistrationFeatureTagStats(anyInt()); } @Test @@ -237,7 +265,7 @@ public class DeviceCapabilityListenerTest extends ImsTestBase { private DeviceCapabilityListener createDeviceCapabilityListener() { DeviceCapabilityListener deviceCapListener = new DeviceCapabilityListener(mContext, - mSubId, mDeviceCapability, mCallback); + mSubId, mDeviceCapability, mCallback, mUceStatsWriter); deviceCapListener.setImsMmTelManagerFactory(mImsMmTelMgrFactory); deviceCapListener.setImsRcsManagerFactory(mImsRcsMgrFactory); deviceCapListener.setProvisioningMgrFactory(mProvisioningMgrFactory); diff --git a/tests/src/com/android/ims/rcs/uce/presence/publish/PublishControllerImplTest.java b/tests/src/com/android/ims/rcs/uce/presence/publish/PublishControllerImplTest.java index b4c9b873..804702c4 100644 --- a/tests/src/com/android/ims/rcs/uce/presence/publish/PublishControllerImplTest.java +++ b/tests/src/com/android/ims/rcs/uce/presence/publish/PublishControllerImplTest.java @@ -43,6 +43,7 @@ import androidx.test.filters.SmallTest; import com.android.ims.RcsFeatureManager; import com.android.ims.rcs.uce.UceController; import com.android.ims.rcs.uce.UceDeviceState.DeviceStateResult; +import com.android.ims.rcs.uce.UceStatsWriter; import com.android.ims.rcs.uce.presence.publish.PublishController.PublishControllerCallback; import com.android.ims.rcs.uce.presence.publish.PublishControllerImpl.DeviceCapListenerFactory; import com.android.ims.rcs.uce.presence.publish.PublishControllerImpl.PublishProcessorFactory; @@ -68,6 +69,7 @@ public class PublishControllerImplTest extends ImsTestBase { @Mock UceController.UceControllerCallback mUceCtrlCallback; @Mock RemoteCallbackList<IRcsUcePublishStateCallback> mPublishStateCallbacks; @Mock DeviceStateResult mDeviceStateResult; + @Mock UceStatsWriter mUceStatsWriter; private int mSubId = 1; @@ -77,7 +79,7 @@ public class PublishControllerImplTest extends ImsTestBase { doReturn(mPublishProcessor).when(mPublishProcessorFactory).createPublishProcessor(any(), eq(mSubId), any(), any()); doReturn(mDeviceCapListener).when(mDeviceCapListenerFactory).createDeviceCapListener(any(), - eq(mSubId), any(), any()); + eq(mSubId), any(), any(), any()); doReturn(mDeviceStateResult).when(mUceCtrlCallback).getDeviceState(); doReturn(false).when(mDeviceStateResult).isRequestForbidden(); } @@ -162,6 +164,8 @@ public class PublishControllerImplTest extends ImsTestBase { @SmallTest public void testUnpublish() throws Exception { PublishControllerImpl publishController = createPublishController(); + //To initialize the public state to publish_ok. + publishController.setCapabilityType(RcsImsCapabilities.CAPABILITY_TYPE_OPTIONS_UCE); publishController.onUnpublish(); @@ -169,6 +173,8 @@ public class PublishControllerImplTest extends ImsTestBase { waitForHandlerAction(handler, 1000); int publishState = publishController.getUcePublishState(); assertEquals(RcsUceAdapter.PUBLISH_STATE_NOT_PUBLISHED, publishState); + verify(mPublishProcessor).resetState(); + verify(mUceStatsWriter).setUnPublish(eq(mSubId)); } @Test @@ -349,7 +355,7 @@ public class PublishControllerImplTest extends ImsTestBase { private PublishControllerImpl createPublishController() { PublishControllerImpl publishController = new PublishControllerImpl(mContext, mSubId, mUceCtrlCallback, Looper.getMainLooper(), mDeviceCapListenerFactory, - mPublishProcessorFactory); + mPublishProcessorFactory, mUceStatsWriter); publishController.setPublishStateCallback(mPublishStateCallbacks); publishController.setCapabilityType(RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE); return publishController; diff --git a/tests/src/com/android/ims/rcs/uce/presence/publish/PublishProcessorTest.java b/tests/src/com/android/ims/rcs/uce/presence/publish/PublishProcessorTest.java index d83158f5..d894c331 100644 --- a/tests/src/com/android/ims/rcs/uce/presence/publish/PublishProcessorTest.java +++ b/tests/src/com/android/ims/rcs/uce/presence/publish/PublishProcessorTest.java @@ -34,6 +34,7 @@ import androidx.test.filters.SmallTest; import com.android.ims.ImsTestBase; import com.android.ims.RcsFeatureManager; +import com.android.ims.rcs.uce.UceStatsWriter; import com.android.ims.rcs.uce.presence.publish.PublishController.PublishControllerCallback; import org.junit.After; @@ -42,6 +43,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +import java.util.Optional; @RunWith(AndroidJUnit4.class) public class PublishProcessorTest extends ImsTestBase { @@ -50,6 +52,7 @@ public class PublishProcessorTest extends ImsTestBase { @Mock PublishControllerCallback mPublishCtrlCallback; @Mock PublishProcessorState mProcessorState; @Mock PublishRequestResponse mResponseCallback; + @Mock UceStatsWriter mUceStatsWriter; private int mSub = 1; private long mTaskId = 1L; @@ -144,6 +147,8 @@ public class PublishProcessorTest extends ImsTestBase { doReturn(mTaskId).when(mProcessorState).getCurrentTaskId(); doReturn(mTaskId).when(mResponseCallback).getTaskId(); doReturn(true).when(mResponseCallback).needRetry(); + doReturn(Optional.of(10)).when(mResponseCallback).getCmdErrorCode(); + PublishProcessor publishProcessor = getPublishProcessor(); publishProcessor.onCommandError(mResponseCallback); @@ -154,6 +159,8 @@ public class PublishProcessorTest extends ImsTestBase { verify(mResponseCallback).onDestroy(); verify(mProcessorState).setPublishingFlag(false); verify(mPublishCtrlCallback).clearRequestCanceledTimer(); + verify(mUceStatsWriter).setUceEvent(eq(mSub), eq(UceStatsWriter.PUBLISH_EVENT), eq(true), + eq(10), eq(0)); } @Test @@ -200,6 +207,7 @@ public class PublishProcessorTest extends ImsTestBase { doReturn(mTaskId).when(mResponseCallback).getTaskId(); doReturn(false).when(mResponseCallback).needRetry(); doReturn(true).when(mResponseCallback).isRequestSuccess(); + doReturn(Optional.of(200)).when(mResponseCallback).getNetworkRespSipCode(); PublishProcessor publishProcessor = getPublishProcessor(); publishProcessor.onNetworkResponse(mResponseCallback); @@ -208,6 +216,9 @@ public class PublishProcessorTest extends ImsTestBase { verify(mResponseCallback).onDestroy(); verify(mProcessorState).setPublishingFlag(false); verify(mPublishCtrlCallback).clearRequestCanceledTimer(); + + verify(mUceStatsWriter).setUceEvent(eq(mSub), eq(UceStatsWriter.PUBLISH_EVENT), eq(true), + eq(0), eq(200)); } @Test @@ -223,7 +234,7 @@ public class PublishProcessorTest extends ImsTestBase { private PublishProcessor getPublishProcessor() { PublishProcessor publishProcessor = new PublishProcessor(mContext, mSub, - mDeviceCapabilities, mPublishCtrlCallback); + mDeviceCapabilities, mPublishCtrlCallback, mUceStatsWriter); publishProcessor.setProcessorState(mProcessorState); publishProcessor.onRcsConnected(mRcsFeatureManager); return publishProcessor; diff --git a/tests/src/com/android/ims/rcs/uce/request/OptionsCoordinatorTest.java b/tests/src/com/android/ims/rcs/uce/request/OptionsCoordinatorTest.java index 9c270fbf..1759de5d 100644 --- a/tests/src/com/android/ims/rcs/uce/request/OptionsCoordinatorTest.java +++ b/tests/src/com/android/ims/rcs/uce/request/OptionsCoordinatorTest.java @@ -38,11 +38,13 @@ import androidx.test.filters.SmallTest; import com.android.ims.ImsTestBase; import com.android.ims.rcs.uce.request.UceRequestCoordinator.RequestResult; import com.android.ims.rcs.uce.request.UceRequestManager.RequestManagerCallback; +import com.android.ims.rcs.uce.UceStatsWriter; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Optional; import org.junit.After; import org.junit.Before; @@ -57,6 +59,7 @@ public class OptionsCoordinatorTest extends ImsTestBase { @Mock CapabilityRequestResponse mResponse; @Mock RequestManagerCallback mRequestMgrCallback; @Mock IRcsUceControllerCallback mUceCallback; + @Mock UceStatsWriter mUceStatsWriter; private int mSubId = 1; private long mTaskId = 1L; @@ -93,11 +96,14 @@ public class OptionsCoordinatorTest extends ImsTestBase { @Test @SmallTest public void testRequestCommandError() throws Exception { + doReturn(Optional.of(3)).when(mResponse).getCommandError(); OptionsRequestCoordinator coordinator = getOptionsCoordinator(); coordinator.onRequestUpdated(mTaskId, REQUEST_UPDATE_COMMAND_ERROR); verify(mRequest).onFinish(); + verify(mUceStatsWriter).setUceEvent(eq(mSubId), eq(UceStatsWriter.OUTGOING_OPTION_EVENT), + eq(false), eq(3), eq(0)); Collection<UceRequest> requestList = coordinator.getActivatedRequest(); Collection<RequestResult> resultList = coordinator.getFinishedRequest(); @@ -111,6 +117,7 @@ public class OptionsCoordinatorTest extends ImsTestBase { public void testRequestNetworkResponse() throws Exception { OptionsRequestCoordinator coordinator = getOptionsCoordinator(); doReturn(true).when(mResponse).isNetworkResponseOK(); + doReturn(Optional.of(200)).when(mResponse).getNetworkRespSipCode(); final List<RcsContactUceCapability> updatedCapList = new ArrayList<>(); RcsContactUceCapability updatedCapability = getContactUceCapability(); @@ -124,6 +131,8 @@ public class OptionsCoordinatorTest extends ImsTestBase { verify(mResponse).removeUpdatedCapabilities(updatedCapList); verify(mRequest).onFinish(); + verify(mUceStatsWriter).setUceEvent(eq(mSubId), eq(UceStatsWriter.OUTGOING_OPTION_EVENT), + eq(true), eq(0), eq(200)); Collection<UceRequest> requestList = coordinator.getActivatedRequest(); Collection<RequestResult> resultList = coordinator.getFinishedRequest(); @@ -134,9 +143,10 @@ public class OptionsCoordinatorTest extends ImsTestBase { private OptionsRequestCoordinator getOptionsCoordinator() { OptionsRequestCoordinator.Builder builder = new OptionsRequestCoordinator.Builder( - mSubId, Collections.singletonList(mRequest), mRequestMgrCallback); + mSubId, Collections.singletonList(mRequest), mRequestMgrCallback, mUceStatsWriter); builder.setCapabilitiesCallback(mUceCallback); - return builder.build(); + OptionsRequestCoordinator coordinator = builder.build(); + return coordinator; } private RcsContactUceCapability getContactUceCapability() { diff --git a/tests/src/com/android/ims/rcs/uce/request/RemoteOptionsCoordinatorTest.java b/tests/src/com/android/ims/rcs/uce/request/RemoteOptionsCoordinatorTest.java index 1a6ed4a4..80077114 100644 --- a/tests/src/com/android/ims/rcs/uce/request/RemoteOptionsCoordinatorTest.java +++ b/tests/src/com/android/ims/rcs/uce/request/RemoteOptionsCoordinatorTest.java @@ -37,6 +37,7 @@ import com.android.ims.ImsTestBase; import com.android.ims.rcs.uce.request.RemoteOptionsRequest.RemoteOptResponse; import com.android.ims.rcs.uce.request.UceRequestCoordinator.RequestResult; import com.android.ims.rcs.uce.request.UceRequestManager.RequestManagerCallback; +import com.android.ims.rcs.uce.UceStatsWriter; import java.util.Collection; import java.util.Collections; @@ -54,6 +55,7 @@ public class RemoteOptionsCoordinatorTest extends ImsTestBase { @Mock RemoteOptResponse mResponse; @Mock RequestManagerCallback mRequestMgrCallback; @Mock IOptionsRequestCallback mOptRequestCallback; + @Mock UceStatsWriter mUceStatsWriter; private int mSubId = 1; private long mTaskId = 1L; @@ -84,6 +86,8 @@ public class RemoteOptionsCoordinatorTest extends ImsTestBase { verify(mOptRequestCallback).respondToCapabilityRequest(updatedCapability, true); verify(mRequest).onFinish(); + verify(mUceStatsWriter).setUceEvent(eq(mSubId), eq(UceStatsWriter.INCOMING_OPTION_EVENT), + eq(true), eq(0), eq(200)); Collection<UceRequest> requestList = coordinator.getActivatedRequest(); Collection<RequestResult> resultList = coordinator.getFinishedRequest(); @@ -94,7 +98,7 @@ public class RemoteOptionsCoordinatorTest extends ImsTestBase { private RemoteOptionsCoordinator getRemoteOptCoordinator() { RemoteOptionsCoordinator.Builder builder = new RemoteOptionsCoordinator.Builder( - mSubId, Collections.singletonList(mRequest), mRequestMgrCallback); + mSubId, Collections.singletonList(mRequest), mRequestMgrCallback, mUceStatsWriter); builder.setOptionsRequestCallback(mOptRequestCallback); return builder.build(); } diff --git a/tests/src/com/android/ims/rcs/uce/request/SubscribeCoordinatorTest.java b/tests/src/com/android/ims/rcs/uce/request/SubscribeCoordinatorTest.java index 137b4ac7..bcd3c98d 100644 --- a/tests/src/com/android/ims/rcs/uce/request/SubscribeCoordinatorTest.java +++ b/tests/src/com/android/ims/rcs/uce/request/SubscribeCoordinatorTest.java @@ -39,6 +39,7 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import android.net.Uri; +import android.telephony.ims.RcsContactPresenceTuple; import android.telephony.ims.RcsContactUceCapability; import android.telephony.ims.aidl.IRcsUceControllerCallback; @@ -47,6 +48,7 @@ import androidx.test.filters.SmallTest; import com.android.ims.ImsTestBase; import com.android.ims.rcs.uce.UceDeviceState.DeviceStateResult; +import com.android.ims.rcs.uce.UceStatsWriter; import com.android.ims.rcs.uce.request.UceRequestCoordinator.RequestResult; import com.android.ims.rcs.uce.request.UceRequestManager.RequestManagerCallback; @@ -70,6 +72,7 @@ public class SubscribeCoordinatorTest extends ImsTestBase { @Mock RequestManagerCallback mRequestMgrCallback; @Mock IRcsUceControllerCallback mUceCallback; @Mock DeviceStateResult mDeviceStateResult; + @Mock UceStatsWriter mUceStatsWriter; private int mSubId = 1; private long mTaskId = 1L; @@ -106,6 +109,7 @@ public class SubscribeCoordinatorTest extends ImsTestBase { @Test @SmallTest public void testRequestCommandError() throws Exception { + doReturn(Optional.of(3)).when(mResponse).getCommandError(); SubscribeRequestCoordinator coordinator = getSubscribeCoordinator(); coordinator.onRequestUpdated(mTaskId, REQUEST_UPDATE_COMMAND_ERROR); @@ -114,6 +118,9 @@ public class SubscribeCoordinatorTest extends ImsTestBase { Collection<RequestResult> resultList = coordinator.getFinishedRequest(); assertTrue(requestList.isEmpty()); assertEquals(1, resultList.size()); + + verify(mUceStatsWriter).setUceEvent(eq(mSubId), eq(UceStatsWriter.SUBSCRIBE_EVENT), + eq(false), eq(3), eq(0)); verify(mRequest).onFinish(); } @@ -122,6 +129,7 @@ public class SubscribeCoordinatorTest extends ImsTestBase { public void testRequestNetworkRespSuccess() throws Exception { SubscribeRequestCoordinator coordinator = getSubscribeCoordinator(); doReturn(true).when(mResponse).isNetworkResponseOK(); + doReturn(Optional.of(200)).when(mResponse).getNetworkRespSipCode(); coordinator.onRequestUpdated(mTaskId, REQUEST_UPDATE_NETWORK_RESPONSE); @@ -129,11 +137,28 @@ public class SubscribeCoordinatorTest extends ImsTestBase { Collection<RequestResult> resultList = coordinator.getFinishedRequest(); assertEquals(1, requestList.size()); assertTrue(resultList.isEmpty()); + + verify(mUceStatsWriter).setSubscribeResponse(eq(mSubId), eq(mTaskId), eq(200)); + verify(mRequest, never()).onFinish(); } @Test @SmallTest + public void testRequestNetworkRespFailure() throws Exception { + doReturn(Optional.of(400)).when(mResponse).getNetworkRespSipCode(); + + SubscribeRequestCoordinator coordinator = getSubscribeCoordinator(); + + coordinator.onRequestUpdated(mTaskId, REQUEST_UPDATE_NETWORK_RESPONSE); + + verify(mUceStatsWriter).setSubscribeResponse(eq(mSubId), eq(mTaskId), eq(400)); + + verify(mRequest).onFinish(); + } + + @Test + @SmallTest public void testRequestNetworkRespError() throws Exception { SubscribeRequestCoordinator coordinator = getSubscribeCoordinator(); doReturn(false).when(mResponse).isNetworkResponseOK(); @@ -162,7 +187,8 @@ public class SubscribeCoordinatorTest extends ImsTestBase { SubscribeRequestCoordinator coordinator = getSubscribeCoordinator(); final List<RcsContactUceCapability> updatedCapList = new ArrayList<>(); - RcsContactUceCapability updatedCapability = getContactUceCapability(); + RcsContactPresenceTuple tuple = getContactPresenceTuple(); + RcsContactUceCapability updatedCapability = getContactUceCapability(tuple); updatedCapList.add(updatedCapability); doReturn(updatedCapList).when(mResponse).getUpdatedContactCapability(); @@ -171,6 +197,8 @@ public class SubscribeCoordinatorTest extends ImsTestBase { verify(mRequestMgrCallback).saveCapabilities(updatedCapList); verify(mUceCallback).onCapabilitiesReceived(updatedCapList); verify(mResponse).removeUpdatedCapabilities(updatedCapList); + + verify(mUceStatsWriter).setPresenceNotifyEvent(eq(mSubId), eq(mTaskId), any()); } @Test @@ -188,6 +216,8 @@ public class SubscribeCoordinatorTest extends ImsTestBase { verify(mRequestMgrCallback).saveCapabilities(updatedCapList); verify(mUceCallback).onCapabilitiesReceived(updatedCapList); verify(mResponse).removeTerminatedResources(updatedCapList); + + verify(mUceStatsWriter).setPresenceNotifyEvent(eq(mSubId), eq(mTaskId), any()); } @Test @@ -211,12 +241,16 @@ public class SubscribeCoordinatorTest extends ImsTestBase { public void testRequestTerminated() throws Exception { SubscribeRequestCoordinator coordinator = getSubscribeCoordinator(); + doReturn("noresource").when(mResponse).getTerminatedReason(); + coordinator.onRequestUpdated(mTaskId, REQUEST_UPDATE_TERMINATED); Collection<UceRequest> requestList = coordinator.getActivatedRequest(); Collection<RequestResult> resultList = coordinator.getFinishedRequest(); assertTrue(requestList.isEmpty()); assertEquals(1, resultList.size()); + + verify(mUceStatsWriter).setSubscribeTerminated(eq(mSubId), eq(mTaskId), eq("noresource")); } @Test @@ -234,8 +268,18 @@ public class SubscribeCoordinatorTest extends ImsTestBase { private SubscribeRequestCoordinator getSubscribeCoordinator() { SubscribeRequestCoordinator.Builder builder = new SubscribeRequestCoordinator.Builder( - mSubId, Collections.singletonList(mRequest), mRequestMgrCallback); + mSubId, Collections.singletonList(mRequest), mRequestMgrCallback, mUceStatsWriter); builder.setCapabilitiesCallback(mUceCallback); + SubscribeRequestCoordinator subCoor = builder.build(); + return subCoor; + } + + private RcsContactUceCapability getContactUceCapability(RcsContactPresenceTuple tuple) { + int requestResult = RcsContactUceCapability.REQUEST_RESULT_FOUND; + RcsContactUceCapability.PresenceBuilder builder = + new RcsContactUceCapability.PresenceBuilder( + mContact, RcsContactUceCapability.SOURCE_TYPE_NETWORK, requestResult); + builder.addCapabilityTuple(tuple); return builder.build(); } @@ -246,4 +290,12 @@ public class SubscribeCoordinatorTest extends ImsTestBase { mContact, RcsContactUceCapability.SOURCE_TYPE_NETWORK, requestResult); return builder.build(); } + + private RcsContactPresenceTuple getContactPresenceTuple() { + RcsContactPresenceTuple.Builder builder = + new RcsContactPresenceTuple.Builder("open", RcsContactPresenceTuple.SERVICE_ID_CHAT_V1, + "1.0"); + return builder.build(); + + } } |