1 /* 2 * Copyright (C) 2022 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.ons; 18 19 import android.content.Context; 20 import android.content.SharedPreferences; 21 import android.telephony.SubscriptionInfo; 22 import android.telephony.SubscriptionManager; 23 24 import com.android.ons.ONSProfileActivator.Result; 25 import com.android.ons.ONSProfileDownloader.DownloadRetryResultCode; 26 27 /** 28 * ONSStats is responsible for collecting and reporting ONS statistics. 29 */ 30 public class ONSStats { 31 private static final String ONS_ATOM_LOG_FILE = "ons_atom_log_info"; 32 private static final String KEY_PROVISIONING_RESULT = "_provisioning_result"; 33 private static final String KEY_DOWNLOAD_RESULT = "_download_result"; 34 private static final String KEY_RETRY_COUNT = "_retry_count"; 35 private static final String KEY_DETAILED_ERROR_CODE = "_detailed_error_code"; 36 private static final String KEY_OPP_CARRIER_ID = "_opportunistic_carrier_id"; 37 private static final String KEY_PRIMARY_CARRIER_ID = "_primary_sim_carrier_id"; 38 private final Context mContext; 39 private final SubscriptionManager mSubscriptionManager; 40 41 /** Constructor to create instance for ONSStats. */ ONSStats(Context context, SubscriptionManager subscriptionManager)42 public ONSStats(Context context, SubscriptionManager subscriptionManager) { 43 mContext = context; 44 mSubscriptionManager = subscriptionManager; 45 } 46 47 /** 48 * It logs the ONS atom with the info passed as ONSStatsInfo. If the information is already 49 * logged, it will be skipped. 50 * 51 * @param info information to be logged. 52 * @return returns true if information is logged, otherwise false. 53 */ logEvent(ONSStatsInfo info)54 public boolean logEvent(ONSStatsInfo info) { 55 // check if the info needs to be ignored. 56 if (ignoreEvent(info)) { 57 return false; 58 } 59 60 int statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_UNKNOWN; 61 if (info.isProvisioningResultUpdated()) { 62 switch (info.provisioningResult()) { 63 case SUCCESS: 64 statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_SUCCESS; 65 break; 66 case ERR_CANNOT_SWITCH_TO_DUAL_SIM_MODE: 67 statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_SWITCH_TO_MULTISIM_FAILED; 68 break; 69 case ERR_CARRIER_DOESNT_SUPPORT_CBRS: 70 case ERR_AUTO_PROVISIONING_DISABLED: 71 statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_AUTO_PROVISIONING_DISABLED; 72 break; 73 case ERR_ESIM_NOT_SUPPORTED: 74 case ERR_MULTISIM_NOT_SUPPORTED: 75 statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_DEVICE_NOT_CAPABLE; 76 break; 77 case ERR_SINGLE_ACTIVE_OPPORTUNISTIC_SIM: 78 case ERR_DUAL_ACTIVE_SUBSCRIPTIONS: 79 case ERR_PSIM_NOT_FOUND: 80 case ERR_DOWNLOADED_ESIM_NOT_FOUND: 81 statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_ESIM_PROVISIONING_FAILED; 82 break; 83 case ERR_WAITING_FOR_INTERNET_CONNECTION: 84 case ERR_WAITING_FOR_WIFI_CONNECTION: 85 statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_INTERNET_NOT_AVAILABLE; 86 break; 87 case ERR_INVALID_CARRIER_CONFIG: 88 statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_UNRESOLVABLE_ERROR; 89 break; 90 default: 91 break; 92 } 93 } else { 94 switch (info.downloadResult()) { 95 case ERR_UNRESOLVABLE: 96 statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_UNRESOLVABLE_ERROR; 97 break; 98 case ERR_MEMORY_FULL: 99 statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_MEMORY_FULL; 100 break; 101 case ERR_INSTALL_ESIM_PROFILE_FAILED: 102 statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_INSTALL_ESIM_PROFILE_FAILED; 103 break; 104 case ERR_RETRY_DOWNLOAD: 105 statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_CONNECTION_ERROR; 106 break; 107 default: 108 break; 109 } 110 } 111 OnsStatsLog.write( 112 OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE, 113 getSimCarrierId(info.primarySimSubId()), 114 info.oppSimCarrierId(), 115 info.isWifiConnected(), 116 statsCode, 117 info.retryCount(), 118 info.detailedErrCode()); 119 updateSharedPreferences(info); 120 return true; 121 } 122 updateSharedPreferences(ONSStatsInfo info)123 private void updateSharedPreferences(ONSStatsInfo info) { 124 SharedPreferences sharedPref = 125 mContext.getSharedPreferences(ONS_ATOM_LOG_FILE, Context.MODE_PRIVATE); 126 SharedPreferences.Editor editor = sharedPref.edit(); 127 if (info.isProvisioningResultUpdated()) { 128 editor.putInt(KEY_PROVISIONING_RESULT, info.provisioningResult().ordinal()); 129 editor.remove(KEY_DOWNLOAD_RESULT); 130 } else { 131 editor.putInt(KEY_DOWNLOAD_RESULT, info.downloadResult().ordinal()); 132 editor.remove(KEY_PROVISIONING_RESULT); 133 } 134 editor.putInt(KEY_PRIMARY_CARRIER_ID, getSimCarrierId(info.primarySimSubId())) 135 .putInt(KEY_RETRY_COUNT, info.retryCount()) 136 .putInt(KEY_OPP_CARRIER_ID, info.oppSimCarrierId()) 137 .putInt(KEY_DETAILED_ERROR_CODE, info.detailedErrCode()) 138 .apply(); 139 } 140 ignoreEvent(ONSStatsInfo info)141 private boolean ignoreEvent(ONSStatsInfo info) { 142 Result result = info.provisioningResult(); 143 if (info.isProvisioningResultUpdated()) { 144 // Codes are ignored since they are intermediate state of CBRS provisioning check. 145 if ((result == Result.DOWNLOAD_REQUESTED) 146 || result == Result.ERR_NO_SIM_INSERTED 147 || result == Result.ERR_DUPLICATE_DOWNLOAD_REQUEST 148 || result == Result.ERR_SWITCHING_TO_DUAL_SIM_MODE) { 149 return true; 150 } 151 } 152 153 SharedPreferences sharedPref = 154 mContext.getSharedPreferences(ONS_ATOM_LOG_FILE, Context.MODE_PRIVATE); 155 156 boolean errorCodeUpdated = 157 (info.isProvisioningResultUpdated() 158 ? sharedPref.getInt(KEY_PROVISIONING_RESULT, -1) != result.ordinal() 159 : sharedPref.getInt(KEY_DOWNLOAD_RESULT, -1) 160 != info.downloadResult().ordinal()); 161 boolean carrierIdUpdated = 162 sharedPref.getInt(KEY_PRIMARY_CARRIER_ID, -1) 163 != getSimCarrierId(info.primarySimSubId()); 164 boolean retryCountUpdated = sharedPref.getInt(KEY_RETRY_COUNT, -1) != info.retryCount(); 165 boolean oppCarrierIdChanged = 166 sharedPref.getInt(KEY_OPP_CARRIER_ID, -1) != info.oppSimCarrierId(); 167 boolean detailedErrorChanged = 168 sharedPref.getInt(KEY_DETAILED_ERROR_CODE, -1) != info.detailedErrCode(); 169 if (!(errorCodeUpdated 170 || carrierIdUpdated 171 || retryCountUpdated 172 || oppCarrierIdChanged 173 || detailedErrorChanged)) { 174 // Result codes are meant to log on every occurrence. These should not be ignored. 175 if (result == Result.SUCCESS 176 || result == Result.ERR_DOWNLOADED_ESIM_NOT_FOUND 177 || info.downloadResult() 178 == DownloadRetryResultCode.ERR_INSTALL_ESIM_PROFILE_FAILED) { 179 return false; 180 } 181 return true; 182 } 183 return false; 184 } 185 getSimCarrierId(int subId)186 private int getSimCarrierId(int subId) { 187 if (subId == -1) return -1; 188 SubscriptionInfo subInfo = mSubscriptionManager.getActiveSubscriptionInfo(subId); 189 return (subInfo != null) ? subInfo.getCarrierId() : -1; 190 } 191 } 192