1 /* 2 * Copyright (C) 2023 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 com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO__ROUTE__EMERGENCY_CALL_ROUTE_EMERGENCY; 20 import static com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO__ROUTE__EMERGENCY_CALL_ROUTE_NORMAL; 21 import static com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO__ROUTE__EMERGENCY_CALL_ROUTE_UNKNOWN; 22 import static com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO__SERVICE_CATEGORIES__EMERGENCY_SERVICE_CATEGORY_AIEC; 23 import static com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO__SERVICE_CATEGORIES__EMERGENCY_SERVICE_CATEGORY_AMBULANCE; 24 import static com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO__SERVICE_CATEGORIES__EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE; 25 import static com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO__SERVICE_CATEGORIES__EMERGENCY_SERVICE_CATEGORY_MARINE_GUARD; 26 import static com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO__SERVICE_CATEGORIES__EMERGENCY_SERVICE_CATEGORY_MIEC; 27 import static com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO__SERVICE_CATEGORIES__EMERGENCY_SERVICE_CATEGORY_MOUNTAIN_RESCUE; 28 import static com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO__SERVICE_CATEGORIES__EMERGENCY_SERVICE_CATEGORY_POLICE; 29 import static com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO__SERVICE_CATEGORIES__EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED; 30 import static com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO__SOURCES__EMERGENCY_NUMBER_SOURCE_DATABASE; 31 import static com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO__SOURCES__EMERGENCY_NUMBER_SOURCE_DEFAULT; 32 import static com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO__SOURCES__EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG; 33 import static com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO__SOURCES__EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING; 34 import static com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO__SOURCES__EMERGENCY_NUMBER_SOURCE_SIM; 35 36 import android.telephony.emergency.EmergencyNumber; 37 import android.util.SparseIntArray; 38 39 import com.android.internal.telephony.nano.PersistAtomsProto; 40 41 import java.util.ArrayList; 42 import java.util.List; 43 44 /** 45 * EmergencyStats logs the atoms for consolidated emergency number list in framework. It also logs 46 * the details of a dialed emergency number. To avoid repeated information this class stores the 47 * emergency numbers list in map and verifies the information for duplicacy before logging it. Note: 48 * This locally stored information will erase on process restart scenarios (like reboot, crash, 49 * etc.). 50 */ 51 public class EmergencyNumberStats { 52 53 private static final String TAG = EmergencyNumberStats.class.getSimpleName(); 54 private static final SparseIntArray sRoutesMap; 55 private static final SparseIntArray sServiceCategoriesMap; 56 private static final SparseIntArray sSourcesMap; 57 private static EmergencyNumberStats sInstance; 58 59 static { 60 sRoutesMap = new SparseIntArray() { 61 { 62 put(EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY, 63 EMERGENCY_NUMBERS_INFO__ROUTE__EMERGENCY_CALL_ROUTE_EMERGENCY); 64 put(EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL, 65 EMERGENCY_NUMBERS_INFO__ROUTE__EMERGENCY_CALL_ROUTE_NORMAL); 66 put(EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN, 67 EMERGENCY_NUMBERS_INFO__ROUTE__EMERGENCY_CALL_ROUTE_UNKNOWN); 68 } 69 }; 70 71 sServiceCategoriesMap = new SparseIntArray() { 72 { 73 put(EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED, 74 EMERGENCY_NUMBERS_INFO__SERVICE_CATEGORIES__EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED); 75 put(EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_POLICE, 76 EMERGENCY_NUMBERS_INFO__SERVICE_CATEGORIES__EMERGENCY_SERVICE_CATEGORY_POLICE); 77 put(EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_AMBULANCE, 78 EMERGENCY_NUMBERS_INFO__SERVICE_CATEGORIES__EMERGENCY_SERVICE_CATEGORY_AMBULANCE); 79 put(EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE, 80 EMERGENCY_NUMBERS_INFO__SERVICE_CATEGORIES__EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE); 81 put(EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_MARINE_GUARD, 82 EMERGENCY_NUMBERS_INFO__SERVICE_CATEGORIES__EMERGENCY_SERVICE_CATEGORY_MARINE_GUARD); 83 put(EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_MOUNTAIN_RESCUE, 84 EMERGENCY_NUMBERS_INFO__SERVICE_CATEGORIES__EMERGENCY_SERVICE_CATEGORY_MOUNTAIN_RESCUE); 85 put(EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_MIEC, 86 EMERGENCY_NUMBERS_INFO__SERVICE_CATEGORIES__EMERGENCY_SERVICE_CATEGORY_MIEC); 87 put(EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_AIEC, 88 EMERGENCY_NUMBERS_INFO__SERVICE_CATEGORIES__EMERGENCY_SERVICE_CATEGORY_AIEC); 89 } 90 }; 91 92 sSourcesMap = new SparseIntArray() { 93 { 94 put(EmergencyNumber.EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING, 95 EMERGENCY_NUMBERS_INFO__SOURCES__EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING); 96 put(EmergencyNumber.EMERGENCY_NUMBER_SOURCE_SIM, 97 EMERGENCY_NUMBERS_INFO__SOURCES__EMERGENCY_NUMBER_SOURCE_SIM); 98 put(EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE, 99 EMERGENCY_NUMBERS_INFO__SOURCES__EMERGENCY_NUMBER_SOURCE_DATABASE); 100 put(EmergencyNumber.EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG, 101 EMERGENCY_NUMBERS_INFO__SOURCES__EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG); 102 put(EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DEFAULT, 103 EMERGENCY_NUMBERS_INFO__SOURCES__EMERGENCY_NUMBER_SOURCE_DEFAULT); 104 } 105 }; 106 } 107 EmergencyNumberStats()108 private EmergencyNumberStats() { 109 } 110 111 /** Static method to provide singleton instance for EmergencyNumberStats. */ getInstance()112 public static EmergencyNumberStats getInstance() { 113 if (sInstance == null) { 114 sInstance = new EmergencyNumberStats(); 115 } 116 return sInstance; 117 } 118 119 /** 120 * It converts the {@link android.telephony.emergency.EmergencyNumber} to 121 * {@link PersistAtomsProto.EmergencyNumber} for 122 * logging the EmergencyNumber atoms with pulled event. 123 * 124 * @param emergencyNumberList android.telephony.EmergencyNumber list 125 * @param assetVersion assert version 126 * @param otaVersion ota version 127 * @param isDbRoutingIgnored flag that defines if routing is ignored through database. 128 */ convertEmergencyNumbersListToProto( List<EmergencyNumber> emergencyNumberList, int assetVersion, int otaVersion, boolean isDbRoutingIgnored)129 public PersistAtomsProto.EmergencyNumbersInfo[] convertEmergencyNumbersListToProto( 130 List<EmergencyNumber> emergencyNumberList, int assetVersion, int otaVersion, 131 boolean isDbRoutingIgnored) { 132 List<PersistAtomsProto.EmergencyNumbersInfo> numberProtoList = new ArrayList<>(); 133 for (EmergencyNumber number : emergencyNumberList) { 134 numberProtoList.add(convertEmergencyNumberToProto(number, assetVersion, otaVersion, 135 isDbRoutingIgnored)); 136 } 137 return numberProtoList.toArray(new PersistAtomsProto.EmergencyNumbersInfo[0]); 138 } 139 convertEmergencyNumberToProto( EmergencyNumber number, int assetVer, int otaVer, boolean isDbRoutingIgnored)140 private PersistAtomsProto.EmergencyNumbersInfo convertEmergencyNumberToProto( 141 EmergencyNumber number, int assetVer, int otaVer, boolean isDbRoutingIgnored) { 142 String dialNumber = number.getNumber(); 143 PersistAtomsProto.EmergencyNumbersInfo emergencyNumber = 144 new PersistAtomsProto.EmergencyNumbersInfo(); 145 emergencyNumber.isDbVersionIgnored = isDbRoutingIgnored; 146 emergencyNumber.assetVersion = assetVer; 147 emergencyNumber.otaVersion = otaVer; 148 emergencyNumber.number = dialNumber; 149 emergencyNumber.countryIso = number.getCountryIso(); 150 emergencyNumber.mnc = number.getMnc(); 151 emergencyNumber.route = sRoutesMap.get(number.getEmergencyCallRouting()); 152 emergencyNumber.urns = number.getEmergencyUrns().toArray(new String[0]); 153 emergencyNumber.serviceCategories = getMappedServiceCategories( 154 number.getEmergencyServiceCategories()); 155 emergencyNumber.sources = getMappedSources(number.getEmergencyNumberSources()); 156 return emergencyNumber; 157 } 158 getMappedServiceCategories(List<Integer> serviceCategories)159 private int[] getMappedServiceCategories(List<Integer> serviceCategories) { 160 if (serviceCategories == null || serviceCategories.isEmpty()) { 161 return null; 162 } 163 return serviceCategories.stream().map(sServiceCategoriesMap::get).mapToInt( 164 Integer::intValue).toArray(); 165 } 166 getMappedSources(List<Integer> sources)167 private int[] getMappedSources(List<Integer> sources) { 168 if (sources == null || sources.isEmpty()) { 169 return null; 170 } 171 return sources.stream().map(sSourcesMap::get).mapToInt(Integer::intValue).toArray(); 172 } 173 } 174