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