
src.com.android.internal.telephony.metrics.RcsStats Maven / Gradle / Ivy
/*
* 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.internal.telephony.metrics;
import static android.text.format.DateUtils.SECOND_IN_MILLIS;
import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CALL_COMPOSER;
import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHATBOT;
import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHATBOT_ROLE;
import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHATBOT_STANDALONE;
import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHAT_V1;
import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHAT_V2;
import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CUSTOM;
import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_FT;
import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_FT_OVER_SMS;
import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_GEO_PUSH;
import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_GEO_PUSH_VIA_SMS;
import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_MMTEL;
import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_POST_CALL;
import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_SHARED_MAP;
import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_SHARED_SKETCH;
import static com.android.internal.telephony.TelephonyStatsLog.PRESENCE_NOTIFY_EVENT__REASON__REASON_CUSTOM;
import static com.android.internal.telephony.TelephonyStatsLog.PRESENCE_NOTIFY_EVENT__REASON__REASON_DEACTIVATED;
import static com.android.internal.telephony.TelephonyStatsLog.PRESENCE_NOTIFY_EVENT__REASON__REASON_GIVEUP;
import static com.android.internal.telephony.TelephonyStatsLog.PRESENCE_NOTIFY_EVENT__REASON__REASON_NORESOURCE;
import static com.android.internal.telephony.TelephonyStatsLog.PRESENCE_NOTIFY_EVENT__REASON__REASON_PROBATION;
import static com.android.internal.telephony.TelephonyStatsLog.PRESENCE_NOTIFY_EVENT__REASON__REASON_REJECTED;
import static com.android.internal.telephony.TelephonyStatsLog.PRESENCE_NOTIFY_EVENT__REASON__REASON_TIMEOUT;
import static com.android.internal.telephony.TelephonyStatsLog.RCS_ACS_PROVISIONING_STATS__RESPONSE_TYPE__ERROR;
import static com.android.internal.telephony.TelephonyStatsLog.RCS_ACS_PROVISIONING_STATS__RESPONSE_TYPE__PRE_PROVISIONING_XML;
import static com.android.internal.telephony.TelephonyStatsLog.UCE_EVENT_STATS__TYPE__INCOMING_OPTION;
import static com.android.internal.telephony.TelephonyStatsLog.UCE_EVENT_STATS__TYPE__OUTGOING_OPTION;
import static com.android.internal.telephony.TelephonyStatsLog.UCE_EVENT_STATS__TYPE__PUBLISH;
import static com.android.internal.telephony.TelephonyStatsLog.UCE_EVENT_STATS__TYPE__SUBSCRIBE;
import android.annotation.NonNull;
import android.os.Binder;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.TelephonyProtoEnums;
import android.telephony.ims.FeatureTagState;
import android.telephony.ims.RcsContactPresenceTuple;
import android.telephony.ims.RcsContactUceCapability;
import android.telephony.ims.aidl.IRcsConfigCallback;
import android.util.Base64;
import android.util.IndentingPrintWriter;
import com.android.ims.rcs.uce.UceStatsWriter;
import com.android.ims.rcs.uce.UceStatsWriter.UceStatsCallback;
import com.android.ims.rcs.uce.util.FeatureTags;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.nano.PersistAtomsProto;
import com.android.internal.telephony.nano.PersistAtomsProto.GbaEvent;
import com.android.internal.telephony.nano.PersistAtomsProto.ImsDedicatedBearerEvent;
import com.android.internal.telephony.nano.PersistAtomsProto.ImsDedicatedBearerListenerEvent;
import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationFeatureTagStats;
import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationServiceDescStats;
import com.android.internal.telephony.nano.PersistAtomsProto.PresenceNotifyEvent;
import com.android.internal.telephony.nano.PersistAtomsProto.RcsAcsProvisioningStats;
import com.android.internal.telephony.nano.PersistAtomsProto.RcsClientProvisioningStats;
import com.android.internal.telephony.nano.PersistAtomsProto.SipDelegateStats;
import com.android.internal.telephony.nano.PersistAtomsProto.SipMessageResponse;
import com.android.internal.telephony.nano.PersistAtomsProto.SipTransportFeatureTagStats;
import com.android.internal.telephony.nano.PersistAtomsProto.SipTransportSession;
import com.android.internal.telephony.nano.PersistAtomsProto.UceEventStats;
import com.android.telephony.Rlog;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
/** Tracks RCS provisioning, sip transport, UCE metrics for phone. */
public class RcsStats {
private static final String TAG = RcsStats.class.getSimpleName();
private static final long MIN_DURATION_MILLIS = 1L * SECOND_IN_MILLIS;
private final PersistAtomsStorage mAtomsStorage =
PhoneFactory.getMetricsCollector().getAtomsStorage();
private static final Random RANDOM = new Random();
private UceStatsWriterCallback mCallback;
private static RcsStats sInstance;
public static final int NONE = -1;
public static final int STATE_REGISTERED = 0;
public static final int STATE_DEREGISTERED = 1;
public static final int STATE_DENIED = 2;
private static final String SIP_REQUEST_MESSAGE_TYPE_INVITE = "INVITE";
private static final String SIP_REQUEST_MESSAGE_TYPE_ACK = "ACK";
private static final String SIP_REQUEST_MESSAGE_TYPE_OPTIONS = "OPTIONS";
private static final String SIP_REQUEST_MESSAGE_TYPE_BYE = "BYE";
private static final String SIP_REQUEST_MESSAGE_TYPE_CANCEL = "CANCEL";
private static final String SIP_REQUEST_MESSAGE_TYPE_REGISTER = "REGISTER";
private static final String SIP_REQUEST_MESSAGE_TYPE_PRACK = "PRACK";
private static final String SIP_REQUEST_MESSAGE_TYPE_SUBSCRIBE = "SUBSCRIBE";
private static final String SIP_REQUEST_MESSAGE_TYPE_NOTIFY = "NOTIFY";
private static final String SIP_REQUEST_MESSAGE_TYPE_PUBLISH = "PUBLISH";
private static final String SIP_REQUEST_MESSAGE_TYPE_INFO = "INFO";
private static final String SIP_REQUEST_MESSAGE_TYPE_REFER = "REFER";
private static final String SIP_REQUEST_MESSAGE_TYPE_MESSAGE = "MESSAGE";
private static final String SIP_REQUEST_MESSAGE_TYPE_UPDATE = "UPDATE";
/**
* Describe Feature Tags
* See frameworks/opt/net/ims/src/java/com/android/ims/rcs/uce/util/FeatureTags.java
* and int value matching the Feature Tags
* See stats/enums/telephony/enums.proto
*/
private static final Map FEATURE_TAGS = new HashMap<>();
static {
FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_STANDALONE_MSG.trim().toLowerCase(),
TelephonyProtoEnums.IMS_FEATURE_TAG_STANDALONE_MSG);
FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_CHAT_IM.trim().toLowerCase(),
TelephonyProtoEnums.IMS_FEATURE_TAG_CHAT_IM);
FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_CHAT_SESSION.trim().toLowerCase(),
TelephonyProtoEnums.IMS_FEATURE_TAG_CHAT_SESSION);
FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_FILE_TRANSFER.trim().toLowerCase(),
TelephonyProtoEnums.IMS_FEATURE_TAG_FILE_TRANSFER);
FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_FILE_TRANSFER_VIA_SMS.trim().toLowerCase(),
TelephonyProtoEnums.IMS_FEATURE_TAG_FILE_TRANSFER_VIA_SMS);
FEATURE_TAGS.put(
FeatureTags.FEATURE_TAG_CALL_COMPOSER_ENRICHED_CALLING.trim().toLowerCase(),
TelephonyProtoEnums.IMS_FEATURE_TAG_CALL_COMPOSER_ENRICHED_CALLING);
FEATURE_TAGS.put(
FeatureTags.FEATURE_TAG_CALL_COMPOSER_VIA_TELEPHONY.trim().toLowerCase(),
TelephonyProtoEnums.IMS_FEATURE_TAG_CALL_COMPOSER_VIA_TELEPHONY);
FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_POST_CALL.trim().toLowerCase(),
TelephonyProtoEnums.IMS_FEATURE_TAG_POST_CALL);
FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_SHARED_MAP.trim().toLowerCase(),
TelephonyProtoEnums.IMS_FEATURE_TAG_SHARED_MAP);
FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_SHARED_SKETCH.trim().toLowerCase(),
TelephonyProtoEnums.IMS_FEATURE_TAG_SHARED_SKETCH);
FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_GEO_PUSH.trim().toLowerCase(),
TelephonyProtoEnums.IMS_FEATURE_TAG_GEO_PUSH);
FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_GEO_PUSH_VIA_SMS.trim().toLowerCase(),
TelephonyProtoEnums.IMS_FEATURE_TAG_GEO_PUSH_VIA_SMS);
FEATURE_TAGS.put(
FeatureTags.FEATURE_TAG_CHATBOT_COMMUNICATION_USING_SESSION.trim().toLowerCase(),
TelephonyProtoEnums.IMS_FEATURE_TAG_CHATBOT_COMMUNICATION_USING_SESSION);
String FeatureTag = FeatureTags.FEATURE_TAG_CHATBOT_COMMUNICATION_USING_STANDALONE_MSG;
FEATURE_TAGS.put(FeatureTag.trim().toLowerCase(),
TelephonyProtoEnums.IMS_FEATURE_TAG_CHATBOT_COMMUNICATION_USING_STANDALONE_MSG);
FEATURE_TAGS.put(
FeatureTags.FEATURE_TAG_CHATBOT_VERSION_SUPPORTED.trim().toLowerCase(),
TelephonyProtoEnums.IMS_FEATURE_TAG_CHATBOT_VERSION_SUPPORTED);
FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_CHATBOT_ROLE.trim().toLowerCase(),
TelephonyProtoEnums.IMS_FEATURE_TAG_CHATBOT_ROLE);
FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_MMTEL.trim().toLowerCase(),
TelephonyProtoEnums.IMS_FEATURE_TAG_MMTEL);
FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_VIDEO.trim().toLowerCase(),
TelephonyProtoEnums.IMS_FEATURE_TAG_VIDEO);
FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_PRESENCE.trim().toLowerCase(),
TelephonyProtoEnums.IMS_FEATURE_TAG_PRESENCE);
}
/**
* Describe Service IDs
* See frameworks/base/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java
* and int value matching the service IDs
* See frameworks/proto_logging/stats/atoms.proto
*/
private static final Map SERVICE_IDS = new HashMap<>();
static {
SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_MMTEL.trim().toLowerCase(),
IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_MMTEL);
SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_CHAT_V1.trim().toLowerCase(),
IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHAT_V1);
SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_CHAT_V2.trim().toLowerCase(),
IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHAT_V2);
SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_FT.trim().toLowerCase(),
IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_FT);
SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_FT_OVER_SMS.trim().toLowerCase(),
IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_FT_OVER_SMS);
SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_GEO_PUSH.trim().toLowerCase(),
IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_GEO_PUSH);
SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_GEO_PUSH_VIA_SMS.trim().toLowerCase(),
IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_GEO_PUSH_VIA_SMS);
SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_CALL_COMPOSER.trim().toLowerCase(),
IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CALL_COMPOSER);
SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_POST_CALL.trim().toLowerCase(),
IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_POST_CALL);
SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_SHARED_MAP.trim().toLowerCase(),
IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_SHARED_MAP);
SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_SHARED_SKETCH.trim().toLowerCase(),
IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_SHARED_SKETCH);
SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_CHATBOT.trim().toLowerCase(),
IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHATBOT);
SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_CHATBOT_STANDALONE.trim().toLowerCase(),
IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHATBOT_STANDALONE
);
SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_CHATBOT_ROLE.trim().toLowerCase(),
IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHATBOT_ROLE);
}
/**
* Describe Message Method Type
* See stats/enums/telephony/enums.proto
*/
private static final Map MESSAGE_TYPE = new HashMap<>();
static {
MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_INVITE.trim().toLowerCase(),
TelephonyProtoEnums.SIP_REQUEST_INVITE);
MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_ACK.trim().toLowerCase(),
TelephonyProtoEnums.SIP_REQUEST_ACK);
MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_OPTIONS.trim().toLowerCase(),
TelephonyProtoEnums.SIP_REQUEST_OPTIONS);
MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_BYE.trim().toLowerCase(),
TelephonyProtoEnums.SIP_REQUEST_BYE);
MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_CANCEL.trim().toLowerCase(),
TelephonyProtoEnums.SIP_REQUEST_CANCEL);
MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_REGISTER.trim().toLowerCase(),
TelephonyProtoEnums.SIP_REQUEST_REGISTER);
MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_PRACK.trim().toLowerCase(),
TelephonyProtoEnums.SIP_REQUEST_PRACK);
MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_SUBSCRIBE.trim().toLowerCase(),
TelephonyProtoEnums.SIP_REQUEST_SUBSCRIBE);
MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_NOTIFY.trim().toLowerCase(),
TelephonyProtoEnums.SIP_REQUEST_NOTIFY);
MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_PUBLISH.trim().toLowerCase(),
TelephonyProtoEnums.SIP_REQUEST_PUBLISH);
MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_INFO.trim().toLowerCase(),
TelephonyProtoEnums.SIP_REQUEST_INFO);
MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_REFER.trim().toLowerCase(),
TelephonyProtoEnums.SIP_REQUEST_REFER);
MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_MESSAGE.trim().toLowerCase(),
TelephonyProtoEnums.SIP_REQUEST_MESSAGE);
MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_UPDATE.trim().toLowerCase(),
TelephonyProtoEnums.SIP_REQUEST_UPDATE);
}
/**
* Describe Reasons
* See frameworks/opt/net/ims/src/java/com/android/ims/rcs/uce/request/
* SubscriptionTerminatedHelper.java
* and int value matching the Reasons
* See frameworks/proto_logging/stats/atoms.proto
*/
private static final Map NOTIFY_REASONS = new HashMap<>();
static {
NOTIFY_REASONS.put("deactivated", PRESENCE_NOTIFY_EVENT__REASON__REASON_DEACTIVATED);
NOTIFY_REASONS.put("probation", PRESENCE_NOTIFY_EVENT__REASON__REASON_PROBATION);
NOTIFY_REASONS.put("rejected", PRESENCE_NOTIFY_EVENT__REASON__REASON_REJECTED);
NOTIFY_REASONS.put("timeout", PRESENCE_NOTIFY_EVENT__REASON__REASON_TIMEOUT);
NOTIFY_REASONS.put("giveup", PRESENCE_NOTIFY_EVENT__REASON__REASON_GIVEUP);
NOTIFY_REASONS.put("noresource", PRESENCE_NOTIFY_EVENT__REASON__REASON_NORESOURCE);
}
/**
* Describe Rcs Capability set
* See frameworks/base/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java
*/
private static final HashSet RCS_SERVICE_ID_SET = new HashSet<>();
static {
RCS_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_CHAT_V1);
RCS_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_CHAT_V2);
RCS_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_FT);
RCS_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_FT_OVER_SMS);
RCS_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_GEO_PUSH);
RCS_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_GEO_PUSH_VIA_SMS);
RCS_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_SHARED_MAP);
RCS_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_SHARED_SKETCH);
RCS_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_CHATBOT);
RCS_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_CHATBOT_STANDALONE);
RCS_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_CHATBOT_ROLE);
}
/**
* Describe Mmtel Capability set
* See frameworks/base/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java
*/
private static final HashSet MMTEL_SERVICE_ID_SET = new HashSet<>();
static {
MMTEL_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_MMTEL);
MMTEL_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_CALL_COMPOSER);
MMTEL_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_POST_CALL);
}
private static final Map sSubscribeTaskIds = new HashMap<>();
private static final int SUBSCRIBE_SUCCESS = 1;
private static final int SUBSCRIBE_NOTIFY = 2;
@VisibleForTesting
protected final Map mDedicatedBearerListenerEventMap =
new HashMap<>();
@VisibleForTesting
protected final List mRcsAcsProvisioningStatsList =
new ArrayList();
@VisibleForTesting
protected final HashMap mRcsProvisioningCallbackMap =
new HashMap<>();
// Maps feature tag name -> ImsRegistrationFeatureTagStats.
private final List mImsRegistrationFeatureTagStatsList =
new ArrayList<>();
// Maps service id -> ImsRegistrationServiceDescStats.
@VisibleForTesting
protected final List mImsRegistrationServiceDescStatsList =
new ArrayList<>();
private List mLastSipDelegateStatList = new ArrayList<>();
private HashMap mLastFeatureTagStatMap = new HashMap<>();
private ArrayList mSipMessageArray = new ArrayList<>();
private ArrayList mSipTransportSessionArray = new ArrayList<>();
private SipTransportSessionArray mSipTransportSession;
private SipMessageArray mSipMessage;
private class LastSipDelegateStat {
public int mSubId;
public SipDelegateStats mLastStat;
private Set mSupportedTags;
LastSipDelegateStat(int subId, Set supportedTags) {
mSubId = subId;
mSupportedTags = supportedTags;
}
public void createSipDelegateStat(int subId) {
mLastStat = getDefaultSipDelegateStat(subId);
mLastStat.uptimeMillis = getWallTimeMillis();
mLastStat.destroyReason = NONE;
}
public void setSipDelegateDestroyReason(int destroyReason) {
mLastStat.destroyReason = destroyReason;
}
public boolean isDestroyed() {
return mLastStat.destroyReason > NONE;
}
public void conclude(long now) {
long duration = now - mLastStat.uptimeMillis;
if (duration < MIN_DURATION_MILLIS) {
logd("concludeSipDelegateStat: discarding transient stats,"
+ " duration= " + duration);
} else {
mLastStat.uptimeMillis = duration;
mAtomsStorage.addSipDelegateStats(copyOf(mLastStat));
}
mLastStat.uptimeMillis = now;
}
public boolean compare(int subId, Set supportedTags) {
if (subId != mSubId || supportedTags == null || supportedTags.isEmpty()) {
return false;
}
for (String tag : supportedTags) {
if (!mSupportedTags.contains(tag)) {
return false;
}
}
return true;
}
private SipDelegateStats getDefaultSipDelegateStat(int subId) {
SipDelegateStats stat = new SipDelegateStats();
stat.dimension = RANDOM.nextInt();
stat.carrierId = getCarrierId(subId);
stat.slotId = getSlotId(subId);
return stat;
}
}
private static SipDelegateStats copyOf(@NonNull SipDelegateStats source) {
SipDelegateStats newStat = new SipDelegateStats();
newStat.dimension = source.dimension;
newStat.slotId = source.slotId;
newStat.carrierId = source.carrierId;
newStat.destroyReason = source.destroyReason;
newStat.uptimeMillis = source.uptimeMillis;
return newStat;
}
private class SipTransportFeatureTags {
private HashMap mFeatureTagMap;
private int mSubId;
private class LastFeatureTagState {
public long timeStamp;
public int carrierId;
public int slotId;
public int state;
public int reason;
LastFeatureTagState(int carrierId, int slotId, int state, int reason, long timeStamp) {
this.carrierId = carrierId;
this.slotId = slotId;
this.state = state;
this.reason = reason;
this.timeStamp = timeStamp;
}
public void update(int state, int reason, long timeStamp) {
this.state = state;
this.reason = reason;
this.timeStamp = timeStamp;
}
public void update(long timeStamp) {
this.timeStamp = timeStamp;
}
}
SipTransportFeatureTags(int subId) {
mFeatureTagMap = new HashMap<>();
mSubId = subId;
}
public HashMap getLastTagStates() {
return mFeatureTagMap;
}
/*** Create or update featureTags whenever feature Tag states are changed */
public synchronized void updateLastFeatureTagState(String tagName, int state, int reason,
long timeStamp) {
int carrierId = getCarrierId(mSubId);
int slotId = getSlotId(mSubId);
if (mFeatureTagMap.containsKey(tagName)) {
LastFeatureTagState lastFeatureTagState = mFeatureTagMap.get(tagName);
if (lastFeatureTagState != null) {
addFeatureTagStat(tagName, lastFeatureTagState, timeStamp);
lastFeatureTagState.update(state, reason, timeStamp);
} else {
create(tagName, carrierId, slotId, state, reason, timeStamp);
}
} else {
create(tagName, carrierId, slotId, state, reason, timeStamp);
}
}
/** Update current featureTags associated to active SipDelegates when metrics is pulled */
public synchronized void conclude(long timeStamp) {
HashMap featureTagsCopy = new HashMap<>();
featureTagsCopy.putAll(mFeatureTagMap);
for (Map.Entry last : featureTagsCopy.entrySet()) {
String tagName = last.getKey();
LastFeatureTagState lastFeatureTagState = last.getValue();
addFeatureTagStat(tagName, lastFeatureTagState, timeStamp);
updateTimeStamp(mSubId, tagName, timeStamp);
}
}
/** Finalizes the durations of the current featureTags associated to active SipDelegates */
private synchronized boolean addFeatureTagStat(@NonNull String tagName,
@NonNull LastFeatureTagState lastFeatureTagState, long now) {
long duration = now - lastFeatureTagState.timeStamp;
if (duration < MIN_DURATION_MILLIS
|| !isValidCarrierId(lastFeatureTagState.carrierId)) {
logd("conclude: discarding transient stats, duration= " + duration
+ ", carrierId = " + lastFeatureTagState.carrierId);
} else {
SipTransportFeatureTagStats sipFeatureTagStat = new SipTransportFeatureTagStats();
switch (lastFeatureTagState.state) {
case STATE_DENIED:
sipFeatureTagStat.sipTransportDeniedReason = lastFeatureTagState.reason;
sipFeatureTagStat.sipTransportDeregisteredReason = NONE;
break;
case STATE_DEREGISTERED:
sipFeatureTagStat.sipTransportDeniedReason = NONE;
sipFeatureTagStat.sipTransportDeregisteredReason =
lastFeatureTagState.reason;
break;
default:
sipFeatureTagStat.sipTransportDeniedReason = NONE;
sipFeatureTagStat.sipTransportDeregisteredReason = NONE;
break;
}
sipFeatureTagStat.carrierId = lastFeatureTagState.carrierId;
sipFeatureTagStat.slotId = lastFeatureTagState.slotId;
sipFeatureTagStat.associatedMillis = duration;
sipFeatureTagStat.featureTagName = convertTagNameToValue(tagName);
mAtomsStorage.addSipTransportFeatureTagStats(sipFeatureTagStat);
return true;
}
return false;
}
private void updateTimeStamp(int subId, String tagName, long timeStamp) {
SipTransportFeatureTags sipTransportFeatureTags = mLastFeatureTagStatMap.get(subId);
if (sipTransportFeatureTags != null) {
HashMap lastTagStates =
sipTransportFeatureTags.getLastTagStates();
if (lastTagStates != null && lastTagStates.containsKey(tagName)) {
LastFeatureTagState lastFeatureTagState = lastTagStates.get(tagName);
if (lastFeatureTagState != null) {
lastFeatureTagState.update(timeStamp);
}
}
}
}
private LastFeatureTagState create(String tagName, int carrierId, int slotId, int state,
int reason, long timeStamp) {
LastFeatureTagState lastFeatureTagState = new LastFeatureTagState(carrierId, slotId,
state, reason, timeStamp);
mFeatureTagMap.put(tagName, lastFeatureTagState);
return lastFeatureTagState;
}
}
class UceStatsWriterCallback implements UceStatsCallback {
private RcsStats mRcsStats;
UceStatsWriterCallback(RcsStats rcsStats) {
logd("created Callback");
mRcsStats = rcsStats;
}
public void onImsRegistrationFeatureTagStats(int subId, List featureTagList,
int registrationTech) {
mRcsStats.onImsRegistrationFeatureTagStats(subId, featureTagList, registrationTech);
}
public void onStoreCompleteImsRegistrationFeatureTagStats(int subId) {
mRcsStats.onStoreCompleteImsRegistrationFeatureTagStats(subId);
}
public void onImsRegistrationServiceDescStats(int subId, List serviceIdList,
List serviceIdVersionList, int registrationTech) {
mRcsStats.onImsRegistrationServiceDescStats(subId, serviceIdList, serviceIdVersionList,
registrationTech);
}
public void onSubscribeResponse(int subId, long taskId, int networkResponse) {
if (networkResponse >= 200 && networkResponse <= 299) {
if (!sSubscribeTaskIds.containsKey(taskId)) {
sSubscribeTaskIds.put(taskId, SUBSCRIBE_SUCCESS);
}
}
mRcsStats.onUceEventStats(subId, UCE_EVENT_STATS__TYPE__SUBSCRIBE,
true, 0, networkResponse);
}
public void onUceEvent(int subId, int type, boolean successful, int commandCode,
int networkResponse) {
int eventType = 0;
switch (type) {
case UceStatsWriter.PUBLISH_EVENT:
eventType = UCE_EVENT_STATS__TYPE__PUBLISH;
break;
case UceStatsWriter.SUBSCRIBE_EVENT:
eventType = UCE_EVENT_STATS__TYPE__SUBSCRIBE;
break;
case UceStatsWriter.INCOMING_OPTION_EVENT:
eventType = UCE_EVENT_STATS__TYPE__INCOMING_OPTION;
break;
case UceStatsWriter.OUTGOING_OPTION_EVENT:
eventType = UCE_EVENT_STATS__TYPE__OUTGOING_OPTION;
break;
default:
return;
}
mRcsStats.onUceEventStats(subId, eventType, successful, commandCode, networkResponse);
}
public void onSubscribeTerminated(int subId, long taskId, String reason) {
if (sSubscribeTaskIds.containsKey(taskId)) {
int previousSubscribeStatus = sSubscribeTaskIds.get(taskId);
sSubscribeTaskIds.remove(taskId);
// The device received a success response related to the subscription request.
// However, PIDF was not received due to reason value.
if (previousSubscribeStatus == SUBSCRIBE_SUCCESS) {
mRcsStats.onPresenceNotifyEvent(subId, reason, false,
false, false, false);
}
}
}
public void onPresenceNotifyEvent(int subId, long taskId,
List updatedCapList) {
if (updatedCapList == null || updatedCapList.isEmpty()) {
return;
}
if (sSubscribeTaskIds.containsKey(taskId)) {
sSubscribeTaskIds.replace(taskId, SUBSCRIBE_NOTIFY);
}
for (RcsContactUceCapability capability : updatedCapList) {
boolean rcsCap = false;
boolean mmtelCap = false;
boolean noCap = true;
List tupleList = capability.getCapabilityTuples();
if (tupleList.isEmpty()) {
noCap = true;
mRcsStats.onPresenceNotifyEvent(subId, "", true,
rcsCap, mmtelCap, noCap);
continue;
}
for (RcsContactPresenceTuple tuple : tupleList) {
String serviceId = tuple.getServiceId();
if (RCS_SERVICE_ID_SET.contains(serviceId)) {
rcsCap = true;
noCap = false;
} else if (MMTEL_SERVICE_ID_SET.contains(serviceId)) {
if (serviceId.equals(RcsContactPresenceTuple.SERVICE_ID_CALL_COMPOSER)) {
if ("1.0".equals(tuple.getServiceVersion())) {
rcsCap = true;
noCap = false;
continue;
}
}
mmtelCap = true;
noCap = false;
}
}
mRcsStats.onPresenceNotifyEvent(subId, "", true, rcsCap,
mmtelCap, noCap);
}
}
public void onStoreCompleteImsRegistrationServiceDescStats(int subId) {
mRcsStats.onStoreCompleteImsRegistrationServiceDescStats(subId);
}
}
/** Callback class to receive RCS ACS result and to store metrics. */
public class RcsProvisioningCallback extends IRcsConfigCallback.Stub {
private RcsStats mRcsStats;
private int mSubId;
private boolean mEnableSingleRegistration;
private boolean mRegistered;
RcsProvisioningCallback(RcsStats rcsStats, int subId, boolean enableSingleRegistration) {
logd("created RcsProvisioningCallback");
mRcsStats = rcsStats;
mSubId = subId;
mEnableSingleRegistration = enableSingleRegistration;
mRegistered = false;
}
public synchronized void setEnableSingleRegistration(boolean enableSingleRegistration) {
mEnableSingleRegistration = enableSingleRegistration;
}
public boolean getRegistered() {
return mRegistered;
}
public void setRegistered(boolean registered) {
mRegistered = registered;
}
@Override
public void onConfigurationChanged(byte[] config) {
// this callback will not be handled.
}
@Override
public void onAutoConfigurationErrorReceived(int errorCode, String errorString) {
final long callingIdentity = Binder.clearCallingIdentity();
try {
mRcsStats.onRcsAcsProvisioningStats(mSubId, errorCode,
RCS_ACS_PROVISIONING_STATS__RESPONSE_TYPE__ERROR,
mEnableSingleRegistration);
} finally {
restoreCallingIdentity(callingIdentity);
}
}
@Override
public void onConfigurationReset() {
// this callback will not be handled.
}
@Override
public void onRemoved() {
final long callingIdentity = Binder.clearCallingIdentity();
try {
// store cached metrics
mRcsStats.onStoreCompleteRcsAcsProvisioningStats(mSubId);
// remove this obj from Map
mRcsStats.removeRcsProvisioningCallback(mSubId);
} finally {
restoreCallingIdentity(callingIdentity);
}
}
@Override
public void onPreProvisioningReceived(byte[] config) {
final long callingIdentity = Binder.clearCallingIdentity();
try {
// Receiving pre provisioning means http 200 OK with body.
mRcsStats.onRcsAcsProvisioningStats(mSubId, 200,
RCS_ACS_PROVISIONING_STATS__RESPONSE_TYPE__PRE_PROVISIONING_XML,
mEnableSingleRegistration);
} finally {
restoreCallingIdentity(callingIdentity);
}
}
};
private class SipMessageArray {
private String mMethod;
private String mCallId;
private int mDirection;
SipMessageArray(String method, int direction, String callId) {
this.mMethod = method;
this.mCallId = callId;
this.mDirection = direction;
}
private synchronized void addSipMessageStat(
@NonNull int subId, @NonNull String sipMessageMethod,
int sipMessageResponse, int sipMessageDirection, int messageError) {
int carrierId = getCarrierId(subId);
if (!isValidCarrierId(carrierId)) {
return;
}
SipMessageResponse proto = new SipMessageResponse();
proto.carrierId = carrierId;
proto.slotId = getSlotId(subId);
proto.sipMessageMethod = convertMessageTypeToValue(sipMessageMethod);
proto.sipMessageResponse = sipMessageResponse;
proto.sipMessageDirection = sipMessageDirection;
proto.messageError = messageError;
proto.count = 1;
mAtomsStorage.addSipMessageResponse(proto);
}
}
private class SipTransportSessionArray {
private String mMethod;
private String mCallId;
private int mDirection;
private int mSipResponse;
SipTransportSessionArray(String method, int direction, String callId) {
this.mMethod = method;
this.mCallId = callId;
this.mDirection = direction;
this.mSipResponse = 0;
}
private synchronized void addSipTransportSessionStat(
@NonNull int subId, @NonNull String sessionMethod, int sipMessageDirection,
int sipResponse, boolean isEndedGracefully) {
int carrierId = getCarrierId(subId);
if (!isValidCarrierId(carrierId)) {
return;
}
SipTransportSession proto = new SipTransportSession();
proto.carrierId = carrierId;
proto.slotId = getSlotId(subId);
proto.sessionMethod = convertMessageTypeToValue(sessionMethod);
proto.sipMessageDirection = sipMessageDirection;
proto.sipResponse = sipResponse;
proto.sessionCount = 1;
proto.endedGracefullyCount = 1;
proto.isEndedGracefully = isEndedGracefully;
mAtomsStorage.addCompleteSipTransportSession(proto);
}
}
@VisibleForTesting
protected RcsStats() {
mCallback = null;
}
/** Gets a RcsStats instance. */
public static RcsStats getInstance() {
synchronized (RcsStats.class) {
if (sInstance == null) {
Rlog.d(TAG, "RcsStats created.");
sInstance = new RcsStats();
}
return sInstance;
}
}
/** register callback to UceStatsWriter. */
public void registerUceCallback() {
if (mCallback == null) {
mCallback = new UceStatsWriterCallback(sInstance);
Rlog.d(TAG, "UceStatsWriterCallback created.");
UceStatsWriter.init(mCallback);
}
}
/** Update or create new atom when RCS service registered. */
public void onImsRegistrationFeatureTagStats(int subId, List featureTagList,
int registrationTech) {
synchronized (mImsRegistrationFeatureTagStatsList) {
int carrierId = getCarrierId(subId);
if (!isValidCarrierId(carrierId)) {
flushImsRegistrationFeatureTagStatsInvalid();
return;
}
// update cached atom if exists
onStoreCompleteImsRegistrationFeatureTagStats(subId);
if (featureTagList == null) {
Rlog.d(TAG, "featureTagNames is null or empty");
return;
}
for (String featureTag : featureTagList) {
ImsRegistrationFeatureTagStats proto = new ImsRegistrationFeatureTagStats();
proto.carrierId = carrierId;
proto.slotId = getSlotId(subId);
proto.featureTagName = convertTagNameToValue(featureTag);
proto.registrationTech = registrationTech;
proto.registeredMillis = getWallTimeMillis();
mImsRegistrationFeatureTagStatsList.add(proto);
}
}
}
/** Update duration, store and delete cached ImsRegistrationFeatureTagStats list to storage. */
public void onStoreCompleteImsRegistrationFeatureTagStats(int subId) {
synchronized (mImsRegistrationFeatureTagStatsList) {
int carrierId = getCarrierId(subId);
List deleteList = new ArrayList<>();
long now = getWallTimeMillis();
for (ImsRegistrationFeatureTagStats proto : mImsRegistrationFeatureTagStatsList) {
if (proto.carrierId == carrierId) {
proto.registeredMillis = now - proto.registeredMillis;
mAtomsStorage.addImsRegistrationFeatureTagStats(proto);
deleteList.add(proto);
}
}
for (ImsRegistrationFeatureTagStats proto : deleteList) {
mImsRegistrationFeatureTagStatsList.remove(proto);
}
}
}
/** Update duration and store cached ImsRegistrationFeatureTagStats when metrics are pulled */
public void onFlushIncompleteImsRegistrationFeatureTagStats() {
synchronized (mImsRegistrationFeatureTagStatsList) {
long now = getWallTimeMillis();
for (ImsRegistrationFeatureTagStats proto : mImsRegistrationFeatureTagStatsList) {
ImsRegistrationFeatureTagStats newProto = copyImsRegistrationFeatureTagStats(proto);
// the current time is a placeholder and total registered time will be
// calculated when generating final atoms
newProto.registeredMillis = now - proto.registeredMillis;
mAtomsStorage.addImsRegistrationFeatureTagStats(newProto);
proto.registeredMillis = now;
}
}
}
/** Create a new atom when RCS client stat changed. */
public synchronized void onRcsClientProvisioningStats(int subId, int event) {
int carrierId = getCarrierId(subId);
if (!isValidCarrierId(carrierId)) {
return;
}
RcsClientProvisioningStats proto = new RcsClientProvisioningStats();
proto.carrierId = carrierId;
proto.slotId = getSlotId(subId);
proto.event = event;
proto.count = 1;
mAtomsStorage.addRcsClientProvisioningStats(proto);
}
/** Update or create new atom when RCS ACS stat changed. */
public void onRcsAcsProvisioningStats(int subId, int responseCode, int responseType,
boolean enableSingleRegistration) {
synchronized (mRcsAcsProvisioningStatsList) {
int carrierId = getCarrierId(subId);
if (!isValidCarrierId(carrierId)) {
flushRcsAcsProvisioningStatsInvalid();
return;
}
// update cached atom if exists
onStoreCompleteRcsAcsProvisioningStats(subId);
// create new stats to cache
RcsAcsProvisioningStats newStats = new RcsAcsProvisioningStats();
newStats.carrierId = carrierId;
newStats.slotId = getSlotId(subId);
newStats.responseCode = responseCode;
newStats.responseType = responseType;
newStats.isSingleRegistrationEnabled = enableSingleRegistration;
newStats.count = 1;
newStats.stateTimerMillis = getWallTimeMillis();
// add new stats in list
mRcsAcsProvisioningStatsList.add(newStats);
}
}
/** Update duration, store and delete cached RcsAcsProvisioningStats */
public void onStoreCompleteRcsAcsProvisioningStats(int subId) {
synchronized (mRcsAcsProvisioningStatsList) {
// find cached RcsAcsProvisioningStats based sub ID
RcsAcsProvisioningStats existingStats = getRcsAcsProvisioningStats(subId);
if (existingStats != null) {
existingStats.stateTimerMillis =
getWallTimeMillis() - existingStats.stateTimerMillis;
mAtomsStorage.addRcsAcsProvisioningStats(existingStats);
// remove cached atom from list
mRcsAcsProvisioningStatsList.remove(existingStats);
}
}
}
/** Update duration and store cached RcsAcsProvisioningStats when metrics are pulled */
public void onFlushIncompleteRcsAcsProvisioningStats() {
synchronized (mRcsAcsProvisioningStatsList) {
long now = getWallTimeMillis();
for (RcsAcsProvisioningStats stats : mRcsAcsProvisioningStatsList) {
// we store a copy into atoms storage
// so that we can continue using the original object.
RcsAcsProvisioningStats proto = copyRcsAcsProvisioningStats(stats);
// the current time is a placeholder and total registered time will be
// calculated when generating final atoms
proto.stateTimerMillis = now - proto.stateTimerMillis;
mAtomsStorage.addRcsAcsProvisioningStats(proto);
// update cached atom's time
stats.stateTimerMillis = now;
}
}
}
/** Create SipDelegateStat when SipDelegate is created */
public synchronized void createSipDelegateStats(int subId, Set supportedTags) {
if (supportedTags != null && !supportedTags.isEmpty()) {
LastSipDelegateStat lastState = getLastSipDelegateStat(subId, supportedTags);
lastState.createSipDelegateStat(subId);
}
}
/** Update destroyReason and duration of SipDelegateStat when SipDelegate is destroyed */
public synchronized void onSipDelegateStats(int subId, Set supportedTags,
int destroyReason) {
if (supportedTags != null && !supportedTags.isEmpty()) {
LastSipDelegateStat lastState = getLastSipDelegateStat(subId, supportedTags);
lastState.setSipDelegateDestroyReason(destroyReason);
concludeSipDelegateStat();
}
}
/** Create/Update atoms when states of sipTransportFeatureTags are changed */
public synchronized void onSipTransportFeatureTagStats(
int subId,
Set deniedTags,
Set deRegiTags,
Set regiTags) {
long now = getWallTimeMillis();
SipTransportFeatureTags sipTransportFeatureTags = getLastFeatureTags(subId);
if (regiTags != null && !regiTags.isEmpty()) {
for (String tag : regiTags) {
sipTransportFeatureTags.updateLastFeatureTagState(tag, STATE_REGISTERED,
NONE, now);
}
}
if (deniedTags != null && !deniedTags.isEmpty()) {
for (FeatureTagState tag : deniedTags) {
sipTransportFeatureTags.updateLastFeatureTagState(tag.getFeatureTag(), STATE_DENIED,
tag.getState(), now);
}
}
if (deRegiTags != null && !deRegiTags.isEmpty()) {
for (FeatureTagState tag : deRegiTags) {
sipTransportFeatureTags.updateLastFeatureTagState(
tag.getFeatureTag(), STATE_DEREGISTERED, tag.getState(), now);
}
}
}
/** Update duration of sipTransportFeatureTags when metrics are pulled */
public synchronized void concludeSipTransportFeatureTagsStat() {
if (mLastFeatureTagStatMap.isEmpty()) {
return;
}
long now = getWallTimeMillis();
HashMap lastFeatureTagStatsCopy = new HashMap<>();
lastFeatureTagStatsCopy.putAll(mLastFeatureTagStatMap);
for (SipTransportFeatureTags sipTransportFeatureTags : lastFeatureTagStatsCopy.values()) {
if (sipTransportFeatureTags != null) {
sipTransportFeatureTags.conclude(now);
}
}
}
/** Request Message */
public synchronized void onSipMessageRequest(String callId, String sipMessageMethod,
int sipMessageDirection) {
mSipMessage = new SipMessageArray(sipMessageMethod, sipMessageDirection, callId);
mSipMessageArray.add(mSipMessage);
}
/** invalidated result when Request message is sent */
public synchronized void invalidatedMessageResult(int subId, String sipMessageMethod,
int sipMessageDirection, int messageError) {
mSipMessage.addSipMessageStat(subId, sipMessageMethod, 0,
sipMessageDirection, messageError);
}
/** Create a new atom when RCS SIP Message Response changed. */
public synchronized void onSipMessageResponse(int subId, String callId,
int sipMessageResponse, int messageError) {
SipMessageArray match = mSipMessageArray.stream()
.filter(d -> d.mCallId.equals(callId)).findFirst().orElse(null);
if (match != null) {
mSipMessage.addSipMessageStat(subId, match.mMethod, sipMessageResponse,
match.mDirection, messageError);
mSipMessageArray.removeIf(d -> d.mCallId.equals(callId));
}
}
/** Request SIP Method Message */
public synchronized void earlySipTransportSession(String sessionMethod, String callId,
int sipMessageDirection) {
mSipTransportSession = new SipTransportSessionArray(sessionMethod,
sipMessageDirection, callId);
mSipTransportSessionArray.add(mSipTransportSession);
}
/** Response Message */
public synchronized void confirmedSipTransportSession(String callId,
int sipResponse) {
SipTransportSessionArray match = mSipTransportSessionArray.stream()
.filter(d -> d.mCallId.equals(callId)).findFirst().orElse(null);
if (match != null) {
match.mSipResponse = sipResponse;
}
}
/** Create a new atom when RCS SIP Transport Session changed. */
public synchronized void onSipTransportSessionClosed(int subId, String callId,
int sipResponse, boolean isEndedGracefully) {
SipTransportSessionArray match = mSipTransportSessionArray.stream()
.filter(d -> d.mCallId.equals(callId)).findFirst().orElse(null);
if (match != null) {
if (sipResponse != 0) {
match.mSipResponse = sipResponse;
}
mSipTransportSession.addSipTransportSessionStat(subId, match.mMethod, match.mDirection,
sipResponse, isEndedGracefully);
mSipTransportSessionArray.removeIf(d -> d.mCallId.equals(callId));
}
}
/** Add a listener to the hashmap for waiting upcoming DedicatedBearer established event */
public synchronized void onImsDedicatedBearerListenerAdded(@NonNull final int listenerId,
@NonNull final int slotId, @NonNull final int ratAtEnd, @NonNull final int qci) {
int subId = getSubId(slotId);
int carrierId = getCarrierId(subId);
if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID
|| !isValidCarrierId(carrierId)) {
return;
}
if (mDedicatedBearerListenerEventMap.containsKey(listenerId)) {
return;
}
ImsDedicatedBearerListenerEvent preProto = new ImsDedicatedBearerListenerEvent();
preProto.carrierId = carrierId;
preProto.slotId = slotId;
preProto.ratAtEnd = ratAtEnd;
preProto.qci = qci;
preProto.dedicatedBearerEstablished = false;
preProto.eventCount = 1;
mDedicatedBearerListenerEventMap.put(listenerId, preProto);
}
/** update previously added atom with dedicatedBearerEstablished = true when
* DedicatedBearerListener Event changed. */
public synchronized void onImsDedicatedBearerListenerUpdateSession(final int listenerId,
final int slotId, final int rat, final int qci,
@NonNull final boolean dedicatedBearerEstablished) {
int subId = getSubId(slotId);
int carrierId = getCarrierId(subId);
if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID
|| !isValidCarrierId(carrierId)) {
return;
}
if (mDedicatedBearerListenerEventMap.containsKey(listenerId)) {
ImsDedicatedBearerListenerEvent preProto =
mDedicatedBearerListenerEventMap.get(listenerId);
preProto.ratAtEnd = rat;
preProto.qci = qci;
preProto.dedicatedBearerEstablished = dedicatedBearerEstablished;
mDedicatedBearerListenerEventMap.replace(listenerId, preProto);
} else {
ImsDedicatedBearerListenerEvent preProto = new ImsDedicatedBearerListenerEvent();
preProto.carrierId = carrierId;
preProto.slotId = slotId;
preProto.ratAtEnd = rat;
preProto.qci = qci;
preProto.dedicatedBearerEstablished = dedicatedBearerEstablished;
preProto.eventCount = 1;
mDedicatedBearerListenerEventMap.put(listenerId, preProto);
}
}
/** add proto to atom when listener is removed, so that I can save the status of dedicatedbearer
* establishment per listener id */
public synchronized void onImsDedicatedBearerListenerRemoved(@NonNull final int listenerId) {
if (mDedicatedBearerListenerEventMap.containsKey(listenerId)) {
ImsDedicatedBearerListenerEvent newProto =
mDedicatedBearerListenerEventMap.get(listenerId);
mAtomsStorage.addImsDedicatedBearerListenerEvent(newProto);
mDedicatedBearerListenerEventMap.remove(listenerId);
}
}
/** Create a new atom when DedicatedBearer Event changed. */
public synchronized void onImsDedicatedBearerEvent(int slotId, int ratAtEnd, int qci,
int bearerState, boolean localConnectionInfoReceived,
boolean remoteConnectionInfoReceived, boolean hasListeners) {
int subId = getSubId(slotId);
if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
return;
}
ImsDedicatedBearerEvent proto = new ImsDedicatedBearerEvent();
proto.carrierId = getCarrierId(subId);
proto.slotId = getSlotId(subId);
proto.ratAtEnd = ratAtEnd;
proto.qci = qci;
proto.bearerState = bearerState;
proto.localConnectionInfoReceived = localConnectionInfoReceived;
proto.remoteConnectionInfoReceived = remoteConnectionInfoReceived;
proto.hasListeners = hasListeners;
proto.count = 1;
mAtomsStorage.addImsDedicatedBearerEvent(proto);
}
/**
* Update or Create a new atom when Ims Registration Service Desc state changed.
* Use-related parts are already converted from UseStatsWriter based on RcsContactPresenceTuple.
*/
public void onImsRegistrationServiceDescStats(int subId, List serviceIdList,
List serviceIdVersionList, int registrationTech) {
synchronized (mImsRegistrationServiceDescStatsList) {
int carrierId = getCarrierId(subId);
if (!isValidCarrierId(carrierId)) {
handleImsRegistrationServiceDescStats();
return;
}
// update cached atom if exists
onStoreCompleteImsRegistrationServiceDescStats(subId);
if (serviceIdList == null) {
Rlog.d(TAG, "serviceIds is null or empty");
return;
}
int index = 0;
for (String serviceId : serviceIdList) {
ImsRegistrationServiceDescStats mImsRegistrationServiceDescStats =
new ImsRegistrationServiceDescStats();
mImsRegistrationServiceDescStats.carrierId = carrierId;
mImsRegistrationServiceDescStats.slotId = getSlotId(subId);
mImsRegistrationServiceDescStats.serviceIdName = convertServiceIdToValue(serviceId);
mImsRegistrationServiceDescStats.serviceIdVersion =
Float.parseFloat(serviceIdVersionList.get(index++));
mImsRegistrationServiceDescStats.registrationTech = registrationTech;
mImsRegistrationServiceDescStatsList.add(mImsRegistrationServiceDescStats);
}
}
}
/** Update duration and cached of ImsRegistrationServiceDescStats when metrics are pulled */
public void onFlushIncompleteImsRegistrationServiceDescStats() {
synchronized (mImsRegistrationServiceDescStatsList) {
for (ImsRegistrationServiceDescStats proto : mImsRegistrationServiceDescStatsList) {
ImsRegistrationServiceDescStats newProto =
copyImsRegistrationServiceDescStats(proto);
long now = getWallTimeMillis();
// the current time is a placeholder and total registered time will be
// calculated when generating final atoms
newProto.publishedMillis = now - proto.publishedMillis;
mAtomsStorage.addImsRegistrationServiceDescStats(newProto);
proto.publishedMillis = now;
}
}
}
/** Create a new atom when Uce Event Stats changed. */
public synchronized void onUceEventStats(int subId, int type, boolean successful,
int commandCode, int networkResponse) {
UceEventStats proto = new UceEventStats();
int carrierId = getCarrierId(subId);
if (!isValidCarrierId(carrierId)) {
handleImsRegistrationServiceDescStats();
return;
}
proto.carrierId = carrierId;
proto.slotId = getSlotId(subId);
proto.type = type;
proto.successful = successful;
proto.commandCode = commandCode;
proto.networkResponse = networkResponse;
proto.count = 1;
mAtomsStorage.addUceEventStats(proto);
/**
* The publishedMillis of ImsRegistrationServiceDescStat is the time gap between
* Publish success and Un publish.
* So, when the publish operation is successful, the corresponding time gap is set,
* and in case of failure, the cached stat is deleted.
*/
if (type == UCE_EVENT_STATS__TYPE__PUBLISH) {
if (successful) {
setImsRegistrationServiceDescStatsTime(proto.carrierId);
} else {
deleteImsRegistrationServiceDescStats(proto.carrierId);
}
}
}
/** Create a new atom when Presence Notify Event changed. */
public synchronized void onPresenceNotifyEvent(int subId, String reason,
boolean contentBodyReceived, boolean rcsCaps, boolean mmtelCaps, boolean noCaps) {
PresenceNotifyEvent proto = new PresenceNotifyEvent();
int carrierId = getCarrierId(subId);
if (!isValidCarrierId(carrierId)) {
handleImsRegistrationServiceDescStats();
return;
}
proto.carrierId = carrierId;
proto.slotId = getSlotId(subId);
proto.reason = convertPresenceNotifyReason(reason);
proto.contentBodyReceived = contentBodyReceived;
proto.rcsCapsCount = rcsCaps ? 1 : 0;
proto.mmtelCapsCount = mmtelCaps ? 1 : 0;
proto.noCapsCount = noCaps ? 1 : 0;
proto.count = 1;
mAtomsStorage.addPresenceNotifyEvent(proto);
}
/** Update duration a created Ims Registration Desc Stat atom when Un publish event happened. */
public void onStoreCompleteImsRegistrationServiceDescStats(int subId) {
synchronized (mImsRegistrationServiceDescStatsList) {
int carrierId = getCarrierId(subId);
List deleteList = new ArrayList<>();
for (ImsRegistrationServiceDescStats proto : mImsRegistrationServiceDescStatsList) {
if (proto.carrierId == carrierId) {
proto.publishedMillis = getWallTimeMillis() - proto.publishedMillis;
mAtomsStorage.addImsRegistrationServiceDescStats(proto);
deleteList.add(proto);
}
}
for (ImsRegistrationServiceDescStats proto : deleteList) {
mImsRegistrationServiceDescStatsList.remove(proto);
}
}
}
/** Create a new atom when GBA Success Event changed. */
public synchronized void onGbaSuccessEvent(int subId) {
int carrierId = getCarrierId(subId);
if (!isValidCarrierId(carrierId)) {
return;
}
GbaEvent proto = new GbaEvent();
proto.carrierId = carrierId;
proto.slotId = getSlotId(subId);
proto.successful = true;
proto.failedReason = -1;
proto.count = 1;
mAtomsStorage.addGbaEvent(proto);
}
/** Create a new atom when GBA Failure Event changed. */
public synchronized void onGbaFailureEvent(int subId, int reason) {
int carrierId = getCarrierId(subId);
if (!isValidCarrierId(carrierId)) {
return;
}
GbaEvent proto = new GbaEvent();
proto.carrierId = carrierId;
proto.slotId = getSlotId(subId);
proto.successful = false;
proto.failedReason = reason;
proto.count = 1;
mAtomsStorage.addGbaEvent(proto);
}
/** Create or return exist RcsProvisioningCallback based on subId. */
public synchronized RcsProvisioningCallback getRcsProvisioningCallback(int subId,
boolean enableSingleRegistration) {
// find exist obj in Map
RcsProvisioningCallback rcsProvisioningCallback = mRcsProvisioningCallbackMap.get(subId);
if (rcsProvisioningCallback != null) {
return rcsProvisioningCallback;
}
// create new, add Map and return
rcsProvisioningCallback = new RcsProvisioningCallback(this, subId,
enableSingleRegistration);
mRcsProvisioningCallbackMap.put(subId, rcsProvisioningCallback);
return rcsProvisioningCallback;
}
/** Set whether single registration is supported. */
public synchronized void setEnableSingleRegistration(int subId,
boolean enableSingleRegistration) {
// find exist obj and set
RcsProvisioningCallback callbackBinder = mRcsProvisioningCallbackMap.get(subId);
if (callbackBinder != null) {
callbackBinder.setEnableSingleRegistration(enableSingleRegistration);
}
}
private synchronized void removeRcsProvisioningCallback(int subId) {
// remove obj from Map based on subId
mRcsProvisioningCallbackMap.remove(subId);
}
private ImsRegistrationFeatureTagStats copyImsRegistrationFeatureTagStats(
ImsRegistrationFeatureTagStats proto) {
ImsRegistrationFeatureTagStats newProto = new ImsRegistrationFeatureTagStats();
newProto.carrierId = proto.carrierId;
newProto.slotId = proto.slotId;
newProto.featureTagName = proto.featureTagName;
newProto.registrationTech = proto.registrationTech;
newProto.registeredMillis = proto.registeredMillis;
return newProto;
}
private RcsAcsProvisioningStats copyRcsAcsProvisioningStats(RcsAcsProvisioningStats proto) {
RcsAcsProvisioningStats newProto = new RcsAcsProvisioningStats();
newProto.carrierId = proto.carrierId;
newProto.slotId = proto.slotId;
newProto.responseCode = proto.responseCode;
newProto.responseType = proto.responseType;
newProto.isSingleRegistrationEnabled = proto.isSingleRegistrationEnabled;
newProto.count = proto.count;
newProto.stateTimerMillis = proto.stateTimerMillis;
return newProto;
}
private ImsRegistrationServiceDescStats copyImsRegistrationServiceDescStats(
ImsRegistrationServiceDescStats proto) {
ImsRegistrationServiceDescStats newProto = new ImsRegistrationServiceDescStats();
newProto.carrierId = proto.carrierId;
newProto.slotId = proto.slotId;
newProto.serviceIdName = proto.serviceIdName;
newProto.serviceIdVersion = proto.serviceIdVersion;
newProto.registrationTech = proto.registrationTech;
return newProto;
}
private void setImsRegistrationServiceDescStatsTime(int carrierId) {
synchronized (mImsRegistrationServiceDescStatsList) {
for (ImsRegistrationServiceDescStats descStats : mImsRegistrationServiceDescStatsList) {
if (descStats.carrierId == carrierId) {
descStats.publishedMillis = getWallTimeMillis();
}
}
}
}
private void deleteImsRegistrationServiceDescStats(int carrierId) {
synchronized (mImsRegistrationServiceDescStatsList) {
List deleteList = new ArrayList<>();
for (ImsRegistrationServiceDescStats proto : mImsRegistrationServiceDescStatsList) {
if (proto.carrierId == carrierId) {
deleteList.add(proto);
}
}
for (ImsRegistrationServiceDescStats stats : deleteList) {
mImsRegistrationServiceDescStatsList.remove(stats);
}
}
}
private void handleImsRegistrationServiceDescStats() {
synchronized (mImsRegistrationServiceDescStatsList) {
List deleteList = new ArrayList<>();
for (ImsRegistrationServiceDescStats proto : mImsRegistrationServiceDescStatsList) {
int subId = getSubId(proto.slotId);
int newCarrierId = getCarrierId(subId);
if (proto.carrierId != newCarrierId) {
deleteList.add(proto);
if (proto.publishedMillis != 0) {
proto.publishedMillis = getWallTimeMillis() - proto.publishedMillis;
mAtomsStorage.addImsRegistrationServiceDescStats(proto);
}
}
}
for (ImsRegistrationServiceDescStats stats : deleteList) {
mImsRegistrationServiceDescStatsList.remove(stats);
}
}
}
private RcsAcsProvisioningStats getRcsAcsProvisioningStats(int subId) {
int carrierId = getCarrierId(subId);
int slotId = getSlotId(subId);
for (RcsAcsProvisioningStats stats : mRcsAcsProvisioningStatsList) {
if (stats == null) {
continue;
}
if (stats.carrierId == carrierId && stats.slotId == slotId) {
return stats;
}
}
return null;
}
private void flushRcsAcsProvisioningStatsInvalid() {
List inValidList = new ArrayList();
int subId;
int newCarrierId;
for (RcsAcsProvisioningStats stats : mRcsAcsProvisioningStatsList) {
subId = getSubId(stats.slotId);
newCarrierId = getCarrierId(subId);
if (stats.carrierId != newCarrierId) {
inValidList.add(stats);
}
}
for (RcsAcsProvisioningStats inValid : inValidList) {
inValid.stateTimerMillis = getWallTimeMillis() - inValid.stateTimerMillis;
mAtomsStorage.addRcsAcsProvisioningStats(inValid);
mRcsAcsProvisioningStatsList.remove(inValid);
}
inValidList.clear();
}
private void flushImsRegistrationFeatureTagStatsInvalid() {
List inValidList =
new ArrayList();
int subId;
int newCarrierId;
for (ImsRegistrationFeatureTagStats stats : mImsRegistrationFeatureTagStatsList) {
subId = getSubId(stats.slotId);
newCarrierId = getCarrierId(subId);
if (stats.carrierId != newCarrierId) {
inValidList.add(stats);
}
}
for (ImsRegistrationFeatureTagStats inValid : inValidList) {
inValid.registeredMillis = getWallTimeMillis() - inValid.registeredMillis;
mAtomsStorage.addImsRegistrationFeatureTagStats(inValid);
mImsRegistrationFeatureTagStatsList.remove(inValid);
}
inValidList.clear();
}
private LastSipDelegateStat getLastSipDelegateStat(int subId, Set supportedTags) {
LastSipDelegateStat stat = null;
for (LastSipDelegateStat lastStat : mLastSipDelegateStatList) {
if (lastStat.compare(subId, supportedTags)) {
stat = lastStat;
break;
}
}
if (stat == null) {
stat = new LastSipDelegateStat(subId, supportedTags);
mLastSipDelegateStatList.add(stat);
}
return stat;
}
private void concludeSipDelegateStat() {
if (mLastSipDelegateStatList.isEmpty()) {
return;
}
long now = getWallTimeMillis();
List sipDelegateStatsCopy = new ArrayList<>(mLastSipDelegateStatList);
for (LastSipDelegateStat stat : sipDelegateStatsCopy) {
if (stat.isDestroyed()) {
stat.conclude(now);
mLastSipDelegateStatList.remove(stat);
}
}
}
private SipTransportFeatureTags getLastFeatureTags(int subId) {
SipTransportFeatureTags sipTransportFeatureTags;
if (mLastFeatureTagStatMap.containsKey(subId)) {
sipTransportFeatureTags = mLastFeatureTagStatMap.get(subId);
} else {
sipTransportFeatureTags = new SipTransportFeatureTags(subId);
mLastFeatureTagStatMap.put(subId, sipTransportFeatureTags);
}
return sipTransportFeatureTags;
}
@VisibleForTesting
protected boolean isValidCarrierId(int carrierId) {
return carrierId > TelephonyManager.UNKNOWN_CARRIER_ID;
}
@VisibleForTesting
protected int getSlotId(int subId) {
return SubscriptionManager.getPhoneId(subId);
}
@VisibleForTesting
protected int getCarrierId(int subId) {
int phoneId = SubscriptionManager.getPhoneId(subId);
Phone phone = PhoneFactory.getPhone(phoneId);
return phone != null ? phone.getCarrierId() : TelephonyManager.UNKNOWN_CARRIER_ID;
}
@VisibleForTesting
protected long getWallTimeMillis() {
//time in UTC, preserved across reboots, but can be adjusted e.g. by the user or NTP
return System.currentTimeMillis();
}
@VisibleForTesting
protected void logd(String msg) {
Rlog.d(TAG, msg);
}
@VisibleForTesting
protected int getSubId(int slotId) {
final int[] subIds = SubscriptionManager.getSubId(slotId);
int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
if (subIds != null && subIds.length >= 1) {
subId = subIds[0];
}
return subId;
}
/** Get a enum value from pre-defined feature tag name list */
@VisibleForTesting
public int convertTagNameToValue(@NonNull String tagName) {
return FEATURE_TAGS.getOrDefault(tagName.trim().toLowerCase(),
TelephonyProtoEnums.IMS_FEATURE_TAG_CUSTOM);
}
/** Get a enum value from pre-defined service id list */
@VisibleForTesting
public int convertServiceIdToValue(@NonNull String serviceId) {
return SERVICE_IDS.getOrDefault(serviceId.trim().toLowerCase(),
IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CUSTOM);
}
/** Get a enum value from pre-defined message type list */
@VisibleForTesting
public int convertMessageTypeToValue(@NonNull String messageType) {
return MESSAGE_TYPE.getOrDefault(messageType.trim().toLowerCase(),
TelephonyProtoEnums.SIP_REQUEST_CUSTOM);
}
/** Get a enum value from pre-defined reason list */
@VisibleForTesting
public int convertPresenceNotifyReason(@NonNull String reason) {
return NOTIFY_REASONS.getOrDefault(reason.trim().toLowerCase(),
PRESENCE_NOTIFY_EVENT__REASON__REASON_CUSTOM);
}
/**
* Print all metrics data for debugging purposes
*
* @param rawWriter Print writer
*/
public synchronized void printAllMetrics(PrintWriter rawWriter) {
if (mAtomsStorage == null || mAtomsStorage.mAtoms == null) {
return;
}
final IndentingPrintWriter pw = new IndentingPrintWriter(rawWriter, " ");
PersistAtomsProto.PersistAtoms metricAtoms = mAtomsStorage.mAtoms;
pw.println("RcsStats Metrics Proto: ");
pw.println("------------------------------------------");
pw.println("ImsRegistrationFeatureTagStats:");
pw.increaseIndent();
for (ImsRegistrationFeatureTagStats stat : metricAtoms.imsRegistrationFeatureTagStats) {
pw.println("[" + stat.carrierId + "]"
+ " [" + stat.slotId + "]"
+ " Feature Tag Name = " + stat.featureTagName
+ ", Registration Tech = " + stat.registrationTech
+ ", Registered Duration (ms) = " + stat.registeredMillis);
}
pw.decreaseIndent();
pw.println("RcsClientProvisioningStats:");
pw.increaseIndent();
for (RcsClientProvisioningStats stat : metricAtoms.rcsClientProvisioningStats) {
pw.println("[" + stat.carrierId + "]"
+ " [" + stat.slotId + "]"
+ " Event = " + stat.event
+ ", Count = " + stat.count);
}
pw.decreaseIndent();
pw.println("RcsAcsProvisioningStats:");
pw.increaseIndent();
for (RcsAcsProvisioningStats stat : metricAtoms.rcsAcsProvisioningStats) {
pw.println("[" + stat.carrierId + "]"
+ " [" + stat.slotId + "]"
+ " Response Code = " + stat.responseCode
+ ", Response Type = " + stat.responseType
+ ", Single Registration Enabled = " + stat.isSingleRegistrationEnabled
+ ", Count = " + stat.count
+ ", State Timer (ms) = " + stat.stateTimerMillis);
}
pw.decreaseIndent();
pw.println("SipDelegateStats:");
pw.increaseIndent();
for (SipDelegateStats stat : metricAtoms.sipDelegateStats) {
pw.println("[" + stat.carrierId + "]"
+ " [" + stat.slotId + "]"
+ " [" + stat.dimension + "]"
+ " Destroy Reason = " + stat.destroyReason
+ ", Uptime (ms) = " + stat.uptimeMillis);
}
pw.decreaseIndent();
pw.println("SipTransportFeatureTagStats:");
pw.increaseIndent();
for (SipTransportFeatureTagStats stat : metricAtoms.sipTransportFeatureTagStats) {
pw.println("[" + stat.carrierId + "]"
+ " [" + stat.slotId + "]"
+ " Feature Tag Name = " + stat.featureTagName
+ ", Denied Reason = " + stat.sipTransportDeniedReason
+ ", Deregistered Reason = " + stat.sipTransportDeregisteredReason
+ ", Associated Time (ms) = " + stat.associatedMillis);
}
pw.decreaseIndent();
pw.println("SipMessageResponse:");
pw.increaseIndent();
for (SipMessageResponse stat : metricAtoms.sipMessageResponse) {
pw.println("[" + stat.carrierId + "]"
+ " [" + stat.slotId + "]"
+ " Message Method = " + stat.sipMessageMethod
+ ", Response = " + stat.sipMessageResponse
+ ", Direction = " + stat.sipMessageDirection
+ ", Error = " + stat.messageError
+ ", Count = " + stat.count);
}
pw.decreaseIndent();
pw.println("SipTransportSession:");
pw.increaseIndent();
for (SipTransportSession stat : metricAtoms.sipTransportSession) {
pw.println("[" + stat.carrierId + "]"
+ " [" + stat.slotId + "]"
+ " Session Method = " + stat.sessionMethod
+ ", Direction = " + stat.sipMessageDirection
+ ", Response = " + stat.sipResponse
+ ", Count = " + stat.sessionCount
+ ", GraceFully Count = " + stat.endedGracefullyCount);
}
pw.decreaseIndent();
pw.println("ImsDedicatedBearerListenerEvent:");
pw.increaseIndent();
for (ImsDedicatedBearerListenerEvent stat : metricAtoms.imsDedicatedBearerListenerEvent) {
pw.println("[" + stat.carrierId + "]"
+ " [" + stat.slotId + "]"
+ " RAT = " + stat.ratAtEnd
+ ", QCI = " + stat.qci
+ ", Dedicated Bearer Established = " + stat.dedicatedBearerEstablished
+ ", Count = " + stat.eventCount);
}
pw.decreaseIndent();
pw.println("ImsDedicatedBearerEvent:");
pw.increaseIndent();
for (ImsDedicatedBearerEvent stat : metricAtoms.imsDedicatedBearerEvent) {
pw.println("[" + stat.carrierId + "]"
+ " [" + stat.slotId + "]"
+ " RAT = " + stat.ratAtEnd
+ ", QCI = " + stat.qci
+ ", Bearer State = " + stat.bearerState
+ ", Local Connection Info = " + stat.localConnectionInfoReceived
+ ", Remote Connection Info = " + stat.remoteConnectionInfoReceived
+ ", Listener Existence = " + stat.hasListeners
+ ", Count = " + stat.count);
}
pw.decreaseIndent();
pw.println("ImsRegistrationServiceDescStats:");
pw.increaseIndent();
for (ImsRegistrationServiceDescStats stat : metricAtoms.imsRegistrationServiceDescStats) {
pw.println("[" + stat.carrierId + "]"
+ " [" + stat.slotId + "]"
+ " Name = " + stat.serviceIdName
+ ", Version = " + stat.serviceIdVersion
+ ", Registration Tech = " + stat.registrationTech
+ ", Published Time (ms) = " + stat.publishedMillis);
}
pw.decreaseIndent();
pw.println("UceEventStats:");
pw.increaseIndent();
for (UceEventStats stat : metricAtoms.uceEventStats) {
pw.println("[" + stat.carrierId + "]"
+ " [" + stat.slotId + "]"
+ " Type = " + stat.type
+ ", Successful = " + stat.successful
+ ", Code = " + stat.commandCode
+ ", Response = " + stat.networkResponse
+ ", Count = " + stat.count);
}
pw.decreaseIndent();
pw.println("PresenceNotifyEvent:");
pw.increaseIndent();
for (PresenceNotifyEvent stat : metricAtoms.presenceNotifyEvent) {
pw.println("[" + stat.carrierId + "]"
+ " [" + stat.slotId + "]"
+ " Reason = " + stat.reason
+ ", Body = " + stat.contentBodyReceived
+ ", RCS Count = " + stat.rcsCapsCount
+ ", MMTEL Count = " + stat.mmtelCapsCount
+ ", NoCaps Count = " + stat.noCapsCount
+ ", Count = " + stat.count);
}
pw.decreaseIndent();
pw.println("GbaEvent:");
pw.increaseIndent();
for (GbaEvent stat : metricAtoms.gbaEvent) {
pw.println("[" + stat.carrierId + "]"
+ " [" + stat.slotId + "]"
+ " Successful = " + stat.successful
+ ", Fail Reason = " + stat.failedReason
+ ", Count = " + stat.count);
}
pw.decreaseIndent();
}
/**
* Reset all events
*/
public synchronized void reset() {
if (mAtomsStorage == null || mAtomsStorage.mAtoms == null) {
return;
}
PersistAtomsProto.PersistAtoms metricAtoms = mAtomsStorage.mAtoms;
metricAtoms.imsRegistrationFeatureTagStats =
PersistAtomsProto.ImsRegistrationFeatureTagStats.emptyArray();
metricAtoms.rcsClientProvisioningStats =
PersistAtomsProto.RcsClientProvisioningStats.emptyArray();
metricAtoms.rcsAcsProvisioningStats =
PersistAtomsProto.RcsAcsProvisioningStats.emptyArray();
metricAtoms.sipDelegateStats = PersistAtomsProto.SipDelegateStats.emptyArray();
metricAtoms.sipTransportFeatureTagStats =
PersistAtomsProto.SipTransportFeatureTagStats.emptyArray();
metricAtoms.sipMessageResponse = PersistAtomsProto.SipMessageResponse.emptyArray();
metricAtoms.sipTransportSession = PersistAtomsProto.SipTransportSession.emptyArray();
metricAtoms.imsDedicatedBearerListenerEvent =
PersistAtomsProto.ImsDedicatedBearerListenerEvent.emptyArray();
metricAtoms.imsDedicatedBearerEvent =
PersistAtomsProto.ImsDedicatedBearerEvent.emptyArray();
metricAtoms.imsRegistrationServiceDescStats =
PersistAtomsProto.ImsRegistrationServiceDescStats.emptyArray();
metricAtoms.uceEventStats = PersistAtomsProto.UceEventStats.emptyArray();
metricAtoms.presenceNotifyEvent = PersistAtomsProto.PresenceNotifyEvent.emptyArray();
metricAtoms.gbaEvent = PersistAtomsProto.GbaEvent.emptyArray();
}
/**
* Convert the PersistAtomsProto into Base-64 encoded string
*
* @return Encoded string
*/
public String buildLog() {
PersistAtomsProto.PersistAtoms log = buildProto();
return Base64.encodeToString(
PersistAtomsProto.PersistAtoms.toByteArray(log), Base64.DEFAULT);
}
/**
* Build the PersistAtomsProto
*
* @return PersistAtomsProto.PersistAtoms
*/
public PersistAtomsProto.PersistAtoms buildProto() {
PersistAtomsProto.PersistAtoms log = new PersistAtomsProto.PersistAtoms();
PersistAtomsProto.PersistAtoms atoms = mAtomsStorage.mAtoms;
log.imsRegistrationFeatureTagStats = Arrays.copyOf(atoms.imsRegistrationFeatureTagStats,
atoms.imsRegistrationFeatureTagStats.length);
log.rcsClientProvisioningStats = Arrays.copyOf(atoms.rcsClientProvisioningStats,
atoms.rcsClientProvisioningStats.length);
log.rcsAcsProvisioningStats = Arrays.copyOf(atoms.rcsAcsProvisioningStats,
atoms.rcsAcsProvisioningStats.length);
log.sipDelegateStats = Arrays.copyOf(atoms.sipDelegateStats, atoms.sipDelegateStats.length);
log.sipTransportFeatureTagStats = Arrays.copyOf(atoms.sipTransportFeatureTagStats,
atoms.sipTransportFeatureTagStats.length);
log.sipMessageResponse = Arrays.copyOf(atoms.sipMessageResponse,
atoms.sipMessageResponse.length);
log.sipTransportSession = Arrays.copyOf(atoms.sipTransportSession,
atoms.sipTransportSession.length);
log.imsDedicatedBearerListenerEvent = Arrays.copyOf(atoms.imsDedicatedBearerListenerEvent,
atoms.imsDedicatedBearerListenerEvent.length);
log.imsDedicatedBearerEvent = Arrays.copyOf(atoms.imsDedicatedBearerEvent,
atoms.imsDedicatedBearerEvent.length);
log.imsRegistrationServiceDescStats = Arrays.copyOf(atoms.imsRegistrationServiceDescStats,
atoms.imsRegistrationServiceDescStats.length);
log.uceEventStats = Arrays.copyOf(atoms.uceEventStats, atoms.uceEventStats.length);
log.presenceNotifyEvent = Arrays.copyOf(atoms.presenceNotifyEvent,
atoms.presenceNotifyEvent.length);
log.gbaEvent = Arrays.copyOf(atoms.gbaEvent, atoms.gbaEvent.length);
return log;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy