/* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.ons; import android.content.Context; import android.content.SharedPreferences; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import com.android.ons.ONSProfileActivator.Result; import com.android.ons.ONSProfileDownloader.DownloadRetryResultCode; /** * ONSStats is responsible for collecting and reporting ONS statistics. */ public class ONSStats { private static final String ONS_ATOM_LOG_FILE = "ons_atom_log_info"; private static final String KEY_PROVISIONING_RESULT = "_provisioning_result"; private static final String KEY_DOWNLOAD_RESULT = "_download_result"; private static final String KEY_RETRY_COUNT = "_retry_count"; private static final String KEY_DETAILED_ERROR_CODE = "_detailed_error_code"; private static final String KEY_OPP_CARRIER_ID = "_opportunistic_carrier_id"; private static final String KEY_PRIMARY_CARRIER_ID = "_primary_sim_carrier_id"; private final Context mContext; private final SubscriptionManager mSubscriptionManager; /** Constructor to create instance for ONSStats. */ public ONSStats(Context context, SubscriptionManager subscriptionManager) { mContext = context; mSubscriptionManager = subscriptionManager; } /** * It logs the ONS atom with the info passed as ONSStatsInfo. If the information is already * logged, it will be skipped. * * @param info information to be logged. * @return returns true if information is logged, otherwise false. */ public boolean logEvent(ONSStatsInfo info) { // check if the info needs to be ignored. if (ignoreEvent(info)) { return false; } int statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_UNKNOWN; if (info.isProvisioningResultUpdated()) { switch (info.provisioningResult()) { case SUCCESS: statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_SUCCESS; break; case ERR_CANNOT_SWITCH_TO_DUAL_SIM_MODE: statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_SWITCH_TO_MULTISIM_FAILED; break; case ERR_CARRIER_DOESNT_SUPPORT_CBRS: case ERR_AUTO_PROVISIONING_DISABLED: statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_AUTO_PROVISIONING_DISABLED; break; case ERR_ESIM_NOT_SUPPORTED: case ERR_MULTISIM_NOT_SUPPORTED: statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_DEVICE_NOT_CAPABLE; break; case ERR_SINGLE_ACTIVE_OPPORTUNISTIC_SIM: case ERR_DUAL_ACTIVE_SUBSCRIPTIONS: case ERR_PSIM_NOT_FOUND: case ERR_DOWNLOADED_ESIM_NOT_FOUND: statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_ESIM_PROVISIONING_FAILED; break; case ERR_WAITING_FOR_INTERNET_CONNECTION: case ERR_WAITING_FOR_WIFI_CONNECTION: statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_INTERNET_NOT_AVAILABLE; break; case ERR_INVALID_CARRIER_CONFIG: statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_UNRESOLVABLE_ERROR; break; default: break; } } else { switch (info.downloadResult()) { case ERR_UNRESOLVABLE: statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_UNRESOLVABLE_ERROR; break; case ERR_MEMORY_FULL: statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_MEMORY_FULL; break; case ERR_INSTALL_ESIM_PROFILE_FAILED: statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_INSTALL_ESIM_PROFILE_FAILED; break; case ERR_RETRY_DOWNLOAD: statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_CONNECTION_ERROR; break; default: break; } } OnsStatsLog.write( OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE, getSimCarrierId(info.primarySimSubId()), info.oppSimCarrierId(), info.isWifiConnected(), statsCode, info.retryCount(), info.detailedErrCode()); updateSharedPreferences(info); return true; } private void updateSharedPreferences(ONSStatsInfo info) { SharedPreferences sharedPref = mContext.getSharedPreferences(ONS_ATOM_LOG_FILE, Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPref.edit(); if (info.isProvisioningResultUpdated()) { editor.putInt(KEY_PROVISIONING_RESULT, info.provisioningResult().ordinal()); editor.remove(KEY_DOWNLOAD_RESULT); } else { editor.putInt(KEY_DOWNLOAD_RESULT, info.downloadResult().ordinal()); editor.remove(KEY_PROVISIONING_RESULT); } editor.putInt(KEY_PRIMARY_CARRIER_ID, getSimCarrierId(info.primarySimSubId())) .putInt(KEY_RETRY_COUNT, info.retryCount()) .putInt(KEY_OPP_CARRIER_ID, info.oppSimCarrierId()) .putInt(KEY_DETAILED_ERROR_CODE, info.detailedErrCode()) .apply(); } private boolean ignoreEvent(ONSStatsInfo info) { Result result = info.provisioningResult(); if (info.isProvisioningResultUpdated()) { // Codes are ignored since they are intermediate state of CBRS provisioning check. if ((result == Result.DOWNLOAD_REQUESTED) || result == Result.ERR_NO_SIM_INSERTED || result == Result.ERR_DUPLICATE_DOWNLOAD_REQUEST || result == Result.ERR_SWITCHING_TO_DUAL_SIM_MODE) { return true; } } SharedPreferences sharedPref = mContext.getSharedPreferences(ONS_ATOM_LOG_FILE, Context.MODE_PRIVATE); boolean errorCodeUpdated = (info.isProvisioningResultUpdated() ? sharedPref.getInt(KEY_PROVISIONING_RESULT, -1) != result.ordinal() : sharedPref.getInt(KEY_DOWNLOAD_RESULT, -1) != info.downloadResult().ordinal()); boolean carrierIdUpdated = sharedPref.getInt(KEY_PRIMARY_CARRIER_ID, -1) != getSimCarrierId(info.primarySimSubId()); boolean retryCountUpdated = sharedPref.getInt(KEY_RETRY_COUNT, -1) != info.retryCount(); boolean oppCarrierIdChanged = sharedPref.getInt(KEY_OPP_CARRIER_ID, -1) != info.oppSimCarrierId(); boolean detailedErrorChanged = sharedPref.getInt(KEY_DETAILED_ERROR_CODE, -1) != info.detailedErrCode(); if (!(errorCodeUpdated || carrierIdUpdated || retryCountUpdated || oppCarrierIdChanged || detailedErrorChanged)) { // Result codes are meant to log on every occurrence. These should not be ignored. if (result == Result.SUCCESS || result == Result.ERR_DOWNLOADED_ESIM_NOT_FOUND || info.downloadResult() == DownloadRetryResultCode.ERR_INSTALL_ESIM_PROFILE_FAILED) { return false; } return true; } return false; } private int getSimCarrierId(int subId) { if (subId == -1) return -1; SubscriptionInfo subInfo = mSubscriptionManager.getActiveSubscriptionInfo(subId); return (subInfo != null) ? subInfo.getCarrierId() : -1; } }