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(int subId, String sipMessageMethod, int sipMessageDirection, int messageError)1032 public synchronized void invalidatedMessageResult(int subId, String sipMessageMethod, 1033 int sipMessageDirection, int messageError) { 1034 mSipMessage.addSipMessageStat(subId, sipMessageMethod, 0, 1035 sipMessageDirection, messageError); 1036 } 1037 1038 /** Create a new atom when RCS SIP Message Response changed. */ onSipMessageResponse(int subId, String callId, int sipMessageResponse, int messageError)1039 public synchronized void onSipMessageResponse(int subId, String callId, 1040 int sipMessageResponse, int messageError) { 1041 SipMessageArray match = mSipMessageArray.stream() 1042 .filter(d -> d.mCallId.equals(callId)).findFirst().orElse(null); 1043 if (match != null) { 1044 mSipMessage.addSipMessageStat(subId, match.mMethod, sipMessageResponse, 1045 match.mDirection, messageError); 1046 mSipMessageArray.removeIf(d -> d.mCallId.equals(callId)); 1047 } 1048 } 1049 1050 /** Request SIP Method Message */ earlySipTransportSession(String sessionMethod, String callId, int sipMessageDirection)1051 public synchronized void earlySipTransportSession(String sessionMethod, String callId, 1052 int sipMessageDirection) { 1053 mSipTransportSession = new SipTransportSessionArray(sessionMethod, 1054 sipMessageDirection, callId); 1055 mSipTransportSessionArray.add(mSipTransportSession); 1056 } 1057 1058 /** Response Message */ confirmedSipTransportSession(String callId, int sipResponse)1059 public synchronized void confirmedSipTransportSession(String callId, 1060 int sipResponse) { 1061 SipTransportSessionArray match = mSipTransportSessionArray.stream() 1062 .filter(d -> d.mCallId.equals(callId)).findFirst().orElse(null); 1063 if (match != null) { 1064 match.mSipResponse = sipResponse; 1065 } 1066 } 1067 1068 /** Create a new atom when RCS SIP Transport Session changed. */ onSipTransportSessionClosed(int subId, String callId, int sipResponse, boolean isEndedGracefully)1069 public synchronized void onSipTransportSessionClosed(int subId, String callId, 1070 int sipResponse, boolean isEndedGracefully) { 1071 SipTransportSessionArray match = mSipTransportSessionArray.stream() 1072 .filter(d -> d.mCallId.equals(callId)).findFirst().orElse(null); 1073 if (match != null) { 1074 if (sipResponse != 0) { 1075 match.mSipResponse = sipResponse; 1076 } 1077 mSipTransportSession.addSipTransportSessionStat(subId, match.mMethod, match.mDirection, 1078 sipResponse, isEndedGracefully); 1079 mSipTransportSessionArray.removeIf(d -> d.mCallId.equals(callId)); 1080 } 1081 } 1082 1083 /** 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)1084 public synchronized void onImsDedicatedBearerListenerAdded(@NonNull final int listenerId, 1085 @NonNull final int slotId, @NonNull final int ratAtEnd, @NonNull final int qci) { 1086 int subId = getSubId(slotId); 1087 int carrierId = getCarrierId(subId); 1088 1089 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID 1090 || !isValidCarrierId(carrierId)) { 1091 return; 1092 } 1093 1094 if (mDedicatedBearerListenerEventMap.containsKey(listenerId)) { 1095 return; 1096 } 1097 1098 ImsDedicatedBearerListenerEvent preProto = new ImsDedicatedBearerListenerEvent(); 1099 preProto.carrierId = carrierId; 1100 preProto.slotId = slotId; 1101 preProto.ratAtEnd = ratAtEnd; 1102 preProto.qci = qci; 1103 preProto.dedicatedBearerEstablished = false; 1104 preProto.eventCount = 1; 1105 1106 mDedicatedBearerListenerEventMap.put(listenerId, preProto); 1107 } 1108 1109 /** update previously added atom with dedicatedBearerEstablished = true when 1110 * DedicatedBearerListener Event changed. */ onImsDedicatedBearerListenerUpdateSession(final int listenerId, final int slotId, final int rat, final int qci, @NonNull final boolean dedicatedBearerEstablished)1111 public synchronized void onImsDedicatedBearerListenerUpdateSession(final int listenerId, 1112 final int slotId, final int rat, final int qci, 1113 @NonNull final boolean dedicatedBearerEstablished) { 1114 int subId = getSubId(slotId); 1115 int carrierId = getCarrierId(subId); 1116 1117 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID 1118 || !isValidCarrierId(carrierId)) { 1119 return; 1120 } 1121 1122 if (mDedicatedBearerListenerEventMap.containsKey(listenerId)) { 1123 ImsDedicatedBearerListenerEvent preProto = 1124 mDedicatedBearerListenerEventMap.get(listenerId); 1125 1126 preProto.ratAtEnd = rat; 1127 preProto.qci = qci; 1128 preProto.dedicatedBearerEstablished = dedicatedBearerEstablished; 1129 1130 mDedicatedBearerListenerEventMap.replace(listenerId, preProto); 1131 } else { 1132 ImsDedicatedBearerListenerEvent preProto = new ImsDedicatedBearerListenerEvent(); 1133 preProto.carrierId = carrierId; 1134 preProto.slotId = slotId; 1135 preProto.ratAtEnd = rat; 1136 preProto.qci = qci; 1137 preProto.dedicatedBearerEstablished = dedicatedBearerEstablished; 1138 preProto.eventCount = 1; 1139 1140 mDedicatedBearerListenerEventMap.put(listenerId, preProto); 1141 } 1142 } 1143 1144 /** add proto to atom when listener is removed, so that I can save the status of dedicatedbearer 1145 * establishment per listener id */ onImsDedicatedBearerListenerRemoved(@onNull final int listenerId)1146 public synchronized void onImsDedicatedBearerListenerRemoved(@NonNull final int listenerId) { 1147 if (mDedicatedBearerListenerEventMap.containsKey(listenerId)) { 1148 1149 ImsDedicatedBearerListenerEvent newProto = 1150 mDedicatedBearerListenerEventMap.get(listenerId); 1151 1152 mAtomsStorage.addImsDedicatedBearerListenerEvent(newProto); 1153 mDedicatedBearerListenerEventMap.remove(listenerId); 1154 } 1155 } 1156 1157 /** Create a new atom when DedicatedBearer Event changed. */ onImsDedicatedBearerEvent(int slotId, int ratAtEnd, int qci, int bearerState, boolean localConnectionInfoReceived, boolean remoteConnectionInfoReceived, boolean hasListeners)1158 public synchronized void onImsDedicatedBearerEvent(int slotId, int ratAtEnd, int qci, 1159 int bearerState, boolean localConnectionInfoReceived, 1160 boolean remoteConnectionInfoReceived, boolean hasListeners) { 1161 int subId = getSubId(slotId); 1162 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 1163 return; 1164 } 1165 1166 ImsDedicatedBearerEvent proto = new ImsDedicatedBearerEvent(); 1167 proto.carrierId = getCarrierId(subId); 1168 proto.slotId = getSlotId(subId); 1169 proto.ratAtEnd = ratAtEnd; 1170 proto.qci = qci; 1171 proto.bearerState = bearerState; 1172 proto.localConnectionInfoReceived = localConnectionInfoReceived; 1173 proto.remoteConnectionInfoReceived = remoteConnectionInfoReceived; 1174 proto.hasListeners = hasListeners; 1175 proto.count = 1; 1176 mAtomsStorage.addImsDedicatedBearerEvent(proto); 1177 } 1178 1179 /** 1180 * Update or Create a new atom when Ims Registration Service Desc state changed. 1181 * Use-related parts are already converted from UseStatsWriter based on RcsContactPresenceTuple. 1182 */ onImsRegistrationServiceDescStats(int subId, List<String> serviceIdList, List<String> serviceIdVersionList, int registrationTech)1183 public void onImsRegistrationServiceDescStats(int subId, List<String> serviceIdList, 1184 List<String> serviceIdVersionList, int registrationTech) { 1185 synchronized (mImsRegistrationServiceDescStatsList) { 1186 int carrierId = getCarrierId(subId); 1187 if (!isValidCarrierId(carrierId)) { 1188 handleImsRegistrationServiceDescStats(); 1189 return; 1190 } 1191 // update cached atom if exists 1192 onStoreCompleteImsRegistrationServiceDescStats(subId); 1193 1194 if (serviceIdList == null) { 1195 Rlog.d(TAG, "serviceIds is null or empty"); 1196 return; 1197 } 1198 1199 int index = 0; 1200 for (String serviceId : serviceIdList) { 1201 ImsRegistrationServiceDescStats mImsRegistrationServiceDescStats = 1202 new ImsRegistrationServiceDescStats(); 1203 1204 mImsRegistrationServiceDescStats.carrierId = carrierId; 1205 mImsRegistrationServiceDescStats.slotId = getSlotId(subId); 1206 mImsRegistrationServiceDescStats.serviceIdName = convertServiceIdToValue(serviceId); 1207 mImsRegistrationServiceDescStats.serviceIdVersion = 1208 Float.parseFloat(serviceIdVersionList.get(index++)); 1209 mImsRegistrationServiceDescStats.registrationTech = registrationTech; 1210 mImsRegistrationServiceDescStatsList.add(mImsRegistrationServiceDescStats); 1211 } 1212 } 1213 } 1214 1215 /** Update duration and cached of ImsRegistrationServiceDescStats when metrics are pulled */ onFlushIncompleteImsRegistrationServiceDescStats()1216 public void onFlushIncompleteImsRegistrationServiceDescStats() { 1217 synchronized (mImsRegistrationServiceDescStatsList) { 1218 for (ImsRegistrationServiceDescStats proto : mImsRegistrationServiceDescStatsList) { 1219 ImsRegistrationServiceDescStats newProto = 1220 copyImsRegistrationServiceDescStats(proto); 1221 long now = getWallTimeMillis(); 1222 // the current time is a placeholder and total registered time will be 1223 // calculated when generating final atoms 1224 newProto.publishedMillis = now - proto.publishedMillis; 1225 mAtomsStorage.addImsRegistrationServiceDescStats(newProto); 1226 proto.publishedMillis = now; 1227 } 1228 } 1229 } 1230 1231 /** Create a new atom when Uce Event Stats changed. */ onUceEventStats(int subId, int type, boolean successful, int commandCode, int networkResponse)1232 public synchronized void onUceEventStats(int subId, int type, boolean successful, 1233 int commandCode, int networkResponse) { 1234 UceEventStats proto = new UceEventStats(); 1235 1236 int carrierId = getCarrierId(subId); 1237 if (!isValidCarrierId(carrierId)) { 1238 handleImsRegistrationServiceDescStats(); 1239 return; 1240 } 1241 proto.carrierId = carrierId; 1242 proto.slotId = getSlotId(subId); 1243 proto.type = type; 1244 proto.successful = successful; 1245 proto.commandCode = commandCode; 1246 proto.networkResponse = networkResponse; 1247 proto.count = 1; 1248 mAtomsStorage.addUceEventStats(proto); 1249 1250 /** 1251 * The publishedMillis of ImsRegistrationServiceDescStat is the time gap between 1252 * Publish success and Un publish. 1253 * So, when the publish operation is successful, the corresponding time gap is set, 1254 * and in case of failure, the cached stat is deleted. 1255 */ 1256 if (type == UCE_EVENT_STATS__TYPE__PUBLISH) { 1257 if (successful) { 1258 setImsRegistrationServiceDescStatsTime(proto.carrierId); 1259 } else { 1260 deleteImsRegistrationServiceDescStats(proto.carrierId); 1261 } 1262 } 1263 } 1264 1265 /** Create a new atom when Presence Notify Event changed. */ onPresenceNotifyEvent(int subId, String reason, boolean contentBodyReceived, boolean rcsCaps, boolean mmtelCaps, boolean noCaps)1266 public synchronized void onPresenceNotifyEvent(int subId, String reason, 1267 boolean contentBodyReceived, boolean rcsCaps, boolean mmtelCaps, boolean noCaps) { 1268 PresenceNotifyEvent proto = new PresenceNotifyEvent(); 1269 1270 int carrierId = getCarrierId(subId); 1271 if (!isValidCarrierId(carrierId)) { 1272 handleImsRegistrationServiceDescStats(); 1273 return; 1274 } 1275 1276 proto.carrierId = carrierId; 1277 proto.slotId = getSlotId(subId); 1278 proto.reason = convertPresenceNotifyReason(reason); 1279 proto.contentBodyReceived = contentBodyReceived; 1280 proto.rcsCapsCount = rcsCaps ? 1 : 0; 1281 proto.mmtelCapsCount = mmtelCaps ? 1 : 0; 1282 proto.noCapsCount = noCaps ? 1 : 0; 1283 proto.count = 1; 1284 mAtomsStorage.addPresenceNotifyEvent(proto); 1285 } 1286 1287 /** Update duration a created Ims Registration Desc Stat atom when Un publish event happened. */ onStoreCompleteImsRegistrationServiceDescStats(int subId)1288 public void onStoreCompleteImsRegistrationServiceDescStats(int subId) { 1289 synchronized (mImsRegistrationServiceDescStatsList) { 1290 int carrierId = getCarrierId(subId); 1291 List<ImsRegistrationServiceDescStats> deleteList = new ArrayList<>(); 1292 for (ImsRegistrationServiceDescStats proto : mImsRegistrationServiceDescStatsList) { 1293 if (proto.carrierId == carrierId) { 1294 proto.publishedMillis = getWallTimeMillis() - proto.publishedMillis; 1295 mAtomsStorage.addImsRegistrationServiceDescStats(proto); 1296 deleteList.add(proto); 1297 } 1298 } 1299 for (ImsRegistrationServiceDescStats proto : deleteList) { 1300 mImsRegistrationServiceDescStatsList.remove(proto); 1301 } 1302 } 1303 } 1304 1305 /** Create a new atom when GBA Success Event changed. */ onGbaSuccessEvent(int subId)1306 public synchronized void onGbaSuccessEvent(int subId) { 1307 int carrierId = getCarrierId(subId); 1308 if (!isValidCarrierId(carrierId)) { 1309 return; 1310 } 1311 1312 GbaEvent proto = new GbaEvent(); 1313 proto.carrierId = carrierId; 1314 proto.slotId = getSlotId(subId); 1315 proto.successful = true; 1316 proto.failedReason = -1; 1317 proto.count = 1; 1318 mAtomsStorage.addGbaEvent(proto); 1319 } 1320 1321 /** Create a new atom when GBA Failure Event changed. */ onGbaFailureEvent(int subId, int reason)1322 public synchronized void onGbaFailureEvent(int subId, int reason) { 1323 int carrierId = getCarrierId(subId); 1324 if (!isValidCarrierId(carrierId)) { 1325 return; 1326 } 1327 1328 GbaEvent proto = new GbaEvent(); 1329 proto.carrierId = carrierId; 1330 proto.slotId = getSlotId(subId); 1331 proto.successful = false; 1332 proto.failedReason = reason; 1333 proto.count = 1; 1334 mAtomsStorage.addGbaEvent(proto); 1335 } 1336 1337 /** Create or return exist RcsProvisioningCallback based on subId. */ getRcsProvisioningCallback(int subId, boolean enableSingleRegistration)1338 public synchronized RcsProvisioningCallback getRcsProvisioningCallback(int subId, 1339 boolean enableSingleRegistration) { 1340 // find exist obj in Map 1341 RcsProvisioningCallback rcsProvisioningCallback = mRcsProvisioningCallbackMap.get(subId); 1342 if (rcsProvisioningCallback != null) { 1343 return rcsProvisioningCallback; 1344 } 1345 1346 // create new, add Map and return 1347 rcsProvisioningCallback = new RcsProvisioningCallback(this, subId, 1348 enableSingleRegistration); 1349 mRcsProvisioningCallbackMap.put(subId, rcsProvisioningCallback); 1350 return rcsProvisioningCallback; 1351 } 1352 1353 /** Set whether single registration is supported. */ setEnableSingleRegistration(int subId, boolean enableSingleRegistration)1354 public synchronized void setEnableSingleRegistration(int subId, 1355 boolean enableSingleRegistration) { 1356 // find exist obj and set 1357 RcsProvisioningCallback callbackBinder = mRcsProvisioningCallbackMap.get(subId); 1358 if (callbackBinder != null) { 1359 callbackBinder.setEnableSingleRegistration(enableSingleRegistration); 1360 } 1361 } 1362 removeRcsProvisioningCallback(int subId)1363 private synchronized void removeRcsProvisioningCallback(int subId) { 1364 // remove obj from Map based on subId 1365 mRcsProvisioningCallbackMap.remove(subId); 1366 } 1367 copyImsRegistrationFeatureTagStats( ImsRegistrationFeatureTagStats proto)1368 private ImsRegistrationFeatureTagStats copyImsRegistrationFeatureTagStats( 1369 ImsRegistrationFeatureTagStats proto) { 1370 ImsRegistrationFeatureTagStats newProto = new ImsRegistrationFeatureTagStats(); 1371 newProto.carrierId = proto.carrierId; 1372 newProto.slotId = proto.slotId; 1373 newProto.featureTagName = proto.featureTagName; 1374 newProto.registrationTech = proto.registrationTech; 1375 newProto.registeredMillis = proto.registeredMillis; 1376 1377 return newProto; 1378 } 1379 copyRcsAcsProvisioningStats(RcsAcsProvisioningStats proto)1380 private RcsAcsProvisioningStats copyRcsAcsProvisioningStats(RcsAcsProvisioningStats proto) { 1381 RcsAcsProvisioningStats newProto = new RcsAcsProvisioningStats(); 1382 newProto.carrierId = proto.carrierId; 1383 newProto.slotId = proto.slotId; 1384 newProto.responseCode = proto.responseCode; 1385 newProto.responseType = proto.responseType; 1386 newProto.isSingleRegistrationEnabled = proto.isSingleRegistrationEnabled; 1387 newProto.count = proto.count; 1388 newProto.stateTimerMillis = proto.stateTimerMillis; 1389 1390 return newProto; 1391 } 1392 copyImsRegistrationServiceDescStats( ImsRegistrationServiceDescStats proto)1393 private ImsRegistrationServiceDescStats copyImsRegistrationServiceDescStats( 1394 ImsRegistrationServiceDescStats proto) { 1395 ImsRegistrationServiceDescStats newProto = new ImsRegistrationServiceDescStats(); 1396 newProto.carrierId = proto.carrierId; 1397 newProto.slotId = proto.slotId; 1398 newProto.serviceIdName = proto.serviceIdName; 1399 newProto.serviceIdVersion = proto.serviceIdVersion; 1400 newProto.registrationTech = proto.registrationTech; 1401 return newProto; 1402 } 1403 setImsRegistrationServiceDescStatsTime(int carrierId)1404 private void setImsRegistrationServiceDescStatsTime(int carrierId) { 1405 synchronized (mImsRegistrationServiceDescStatsList) { 1406 for (ImsRegistrationServiceDescStats descStats : mImsRegistrationServiceDescStatsList) { 1407 if (descStats.carrierId == carrierId) { 1408 descStats.publishedMillis = getWallTimeMillis(); 1409 } 1410 } 1411 } 1412 } 1413 deleteImsRegistrationServiceDescStats(int carrierId)1414 private void deleteImsRegistrationServiceDescStats(int carrierId) { 1415 synchronized (mImsRegistrationServiceDescStatsList) { 1416 List<ImsRegistrationServiceDescStats> deleteList = new ArrayList<>(); 1417 for (ImsRegistrationServiceDescStats proto : mImsRegistrationServiceDescStatsList) { 1418 if (proto.carrierId == carrierId) { 1419 deleteList.add(proto); 1420 } 1421 } 1422 for (ImsRegistrationServiceDescStats stats : deleteList) { 1423 mImsRegistrationServiceDescStatsList.remove(stats); 1424 } 1425 } 1426 } 1427 handleImsRegistrationServiceDescStats()1428 private void handleImsRegistrationServiceDescStats() { 1429 synchronized (mImsRegistrationServiceDescStatsList) { 1430 List<ImsRegistrationServiceDescStats> deleteList = new ArrayList<>(); 1431 for (ImsRegistrationServiceDescStats proto : mImsRegistrationServiceDescStatsList) { 1432 int subId = getSubId(proto.slotId); 1433 int newCarrierId = getCarrierId(subId); 1434 if (proto.carrierId != newCarrierId) { 1435 deleteList.add(proto); 1436 if (proto.publishedMillis != 0) { 1437 proto.publishedMillis = getWallTimeMillis() - proto.publishedMillis; 1438 mAtomsStorage.addImsRegistrationServiceDescStats(proto); 1439 } 1440 } 1441 } 1442 for (ImsRegistrationServiceDescStats stats : deleteList) { 1443 mImsRegistrationServiceDescStatsList.remove(stats); 1444 } 1445 } 1446 } 1447 getRcsAcsProvisioningStats(int subId)1448 private RcsAcsProvisioningStats getRcsAcsProvisioningStats(int subId) { 1449 int carrierId = getCarrierId(subId); 1450 int slotId = getSlotId(subId); 1451 1452 for (RcsAcsProvisioningStats stats : mRcsAcsProvisioningStatsList) { 1453 if (stats == null) { 1454 continue; 1455 } 1456 if (stats.carrierId == carrierId && stats.slotId == slotId) { 1457 return stats; 1458 } 1459 } 1460 return null; 1461 } 1462 flushRcsAcsProvisioningStatsInvalid()1463 private void flushRcsAcsProvisioningStatsInvalid() { 1464 List<RcsAcsProvisioningStats> inValidList = new ArrayList<RcsAcsProvisioningStats>(); 1465 1466 int subId; 1467 int newCarrierId; 1468 1469 for (RcsAcsProvisioningStats stats : mRcsAcsProvisioningStatsList) { 1470 subId = getSubId(stats.slotId); 1471 newCarrierId = getCarrierId(subId); 1472 if (stats.carrierId != newCarrierId) { 1473 inValidList.add(stats); 1474 } 1475 } 1476 1477 for (RcsAcsProvisioningStats inValid : inValidList) { 1478 inValid.stateTimerMillis = getWallTimeMillis() - inValid.stateTimerMillis; 1479 mAtomsStorage.addRcsAcsProvisioningStats(inValid); 1480 mRcsAcsProvisioningStatsList.remove(inValid); 1481 } 1482 inValidList.clear(); 1483 } 1484 flushImsRegistrationFeatureTagStatsInvalid()1485 private void flushImsRegistrationFeatureTagStatsInvalid() { 1486 List<ImsRegistrationFeatureTagStats> inValidList = 1487 new ArrayList<ImsRegistrationFeatureTagStats>(); 1488 1489 int subId; 1490 int newCarrierId; 1491 1492 for (ImsRegistrationFeatureTagStats stats : mImsRegistrationFeatureTagStatsList) { 1493 subId = getSubId(stats.slotId); 1494 newCarrierId = getCarrierId(subId); 1495 if (stats.carrierId != newCarrierId) { 1496 inValidList.add(stats); 1497 } 1498 } 1499 1500 for (ImsRegistrationFeatureTagStats inValid : inValidList) { 1501 inValid.registeredMillis = getWallTimeMillis() - inValid.registeredMillis; 1502 mAtomsStorage.addImsRegistrationFeatureTagStats(inValid); 1503 mImsRegistrationFeatureTagStatsList.remove(inValid); 1504 } 1505 inValidList.clear(); 1506 } 1507 getLastSipDelegateStat(int subId, Set<String> supportedTags)1508 private LastSipDelegateStat getLastSipDelegateStat(int subId, Set<String> supportedTags) { 1509 LastSipDelegateStat stat = null; 1510 for (LastSipDelegateStat lastStat : mLastSipDelegateStatList) { 1511 if (lastStat.compare(subId, supportedTags)) { 1512 stat = lastStat; 1513 break; 1514 } 1515 } 1516 1517 if (stat == null) { 1518 stat = new LastSipDelegateStat(subId, supportedTags); 1519 mLastSipDelegateStatList.add(stat); 1520 } 1521 1522 return stat; 1523 } 1524 concludeSipDelegateStat()1525 private void concludeSipDelegateStat() { 1526 if (mLastSipDelegateStatList.isEmpty()) { 1527 return; 1528 } 1529 long now = getWallTimeMillis(); 1530 List<LastSipDelegateStat> sipDelegateStatsCopy = new ArrayList<>(mLastSipDelegateStatList); 1531 for (LastSipDelegateStat stat : sipDelegateStatsCopy) { 1532 if (stat.isDestroyed()) { 1533 stat.conclude(now); 1534 mLastSipDelegateStatList.remove(stat); 1535 } 1536 } 1537 } 1538 getLastFeatureTags(int subId)1539 private SipTransportFeatureTags getLastFeatureTags(int subId) { 1540 SipTransportFeatureTags sipTransportFeatureTags; 1541 if (mLastFeatureTagStatMap.containsKey(subId)) { 1542 sipTransportFeatureTags = mLastFeatureTagStatMap.get(subId); 1543 } else { 1544 sipTransportFeatureTags = new SipTransportFeatureTags(subId); 1545 mLastFeatureTagStatMap.put(subId, sipTransportFeatureTags); 1546 } 1547 return sipTransportFeatureTags; 1548 } 1549 @VisibleForTesting isValidCarrierId(int carrierId)1550 protected boolean isValidCarrierId(int carrierId) { 1551 return carrierId > TelephonyManager.UNKNOWN_CARRIER_ID; 1552 } 1553 1554 @VisibleForTesting getSlotId(int subId)1555 protected int getSlotId(int subId) { 1556 return SubscriptionManager.getPhoneId(subId); 1557 } 1558 1559 @VisibleForTesting getCarrierId(int subId)1560 protected int getCarrierId(int subId) { 1561 int phoneId = SubscriptionManager.getPhoneId(subId); 1562 Phone phone = PhoneFactory.getPhone(phoneId); 1563 return phone != null ? phone.getCarrierId() : TelephonyManager.UNKNOWN_CARRIER_ID; 1564 } 1565 1566 @VisibleForTesting getWallTimeMillis()1567 protected long getWallTimeMillis() { 1568 //time in UTC, preserved across reboots, but can be adjusted e.g. by the user or NTP 1569 return System.currentTimeMillis(); 1570 } 1571 1572 @VisibleForTesting logd(String msg)1573 protected void logd(String msg) { 1574 Rlog.d(TAG, msg); 1575 } 1576 1577 @VisibleForTesting getSubId(int slotId)1578 protected int getSubId(int slotId) { 1579 return SubscriptionManager.getSubscriptionId(slotId); 1580 } 1581 1582 /** Get a enum value from pre-defined feature tag name list */ 1583 @VisibleForTesting convertTagNameToValue(@onNull String tagName)1584 public int convertTagNameToValue(@NonNull String tagName) { 1585 return FEATURE_TAGS.getOrDefault(tagName.trim().toLowerCase(Locale.ROOT), 1586 TelephonyProtoEnums.IMS_FEATURE_TAG_CUSTOM); 1587 } 1588 1589 /** Get a enum value from pre-defined service id list */ 1590 @VisibleForTesting convertServiceIdToValue(@onNull String serviceId)1591 public int convertServiceIdToValue(@NonNull String serviceId) { 1592 return SERVICE_IDS.getOrDefault(serviceId.trim().toLowerCase(Locale.ROOT), 1593 IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CUSTOM); 1594 } 1595 1596 /** Get a enum value from pre-defined message type list */ 1597 @VisibleForTesting convertMessageTypeToValue(@onNull String messageType)1598 public int convertMessageTypeToValue(@NonNull String messageType) { 1599 return MESSAGE_TYPE.getOrDefault(messageType.trim().toLowerCase(Locale.ROOT), 1600 TelephonyProtoEnums.SIP_REQUEST_CUSTOM); 1601 } 1602 1603 /** Get a enum value from pre-defined reason list */ 1604 @VisibleForTesting convertPresenceNotifyReason(@onNull String reason)1605 public int convertPresenceNotifyReason(@NonNull String reason) { 1606 return NOTIFY_REASONS.getOrDefault(reason.trim().toLowerCase(Locale.ROOT), 1607 PRESENCE_NOTIFY_EVENT__REASON__REASON_CUSTOM); 1608 } 1609 1610 /** 1611 * Print all metrics data for debugging purposes 1612 * 1613 * @param rawWriter Print writer 1614 */ printAllMetrics(PrintWriter rawWriter)1615 public synchronized void printAllMetrics(PrintWriter rawWriter) { 1616 if (mAtomsStorage == null || mAtomsStorage.mAtoms == null) { 1617 return; 1618 } 1619 1620 final IndentingPrintWriter pw = new IndentingPrintWriter(rawWriter, " "); 1621 PersistAtomsProto.PersistAtoms metricAtoms = mAtomsStorage.mAtoms; 1622 1623 pw.println("RcsStats Metrics Proto: "); 1624 pw.println("------------------------------------------"); 1625 pw.println("ImsRegistrationFeatureTagStats:"); 1626 pw.increaseIndent(); 1627 for (ImsRegistrationFeatureTagStats stat : metricAtoms.imsRegistrationFeatureTagStats) { 1628 pw.println("[" + stat.carrierId + "]" 1629 + " [" + stat.slotId + "]" 1630 + " Feature Tag Name = " + stat.featureTagName 1631 + ", Registration Tech = " + stat.registrationTech 1632 + ", Registered Duration (ms) = " + stat.registeredMillis); 1633 } 1634 pw.decreaseIndent(); 1635 1636 pw.println("RcsClientProvisioningStats:"); 1637 pw.increaseIndent(); 1638 for (RcsClientProvisioningStats stat : metricAtoms.rcsClientProvisioningStats) { 1639 pw.println("[" + stat.carrierId + "]" 1640 + " [" + stat.slotId + "]" 1641 + " Event = " + stat.event 1642 + ", Count = " + stat.count); 1643 } 1644 pw.decreaseIndent(); 1645 1646 pw.println("RcsAcsProvisioningStats:"); 1647 pw.increaseIndent(); 1648 for (RcsAcsProvisioningStats stat : metricAtoms.rcsAcsProvisioningStats) { 1649 pw.println("[" + stat.carrierId + "]" 1650 + " [" + stat.slotId + "]" 1651 + " Response Code = " + stat.responseCode 1652 + ", Response Type = " + stat.responseType 1653 + ", Single Registration Enabled = " + stat.isSingleRegistrationEnabled 1654 + ", Count = " + stat.count 1655 + ", State Timer (ms) = " + stat.stateTimerMillis); 1656 } 1657 pw.decreaseIndent(); 1658 1659 pw.println("SipDelegateStats:"); 1660 pw.increaseIndent(); 1661 for (SipDelegateStats stat : metricAtoms.sipDelegateStats) { 1662 pw.println("[" + stat.carrierId + "]" 1663 + " [" + stat.slotId + "]" 1664 + " [" + stat.dimension + "]" 1665 + " Destroy Reason = " + stat.destroyReason 1666 + ", Uptime (ms) = " + stat.uptimeMillis); 1667 } 1668 pw.decreaseIndent(); 1669 1670 pw.println("SipTransportFeatureTagStats:"); 1671 pw.increaseIndent(); 1672 for (SipTransportFeatureTagStats stat : metricAtoms.sipTransportFeatureTagStats) { 1673 pw.println("[" + stat.carrierId + "]" 1674 + " [" + stat.slotId + "]" 1675 + " Feature Tag Name = " + stat.featureTagName 1676 + ", Denied Reason = " + stat.sipTransportDeniedReason 1677 + ", Deregistered Reason = " + stat.sipTransportDeregisteredReason 1678 + ", Associated Time (ms) = " + stat.associatedMillis); 1679 } 1680 pw.decreaseIndent(); 1681 1682 pw.println("SipMessageResponse:"); 1683 pw.increaseIndent(); 1684 for (SipMessageResponse stat : metricAtoms.sipMessageResponse) { 1685 pw.println("[" + stat.carrierId + "]" 1686 + " [" + stat.slotId + "]" 1687 + " Message Method = " + stat.sipMessageMethod 1688 + ", Response = " + stat.sipMessageResponse 1689 + ", Direction = " + stat.sipMessageDirection 1690 + ", Error = " + stat.messageError 1691 + ", Count = " + stat.count); 1692 } 1693 pw.decreaseIndent(); 1694 1695 pw.println("SipTransportSession:"); 1696 pw.increaseIndent(); 1697 for (SipTransportSession stat : metricAtoms.sipTransportSession) { 1698 pw.println("[" + stat.carrierId + "]" 1699 + " [" + stat.slotId + "]" 1700 + " Session Method = " + stat.sessionMethod 1701 + ", Direction = " + stat.sipMessageDirection 1702 + ", Response = " + stat.sipResponse 1703 + ", Count = " + stat.sessionCount 1704 + ", GraceFully Count = " + stat.endedGracefullyCount); 1705 } 1706 pw.decreaseIndent(); 1707 1708 pw.println("ImsDedicatedBearerListenerEvent:"); 1709 pw.increaseIndent(); 1710 for (ImsDedicatedBearerListenerEvent stat : metricAtoms.imsDedicatedBearerListenerEvent) { 1711 pw.println("[" + stat.carrierId + "]" 1712 + " [" + stat.slotId + "]" 1713 + " RAT = " + stat.ratAtEnd 1714 + ", QCI = " + stat.qci 1715 + ", Dedicated Bearer Established = " + stat.dedicatedBearerEstablished 1716 + ", Count = " + stat.eventCount); 1717 } 1718 pw.decreaseIndent(); 1719 1720 pw.println("ImsDedicatedBearerEvent:"); 1721 pw.increaseIndent(); 1722 for (ImsDedicatedBearerEvent stat : metricAtoms.imsDedicatedBearerEvent) { 1723 pw.println("[" + stat.carrierId + "]" 1724 + " [" + stat.slotId + "]" 1725 + " RAT = " + stat.ratAtEnd 1726 + ", QCI = " + stat.qci 1727 + ", Bearer State = " + stat.bearerState 1728 + ", Local Connection Info = " + stat.localConnectionInfoReceived 1729 + ", Remote Connection Info = " + stat.remoteConnectionInfoReceived 1730 + ", Listener Existence = " + stat.hasListeners 1731 + ", Count = " + stat.count); 1732 } 1733 pw.decreaseIndent(); 1734 1735 pw.println("ImsRegistrationServiceDescStats:"); 1736 pw.increaseIndent(); 1737 for (ImsRegistrationServiceDescStats stat : metricAtoms.imsRegistrationServiceDescStats) { 1738 pw.println("[" + stat.carrierId + "]" 1739 + " [" + stat.slotId + "]" 1740 + " Name = " + stat.serviceIdName 1741 + ", Version = " + stat.serviceIdVersion 1742 + ", Registration Tech = " + stat.registrationTech 1743 + ", Published Time (ms) = " + stat.publishedMillis); 1744 } 1745 pw.decreaseIndent(); 1746 1747 pw.println("UceEventStats:"); 1748 pw.increaseIndent(); 1749 for (UceEventStats stat : metricAtoms.uceEventStats) { 1750 pw.println("[" + stat.carrierId + "]" 1751 + " [" + stat.slotId + "]" 1752 + " Type = " + stat.type 1753 + ", Successful = " + stat.successful 1754 + ", Code = " + stat.commandCode 1755 + ", Response = " + stat.networkResponse 1756 + ", Count = " + stat.count); 1757 } 1758 pw.decreaseIndent(); 1759 1760 pw.println("PresenceNotifyEvent:"); 1761 pw.increaseIndent(); 1762 for (PresenceNotifyEvent stat : metricAtoms.presenceNotifyEvent) { 1763 pw.println("[" + stat.carrierId + "]" 1764 + " [" + stat.slotId + "]" 1765 + " Reason = " + stat.reason 1766 + ", Body = " + stat.contentBodyReceived 1767 + ", RCS Count = " + stat.rcsCapsCount 1768 + ", MMTEL Count = " + stat.mmtelCapsCount 1769 + ", NoCaps Count = " + stat.noCapsCount 1770 + ", Count = " + stat.count); 1771 } 1772 pw.decreaseIndent(); 1773 1774 pw.println("GbaEvent:"); 1775 pw.increaseIndent(); 1776 for (GbaEvent stat : metricAtoms.gbaEvent) { 1777 pw.println("[" + stat.carrierId + "]" 1778 + " [" + stat.slotId + "]" 1779 + " Successful = " + stat.successful 1780 + ", Fail Reason = " + stat.failedReason 1781 + ", Count = " + stat.count); 1782 } 1783 pw.decreaseIndent(); 1784 } 1785 } 1786