1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.telephony.metrics; 18 19 import static android.text.format.DateUtils.SECOND_IN_MILLIS; 20 21 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CALL_COMPOSER; 22 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHATBOT; 23 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHATBOT_ROLE; 24 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHATBOT_STANDALONE; 25 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHAT_V1; 26 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHAT_V2; 27 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CUSTOM; 28 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_FT; 29 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_FT_OVER_SMS; 30 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_GEO_PUSH; 31 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_GEO_PUSH_VIA_SMS; 32 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_MMTEL; 33 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_POST_CALL; 34 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_SHARED_MAP; 35 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_SHARED_SKETCH; 36 import static com.android.internal.telephony.TelephonyStatsLog.PRESENCE_NOTIFY_EVENT__REASON__REASON_CUSTOM; 37 import static com.android.internal.telephony.TelephonyStatsLog.PRESENCE_NOTIFY_EVENT__REASON__REASON_DEACTIVATED; 38 import static com.android.internal.telephony.TelephonyStatsLog.PRESENCE_NOTIFY_EVENT__REASON__REASON_GIVEUP; 39 import static com.android.internal.telephony.TelephonyStatsLog.PRESENCE_NOTIFY_EVENT__REASON__REASON_NORESOURCE; 40 import static com.android.internal.telephony.TelephonyStatsLog.PRESENCE_NOTIFY_EVENT__REASON__REASON_PROBATION; 41 import static com.android.internal.telephony.TelephonyStatsLog.PRESENCE_NOTIFY_EVENT__REASON__REASON_REJECTED; 42 import static com.android.internal.telephony.TelephonyStatsLog.PRESENCE_NOTIFY_EVENT__REASON__REASON_TIMEOUT; 43 import static com.android.internal.telephony.TelephonyStatsLog.RCS_ACS_PROVISIONING_STATS__RESPONSE_TYPE__ERROR; 44 import static com.android.internal.telephony.TelephonyStatsLog.RCS_ACS_PROVISIONING_STATS__RESPONSE_TYPE__PRE_PROVISIONING_XML; 45 import static com.android.internal.telephony.TelephonyStatsLog.UCE_EVENT_STATS__TYPE__INCOMING_OPTION; 46 import static com.android.internal.telephony.TelephonyStatsLog.UCE_EVENT_STATS__TYPE__OUTGOING_OPTION; 47 import static com.android.internal.telephony.TelephonyStatsLog.UCE_EVENT_STATS__TYPE__PUBLISH; 48 import static com.android.internal.telephony.TelephonyStatsLog.UCE_EVENT_STATS__TYPE__SUBSCRIBE; 49 50 import android.annotation.NonNull; 51 import android.os.Binder; 52 import android.telephony.SubscriptionManager; 53 import android.telephony.TelephonyManager; 54 import android.telephony.TelephonyProtoEnums; 55 import android.telephony.ims.FeatureTagState; 56 import android.telephony.ims.RcsContactPresenceTuple; 57 import android.telephony.ims.RcsContactUceCapability; 58 import android.telephony.ims.aidl.IRcsConfigCallback; 59 import android.util.IndentingPrintWriter; 60 61 import com.android.ims.rcs.uce.UceStatsWriter; 62 import com.android.ims.rcs.uce.UceStatsWriter.UceStatsCallback; 63 import com.android.ims.rcs.uce.util.FeatureTags; 64 import com.android.internal.annotations.VisibleForTesting; 65 import com.android.internal.telephony.Phone; 66 import com.android.internal.telephony.PhoneFactory; 67 import com.android.internal.telephony.nano.PersistAtomsProto; 68 import com.android.internal.telephony.nano.PersistAtomsProto.GbaEvent; 69 import com.android.internal.telephony.nano.PersistAtomsProto.ImsDedicatedBearerEvent; 70 import com.android.internal.telephony.nano.PersistAtomsProto.ImsDedicatedBearerListenerEvent; 71 import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationFeatureTagStats; 72 import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationServiceDescStats; 73 import com.android.internal.telephony.nano.PersistAtomsProto.PresenceNotifyEvent; 74 import com.android.internal.telephony.nano.PersistAtomsProto.RcsAcsProvisioningStats; 75 import com.android.internal.telephony.nano.PersistAtomsProto.RcsClientProvisioningStats; 76 import com.android.internal.telephony.nano.PersistAtomsProto.SipDelegateStats; 77 import com.android.internal.telephony.nano.PersistAtomsProto.SipMessageResponse; 78 import com.android.internal.telephony.nano.PersistAtomsProto.SipTransportFeatureTagStats; 79 import com.android.internal.telephony.nano.PersistAtomsProto.SipTransportSession; 80 import com.android.internal.telephony.nano.PersistAtomsProto.UceEventStats; 81 import com.android.telephony.Rlog; 82 83 import java.io.PrintWriter; 84 import java.util.ArrayList; 85 import java.util.HashMap; 86 import java.util.HashSet; 87 import java.util.List; 88 import java.util.Locale; 89 import java.util.Map; 90 import java.util.Random; 91 import java.util.Set; 92 93 /** Tracks RCS provisioning, sip transport, UCE metrics for phone. */ 94 public class RcsStats { 95 private static final String TAG = RcsStats.class.getSimpleName(); 96 private static final long MIN_DURATION_MILLIS = 1L * SECOND_IN_MILLIS; 97 private final PersistAtomsStorage mAtomsStorage = 98 PhoneFactory.getMetricsCollector().getAtomsStorage(); 99 private static final Random RANDOM = new Random(); 100 101 private UceStatsWriterCallback mCallback; 102 private static RcsStats sInstance; 103 104 public static final int NONE = -1; 105 public static final int STATE_REGISTERED = 0; 106 public static final int STATE_DEREGISTERED = 1; 107 public static final int STATE_DENIED = 2; 108 109 private static final String SIP_REQUEST_MESSAGE_TYPE_INVITE = "INVITE"; 110 private static final String SIP_REQUEST_MESSAGE_TYPE_ACK = "ACK"; 111 private static final String SIP_REQUEST_MESSAGE_TYPE_OPTIONS = "OPTIONS"; 112 private static final String SIP_REQUEST_MESSAGE_TYPE_BYE = "BYE"; 113 private static final String SIP_REQUEST_MESSAGE_TYPE_CANCEL = "CANCEL"; 114 private static final String SIP_REQUEST_MESSAGE_TYPE_REGISTER = "REGISTER"; 115 private static final String SIP_REQUEST_MESSAGE_TYPE_PRACK = "PRACK"; 116 private static final String SIP_REQUEST_MESSAGE_TYPE_SUBSCRIBE = "SUBSCRIBE"; 117 private static final String SIP_REQUEST_MESSAGE_TYPE_NOTIFY = "NOTIFY"; 118 private static final String SIP_REQUEST_MESSAGE_TYPE_PUBLISH = "PUBLISH"; 119 private static final String SIP_REQUEST_MESSAGE_TYPE_INFO = "INFO"; 120 private static final String SIP_REQUEST_MESSAGE_TYPE_REFER = "REFER"; 121 private static final String SIP_REQUEST_MESSAGE_TYPE_MESSAGE = "MESSAGE"; 122 private static final String SIP_REQUEST_MESSAGE_TYPE_UPDATE = "UPDATE"; 123 124 /** 125 * Describe Feature Tags 126 * See frameworks/opt/net/ims/src/java/com/android/ims/rcs/uce/util/FeatureTags.java 127 * and int value matching the Feature Tags 128 * See stats/enums/telephony/enums.proto 129 */ 130 private static final Map<String, Integer> FEATURE_TAGS = new HashMap<>(); 131 132 static { 133 FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_STANDALONE_MSG.trim().toLowerCase(Locale.ROOT), 134 TelephonyProtoEnums.IMS_FEATURE_TAG_STANDALONE_MSG); 135 FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_CHAT_IM.trim().toLowerCase(Locale.ROOT), 136 TelephonyProtoEnums.IMS_FEATURE_TAG_CHAT_IM); 137 FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_CHAT_SESSION.trim().toLowerCase(Locale.ROOT), 138 TelephonyProtoEnums.IMS_FEATURE_TAG_CHAT_SESSION); 139 FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_FILE_TRANSFER.trim().toLowerCase(Locale.ROOT), 140 TelephonyProtoEnums.IMS_FEATURE_TAG_FILE_TRANSFER); 141 FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_FILE_TRANSFER_VIA_SMS.trim() 142 .toLowerCase(Locale.ROOT), 143 TelephonyProtoEnums.IMS_FEATURE_TAG_FILE_TRANSFER_VIA_SMS); 144 FEATURE_TAGS.put( 145 FeatureTags.FEATURE_TAG_CALL_COMPOSER_ENRICHED_CALLING.trim() 146 .toLowerCase(Locale.ROOT), 147 TelephonyProtoEnums.IMS_FEATURE_TAG_CALL_COMPOSER_ENRICHED_CALLING); 148 FEATURE_TAGS.put( 149 FeatureTags.FEATURE_TAG_CALL_COMPOSER_VIA_TELEPHONY.trim().toLowerCase(Locale.ROOT), 150 TelephonyProtoEnums.IMS_FEATURE_TAG_CALL_COMPOSER_VIA_TELEPHONY); 151 FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_POST_CALL.trim().toLowerCase(Locale.ROOT), 152 TelephonyProtoEnums.IMS_FEATURE_TAG_POST_CALL); 153 FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_SHARED_MAP.trim().toLowerCase(Locale.ROOT), 154 TelephonyProtoEnums.IMS_FEATURE_TAG_SHARED_MAP); 155 FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_SHARED_SKETCH.trim().toLowerCase(Locale.ROOT), 156 TelephonyProtoEnums.IMS_FEATURE_TAG_SHARED_SKETCH); 157 FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_GEO_PUSH.trim().toLowerCase(Locale.ROOT), 158 TelephonyProtoEnums.IMS_FEATURE_TAG_GEO_PUSH); 159 FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_GEO_PUSH_VIA_SMS.trim().toLowerCase(Locale.ROOT), 160 TelephonyProtoEnums.IMS_FEATURE_TAG_GEO_PUSH_VIA_SMS); 161 FEATURE_TAGS.put( 162 FeatureTags.FEATURE_TAG_CHATBOT_COMMUNICATION_USING_SESSION.trim() 163 .toLowerCase(Locale.ROOT), 164 TelephonyProtoEnums.IMS_FEATURE_TAG_CHATBOT_COMMUNICATION_USING_SESSION); 165 String FeatureTag = FeatureTags.FEATURE_TAG_CHATBOT_COMMUNICATION_USING_STANDALONE_MSG; 166 FEATURE_TAGS.put(FeatureTag.trim().toLowerCase(Locale.ROOT), 167 TelephonyProtoEnums.IMS_FEATURE_TAG_CHATBOT_COMMUNICATION_USING_STANDALONE_MSG); 168 FEATURE_TAGS.put( 169 FeatureTags.FEATURE_TAG_CHATBOT_VERSION_SUPPORTED.trim().toLowerCase(Locale.ROOT), 170 TelephonyProtoEnums.IMS_FEATURE_TAG_CHATBOT_VERSION_SUPPORTED); 171 FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_CHATBOT_ROLE.trim().toLowerCase(Locale.ROOT), 172 TelephonyProtoEnums.IMS_FEATURE_TAG_CHATBOT_ROLE); 173 FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_MMTEL.trim().toLowerCase(Locale.ROOT), 174 TelephonyProtoEnums.IMS_FEATURE_TAG_MMTEL); 175 FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_VIDEO.trim().toLowerCase(Locale.ROOT), 176 TelephonyProtoEnums.IMS_FEATURE_TAG_VIDEO); 177 FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_PRESENCE.trim().toLowerCase(Locale.ROOT), 178 TelephonyProtoEnums.IMS_FEATURE_TAG_PRESENCE); 179 } 180 181 /** 182 * Describe Service IDs 183 * See frameworks/base/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java 184 * and int value matching the service IDs 185 * See frameworks/proto_logging/stats/atoms.proto 186 */ 187 private static final Map<String, Integer> SERVICE_IDS = new HashMap<>(); 188 189 static { 190 SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_MMTEL.trim().toLowerCase(Locale.ROOT), 191 IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_MMTEL); 192 SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_CHAT_V1.trim().toLowerCase(Locale.ROOT), 193 IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHAT_V1); 194 SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_CHAT_V2.trim().toLowerCase(Locale.ROOT), 195 IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHAT_V2); 196 SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_FT.trim().toLowerCase(Locale.ROOT), 197 IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_FT); 198 SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_FT_OVER_SMS.trim() 199 .toLowerCase(Locale.ROOT), 200 IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_FT_OVER_SMS); 201 SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_GEO_PUSH.trim().toLowerCase(Locale.ROOT), 202 IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_GEO_PUSH); 203 SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_GEO_PUSH_VIA_SMS.trim() 204 .toLowerCase(Locale.ROOT), 205 IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_GEO_PUSH_VIA_SMS); 206 SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_CALL_COMPOSER.trim() 207 .toLowerCase(Locale.ROOT), 208 IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CALL_COMPOSER); 209 SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_POST_CALL.trim() 210 .toLowerCase(Locale.ROOT), 211 IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_POST_CALL); 212 SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_SHARED_MAP.trim() 213 .toLowerCase(Locale.ROOT), 214 IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_SHARED_MAP); 215 SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_SHARED_SKETCH.trim() 216 .toLowerCase(Locale.ROOT), 217 IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_SHARED_SKETCH); 218 SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_CHATBOT.trim().toLowerCase(Locale.ROOT), 219 IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHATBOT); 220 SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_CHATBOT_STANDALONE.trim() 221 .toLowerCase(Locale.ROOT), 222 IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHATBOT_STANDALONE 223 ); 224 SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_CHATBOT_ROLE.trim() 225 .toLowerCase(Locale.ROOT), 226 IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHATBOT_ROLE); 227 } 228 229 /** 230 * Describe Message Method Type 231 * See stats/enums/telephony/enums.proto 232 */ 233 private static final Map<String, Integer> MESSAGE_TYPE = new HashMap<>(); 234 235 static { 236 MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_INVITE.trim().toLowerCase(Locale.ROOT), 237 TelephonyProtoEnums.SIP_REQUEST_INVITE); 238 MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_ACK.trim().toLowerCase(Locale.ROOT), 239 TelephonyProtoEnums.SIP_REQUEST_ACK); 240 MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_OPTIONS.trim().toLowerCase(Locale.ROOT), 241 TelephonyProtoEnums.SIP_REQUEST_OPTIONS); 242 MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_BYE.trim().toLowerCase(Locale.ROOT), 243 TelephonyProtoEnums.SIP_REQUEST_BYE); 244 MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_CANCEL.trim().toLowerCase(Locale.ROOT), 245 TelephonyProtoEnums.SIP_REQUEST_CANCEL); 246 MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_REGISTER.trim().toLowerCase(Locale.ROOT), 247 TelephonyProtoEnums.SIP_REQUEST_REGISTER); 248 MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_PRACK.trim().toLowerCase(Locale.ROOT), 249 TelephonyProtoEnums.SIP_REQUEST_PRACK); 250 MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_SUBSCRIBE.trim().toLowerCase(Locale.ROOT), 251 TelephonyProtoEnums.SIP_REQUEST_SUBSCRIBE); 252 MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_NOTIFY.trim().toLowerCase(Locale.ROOT), 253 TelephonyProtoEnums.SIP_REQUEST_NOTIFY); 254 MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_PUBLISH.trim().toLowerCase(Locale.ROOT), 255 TelephonyProtoEnums.SIP_REQUEST_PUBLISH); 256 MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_INFO.trim().toLowerCase(Locale.ROOT), 257 TelephonyProtoEnums.SIP_REQUEST_INFO); 258 MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_REFER.trim().toLowerCase(Locale.ROOT), 259 TelephonyProtoEnums.SIP_REQUEST_REFER); 260 MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_MESSAGE.trim().toLowerCase(Locale.ROOT), 261 TelephonyProtoEnums.SIP_REQUEST_MESSAGE); 262 MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_UPDATE.trim().toLowerCase(Locale.ROOT), 263 TelephonyProtoEnums.SIP_REQUEST_UPDATE); 264 } 265 266 /** 267 * Describe Reasons 268 * See frameworks/opt/net/ims/src/java/com/android/ims/rcs/uce/request/ 269 * SubscriptionTerminatedHelper.java 270 * and int value matching the Reasons 271 * See frameworks/proto_logging/stats/atoms.proto 272 */ 273 private static final Map<String, Integer> NOTIFY_REASONS = new HashMap<>(); 274 275 static { 276 NOTIFY_REASONS.put("deactivated", PRESENCE_NOTIFY_EVENT__REASON__REASON_DEACTIVATED); 277 NOTIFY_REASONS.put("probation", PRESENCE_NOTIFY_EVENT__REASON__REASON_PROBATION); 278 NOTIFY_REASONS.put("rejected", PRESENCE_NOTIFY_EVENT__REASON__REASON_REJECTED); 279 NOTIFY_REASONS.put("timeout", PRESENCE_NOTIFY_EVENT__REASON__REASON_TIMEOUT); 280 NOTIFY_REASONS.put("giveup", PRESENCE_NOTIFY_EVENT__REASON__REASON_GIVEUP); 281 NOTIFY_REASONS.put("noresource", PRESENCE_NOTIFY_EVENT__REASON__REASON_NORESOURCE); 282 } 283 284 /** 285 * Describe Rcs Capability set 286 * See frameworks/base/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java 287 */ 288 private static final HashSet<String> RCS_SERVICE_ID_SET = new HashSet<>(); 289 static { 290 RCS_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_CHAT_V1); 291 RCS_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_CHAT_V2); 292 RCS_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_FT); 293 RCS_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_FT_OVER_SMS); 294 RCS_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_GEO_PUSH); 295 RCS_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_GEO_PUSH_VIA_SMS); 296 RCS_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_SHARED_MAP); 297 RCS_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_SHARED_SKETCH); 298 RCS_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_CHATBOT); 299 RCS_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_CHATBOT_STANDALONE); 300 RCS_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_CHATBOT_ROLE); 301 } 302 303 /** 304 * Describe Mmtel Capability set 305 * See frameworks/base/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java 306 */ 307 private static final HashSet<String> MMTEL_SERVICE_ID_SET = new HashSet<>(); 308 static { 309 MMTEL_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_MMTEL); 310 MMTEL_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_CALL_COMPOSER); 311 MMTEL_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_POST_CALL); 312 } 313 314 private static final Map<Long, Integer> sSubscribeTaskIds = new HashMap<>(); 315 private static final int SUBSCRIBE_SUCCESS = 1; 316 private static final int SUBSCRIBE_NOTIFY = 2; 317 318 @VisibleForTesting 319 protected final Map<Integer, ImsDedicatedBearerListenerEvent> mDedicatedBearerListenerEventMap = 320 new HashMap<>(); 321 @VisibleForTesting 322 protected final List<RcsAcsProvisioningStats> mRcsAcsProvisioningStatsList = 323 new ArrayList<RcsAcsProvisioningStats>(); 324 @VisibleForTesting 325 protected final HashMap<Integer, RcsProvisioningCallback> mRcsProvisioningCallbackMap = 326 new HashMap<>(); 327 328 // Maps feature tag name -> ImsRegistrationFeatureTagStats. 329 private final List<ImsRegistrationFeatureTagStats> mImsRegistrationFeatureTagStatsList = 330 new ArrayList<>(); 331 332 // Maps service id -> ImsRegistrationServiceDescStats. 333 @VisibleForTesting 334 protected final List<ImsRegistrationServiceDescStats> mImsRegistrationServiceDescStatsList = 335 new ArrayList<>(); 336 337 private List<LastSipDelegateStat> mLastSipDelegateStatList = new ArrayList<>(); 338 private HashMap<Integer, SipTransportFeatureTags> mLastFeatureTagStatMap = new HashMap<>(); 339 private ArrayList<SipMessageArray> mSipMessageArray = new ArrayList<>(); 340 private ArrayList<SipTransportSessionArray> mSipTransportSessionArray = new ArrayList<>(); 341 private SipTransportSessionArray mSipTransportSession; 342 private SipMessageArray mSipMessage; 343 344 private class LastSipDelegateStat { 345 public int mSubId; 346 public SipDelegateStats mLastStat; 347 private Set<String> mSupportedTags; 348 LastSipDelegateStat(int subId, Set<String> supportedTags)349 LastSipDelegateStat(int subId, Set<String> supportedTags) { 350 mSubId = subId; 351 mSupportedTags = supportedTags; 352 } 353 createSipDelegateStat(int subId)354 public void createSipDelegateStat(int subId) { 355 mLastStat = getDefaultSipDelegateStat(subId); 356 mLastStat.uptimeMillis = getWallTimeMillis(); 357 mLastStat.destroyReason = NONE; 358 } 359 setSipDelegateDestroyReason(int destroyReason)360 public void setSipDelegateDestroyReason(int destroyReason) { 361 mLastStat.destroyReason = destroyReason; 362 } 363 isDestroyed()364 public boolean isDestroyed() { 365 return mLastStat.destroyReason > NONE; 366 } 367 conclude(long now)368 public void conclude(long now) { 369 long duration = now - mLastStat.uptimeMillis; 370 if (duration < MIN_DURATION_MILLIS) { 371 logd("concludeSipDelegateStat: discarding transient stats," 372 + " duration= " + duration); 373 } else { 374 mLastStat.uptimeMillis = duration; 375 mAtomsStorage.addSipDelegateStats(copyOf(mLastStat)); 376 } 377 mLastStat.uptimeMillis = now; 378 } 379 compare(int subId, Set<String> supportedTags)380 public boolean compare(int subId, Set<String> supportedTags) { 381 if (subId != mSubId || supportedTags == null || supportedTags.isEmpty()) { 382 return false; 383 } 384 for (String tag : supportedTags) { 385 if (!mSupportedTags.contains(tag)) { 386 return false; 387 } 388 } 389 return true; 390 } 391 getDefaultSipDelegateStat(int subId)392 private SipDelegateStats getDefaultSipDelegateStat(int subId) { 393 SipDelegateStats stat = new SipDelegateStats(); 394 stat.dimension = RANDOM.nextInt(); 395 stat.carrierId = getCarrierId(subId); 396 stat.slotId = getSlotId(subId); 397 return stat; 398 } 399 } 400 copyOf(@onNull SipDelegateStats source)401 private static SipDelegateStats copyOf(@NonNull SipDelegateStats source) { 402 SipDelegateStats newStat = new SipDelegateStats(); 403 404 newStat.dimension = source.dimension; 405 newStat.slotId = source.slotId; 406 newStat.carrierId = source.carrierId; 407 newStat.destroyReason = source.destroyReason; 408 newStat.uptimeMillis = source.uptimeMillis; 409 410 return newStat; 411 } 412 413 private class SipTransportFeatureTags { 414 private HashMap<String, LastFeatureTagState> mFeatureTagMap; 415 private int mSubId; 416 417 private class LastFeatureTagState { 418 public long timeStamp; 419 public int carrierId; 420 public int slotId; 421 public int state; 422 public int reason; 423 LastFeatureTagState(int carrierId, int slotId, int state, int reason, long timeStamp)424 LastFeatureTagState(int carrierId, int slotId, int state, int reason, long timeStamp) { 425 this.carrierId = carrierId; 426 this.slotId = slotId; 427 this.state = state; 428 this.reason = reason; 429 this.timeStamp = timeStamp; 430 } 431 update(int state, int reason, long timeStamp)432 public void update(int state, int reason, long timeStamp) { 433 this.state = state; 434 this.reason = reason; 435 this.timeStamp = timeStamp; 436 } 437 update(long timeStamp)438 public void update(long timeStamp) { 439 this.timeStamp = timeStamp; 440 } 441 } 442 SipTransportFeatureTags(int subId)443 SipTransportFeatureTags(int subId) { 444 mFeatureTagMap = new HashMap<>(); 445 mSubId = subId; 446 } 447 getLastTagStates()448 public HashMap<String, LastFeatureTagState> getLastTagStates() { 449 return mFeatureTagMap; 450 } 451 452 /*** Create or update featureTags whenever feature Tag states are changed */ updateLastFeatureTagState(String tagName, int state, int reason, long timeStamp)453 public synchronized void updateLastFeatureTagState(String tagName, int state, int reason, 454 long timeStamp) { 455 int carrierId = getCarrierId(mSubId); 456 int slotId = getSlotId(mSubId); 457 if (mFeatureTagMap.containsKey(tagName)) { 458 LastFeatureTagState lastFeatureTagState = mFeatureTagMap.get(tagName); 459 if (lastFeatureTagState != null) { 460 addFeatureTagStat(tagName, lastFeatureTagState, timeStamp); 461 lastFeatureTagState.update(state, reason, timeStamp); 462 } else { 463 create(tagName, carrierId, slotId, state, reason, timeStamp); 464 } 465 466 } else { 467 create(tagName, carrierId, slotId, state, reason, timeStamp); 468 } 469 } 470 471 /** Update current featureTags associated to active SipDelegates when metrics is pulled */ conclude(long timeStamp)472 public synchronized void conclude(long timeStamp) { 473 HashMap<String, LastFeatureTagState> featureTagsCopy = new HashMap<>(); 474 featureTagsCopy.putAll(mFeatureTagMap); 475 for (Map.Entry<String, LastFeatureTagState> last : featureTagsCopy.entrySet()) { 476 String tagName = last.getKey(); 477 LastFeatureTagState lastFeatureTagState = last.getValue(); 478 addFeatureTagStat(tagName, lastFeatureTagState, timeStamp); 479 updateTimeStamp(mSubId, tagName, timeStamp); 480 } 481 } 482 483 /** Finalizes the durations of the current featureTags associated to active SipDelegates */ addFeatureTagStat(@onNull String tagName, @NonNull LastFeatureTagState lastFeatureTagState, long now)484 private synchronized boolean addFeatureTagStat(@NonNull String tagName, 485 @NonNull LastFeatureTagState lastFeatureTagState, long now) { 486 long duration = now - lastFeatureTagState.timeStamp; 487 if (duration < MIN_DURATION_MILLIS 488 || !isValidCarrierId(lastFeatureTagState.carrierId)) { 489 logd("conclude: discarding transient stats, duration= " + duration 490 + ", carrierId = " + lastFeatureTagState.carrierId); 491 } else { 492 SipTransportFeatureTagStats sipFeatureTagStat = new SipTransportFeatureTagStats(); 493 switch (lastFeatureTagState.state) { 494 case STATE_DENIED: 495 sipFeatureTagStat.sipTransportDeniedReason = lastFeatureTagState.reason; 496 sipFeatureTagStat.sipTransportDeregisteredReason = NONE; 497 break; 498 case STATE_DEREGISTERED: 499 sipFeatureTagStat.sipTransportDeniedReason = NONE; 500 sipFeatureTagStat.sipTransportDeregisteredReason = 501 lastFeatureTagState.reason; 502 break; 503 default: 504 sipFeatureTagStat.sipTransportDeniedReason = NONE; 505 sipFeatureTagStat.sipTransportDeregisteredReason = NONE; 506 break; 507 } 508 509 sipFeatureTagStat.carrierId = lastFeatureTagState.carrierId; 510 sipFeatureTagStat.slotId = lastFeatureTagState.slotId; 511 sipFeatureTagStat.associatedMillis = duration; 512 sipFeatureTagStat.featureTagName = convertTagNameToValue(tagName); 513 mAtomsStorage.addSipTransportFeatureTagStats(sipFeatureTagStat); 514 return true; 515 } 516 return false; 517 } 518 updateTimeStamp(int subId, String tagName, long timeStamp)519 private void updateTimeStamp(int subId, String tagName, long timeStamp) { 520 SipTransportFeatureTags sipTransportFeatureTags = mLastFeatureTagStatMap.get(subId); 521 if (sipTransportFeatureTags != null) { 522 HashMap<String, LastFeatureTagState> lastTagStates = 523 sipTransportFeatureTags.getLastTagStates(); 524 if (lastTagStates != null && lastTagStates.containsKey(tagName)) { 525 LastFeatureTagState lastFeatureTagState = lastTagStates.get(tagName); 526 if (lastFeatureTagState != null) { 527 lastFeatureTagState.update(timeStamp); 528 } 529 } 530 } 531 } 532 create(String tagName, int carrierId, int slotId, int state, int reason, long timeStamp)533 private LastFeatureTagState create(String tagName, int carrierId, int slotId, int state, 534 int reason, long timeStamp) { 535 LastFeatureTagState lastFeatureTagState = new LastFeatureTagState(carrierId, slotId, 536 state, reason, timeStamp); 537 mFeatureTagMap.put(tagName, lastFeatureTagState); 538 return lastFeatureTagState; 539 } 540 } 541 542 class UceStatsWriterCallback implements UceStatsCallback { 543 private RcsStats mRcsStats; 544 UceStatsWriterCallback(RcsStats rcsStats)545 UceStatsWriterCallback(RcsStats rcsStats) { 546 logd("created Callback"); 547 mRcsStats = rcsStats; 548 } 549 onImsRegistrationFeatureTagStats(int subId, List<String> featureTagList, int registrationTech)550 public void onImsRegistrationFeatureTagStats(int subId, List<String> featureTagList, 551 int registrationTech) { 552 mRcsStats.onImsRegistrationFeatureTagStats(subId, featureTagList, registrationTech); 553 } 554 onStoreCompleteImsRegistrationFeatureTagStats(int subId)555 public void onStoreCompleteImsRegistrationFeatureTagStats(int subId) { 556 mRcsStats.onStoreCompleteImsRegistrationFeatureTagStats(subId); 557 } 558 onImsRegistrationServiceDescStats(int subId, List<String> serviceIdList, List<String> serviceIdVersionList, int registrationTech)559 public void onImsRegistrationServiceDescStats(int subId, List<String> serviceIdList, 560 List<String> serviceIdVersionList, int registrationTech) { 561 mRcsStats.onImsRegistrationServiceDescStats(subId, serviceIdList, serviceIdVersionList, 562 registrationTech); 563 } 564 onSubscribeResponse(int subId, long taskId, int networkResponse)565 public void onSubscribeResponse(int subId, long taskId, int networkResponse) { 566 if (networkResponse >= 200 && networkResponse <= 299) { 567 if (!sSubscribeTaskIds.containsKey(taskId)) { 568 sSubscribeTaskIds.put(taskId, SUBSCRIBE_SUCCESS); 569 } 570 } 571 mRcsStats.onUceEventStats(subId, UCE_EVENT_STATS__TYPE__SUBSCRIBE, 572 true, 0, networkResponse); 573 } 574 onUceEvent(int subId, int type, boolean successful, int commandCode, int networkResponse)575 public void onUceEvent(int subId, int type, boolean successful, int commandCode, 576 int networkResponse) { 577 int eventType = 0; 578 switch (type) { 579 case UceStatsWriter.PUBLISH_EVENT: 580 eventType = UCE_EVENT_STATS__TYPE__PUBLISH; 581 break; 582 case UceStatsWriter.SUBSCRIBE_EVENT: 583 eventType = UCE_EVENT_STATS__TYPE__SUBSCRIBE; 584 break; 585 case UceStatsWriter.INCOMING_OPTION_EVENT: 586 eventType = UCE_EVENT_STATS__TYPE__INCOMING_OPTION; 587 break; 588 case UceStatsWriter.OUTGOING_OPTION_EVENT: 589 eventType = UCE_EVENT_STATS__TYPE__OUTGOING_OPTION; 590 break; 591 default: 592 return; 593 } 594 mRcsStats.onUceEventStats(subId, eventType, successful, commandCode, networkResponse); 595 } 596 onSubscribeTerminated(int subId, long taskId, String reason)597 public void onSubscribeTerminated(int subId, long taskId, String reason) { 598 if (sSubscribeTaskIds.containsKey(taskId)) { 599 int previousSubscribeStatus = sSubscribeTaskIds.get(taskId); 600 sSubscribeTaskIds.remove(taskId); 601 // The device received a success response related to the subscription request. 602 // However, PIDF was not received due to reason value. 603 if (previousSubscribeStatus == SUBSCRIBE_SUCCESS) { 604 mRcsStats.onPresenceNotifyEvent(subId, reason, false, 605 false, false, false); 606 } 607 } 608 } 609 onPresenceNotifyEvent(int subId, long taskId, List<RcsContactUceCapability> updatedCapList)610 public void onPresenceNotifyEvent(int subId, long taskId, 611 List<RcsContactUceCapability> updatedCapList) { 612 if (updatedCapList == null || updatedCapList.isEmpty()) { 613 return; 614 } 615 if (sSubscribeTaskIds.containsKey(taskId)) { 616 sSubscribeTaskIds.replace(taskId, SUBSCRIBE_NOTIFY); 617 } 618 for (RcsContactUceCapability capability : updatedCapList) { 619 boolean rcsCap = false; 620 boolean mmtelCap = false; 621 boolean noCap = true; 622 List<RcsContactPresenceTuple> tupleList = capability.getCapabilityTuples(); 623 if (tupleList.isEmpty()) { 624 noCap = true; 625 mRcsStats.onPresenceNotifyEvent(subId, "", true, 626 rcsCap, mmtelCap, noCap); 627 continue; 628 } 629 for (RcsContactPresenceTuple tuple : tupleList) { 630 String serviceId = tuple.getServiceId(); 631 if (RCS_SERVICE_ID_SET.contains(serviceId)) { 632 rcsCap = true; 633 noCap = false; 634 } else if (MMTEL_SERVICE_ID_SET.contains(serviceId)) { 635 if (serviceId.equals(RcsContactPresenceTuple.SERVICE_ID_CALL_COMPOSER)) { 636 if ("1.0".equals(tuple.getServiceVersion())) { 637 rcsCap = true; 638 noCap = false; 639 continue; 640 } 641 } 642 mmtelCap = true; 643 noCap = false; 644 } 645 } 646 mRcsStats.onPresenceNotifyEvent(subId, "", true, rcsCap, 647 mmtelCap, noCap); 648 } 649 } 650 onStoreCompleteImsRegistrationServiceDescStats(int subId)651 public void onStoreCompleteImsRegistrationServiceDescStats(int subId) { 652 mRcsStats.onStoreCompleteImsRegistrationServiceDescStats(subId); 653 } 654 } 655 656 /** Callback class to receive RCS ACS result and to store metrics. */ 657 public class RcsProvisioningCallback extends IRcsConfigCallback.Stub { 658 private RcsStats mRcsStats; 659 private int mSubId; 660 private boolean mEnableSingleRegistration; 661 private boolean mRegistered; 662 RcsProvisioningCallback(RcsStats rcsStats, int subId, boolean enableSingleRegistration)663 RcsProvisioningCallback(RcsStats rcsStats, int subId, boolean enableSingleRegistration) { 664 logd("created RcsProvisioningCallback"); 665 mRcsStats = rcsStats; 666 mSubId = subId; 667 mEnableSingleRegistration = enableSingleRegistration; 668 mRegistered = false; 669 } 670 setEnableSingleRegistration(boolean enableSingleRegistration)671 public synchronized void setEnableSingleRegistration(boolean enableSingleRegistration) { 672 mEnableSingleRegistration = enableSingleRegistration; 673 } 674 getRegistered()675 public boolean getRegistered() { 676 return mRegistered; 677 } 678 setRegistered(boolean registered)679 public void setRegistered(boolean registered) { 680 mRegistered = registered; 681 } 682 683 @Override onConfigurationChanged(byte[] config)684 public void onConfigurationChanged(byte[] config) { 685 // this callback will not be handled. 686 } 687 688 @Override onAutoConfigurationErrorReceived(int errorCode, String errorString)689 public void onAutoConfigurationErrorReceived(int errorCode, String errorString) { 690 final long callingIdentity = Binder.clearCallingIdentity(); 691 try { 692 mRcsStats.onRcsAcsProvisioningStats(mSubId, errorCode, 693 RCS_ACS_PROVISIONING_STATS__RESPONSE_TYPE__ERROR, 694 mEnableSingleRegistration); 695 } finally { 696 restoreCallingIdentity(callingIdentity); 697 } 698 } 699 700 @Override onConfigurationReset()701 public void onConfigurationReset() { 702 // this callback will not be handled. 703 } 704 705 @Override onRemoved()706 public void onRemoved() { 707 final long callingIdentity = Binder.clearCallingIdentity(); 708 try { 709 // store cached metrics 710 mRcsStats.onStoreCompleteRcsAcsProvisioningStats(mSubId); 711 // remove this obj from Map 712 mRcsStats.removeRcsProvisioningCallback(mSubId); 713 } finally { 714 restoreCallingIdentity(callingIdentity); 715 } 716 } 717 718 @Override onPreProvisioningReceived(byte[] config)719 public void onPreProvisioningReceived(byte[] config) { 720 final long callingIdentity = Binder.clearCallingIdentity(); 721 try { 722 // Receiving pre provisioning means http 200 OK with body. 723 mRcsStats.onRcsAcsProvisioningStats(mSubId, 200, 724 RCS_ACS_PROVISIONING_STATS__RESPONSE_TYPE__PRE_PROVISIONING_XML, 725 mEnableSingleRegistration); 726 } finally { 727 restoreCallingIdentity(callingIdentity); 728 } 729 } 730 }; 731 732 private class SipMessageArray { 733 private String mMethod; 734 private String mCallId; 735 private int mDirection; 736 SipMessageArray(String method, int direction, String callId)737 SipMessageArray(String method, int direction, String callId) { 738 this.mMethod = method; 739 this.mCallId = callId; 740 this.mDirection = direction; 741 } 742 addSipMessageStat( @onNull int subId, @NonNull String sipMessageMethod, int sipMessageResponse, int sipMessageDirection, int messageError)743 private synchronized void addSipMessageStat( 744 @NonNull int subId, @NonNull String sipMessageMethod, 745 int sipMessageResponse, int sipMessageDirection, int messageError) { 746 int carrierId = getCarrierId(subId); 747 if (!isValidCarrierId(carrierId)) { 748 return; 749 } 750 SipMessageResponse proto = new SipMessageResponse(); 751 proto.carrierId = carrierId; 752 proto.slotId = getSlotId(subId); 753 proto.sipMessageMethod = convertMessageTypeToValue(sipMessageMethod); 754 proto.sipMessageResponse = sipMessageResponse; 755 proto.sipMessageDirection = sipMessageDirection; 756 proto.messageError = messageError; 757 proto.count = 1; 758 mAtomsStorage.addSipMessageResponse(proto); 759 } 760 } 761 762 private class SipTransportSessionArray { 763 private String mMethod; 764 private String mCallId; 765 private int mDirection; 766 private int mSipResponse; 767 SipTransportSessionArray(String method, int direction, String callId)768 SipTransportSessionArray(String method, int direction, String callId) { 769 this.mMethod = method; 770 this.mCallId = callId; 771 this.mDirection = direction; 772 this.mSipResponse = 0; 773 } 774 addSipTransportSessionStat( @onNull int subId, @NonNull String sessionMethod, int sipMessageDirection, int sipResponse, boolean isEndedGracefully)775 private synchronized void addSipTransportSessionStat( 776 @NonNull int subId, @NonNull String sessionMethod, int sipMessageDirection, 777 int sipResponse, boolean isEndedGracefully) { 778 int carrierId = getCarrierId(subId); 779 if (!isValidCarrierId(carrierId)) { 780 return; 781 } 782 SipTransportSession proto = new SipTransportSession(); 783 proto.carrierId = carrierId; 784 proto.slotId = getSlotId(subId); 785 proto.sessionMethod = convertMessageTypeToValue(sessionMethod); 786 proto.sipMessageDirection = sipMessageDirection; 787 proto.sipResponse = sipResponse; 788 proto.sessionCount = 1; 789 proto.endedGracefullyCount = 1; 790 proto.isEndedGracefully = isEndedGracefully; 791 mAtomsStorage.addCompleteSipTransportSession(proto); 792 } 793 } 794 795 @VisibleForTesting RcsStats()796 protected RcsStats() { 797 mCallback = null; 798 } 799 800 /** Gets a RcsStats instance. */ getInstance()801 public static RcsStats getInstance() { 802 synchronized (RcsStats.class) { 803 if (sInstance == null) { 804 Rlog.d(TAG, "RcsStats created."); 805 sInstance = new RcsStats(); 806 } 807 return sInstance; 808 } 809 } 810 811 /** register callback to UceStatsWriter. */ registerUceCallback()812 public void registerUceCallback() { 813 if (mCallback == null) { 814 mCallback = new UceStatsWriterCallback(sInstance); 815 Rlog.d(TAG, "UceStatsWriterCallback created."); 816 UceStatsWriter.init(mCallback); 817 } 818 } 819 820 /** Update or create new atom when RCS service registered. */ onImsRegistrationFeatureTagStats(int subId, List<String> featureTagList, int registrationTech)821 public void onImsRegistrationFeatureTagStats(int subId, List<String> featureTagList, 822 int registrationTech) { 823 synchronized (mImsRegistrationFeatureTagStatsList) { 824 int carrierId = getCarrierId(subId); 825 if (!isValidCarrierId(carrierId)) { 826 flushImsRegistrationFeatureTagStatsInvalid(); 827 return; 828 } 829 830 // update cached atom if exists 831 onStoreCompleteImsRegistrationFeatureTagStats(subId); 832 833 if (featureTagList == null) { 834 Rlog.d(TAG, "featureTagNames is null or empty"); 835 return; 836 } 837 838 for (String featureTag : featureTagList) { 839 ImsRegistrationFeatureTagStats proto = new ImsRegistrationFeatureTagStats(); 840 proto.carrierId = carrierId; 841 proto.slotId = getSlotId(subId); 842 proto.featureTagName = convertTagNameToValue(featureTag); 843 proto.registrationTech = registrationTech; 844 proto.registeredMillis = getWallTimeMillis(); 845 mImsRegistrationFeatureTagStatsList.add(proto); 846 } 847 } 848 } 849 850 /** Update duration, store and delete cached ImsRegistrationFeatureTagStats list to storage. */ onStoreCompleteImsRegistrationFeatureTagStats(int subId)851 public void onStoreCompleteImsRegistrationFeatureTagStats(int subId) { 852 synchronized (mImsRegistrationFeatureTagStatsList) { 853 int carrierId = getCarrierId(subId); 854 List<ImsRegistrationFeatureTagStats> deleteList = new ArrayList<>(); 855 long now = getWallTimeMillis(); 856 for (ImsRegistrationFeatureTagStats proto : mImsRegistrationFeatureTagStatsList) { 857 if (proto.carrierId == carrierId) { 858 proto.registeredMillis = now - proto.registeredMillis; 859 mAtomsStorage.addImsRegistrationFeatureTagStats(proto); 860 deleteList.add(proto); 861 } 862 } 863 for (ImsRegistrationFeatureTagStats proto : deleteList) { 864 mImsRegistrationFeatureTagStatsList.remove(proto); 865 } 866 } 867 } 868 869 /** Update duration and store cached ImsRegistrationFeatureTagStats when metrics are pulled */ onFlushIncompleteImsRegistrationFeatureTagStats()870 public void onFlushIncompleteImsRegistrationFeatureTagStats() { 871 synchronized (mImsRegistrationFeatureTagStatsList) { 872 long now = getWallTimeMillis(); 873 for (ImsRegistrationFeatureTagStats proto : mImsRegistrationFeatureTagStatsList) { 874 ImsRegistrationFeatureTagStats newProto = copyImsRegistrationFeatureTagStats(proto); 875 // the current time is a placeholder and total registered time will be 876 // calculated when generating final atoms 877 newProto.registeredMillis = now - proto.registeredMillis; 878 mAtomsStorage.addImsRegistrationFeatureTagStats(newProto); 879 proto.registeredMillis = now; 880 } 881 } 882 } 883 884 /** Create a new atom when RCS client stat changed. */ onRcsClientProvisioningStats(int subId, int event)885 public synchronized void onRcsClientProvisioningStats(int subId, int event) { 886 int carrierId = getCarrierId(subId); 887 888 if (!isValidCarrierId(carrierId)) { 889 return; 890 } 891 892 RcsClientProvisioningStats proto = new RcsClientProvisioningStats(); 893 proto.carrierId = carrierId; 894 proto.slotId = getSlotId(subId); 895 proto.event = event; 896 proto.count = 1; 897 mAtomsStorage.addRcsClientProvisioningStats(proto); 898 } 899 900 /** Update or create new atom when RCS ACS stat changed. */ onRcsAcsProvisioningStats(int subId, int responseCode, int responseType, boolean enableSingleRegistration)901 public void onRcsAcsProvisioningStats(int subId, int responseCode, int responseType, 902 boolean enableSingleRegistration) { 903 904 synchronized (mRcsAcsProvisioningStatsList) { 905 int carrierId = getCarrierId(subId); 906 if (!isValidCarrierId(carrierId)) { 907 flushRcsAcsProvisioningStatsInvalid(); 908 return; 909 } 910 911 // update cached atom if exists 912 onStoreCompleteRcsAcsProvisioningStats(subId); 913 914 // create new stats to cache 915 RcsAcsProvisioningStats newStats = new RcsAcsProvisioningStats(); 916 newStats.carrierId = carrierId; 917 newStats.slotId = getSlotId(subId); 918 newStats.responseCode = responseCode; 919 newStats.responseType = responseType; 920 newStats.isSingleRegistrationEnabled = enableSingleRegistration; 921 newStats.count = 1; 922 newStats.stateTimerMillis = getWallTimeMillis(); 923 924 // add new stats in list 925 mRcsAcsProvisioningStatsList.add(newStats); 926 } 927 } 928 929 /** Update duration, store and delete cached RcsAcsProvisioningStats */ onStoreCompleteRcsAcsProvisioningStats(int subId)930 public void onStoreCompleteRcsAcsProvisioningStats(int subId) { 931 synchronized (mRcsAcsProvisioningStatsList) { 932 // find cached RcsAcsProvisioningStats based sub ID 933 RcsAcsProvisioningStats existingStats = getRcsAcsProvisioningStats(subId); 934 if (existingStats != null) { 935 existingStats.stateTimerMillis = 936 getWallTimeMillis() - existingStats.stateTimerMillis; 937 mAtomsStorage.addRcsAcsProvisioningStats(existingStats); 938 // remove cached atom from list 939 mRcsAcsProvisioningStatsList.remove(existingStats); 940 } 941 } 942 } 943 944 /** Update duration and store cached RcsAcsProvisioningStats when metrics are pulled */ onFlushIncompleteRcsAcsProvisioningStats()945 public void onFlushIncompleteRcsAcsProvisioningStats() { 946 synchronized (mRcsAcsProvisioningStatsList) { 947 long now = getWallTimeMillis(); 948 for (RcsAcsProvisioningStats stats : mRcsAcsProvisioningStatsList) { 949 // we store a copy into atoms storage 950 // so that we can continue using the original object. 951 RcsAcsProvisioningStats proto = copyRcsAcsProvisioningStats(stats); 952 // the current time is a placeholder and total registered time will be 953 // calculated when generating final atoms 954 proto.stateTimerMillis = now - proto.stateTimerMillis; 955 mAtomsStorage.addRcsAcsProvisioningStats(proto); 956 // update cached atom's time 957 stats.stateTimerMillis = now; 958 } 959 } 960 } 961 962 /** Create SipDelegateStat when SipDelegate is created */ createSipDelegateStats(int subId, Set<String> supportedTags)963 public synchronized void createSipDelegateStats(int subId, Set<String> supportedTags) { 964 if (supportedTags != null && !supportedTags.isEmpty()) { 965 LastSipDelegateStat lastState = getLastSipDelegateStat(subId, supportedTags); 966 lastState.createSipDelegateStat(subId); 967 } 968 } 969 970 /** Update destroyReason and duration of SipDelegateStat when SipDelegate is destroyed */ onSipDelegateStats(int subId, Set<String> supportedTags, int destroyReason)971 public synchronized void onSipDelegateStats(int subId, Set<String> supportedTags, 972 int destroyReason) { 973 if (supportedTags != null && !supportedTags.isEmpty()) { 974 LastSipDelegateStat lastState = getLastSipDelegateStat(subId, supportedTags); 975 lastState.setSipDelegateDestroyReason(destroyReason); 976 concludeSipDelegateStat(); 977 } 978 } 979 980 /** Create/Update atoms when states of sipTransportFeatureTags are changed */ onSipTransportFeatureTagStats( int subId, Set<FeatureTagState> deniedTags, Set<FeatureTagState> deRegiTags, Set<String> regiTags)981 public synchronized void onSipTransportFeatureTagStats( 982 int subId, 983 Set<FeatureTagState> deniedTags, 984 Set<FeatureTagState> deRegiTags, 985 Set<String> regiTags) { 986 long now = getWallTimeMillis(); 987 SipTransportFeatureTags sipTransportFeatureTags = getLastFeatureTags(subId); 988 if (regiTags != null && !regiTags.isEmpty()) { 989 for (String tag : regiTags) { 990 sipTransportFeatureTags.updateLastFeatureTagState(tag, STATE_REGISTERED, 991 NONE, now); 992 } 993 } 994 if (deniedTags != null && !deniedTags.isEmpty()) { 995 for (FeatureTagState tag : deniedTags) { 996 sipTransportFeatureTags.updateLastFeatureTagState(tag.getFeatureTag(), STATE_DENIED, 997 tag.getState(), now); 998 } 999 } 1000 if (deRegiTags != null && !deRegiTags.isEmpty()) { 1001 for (FeatureTagState tag : deRegiTags) { 1002 sipTransportFeatureTags.updateLastFeatureTagState( 1003 tag.getFeatureTag(), STATE_DEREGISTERED, tag.getState(), now); 1004 } 1005 } 1006 } 1007 1008 /** Update duration of sipTransportFeatureTags when metrics are pulled */ concludeSipTransportFeatureTagsStat()1009 public synchronized void concludeSipTransportFeatureTagsStat() { 1010 if (mLastFeatureTagStatMap.isEmpty()) { 1011 return; 1012 } 1013 1014 long now = getWallTimeMillis(); 1015 HashMap<Integer, SipTransportFeatureTags> lastFeatureTagStatsCopy = new HashMap<>(); 1016 lastFeatureTagStatsCopy.putAll(mLastFeatureTagStatMap); 1017 for (SipTransportFeatureTags sipTransportFeatureTags : lastFeatureTagStatsCopy.values()) { 1018 if (sipTransportFeatureTags != null) { 1019 sipTransportFeatureTags.conclude(now); 1020 } 1021 } 1022 } 1023 1024 /** Request Message */ onSipMessageRequest(String callId, String sipMessageMethod, int sipMessageDirection)1025 public synchronized void onSipMessageRequest(String callId, String sipMessageMethod, 1026 int sipMessageDirection) { 1027 mSipMessage = new SipMessageArray(sipMessageMethod, sipMessageDirection, callId); 1028 mSipMessageArray.add(mSipMessage); 1029 } 1030 1031 /** invalidated result when Request message is sent */ invalidatedMessageResult(String callId, int subId, String sipMessageMethod, int sipMessageDirection, int messageError)1032 public synchronized void invalidatedMessageResult(String callId, int subId, 1033 String sipMessageMethod, int sipMessageDirection, int messageError) { 1034 if (mSipMessage == null) { 1035 mSipMessage = new SipMessageArray(sipMessageMethod, sipMessageDirection, callId); 1036 } 1037 mSipMessage.addSipMessageStat(subId, sipMessageMethod, 0, 1038 sipMessageDirection, messageError); 1039 } 1040 1041 /** Create a new atom when RCS SIP Message Response changed. */ onSipMessageResponse(int subId, String callId, int sipMessageResponse, int messageError)1042 public synchronized void onSipMessageResponse(int subId, String callId, 1043 int sipMessageResponse, int messageError) { 1044 SipMessageArray match = mSipMessageArray.stream() 1045 .filter(d -> d.mCallId.equals(callId)).findFirst().orElse(null); 1046 if (match != null) { 1047 mSipMessage.addSipMessageStat(subId, match.mMethod, sipMessageResponse, 1048 match.mDirection, messageError); 1049 mSipMessageArray.removeIf(d -> d.mCallId.equals(callId)); 1050 } 1051 } 1052 1053 /** Request SIP Method Message */ earlySipTransportSession(String sessionMethod, String callId, int sipMessageDirection)1054 public synchronized void earlySipTransportSession(String sessionMethod, String callId, 1055 int sipMessageDirection) { 1056 mSipTransportSession = new SipTransportSessionArray(sessionMethod, 1057 sipMessageDirection, callId); 1058 mSipTransportSessionArray.add(mSipTransportSession); 1059 } 1060 1061 /** Response Message */ confirmedSipTransportSession(String callId, int sipResponse)1062 public synchronized void confirmedSipTransportSession(String callId, 1063 int sipResponse) { 1064 SipTransportSessionArray match = mSipTransportSessionArray.stream() 1065 .filter(d -> d.mCallId.equals(callId)).findFirst().orElse(null); 1066 if (match != null) { 1067 match.mSipResponse = sipResponse; 1068 } 1069 } 1070 1071 /** Create a new atom when RCS SIP Transport Session changed. */ onSipTransportSessionClosed(int subId, String callId, int sipResponse, boolean isEndedGracefully)1072 public synchronized void onSipTransportSessionClosed(int subId, String callId, 1073 int sipResponse, boolean isEndedGracefully) { 1074 SipTransportSessionArray match = mSipTransportSessionArray.stream() 1075 .filter(d -> d.mCallId.equals(callId)).findFirst().orElse(null); 1076 if (match != null) { 1077 if (sipResponse != 0) { 1078 match.mSipResponse = sipResponse; 1079 } 1080 mSipTransportSession.addSipTransportSessionStat(subId, match.mMethod, match.mDirection, 1081 sipResponse, isEndedGracefully); 1082 mSipTransportSessionArray.removeIf(d -> d.mCallId.equals(callId)); 1083 } 1084 } 1085 1086 /** Add a listener to the hashmap for waiting upcoming DedicatedBearer established event */ onImsDedicatedBearerListenerAdded(@onNull final int listenerId, @NonNull final int slotId, @NonNull final int ratAtEnd, @NonNull final int qci)1087 public synchronized void onImsDedicatedBearerListenerAdded(@NonNull final int listenerId, 1088 @NonNull final int slotId, @NonNull final int ratAtEnd, @NonNull final int qci) { 1089 int subId = getSubId(slotId); 1090 int carrierId = getCarrierId(subId); 1091 1092 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID 1093 || !isValidCarrierId(carrierId)) { 1094 return; 1095 } 1096 1097 if (mDedicatedBearerListenerEventMap.containsKey(listenerId)) { 1098 return; 1099 } 1100 1101 ImsDedicatedBearerListenerEvent preProto = new ImsDedicatedBearerListenerEvent(); 1102 preProto.carrierId = carrierId; 1103 preProto.slotId = slotId; 1104 preProto.ratAtEnd = ratAtEnd; 1105 preProto.qci = qci; 1106 preProto.dedicatedBearerEstablished = false; 1107 preProto.eventCount = 1; 1108 1109 mDedicatedBearerListenerEventMap.put(listenerId, preProto); 1110 } 1111 1112 /** update previously added atom with dedicatedBearerEstablished = true when 1113 * DedicatedBearerListener Event changed. */ onImsDedicatedBearerListenerUpdateSession(final int listenerId, final int slotId, final int rat, final int qci, @NonNull final boolean dedicatedBearerEstablished)1114 public synchronized void onImsDedicatedBearerListenerUpdateSession(final int listenerId, 1115 final int slotId, final int rat, final int qci, 1116 @NonNull final boolean dedicatedBearerEstablished) { 1117 int subId = getSubId(slotId); 1118 int carrierId = getCarrierId(subId); 1119 1120 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID 1121 || !isValidCarrierId(carrierId)) { 1122 return; 1123 } 1124 1125 if (mDedicatedBearerListenerEventMap.containsKey(listenerId)) { 1126 ImsDedicatedBearerListenerEvent preProto = 1127 mDedicatedBearerListenerEventMap.get(listenerId); 1128 1129 preProto.ratAtEnd = rat; 1130 preProto.qci = qci; 1131 preProto.dedicatedBearerEstablished = dedicatedBearerEstablished; 1132 1133 mDedicatedBearerListenerEventMap.replace(listenerId, preProto); 1134 } else { 1135 ImsDedicatedBearerListenerEvent preProto = new ImsDedicatedBearerListenerEvent(); 1136 preProto.carrierId = carrierId; 1137 preProto.slotId = slotId; 1138 preProto.ratAtEnd = rat; 1139 preProto.qci = qci; 1140 preProto.dedicatedBearerEstablished = dedicatedBearerEstablished; 1141 preProto.eventCount = 1; 1142 1143 mDedicatedBearerListenerEventMap.put(listenerId, preProto); 1144 } 1145 } 1146 1147 /** add proto to atom when listener is removed, so that I can save the status of dedicatedbearer 1148 * establishment per listener id */ onImsDedicatedBearerListenerRemoved(@onNull final int listenerId)1149 public synchronized void onImsDedicatedBearerListenerRemoved(@NonNull final int listenerId) { 1150 if (mDedicatedBearerListenerEventMap.containsKey(listenerId)) { 1151 1152 ImsDedicatedBearerListenerEvent newProto = 1153 mDedicatedBearerListenerEventMap.get(listenerId); 1154 1155 mAtomsStorage.addImsDedicatedBearerListenerEvent(newProto); 1156 mDedicatedBearerListenerEventMap.remove(listenerId); 1157 } 1158 } 1159 1160 /** Create a new atom when DedicatedBearer Event changed. */ onImsDedicatedBearerEvent(int slotId, int ratAtEnd, int qci, int bearerState, boolean localConnectionInfoReceived, boolean remoteConnectionInfoReceived, boolean hasListeners)1161 public synchronized void onImsDedicatedBearerEvent(int slotId, int ratAtEnd, int qci, 1162 int bearerState, boolean localConnectionInfoReceived, 1163 boolean remoteConnectionInfoReceived, boolean hasListeners) { 1164 int subId = getSubId(slotId); 1165 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 1166 return; 1167 } 1168 1169 ImsDedicatedBearerEvent proto = new ImsDedicatedBearerEvent(); 1170 proto.carrierId = getCarrierId(subId); 1171 proto.slotId = getSlotId(subId); 1172 proto.ratAtEnd = ratAtEnd; 1173 proto.qci = qci; 1174 proto.bearerState = bearerState; 1175 proto.localConnectionInfoReceived = localConnectionInfoReceived; 1176 proto.remoteConnectionInfoReceived = remoteConnectionInfoReceived; 1177 proto.hasListeners = hasListeners; 1178 proto.count = 1; 1179 mAtomsStorage.addImsDedicatedBearerEvent(proto); 1180 } 1181 1182 /** 1183 * Update or Create a new atom when Ims Registration Service Desc state changed. 1184 * Use-related parts are already converted from UseStatsWriter based on RcsContactPresenceTuple. 1185 */ onImsRegistrationServiceDescStats(int subId, List<String> serviceIdList, List<String> serviceIdVersionList, int registrationTech)1186 public void onImsRegistrationServiceDescStats(int subId, List<String> serviceIdList, 1187 List<String> serviceIdVersionList, int registrationTech) { 1188 synchronized (mImsRegistrationServiceDescStatsList) { 1189 int carrierId = getCarrierId(subId); 1190 if (!isValidCarrierId(carrierId)) { 1191 handleImsRegistrationServiceDescStats(); 1192 return; 1193 } 1194 // update cached atom if exists 1195 onStoreCompleteImsRegistrationServiceDescStats(subId); 1196 1197 if (serviceIdList == null) { 1198 Rlog.d(TAG, "serviceIds is null or empty"); 1199 return; 1200 } 1201 1202 int index = 0; 1203 for (String serviceId : serviceIdList) { 1204 ImsRegistrationServiceDescStats mImsRegistrationServiceDescStats = 1205 new ImsRegistrationServiceDescStats(); 1206 1207 mImsRegistrationServiceDescStats.carrierId = carrierId; 1208 mImsRegistrationServiceDescStats.slotId = getSlotId(subId); 1209 mImsRegistrationServiceDescStats.serviceIdName = convertServiceIdToValue(serviceId); 1210 mImsRegistrationServiceDescStats.serviceIdVersion = 1211 Float.parseFloat(serviceIdVersionList.get(index++)); 1212 mImsRegistrationServiceDescStats.registrationTech = registrationTech; 1213 mImsRegistrationServiceDescStatsList.add(mImsRegistrationServiceDescStats); 1214 } 1215 } 1216 } 1217 1218 /** Update duration and cached of ImsRegistrationServiceDescStats when metrics are pulled */ onFlushIncompleteImsRegistrationServiceDescStats()1219 public void onFlushIncompleteImsRegistrationServiceDescStats() { 1220 synchronized (mImsRegistrationServiceDescStatsList) { 1221 for (ImsRegistrationServiceDescStats proto : mImsRegistrationServiceDescStatsList) { 1222 ImsRegistrationServiceDescStats newProto = 1223 copyImsRegistrationServiceDescStats(proto); 1224 long now = getWallTimeMillis(); 1225 // the current time is a placeholder and total registered time will be 1226 // calculated when generating final atoms 1227 newProto.publishedMillis = now - proto.publishedMillis; 1228 mAtomsStorage.addImsRegistrationServiceDescStats(newProto); 1229 proto.publishedMillis = now; 1230 } 1231 } 1232 } 1233 1234 /** Create a new atom when Uce Event Stats changed. */ onUceEventStats(int subId, int type, boolean successful, int commandCode, int networkResponse)1235 public synchronized void onUceEventStats(int subId, int type, boolean successful, 1236 int commandCode, int networkResponse) { 1237 UceEventStats proto = new UceEventStats(); 1238 1239 int carrierId = getCarrierId(subId); 1240 if (!isValidCarrierId(carrierId)) { 1241 handleImsRegistrationServiceDescStats(); 1242 return; 1243 } 1244 proto.carrierId = carrierId; 1245 proto.slotId = getSlotId(subId); 1246 proto.type = type; 1247 proto.successful = successful; 1248 proto.commandCode = commandCode; 1249 proto.networkResponse = networkResponse; 1250 proto.count = 1; 1251 mAtomsStorage.addUceEventStats(proto); 1252 1253 /** 1254 * The publishedMillis of ImsRegistrationServiceDescStat is the time gap between 1255 * Publish success and Un publish. 1256 * So, when the publish operation is successful, the corresponding time gap is set, 1257 * and in case of failure, the cached stat is deleted. 1258 */ 1259 if (type == UCE_EVENT_STATS__TYPE__PUBLISH) { 1260 if (successful) { 1261 setImsRegistrationServiceDescStatsTime(proto.carrierId); 1262 } else { 1263 deleteImsRegistrationServiceDescStats(proto.carrierId); 1264 } 1265 } 1266 } 1267 1268 /** Create a new atom when Presence Notify Event changed. */ onPresenceNotifyEvent(int subId, String reason, boolean contentBodyReceived, boolean rcsCaps, boolean mmtelCaps, boolean noCaps)1269 public synchronized void onPresenceNotifyEvent(int subId, String reason, 1270 boolean contentBodyReceived, boolean rcsCaps, boolean mmtelCaps, boolean noCaps) { 1271 PresenceNotifyEvent proto = new PresenceNotifyEvent(); 1272 1273 int carrierId = getCarrierId(subId); 1274 if (!isValidCarrierId(carrierId)) { 1275 handleImsRegistrationServiceDescStats(); 1276 return; 1277 } 1278 1279 proto.carrierId = carrierId; 1280 proto.slotId = getSlotId(subId); 1281 proto.reason = convertPresenceNotifyReason(reason); 1282 proto.contentBodyReceived = contentBodyReceived; 1283 proto.rcsCapsCount = rcsCaps ? 1 : 0; 1284 proto.mmtelCapsCount = mmtelCaps ? 1 : 0; 1285 proto.noCapsCount = noCaps ? 1 : 0; 1286 proto.count = 1; 1287 mAtomsStorage.addPresenceNotifyEvent(proto); 1288 } 1289 1290 /** Update duration a created Ims Registration Desc Stat atom when Un publish event happened. */ onStoreCompleteImsRegistrationServiceDescStats(int subId)1291 public void onStoreCompleteImsRegistrationServiceDescStats(int subId) { 1292 synchronized (mImsRegistrationServiceDescStatsList) { 1293 int carrierId = getCarrierId(subId); 1294 List<ImsRegistrationServiceDescStats> deleteList = new ArrayList<>(); 1295 for (ImsRegistrationServiceDescStats proto : mImsRegistrationServiceDescStatsList) { 1296 if (proto.carrierId == carrierId) { 1297 proto.publishedMillis = getWallTimeMillis() - proto.publishedMillis; 1298 mAtomsStorage.addImsRegistrationServiceDescStats(proto); 1299 deleteList.add(proto); 1300 } 1301 } 1302 for (ImsRegistrationServiceDescStats proto : deleteList) { 1303 mImsRegistrationServiceDescStatsList.remove(proto); 1304 } 1305 } 1306 } 1307 1308 /** Create a new atom when GBA Success Event changed. */ onGbaSuccessEvent(int subId)1309 public synchronized void onGbaSuccessEvent(int subId) { 1310 int carrierId = getCarrierId(subId); 1311 if (!isValidCarrierId(carrierId)) { 1312 return; 1313 } 1314 1315 GbaEvent proto = new GbaEvent(); 1316 proto.carrierId = carrierId; 1317 proto.slotId = getSlotId(subId); 1318 proto.successful = true; 1319 proto.failedReason = -1; 1320 proto.count = 1; 1321 mAtomsStorage.addGbaEvent(proto); 1322 } 1323 1324 /** Create a new atom when GBA Failure Event changed. */ onGbaFailureEvent(int subId, int reason)1325 public synchronized void onGbaFailureEvent(int subId, int reason) { 1326 int carrierId = getCarrierId(subId); 1327 if (!isValidCarrierId(carrierId)) { 1328 return; 1329 } 1330 1331 GbaEvent proto = new GbaEvent(); 1332 proto.carrierId = carrierId; 1333 proto.slotId = getSlotId(subId); 1334 proto.successful = false; 1335 proto.failedReason = reason; 1336 proto.count = 1; 1337 mAtomsStorage.addGbaEvent(proto); 1338 } 1339 1340 /** Create or return exist RcsProvisioningCallback based on subId. */ getRcsProvisioningCallback(int subId, boolean enableSingleRegistration)1341 public synchronized RcsProvisioningCallback getRcsProvisioningCallback(int subId, 1342 boolean enableSingleRegistration) { 1343 // find exist obj in Map 1344 RcsProvisioningCallback rcsProvisioningCallback = mRcsProvisioningCallbackMap.get(subId); 1345 if (rcsProvisioningCallback != null) { 1346 return rcsProvisioningCallback; 1347 } 1348 1349 // create new, add Map and return 1350 rcsProvisioningCallback = new RcsProvisioningCallback(this, subId, 1351 enableSingleRegistration); 1352 mRcsProvisioningCallbackMap.put(subId, rcsProvisioningCallback); 1353 return rcsProvisioningCallback; 1354 } 1355 1356 /** Set whether single registration is supported. */ setEnableSingleRegistration(int subId, boolean enableSingleRegistration)1357 public synchronized void setEnableSingleRegistration(int subId, 1358 boolean enableSingleRegistration) { 1359 // find exist obj and set 1360 RcsProvisioningCallback callbackBinder = mRcsProvisioningCallbackMap.get(subId); 1361 if (callbackBinder != null) { 1362 callbackBinder.setEnableSingleRegistration(enableSingleRegistration); 1363 } 1364 } 1365 removeRcsProvisioningCallback(int subId)1366 private synchronized void removeRcsProvisioningCallback(int subId) { 1367 // remove obj from Map based on subId 1368 mRcsProvisioningCallbackMap.remove(subId); 1369 } 1370 copyImsRegistrationFeatureTagStats( ImsRegistrationFeatureTagStats proto)1371 private ImsRegistrationFeatureTagStats copyImsRegistrationFeatureTagStats( 1372 ImsRegistrationFeatureTagStats proto) { 1373 ImsRegistrationFeatureTagStats newProto = new ImsRegistrationFeatureTagStats(); 1374 newProto.carrierId = proto.carrierId; 1375 newProto.slotId = proto.slotId; 1376 newProto.featureTagName = proto.featureTagName; 1377 newProto.registrationTech = proto.registrationTech; 1378 newProto.registeredMillis = proto.registeredMillis; 1379 1380 return newProto; 1381 } 1382 copyRcsAcsProvisioningStats(RcsAcsProvisioningStats proto)1383 private RcsAcsProvisioningStats copyRcsAcsProvisioningStats(RcsAcsProvisioningStats proto) { 1384 RcsAcsProvisioningStats newProto = new RcsAcsProvisioningStats(); 1385 newProto.carrierId = proto.carrierId; 1386 newProto.slotId = proto.slotId; 1387 newProto.responseCode = proto.responseCode; 1388 newProto.responseType = proto.responseType; 1389 newProto.isSingleRegistrationEnabled = proto.isSingleRegistrationEnabled; 1390 newProto.count = proto.count; 1391 newProto.stateTimerMillis = proto.stateTimerMillis; 1392 1393 return newProto; 1394 } 1395 copyImsRegistrationServiceDescStats( ImsRegistrationServiceDescStats proto)1396 private ImsRegistrationServiceDescStats copyImsRegistrationServiceDescStats( 1397 ImsRegistrationServiceDescStats proto) { 1398 ImsRegistrationServiceDescStats newProto = new ImsRegistrationServiceDescStats(); 1399 newProto.carrierId = proto.carrierId; 1400 newProto.slotId = proto.slotId; 1401 newProto.serviceIdName = proto.serviceIdName; 1402 newProto.serviceIdVersion = proto.serviceIdVersion; 1403 newProto.registrationTech = proto.registrationTech; 1404 return newProto; 1405 } 1406 setImsRegistrationServiceDescStatsTime(int carrierId)1407 private void setImsRegistrationServiceDescStatsTime(int carrierId) { 1408 synchronized (mImsRegistrationServiceDescStatsList) { 1409 for (ImsRegistrationServiceDescStats descStats : mImsRegistrationServiceDescStatsList) { 1410 if (descStats.carrierId == carrierId) { 1411 descStats.publishedMillis = getWallTimeMillis(); 1412 } 1413 } 1414 } 1415 } 1416 deleteImsRegistrationServiceDescStats(int carrierId)1417 private void deleteImsRegistrationServiceDescStats(int carrierId) { 1418 synchronized (mImsRegistrationServiceDescStatsList) { 1419 List<ImsRegistrationServiceDescStats> deleteList = new ArrayList<>(); 1420 for (ImsRegistrationServiceDescStats proto : mImsRegistrationServiceDescStatsList) { 1421 if (proto.carrierId == carrierId) { 1422 deleteList.add(proto); 1423 } 1424 } 1425 for (ImsRegistrationServiceDescStats stats : deleteList) { 1426 mImsRegistrationServiceDescStatsList.remove(stats); 1427 } 1428 } 1429 } 1430 handleImsRegistrationServiceDescStats()1431 private void handleImsRegistrationServiceDescStats() { 1432 synchronized (mImsRegistrationServiceDescStatsList) { 1433 List<ImsRegistrationServiceDescStats> deleteList = new ArrayList<>(); 1434 for (ImsRegistrationServiceDescStats proto : mImsRegistrationServiceDescStatsList) { 1435 int subId = getSubId(proto.slotId); 1436 int newCarrierId = getCarrierId(subId); 1437 if (proto.carrierId != newCarrierId) { 1438 deleteList.add(proto); 1439 if (proto.publishedMillis != 0) { 1440 proto.publishedMillis = getWallTimeMillis() - proto.publishedMillis; 1441 mAtomsStorage.addImsRegistrationServiceDescStats(proto); 1442 } 1443 } 1444 } 1445 for (ImsRegistrationServiceDescStats stats : deleteList) { 1446 mImsRegistrationServiceDescStatsList.remove(stats); 1447 } 1448 } 1449 } 1450 getRcsAcsProvisioningStats(int subId)1451 private RcsAcsProvisioningStats getRcsAcsProvisioningStats(int subId) { 1452 int carrierId = getCarrierId(subId); 1453 int slotId = getSlotId(subId); 1454 1455 for (RcsAcsProvisioningStats stats : mRcsAcsProvisioningStatsList) { 1456 if (stats == null) { 1457 continue; 1458 } 1459 if (stats.carrierId == carrierId && stats.slotId == slotId) { 1460 return stats; 1461 } 1462 } 1463 return null; 1464 } 1465 flushRcsAcsProvisioningStatsInvalid()1466 private void flushRcsAcsProvisioningStatsInvalid() { 1467 List<RcsAcsProvisioningStats> inValidList = new ArrayList<RcsAcsProvisioningStats>(); 1468 1469 int subId; 1470 int newCarrierId; 1471 1472 for (RcsAcsProvisioningStats stats : mRcsAcsProvisioningStatsList) { 1473 subId = getSubId(stats.slotId); 1474 newCarrierId = getCarrierId(subId); 1475 if (stats.carrierId != newCarrierId) { 1476 inValidList.add(stats); 1477 } 1478 } 1479 1480 for (RcsAcsProvisioningStats inValid : inValidList) { 1481 inValid.stateTimerMillis = getWallTimeMillis() - inValid.stateTimerMillis; 1482 mAtomsStorage.addRcsAcsProvisioningStats(inValid); 1483 mRcsAcsProvisioningStatsList.remove(inValid); 1484 } 1485 inValidList.clear(); 1486 } 1487 flushImsRegistrationFeatureTagStatsInvalid()1488 private void flushImsRegistrationFeatureTagStatsInvalid() { 1489 List<ImsRegistrationFeatureTagStats> inValidList = 1490 new ArrayList<ImsRegistrationFeatureTagStats>(); 1491 1492 int subId; 1493 int newCarrierId; 1494 1495 for (ImsRegistrationFeatureTagStats stats : mImsRegistrationFeatureTagStatsList) { 1496 subId = getSubId(stats.slotId); 1497 newCarrierId = getCarrierId(subId); 1498 if (stats.carrierId != newCarrierId) { 1499 inValidList.add(stats); 1500 } 1501 } 1502 1503 for (ImsRegistrationFeatureTagStats inValid : inValidList) { 1504 inValid.registeredMillis = getWallTimeMillis() - inValid.registeredMillis; 1505 mAtomsStorage.addImsRegistrationFeatureTagStats(inValid); 1506 mImsRegistrationFeatureTagStatsList.remove(inValid); 1507 } 1508 inValidList.clear(); 1509 } 1510 getLastSipDelegateStat(int subId, Set<String> supportedTags)1511 private LastSipDelegateStat getLastSipDelegateStat(int subId, Set<String> supportedTags) { 1512 LastSipDelegateStat stat = null; 1513 for (LastSipDelegateStat lastStat : mLastSipDelegateStatList) { 1514 if (lastStat.compare(subId, supportedTags)) { 1515 stat = lastStat; 1516 break; 1517 } 1518 } 1519 1520 if (stat == null) { 1521 stat = new LastSipDelegateStat(subId, supportedTags); 1522 mLastSipDelegateStatList.add(stat); 1523 } 1524 1525 return stat; 1526 } 1527 concludeSipDelegateStat()1528 private void concludeSipDelegateStat() { 1529 if (mLastSipDelegateStatList.isEmpty()) { 1530 return; 1531 } 1532 long now = getWallTimeMillis(); 1533 List<LastSipDelegateStat> sipDelegateStatsCopy = new ArrayList<>(mLastSipDelegateStatList); 1534 for (LastSipDelegateStat stat : sipDelegateStatsCopy) { 1535 if (stat.isDestroyed()) { 1536 stat.conclude(now); 1537 mLastSipDelegateStatList.remove(stat); 1538 } 1539 } 1540 } 1541 getLastFeatureTags(int subId)1542 private SipTransportFeatureTags getLastFeatureTags(int subId) { 1543 SipTransportFeatureTags sipTransportFeatureTags; 1544 if (mLastFeatureTagStatMap.containsKey(subId)) { 1545 sipTransportFeatureTags = mLastFeatureTagStatMap.get(subId); 1546 } else { 1547 sipTransportFeatureTags = new SipTransportFeatureTags(subId); 1548 mLastFeatureTagStatMap.put(subId, sipTransportFeatureTags); 1549 } 1550 return sipTransportFeatureTags; 1551 } 1552 @VisibleForTesting isValidCarrierId(int carrierId)1553 protected boolean isValidCarrierId(int carrierId) { 1554 return carrierId > TelephonyManager.UNKNOWN_CARRIER_ID; 1555 } 1556 1557 @VisibleForTesting getSlotId(int subId)1558 protected int getSlotId(int subId) { 1559 return SubscriptionManager.getPhoneId(subId); 1560 } 1561 1562 @VisibleForTesting getCarrierId(int subId)1563 protected int getCarrierId(int subId) { 1564 int phoneId = SubscriptionManager.getPhoneId(subId); 1565 Phone phone = PhoneFactory.getPhone(phoneId); 1566 return phone != null ? phone.getCarrierId() : TelephonyManager.UNKNOWN_CARRIER_ID; 1567 } 1568 1569 @VisibleForTesting getWallTimeMillis()1570 protected long getWallTimeMillis() { 1571 //time in UTC, preserved across reboots, but can be adjusted e.g. by the user or NTP 1572 return System.currentTimeMillis(); 1573 } 1574 1575 @VisibleForTesting logd(String msg)1576 protected void logd(String msg) { 1577 Rlog.d(TAG, msg); 1578 } 1579 1580 @VisibleForTesting getSubId(int slotId)1581 protected int getSubId(int slotId) { 1582 return SubscriptionManager.getSubscriptionId(slotId); 1583 } 1584 1585 /** Get a enum value from pre-defined feature tag name list */ 1586 @VisibleForTesting convertTagNameToValue(@onNull String tagName)1587 public int convertTagNameToValue(@NonNull String tagName) { 1588 return FEATURE_TAGS.getOrDefault(tagName.trim().toLowerCase(Locale.ROOT), 1589 TelephonyProtoEnums.IMS_FEATURE_TAG_CUSTOM); 1590 } 1591 1592 /** Get a enum value from pre-defined service id list */ 1593 @VisibleForTesting convertServiceIdToValue(@onNull String serviceId)1594 public int convertServiceIdToValue(@NonNull String serviceId) { 1595 return SERVICE_IDS.getOrDefault(serviceId.trim().toLowerCase(Locale.ROOT), 1596 IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CUSTOM); 1597 } 1598 1599 /** Get a enum value from pre-defined message type list */ 1600 @VisibleForTesting convertMessageTypeToValue(@onNull String messageType)1601 public int convertMessageTypeToValue(@NonNull String messageType) { 1602 return MESSAGE_TYPE.getOrDefault(messageType.trim().toLowerCase(Locale.ROOT), 1603 TelephonyProtoEnums.SIP_REQUEST_CUSTOM); 1604 } 1605 1606 /** Get a enum value from pre-defined reason list */ 1607 @VisibleForTesting convertPresenceNotifyReason(@onNull String reason)1608 public int convertPresenceNotifyReason(@NonNull String reason) { 1609 return NOTIFY_REASONS.getOrDefault(reason.trim().toLowerCase(Locale.ROOT), 1610 PRESENCE_NOTIFY_EVENT__REASON__REASON_CUSTOM); 1611 } 1612 1613 /** 1614 * Print all metrics data for debugging purposes 1615 * 1616 * @param rawWriter Print writer 1617 */ printAllMetrics(PrintWriter rawWriter)1618 public synchronized void printAllMetrics(PrintWriter rawWriter) { 1619 if (mAtomsStorage == null || mAtomsStorage.mAtoms == null) { 1620 return; 1621 } 1622 1623 final IndentingPrintWriter pw = new IndentingPrintWriter(rawWriter, " "); 1624 PersistAtomsProto.PersistAtoms metricAtoms = mAtomsStorage.mAtoms; 1625 1626 pw.println("RcsStats Metrics Proto: "); 1627 pw.println("------------------------------------------"); 1628 pw.println("ImsRegistrationFeatureTagStats:"); 1629 pw.increaseIndent(); 1630 for (ImsRegistrationFeatureTagStats stat : metricAtoms.imsRegistrationFeatureTagStats) { 1631 pw.println("[" + stat.carrierId + "]" 1632 + " [" + stat.slotId + "]" 1633 + " Feature Tag Name = " + stat.featureTagName 1634 + ", Registration Tech = " + stat.registrationTech 1635 + ", Registered Duration (ms) = " + stat.registeredMillis); 1636 } 1637 pw.decreaseIndent(); 1638 1639 pw.println("RcsClientProvisioningStats:"); 1640 pw.increaseIndent(); 1641 for (RcsClientProvisioningStats stat : metricAtoms.rcsClientProvisioningStats) { 1642 pw.println("[" + stat.carrierId + "]" 1643 + " [" + stat.slotId + "]" 1644 + " Event = " + stat.event 1645 + ", Count = " + stat.count); 1646 } 1647 pw.decreaseIndent(); 1648 1649 pw.println("RcsAcsProvisioningStats:"); 1650 pw.increaseIndent(); 1651 for (RcsAcsProvisioningStats stat : metricAtoms.rcsAcsProvisioningStats) { 1652 pw.println("[" + stat.carrierId + "]" 1653 + " [" + stat.slotId + "]" 1654 + " Response Code = " + stat.responseCode 1655 + ", Response Type = " + stat.responseType 1656 + ", Single Registration Enabled = " + stat.isSingleRegistrationEnabled 1657 + ", Count = " + stat.count 1658 + ", State Timer (ms) = " + stat.stateTimerMillis); 1659 } 1660 pw.decreaseIndent(); 1661 1662 pw.println("SipDelegateStats:"); 1663 pw.increaseIndent(); 1664 for (SipDelegateStats stat : metricAtoms.sipDelegateStats) { 1665 pw.println("[" + stat.carrierId + "]" 1666 + " [" + stat.slotId + "]" 1667 + " [" + stat.dimension + "]" 1668 + " Destroy Reason = " + stat.destroyReason 1669 + ", Uptime (ms) = " + stat.uptimeMillis); 1670 } 1671 pw.decreaseIndent(); 1672 1673 pw.println("SipTransportFeatureTagStats:"); 1674 pw.increaseIndent(); 1675 for (SipTransportFeatureTagStats stat : metricAtoms.sipTransportFeatureTagStats) { 1676 pw.println("[" + stat.carrierId + "]" 1677 + " [" + stat.slotId + "]" 1678 + " Feature Tag Name = " + stat.featureTagName 1679 + ", Denied Reason = " + stat.sipTransportDeniedReason 1680 + ", Deregistered Reason = " + stat.sipTransportDeregisteredReason 1681 + ", Associated Time (ms) = " + stat.associatedMillis); 1682 } 1683 pw.decreaseIndent(); 1684 1685 pw.println("SipMessageResponse:"); 1686 pw.increaseIndent(); 1687 for (SipMessageResponse stat : metricAtoms.sipMessageResponse) { 1688 pw.println("[" + stat.carrierId + "]" 1689 + " [" + stat.slotId + "]" 1690 + " Message Method = " + stat.sipMessageMethod 1691 + ", Response = " + stat.sipMessageResponse 1692 + ", Direction = " + stat.sipMessageDirection 1693 + ", Error = " + stat.messageError 1694 + ", Count = " + stat.count); 1695 } 1696 pw.decreaseIndent(); 1697 1698 pw.println("SipTransportSession:"); 1699 pw.increaseIndent(); 1700 for (SipTransportSession stat : metricAtoms.sipTransportSession) { 1701 pw.println("[" + stat.carrierId + "]" 1702 + " [" + stat.slotId + "]" 1703 + " Session Method = " + stat.sessionMethod 1704 + ", Direction = " + stat.sipMessageDirection 1705 + ", Response = " + stat.sipResponse 1706 + ", Count = " + stat.sessionCount 1707 + ", GraceFully Count = " + stat.endedGracefullyCount); 1708 } 1709 pw.decreaseIndent(); 1710 1711 pw.println("ImsDedicatedBearerListenerEvent:"); 1712 pw.increaseIndent(); 1713 for (ImsDedicatedBearerListenerEvent stat : metricAtoms.imsDedicatedBearerListenerEvent) { 1714 pw.println("[" + stat.carrierId + "]" 1715 + " [" + stat.slotId + "]" 1716 + " RAT = " + stat.ratAtEnd 1717 + ", QCI = " + stat.qci 1718 + ", Dedicated Bearer Established = " + stat.dedicatedBearerEstablished 1719 + ", Count = " + stat.eventCount); 1720 } 1721 pw.decreaseIndent(); 1722 1723 pw.println("ImsDedicatedBearerEvent:"); 1724 pw.increaseIndent(); 1725 for (ImsDedicatedBearerEvent stat : metricAtoms.imsDedicatedBearerEvent) { 1726 pw.println("[" + stat.carrierId + "]" 1727 + " [" + stat.slotId + "]" 1728 + " RAT = " + stat.ratAtEnd 1729 + ", QCI = " + stat.qci 1730 + ", Bearer State = " + stat.bearerState 1731 + ", Local Connection Info = " + stat.localConnectionInfoReceived 1732 + ", Remote Connection Info = " + stat.remoteConnectionInfoReceived 1733 + ", Listener Existence = " + stat.hasListeners 1734 + ", Count = " + stat.count); 1735 } 1736 pw.decreaseIndent(); 1737 1738 pw.println("ImsRegistrationServiceDescStats:"); 1739 pw.increaseIndent(); 1740 for (ImsRegistrationServiceDescStats stat : metricAtoms.imsRegistrationServiceDescStats) { 1741 pw.println("[" + stat.carrierId + "]" 1742 + " [" + stat.slotId + "]" 1743 + " Name = " + stat.serviceIdName 1744 + ", Version = " + stat.serviceIdVersion 1745 + ", Registration Tech = " + stat.registrationTech 1746 + ", Published Time (ms) = " + stat.publishedMillis); 1747 } 1748 pw.decreaseIndent(); 1749 1750 pw.println("UceEventStats:"); 1751 pw.increaseIndent(); 1752 for (UceEventStats stat : metricAtoms.uceEventStats) { 1753 pw.println("[" + stat.carrierId + "]" 1754 + " [" + stat.slotId + "]" 1755 + " Type = " + stat.type 1756 + ", Successful = " + stat.successful 1757 + ", Code = " + stat.commandCode 1758 + ", Response = " + stat.networkResponse 1759 + ", Count = " + stat.count); 1760 } 1761 pw.decreaseIndent(); 1762 1763 pw.println("PresenceNotifyEvent:"); 1764 pw.increaseIndent(); 1765 for (PresenceNotifyEvent stat : metricAtoms.presenceNotifyEvent) { 1766 pw.println("[" + stat.carrierId + "]" 1767 + " [" + stat.slotId + "]" 1768 + " Reason = " + stat.reason 1769 + ", Body = " + stat.contentBodyReceived 1770 + ", RCS Count = " + stat.rcsCapsCount 1771 + ", MMTEL Count = " + stat.mmtelCapsCount 1772 + ", NoCaps Count = " + stat.noCapsCount 1773 + ", Count = " + stat.count); 1774 } 1775 pw.decreaseIndent(); 1776 1777 pw.println("GbaEvent:"); 1778 pw.increaseIndent(); 1779 for (GbaEvent stat : metricAtoms.gbaEvent) { 1780 pw.println("[" + stat.carrierId + "]" 1781 + " [" + stat.slotId + "]" 1782 + " Successful = " + stat.successful 1783 + ", Fail Reason = " + stat.failedReason 1784 + ", Count = " + stat.count); 1785 } 1786 pw.decreaseIndent(); 1787 } 1788 } 1789