• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* //device/content/providers/telephony/TelephonyProvider.java
2 **
3 ** Copyright 2006, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 **     http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17 
18 package com.android.providers.telephony;
19 
20 import static android.provider.Telephony.Carriers.ALWAYS_ON;
21 import static android.provider.Telephony.Carriers.APN;
22 import static android.provider.Telephony.Carriers.APN_SET_ID;
23 import static android.provider.Telephony.Carriers.AUTH_TYPE;
24 import static android.provider.Telephony.Carriers.BEARER;
25 import static android.provider.Telephony.Carriers.BEARER_BITMASK;
26 import static android.provider.Telephony.Carriers.CARRIER_DELETED;
27 import static android.provider.Telephony.Carriers.CARRIER_DELETED_BUT_PRESENT_IN_XML;
28 import static android.provider.Telephony.Carriers.CARRIER_EDITED;
29 import static android.provider.Telephony.Carriers.CARRIER_ENABLED;
30 import static android.provider.Telephony.Carriers.CARRIER_ID;
31 import static android.provider.Telephony.Carriers.CONTENT_URI;
32 import static android.provider.Telephony.Carriers.CURRENT;
33 import static android.provider.Telephony.Carriers.DEFAULT_SORT_ORDER;
34 import static android.provider.Telephony.Carriers.EDITED_STATUS;
35 import static android.provider.Telephony.Carriers.INFRASTRUCTURE_BITMASK;
36 import static android.provider.Telephony.Carriers.ESIM_BOOTSTRAP_PROVISIONING;
37 import static android.provider.Telephony.Carriers.LINGERING_NETWORK_TYPE_BITMASK;
38 import static android.provider.Telephony.Carriers.MAX_CONNECTIONS;
39 import static android.provider.Telephony.Carriers.MCC;
40 import static android.provider.Telephony.Carriers.MMSC;
41 import static android.provider.Telephony.Carriers.MMSPORT;
42 import static android.provider.Telephony.Carriers.MMSPROXY;
43 import static android.provider.Telephony.Carriers.MNC;
44 import static android.provider.Telephony.Carriers.MODEM_PERSIST;
45 import static android.provider.Telephony.Carriers.MTU;
46 import static android.provider.Telephony.Carriers.MTU_V4;
47 import static android.provider.Telephony.Carriers.MTU_V6;
48 import static android.provider.Telephony.Carriers.MVNO_MATCH_DATA;
49 import static android.provider.Telephony.Carriers.MVNO_TYPE;
50 import static android.provider.Telephony.Carriers.NAME;
51 import static android.provider.Telephony.Carriers.NETWORK_TYPE_BITMASK;
52 import static android.provider.Telephony.Carriers.NO_APN_SET_ID;
53 import static android.provider.Telephony.Carriers.NUMERIC;
54 import static android.provider.Telephony.Carriers.OWNED_BY;
55 import static android.provider.Telephony.Carriers.OWNED_BY_DPC;
56 import static android.provider.Telephony.Carriers.OWNED_BY_OTHERS;
57 import static android.provider.Telephony.Carriers.PASSWORD;
58 import static android.provider.Telephony.Carriers.PORT;
59 import static android.provider.Telephony.Carriers.PROFILE_ID;
60 import static android.provider.Telephony.Carriers.PROTOCOL;
61 import static android.provider.Telephony.Carriers.PROXY;
62 import static android.provider.Telephony.Carriers.ROAMING_PROTOCOL;
63 import static android.provider.Telephony.Carriers.SERVER;
64 import static android.provider.Telephony.Carriers.SKIP_464XLAT;
65 import static android.provider.Telephony.Carriers.SKIP_464XLAT_DEFAULT;
66 import static android.provider.Telephony.Carriers.SUBSCRIPTION_ID;
67 import static android.provider.Telephony.Carriers.TIME_LIMIT_FOR_MAX_CONNECTIONS;
68 import static android.provider.Telephony.Carriers.TYPE;
69 import static android.provider.Telephony.Carriers.UNEDITED;
70 import static android.provider.Telephony.Carriers.USER;
71 import static android.provider.Telephony.Carriers.USER_DELETED;
72 import static android.provider.Telephony.Carriers.USER_DELETED_BUT_PRESENT_IN_XML;
73 import static android.provider.Telephony.Carriers.USER_EDITABLE;
74 import static android.provider.Telephony.Carriers.USER_EDITED;
75 import static android.provider.Telephony.Carriers.USER_VISIBLE;
76 import static android.provider.Telephony.Carriers.WAIT_TIME_RETRY;
77 import static android.provider.Telephony.Carriers._ID;
78 
79 import android.annotation.NonNull;
80 import android.annotation.Nullable;
81 import android.app.compat.CompatChanges;
82 import android.content.ComponentName;
83 import android.content.ContentProvider;
84 import android.content.ContentResolver;
85 import android.content.ContentUris;
86 import android.content.ContentValues;
87 import android.content.Context;
88 import android.content.Intent;
89 import android.content.ServiceConnection;
90 import android.content.SharedPreferences;
91 import android.content.UriMatcher;
92 import android.content.pm.PackageManager;
93 import android.content.res.Resources;
94 import android.content.res.XmlResourceParser;
95 import android.database.Cursor;
96 import android.database.MatrixCursor;
97 import android.database.SQLException;
98 import android.database.sqlite.SQLiteDatabase;
99 import android.database.sqlite.SQLiteException;
100 import android.database.sqlite.SQLiteOpenHelper;
101 import android.database.sqlite.SQLiteQueryBuilder;
102 import android.net.Uri;
103 import android.os.Binder;
104 import android.os.Bundle;
105 import android.os.Environment;
106 import android.os.IBinder;
107 import android.os.PersistableBundle;
108 import android.os.Process;
109 import android.os.RemoteException;
110 import android.os.SystemProperties;
111 import android.os.UserHandle;
112 import android.provider.Telephony;
113 import android.service.carrier.IApnSourceService;
114 import android.telephony.SubscriptionInfo;
115 import android.telephony.SubscriptionManager;
116 import android.telephony.TelephonyManager;
117 import android.telephony.TelephonyProtoEnums;
118 import android.telephony.data.ApnSetting;
119 import android.text.TextUtils;
120 import android.util.ArrayMap;
121 import android.util.ArraySet;
122 import android.util.AtomicFile;
123 import android.util.IndentingPrintWriter;
124 import android.util.LocalLog;
125 import android.util.Log;
126 import android.util.Pair;
127 import android.util.Xml;
128 
129 import com.android.internal.annotations.GuardedBy;
130 import com.android.internal.annotations.VisibleForTesting;
131 import com.android.internal.telephony.TelephonyPermissions;
132 import com.android.internal.telephony.TelephonyStatsLog;
133 import com.android.internal.telephony.flags.Flags;
134 import com.android.internal.util.XmlUtils;
135 
136 import org.xmlpull.v1.XmlPullParser;
137 import org.xmlpull.v1.XmlPullParserException;
138 
139 import java.io.ByteArrayOutputStream;
140 import java.io.File;
141 import java.io.FileDescriptor;
142 import java.io.FileInputStream;
143 import java.io.FileNotFoundException;
144 import java.io.FileOutputStream;
145 import java.io.FileReader;
146 import java.io.IOException;
147 import java.io.InputStream;
148 import java.io.PrintWriter;
149 import java.util.ArrayList;
150 import java.util.Arrays;
151 import java.util.HashMap;
152 import java.util.HashSet;
153 import java.util.List;
154 import java.util.Locale;
155 import java.util.Map;
156 import java.util.Set;
157 import java.util.concurrent.atomic.AtomicBoolean;
158 import java.util.stream.Collectors;
159 import java.util.zip.CRC32;
160 import java.util.zip.CheckedInputStream;
161 
162 public class TelephonyProvider extends ContentProvider
163 {
164     private static final String DATABASE_NAME = "telephony.db";
165     private static final int IDLE_CONNECTION_TIMEOUT_MS = 30000;
166     private static final boolean DBG = true;
167     private static final boolean VDBG = false; // STOPSHIP if true
168 
169     private static final int DATABASE_VERSION = 74 << 16;
170     private static final int URL_UNKNOWN = 0;
171     private static final int URL_TELEPHONY = 1;
172     private static final int URL_CURRENT = 2;
173     private static final int URL_ID = 3;
174     private static final int URL_RESTOREAPN = 4;
175     private static final int URL_PREFERAPN = 5;
176     private static final int URL_PREFERAPN_NO_UPDATE = 6;
177     private static final int URL_SIMINFO = 7;
178     private static final int URL_TELEPHONY_USING_SUBID = 8;
179     private static final int URL_CURRENT_USING_SUBID = 9;
180     private static final int URL_RESTOREAPN_USING_SUBID = 10;
181     private static final int URL_PREFERAPN_USING_SUBID = 11;
182     private static final int URL_PREFERAPN_NO_UPDATE_USING_SUBID = 12;
183     private static final int URL_SIMINFO_USING_SUBID = 13;
184     private static final int URL_UPDATE_DB = 14;
185     private static final int URL_DELETE = 15;
186     private static final int URL_DPC = 16;
187     private static final int URL_DPC_ID = 17;
188     private static final int URL_FILTERED = 18;
189     private static final int URL_FILTERED_ID = 19;
190     private static final int URL_ENFORCE_MANAGED = 20;
191     // URL_PREFERAPNSET and URL_PREFERAPNSET_USING_SUBID return all APNs for the current
192     // carrier which have an apn_set_id equal to the preferred APN
193     // (if no preferred APN, or preferred APN has no set id, the query will return null)
194     private static final int URL_PREFERAPNSET = 21;
195     private static final int URL_PREFERAPNSET_USING_SUBID = 22;
196     private static final int URL_SIM_APN_LIST = 23;
197     private static final int URL_SIM_APN_LIST_ID = 24;
198     private static final int URL_FILTERED_USING_SUBID = 25;
199     private static final int URL_SIM_APN_LIST_FILTERED = 26;
200     private static final int URL_SIM_APN_LIST_FILTERED_ID = 27;
201     private static final int URL_SIMINFO_SUW_RESTORE = 28;
202     private static final int URL_SIMINFO_SIM_INSERTED_RESTORE = 29;
203 
204     private static final String TAG = "TelephonyProvider";
205     private static final String CARRIERS_TABLE = "carriers";
206     private static final String CARRIERS_TABLE_TMP = "carriers_tmp";
207     private static final String SIMINFO_TABLE = "siminfo";
208     private static final String SIMINFO_TABLE_TMP = "siminfo_tmp";
209 
210     private static final String PREF_FILE_APN = "preferred-apn";
211     private static final String COLUMN_APN_ID = "apn_id";
212     private static final String EXPLICIT_SET_CALLED = "explicit_set_called";
213 
214     private static final String PREF_FILE_FULL_APN = "preferred-full-apn";
215     private static final String DB_VERSION_KEY = "version";
216 
217     private static final String BUILD_ID_FILE = "build-id";
218     private static final String RO_BUILD_ID = "ro_build_id";
219 
220     private static final String ENFORCED_FILE = "dpc-apn-enforced";
221     private static final String ENFORCED_KEY = "enforced";
222 
223     private static final String PREF_FILE = "telephonyprovider";
224     private static final String APN_CONF_CHECKSUM = "apn_conf_checksum";
225 
226     private static final String PARTNER_APNS_PATH = "etc/apns-conf.xml";
227     private static final String OEM_APNS_PATH = "telephony/apns-conf.xml";
228     private static final String OTA_UPDATED_APNS_PATH = "misc/apns/apns-conf.xml";
229     private static final String OLD_APNS_PATH = "etc/old-apns-conf.xml";
230 
231     private static final String DEFAULT_PROTOCOL = "IP";
232     private static final String DEFAULT_ROAMING_PROTOCOL = "IP";
233 
234     private static final UriMatcher s_urlMatcher = new UriMatcher(UriMatcher.NO_MATCH);
235 
236     private static final ContentValues s_currentNullMap;
237     private static final ContentValues s_currentSetMap;
238 
239     private static final String IS_UNEDITED = EDITED_STATUS + "=" + UNEDITED;
240     private static final String IS_EDITED = EDITED_STATUS + "!=" + UNEDITED;
241     private static final String IS_USER_EDITED = EDITED_STATUS + "=" + USER_EDITED;
242     private static final String IS_NOT_USER_EDITED = EDITED_STATUS + "!=" + USER_EDITED;
243     private static final String IS_USER_DELETED = EDITED_STATUS + "=" + USER_DELETED;
244     private static final String IS_NOT_USER_DELETED = EDITED_STATUS + "!=" + USER_DELETED;
245     private static final String IS_USER_DELETED_BUT_PRESENT_IN_XML =
246             EDITED_STATUS + "=" + USER_DELETED_BUT_PRESENT_IN_XML;
247     private static final String IS_NOT_USER_DELETED_BUT_PRESENT_IN_XML =
248             EDITED_STATUS + "!=" + USER_DELETED_BUT_PRESENT_IN_XML;
249     private static final String IS_CARRIER_EDITED = EDITED_STATUS + "=" + CARRIER_EDITED;
250     private static final String IS_NOT_CARRIER_EDITED = EDITED_STATUS + "!=" + CARRIER_EDITED;
251     private static final String IS_CARRIER_DELETED = EDITED_STATUS + "=" + CARRIER_DELETED;
252     private static final String IS_NOT_CARRIER_DELETED = EDITED_STATUS + "!=" + CARRIER_DELETED;
253     private static final String IS_CARRIER_DELETED_BUT_PRESENT_IN_XML =
254             EDITED_STATUS + "=" + CARRIER_DELETED_BUT_PRESENT_IN_XML;
255     private static final String IS_NOT_CARRIER_DELETED_BUT_PRESENT_IN_XML =
256             EDITED_STATUS + "!=" + CARRIER_DELETED_BUT_PRESENT_IN_XML;
257     private static final String IS_OWNED_BY_DPC = OWNED_BY + "=" + OWNED_BY_DPC;
258     private static final String IS_NOT_OWNED_BY_DPC = OWNED_BY + "!=" + OWNED_BY_DPC;
259 
260     private static final String ORDER_BY_SUB_ID =
261             Telephony.SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID + " ASC";
262 
263     @VisibleForTesting
264     static final String BACKED_UP_SIM_SPECIFIC_SETTINGS_FILE = "sim_specific_settings_file";
265     // Holds names and value types of SimInfoDb columns to backup.
266     private static final Map<String, Integer> SIM_INFO_COLUMNS_TO_BACKUP = new HashMap();
267     private static final String KEY_SIMINFO_DB_ROW_PREFIX = "KEY_SIMINFO_DB_ROW_";
268     private static final int DEFAULT_INT_COLUMN_VALUE = -111;
269     private static final String DEFAULT_STRING_COLUMN_VALUE = "DEFAULT_STRING_COLUMN_VALUE";
270     private static final String SIM_INSERTED_RESTORE_URI_SUFFIX = "sim_inserted_restore";
271     @VisibleForTesting
272     static final String KEY_BACKUP_DATA_FORMAT_VERSION = "KEY_BACKUP_DATA_FORMAT_VERSION";
273     @VisibleForTesting
274     static final String KEY_PREVIOUSLY_RESTORED_SUB_IDS = "KEY_PREVIOUSLY_RESTORED_SUB_IDS";
275 
276     private static final int INVALID_APN_ID = -1;
277     private static final List<String> CARRIERS_UNIQUE_FIELDS = new ArrayList<String>();
278     private static final Set<String> CARRIERS_BOOLEAN_FIELDS = new HashSet<String>();
279     private static final Map<String, String> CARRIERS_UNIQUE_FIELDS_DEFAULTS = new HashMap();
280     private static final String ALLOWED_NETWORK_TYPES_TEXT_ENABLE_2G = "enable_2g";
281 
282     @VisibleForTesting
283     static Boolean s_apnSourceServiceExists;
284 
285     protected final Object mLock = new Object();
286     @GuardedBy("mLock")
287     private IApnSourceService mIApnSourceService;
288     private Injector mInjector;
289 
290     private boolean mManagedApnEnforced;
291 
292     /**
293      * Lazy tracking SubscriptionManager#getDefaultSubscriptionId for db operation to prevent race
294      * condition.
295      * Make sure the call is outside of instance synchronization to prevent dead lock between
296      * SubscriptionManager lock and telephony provider lock.
297      */
298     private int mDefaultSubId = SubscriptionManager.getDefaultSubscriptionId();
299 
300     private final LocalLog mLocalLog = new LocalLog(128);
301 
302     /**
303      * Mobile country codes where there is a high likelyhood that the MNC has 3 digits
304      * and need one more prefix zero to set correct mobile network code value.
305      *
306      * Please note! The best solution is to add the MCCMNC combo to carrier id
307      * carrier_list, this is just a best effort.
308      */
309     private static final String[] COUNTRY_MCC_WITH_THREE_DIGIT_MNC = {
310             "302" // Canada
311            ,"310" // Guam, USA
312            ,"311" // USA
313            ,"312" // USA
314            ,"313" // USA
315            ,"316" // USA
316            ,"334" // Mexico
317            ,"338" // Bermuda, Jamaica
318            ,"342" // Barbados
319            ,"344" // Antigua and Barbuda
320            ,"346" // Cayman Islands
321            ,"348" // British Virgin Islands
322            ,"356" // Saint Kitts and Nevis
323            ,"358" // Saint Lucia
324            ,"360" // Saint Vincent and the Grenadines
325            ,"365" // Anguilla
326            ,"366" // Dominica
327            ,"376" // Turks and Caicos Islands
328            ,"405" // India
329            ,"708" // Honduras
330            ,"722" // Argentina
331            ,"732" // Colombia
332            ,"738" // Guyana
333            ,"750" // Falkland Islands
334             };
335 
336     /**
337      * Available radio technologies for GSM, UMTS and CDMA.
338      * Duplicates the constants from hardware/radio/include/ril.h
339      * This should only be used by agents working with the ril.  Others
340      * should use the equivalent TelephonyManager.NETWORK_TYPE_*
341      */
342     private static final int RIL_RADIO_TECHNOLOGY_UNKNOWN = 0;
343     private static final int RIL_RADIO_TECHNOLOGY_GPRS = 1;
344     private static final int RIL_RADIO_TECHNOLOGY_EDGE = 2;
345     private static final int RIL_RADIO_TECHNOLOGY_UMTS = 3;
346     private static final int RIL_RADIO_TECHNOLOGY_IS95A = 4;
347     private static final int RIL_RADIO_TECHNOLOGY_IS95B = 5;
348     private static final int RIL_RADIO_TECHNOLOGY_1xRTT = 6;
349     private static final int RIL_RADIO_TECHNOLOGY_EVDO_0 = 7;
350     private static final int RIL_RADIO_TECHNOLOGY_EVDO_A = 8;
351     private static final int RIL_RADIO_TECHNOLOGY_HSDPA = 9;
352     private static final int RIL_RADIO_TECHNOLOGY_HSUPA = 10;
353     private static final int RIL_RADIO_TECHNOLOGY_HSPA = 11;
354     private static final int RIL_RADIO_TECHNOLOGY_EVDO_B = 12;
355     private static final int RIL_RADIO_TECHNOLOGY_EHRPD = 13;
356     private static final int RIL_RADIO_TECHNOLOGY_LTE = 14;
357     private static final int RIL_RADIO_TECHNOLOGY_HSPAP = 15;
358 
359     /**
360      * GSM radio technology only supports voice. It does not support data.
361      */
362     private static final int RIL_RADIO_TECHNOLOGY_GSM = 16;
363     private static final int RIL_RADIO_TECHNOLOGY_TD_SCDMA = 17;
364 
365     /**
366      * IWLAN
367      */
368     private static final int RIL_RADIO_TECHNOLOGY_IWLAN = 18;
369 
370     /**
371      * LTE_CA
372      */
373     private static final int RIL_RADIO_TECHNOLOGY_LTE_CA = 19;
374 
375     /**
376      * NR(New Radio) 5G.
377      */
378     private static final int  RIL_RADIO_TECHNOLOGY_NR = 20;
379 
380     /**
381      * The number of the radio technologies.
382      */
383     private static final int NEXT_RIL_RADIO_TECHNOLOGY = 21;
384 
385     private static final Map<String, Integer> MVNO_TYPE_STRING_MAP;
386 
387     static {
388         // Columns not included in UNIQUE constraint: name, current, edited, user, server, password,
389         // authtype, type, protocol, roaming_protocol, sub_id, modem_cognitive, max_conns,
390         // wait_time, max_conns_time, mtu, mtu_v4, mtu_v6, bearer_bitmask, user_visible,
391         // network_type_bitmask, skip_464xlat, lingering_network_type_bitmask, always_on.
CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(NUMERIC, "")392         CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(NUMERIC, "");
CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(MCC, "")393         CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(MCC, "");
CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(MNC, "")394         CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(MNC, "");
CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(APN, "")395         CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(APN, "");
CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(PROXY, "")396         CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(PROXY, "");
CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(PORT, "")397         CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(PORT, "");
CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(MMSPROXY, "")398         CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(MMSPROXY, "");
CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(MMSPORT, "")399         CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(MMSPORT, "");
CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(MMSC, "")400         CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(MMSC, "");
CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(CARRIER_ENABLED, "1")401         CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(CARRIER_ENABLED, "1");
CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(BEARER, "0")402         CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(BEARER, "0");
CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(MVNO_TYPE, "")403         CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(MVNO_TYPE, "");
CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(MVNO_MATCH_DATA, "")404         CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(MVNO_MATCH_DATA, "");
CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(PROFILE_ID, "0")405         CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(PROFILE_ID, "0");
CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(PROTOCOL, "IP")406         CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(PROTOCOL, "IP");
CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(ROAMING_PROTOCOL, "IP")407         CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(ROAMING_PROTOCOL, "IP");
CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(USER_EDITABLE, "1")408         CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(USER_EDITABLE, "1");
CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(OWNED_BY, String.valueOf(OWNED_BY_OTHERS))409         CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(OWNED_BY, String.valueOf(OWNED_BY_OTHERS));
CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(APN_SET_ID, String.valueOf(NO_APN_SET_ID))410         CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(APN_SET_ID, String.valueOf(NO_APN_SET_ID));
CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(CARRIER_ID, String.valueOf(TelephonyManager.UNKNOWN_CARRIER_ID))411         CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(CARRIER_ID,
412                 String.valueOf(TelephonyManager.UNKNOWN_CARRIER_ID));
CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(INFRASTRUCTURE_BITMASK, String.valueOf( ApnSetting.INFRASTRUCTURE_CELLULAR | ApnSetting.INFRASTRUCTURE_SATELLITE))413         CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(INFRASTRUCTURE_BITMASK,
414                 String.valueOf(
415                         ApnSetting.INFRASTRUCTURE_CELLULAR | ApnSetting.INFRASTRUCTURE_SATELLITE));
CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(ESIM_BOOTSTRAP_PROVISIONING, "0")416         CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(ESIM_BOOTSTRAP_PROVISIONING, "0");
417 
CARRIERS_UNIQUE_FIELDS_DEFAULTS.keySet()418         CARRIERS_UNIQUE_FIELDS.addAll(CARRIERS_UNIQUE_FIELDS_DEFAULTS.keySet());
419 
420         // SQLite databases store bools as ints but the ContentValues objects passed in through
421         // queries use bools. As a result there is some special handling of boolean fields within
422         // the TelephonyProvider.
423         CARRIERS_BOOLEAN_FIELDS.add(CARRIER_ENABLED);
424         CARRIERS_BOOLEAN_FIELDS.add(MODEM_PERSIST);
425         CARRIERS_BOOLEAN_FIELDS.add(USER_VISIBLE);
426         CARRIERS_BOOLEAN_FIELDS.add(USER_EDITABLE);
427         CARRIERS_BOOLEAN_FIELDS.add(ESIM_BOOTSTRAP_PROVISIONING);
428 
429         MVNO_TYPE_STRING_MAP = new ArrayMap<>();
430         MVNO_TYPE_STRING_MAP.put("spn", ApnSetting.MVNO_TYPE_SPN);
431         MVNO_TYPE_STRING_MAP.put("imsi", ApnSetting.MVNO_TYPE_IMSI);
432         MVNO_TYPE_STRING_MAP.put("gid", ApnSetting.MVNO_TYPE_GID);
433         MVNO_TYPE_STRING_MAP.put("iccid", ApnSetting.MVNO_TYPE_ICCID);
434 
435         // To B&R a new config, simply add the column name and its appropriate value type to
436         // SIM_INFO_COLUMNS_TO_BACKUP. To no longer B&R a column, simply remove it from
437         // SIM_INFO_COLUMNS_TO_BACKUP. For both cases, add appropriate versioning logic in
438         // convertBackedUpDataToContentValues(ContentValues contenValues)
SIM_INFO_COLUMNS_TO_BACKUP.put( Telephony.SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID, Cursor.FIELD_TYPE_INTEGER)439         SIM_INFO_COLUMNS_TO_BACKUP.put(
440                 Telephony.SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID, Cursor.FIELD_TYPE_INTEGER);
SIM_INFO_COLUMNS_TO_BACKUP.put( Telephony.SimInfo.COLUMN_ICC_ID, Cursor.FIELD_TYPE_STRING)441         SIM_INFO_COLUMNS_TO_BACKUP.put(
442                 Telephony.SimInfo.COLUMN_ICC_ID, Cursor.FIELD_TYPE_STRING);
SIM_INFO_COLUMNS_TO_BACKUP.put( Telephony.SimInfo.COLUMN_NUMBER, Cursor.FIELD_TYPE_STRING)443         SIM_INFO_COLUMNS_TO_BACKUP.put(
444                 Telephony.SimInfo.COLUMN_NUMBER, Cursor.FIELD_TYPE_STRING);
SIM_INFO_COLUMNS_TO_BACKUP.put( Telephony.SimInfo.COLUMN_CARRIER_ID, Cursor.FIELD_TYPE_INTEGER)445         SIM_INFO_COLUMNS_TO_BACKUP.put(
446             Telephony.SimInfo.COLUMN_CARRIER_ID, Cursor.FIELD_TYPE_INTEGER);
SIM_INFO_COLUMNS_TO_BACKUP.put( Telephony.SimInfo.COLUMN_IMS_RCS_UCE_ENABLED, Cursor.FIELD_TYPE_INTEGER)447         SIM_INFO_COLUMNS_TO_BACKUP.put(
448             Telephony.SimInfo.COLUMN_IMS_RCS_UCE_ENABLED, Cursor.FIELD_TYPE_INTEGER);
SIM_INFO_COLUMNS_TO_BACKUP.put( Telephony.SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED, Cursor.FIELD_TYPE_INTEGER)449         SIM_INFO_COLUMNS_TO_BACKUP.put(
450                 Telephony.SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED, Cursor.FIELD_TYPE_INTEGER);
SIM_INFO_COLUMNS_TO_BACKUP.put( Telephony.SimInfo.COLUMN_VT_IMS_ENABLED, Cursor.FIELD_TYPE_INTEGER)451         SIM_INFO_COLUMNS_TO_BACKUP.put(
452                 Telephony.SimInfo.COLUMN_VT_IMS_ENABLED, Cursor.FIELD_TYPE_INTEGER);
SIM_INFO_COLUMNS_TO_BACKUP.put( Telephony.SimInfo.COLUMN_D2D_STATUS_SHARING, Cursor.FIELD_TYPE_INTEGER)453         SIM_INFO_COLUMNS_TO_BACKUP.put(
454                 Telephony.SimInfo.COLUMN_D2D_STATUS_SHARING, Cursor.FIELD_TYPE_INTEGER);
SIM_INFO_COLUMNS_TO_BACKUP.put( Telephony.SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS, Cursor.FIELD_TYPE_STRING)455         SIM_INFO_COLUMNS_TO_BACKUP.put(
456                 Telephony.SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS,
457                 Cursor.FIELD_TYPE_STRING);
SIM_INFO_COLUMNS_TO_BACKUP.put( Telephony.SimInfo.COLUMN_WFC_IMS_ENABLED, Cursor.FIELD_TYPE_INTEGER)458         SIM_INFO_COLUMNS_TO_BACKUP.put(
459                 Telephony.SimInfo.COLUMN_WFC_IMS_ENABLED, Cursor.FIELD_TYPE_INTEGER);
SIM_INFO_COLUMNS_TO_BACKUP.put( Telephony.SimInfo.COLUMN_WFC_IMS_MODE, Cursor.FIELD_TYPE_INTEGER)460         SIM_INFO_COLUMNS_TO_BACKUP.put(
461                 Telephony.SimInfo.COLUMN_WFC_IMS_MODE, Cursor.FIELD_TYPE_INTEGER);
SIM_INFO_COLUMNS_TO_BACKUP.put( Telephony.SimInfo.COLUMN_WFC_IMS_ROAMING_MODE, Cursor.FIELD_TYPE_INTEGER)462         SIM_INFO_COLUMNS_TO_BACKUP.put(
463                 Telephony.SimInfo.COLUMN_WFC_IMS_ROAMING_MODE, Cursor.FIELD_TYPE_INTEGER);
SIM_INFO_COLUMNS_TO_BACKUP.put( Telephony.SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED, Cursor.FIELD_TYPE_INTEGER)464         SIM_INFO_COLUMNS_TO_BACKUP.put(
465                 Telephony.SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED, Cursor.FIELD_TYPE_INTEGER);
SIM_INFO_COLUMNS_TO_BACKUP.put( Telephony.SimInfo.COLUMN_USAGE_SETTING, Cursor.FIELD_TYPE_INTEGER)466         SIM_INFO_COLUMNS_TO_BACKUP.put(
467                 Telephony.SimInfo.COLUMN_USAGE_SETTING,
468                 Cursor.FIELD_TYPE_INTEGER);
SIM_INFO_COLUMNS_TO_BACKUP.put( Telephony.SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES, Cursor.FIELD_TYPE_STRING)469         SIM_INFO_COLUMNS_TO_BACKUP.put(
470                 Telephony.SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES, Cursor.FIELD_TYPE_STRING);
SIM_INFO_COLUMNS_TO_BACKUP.put( Telephony.SimInfo.COLUMN_SATELLITE_ENABLED, Cursor.FIELD_TYPE_INTEGER)471         SIM_INFO_COLUMNS_TO_BACKUP.put(
472                 Telephony.SimInfo.COLUMN_SATELLITE_ENABLED, Cursor.FIELD_TYPE_INTEGER);
SIM_INFO_COLUMNS_TO_BACKUP.put( Telephony.SimInfo.COLUMN_SATELLITE_ATTACH_ENABLED_FOR_CARRIER, Cursor.FIELD_TYPE_INTEGER)473         SIM_INFO_COLUMNS_TO_BACKUP.put(
474                 Telephony.SimInfo.COLUMN_SATELLITE_ATTACH_ENABLED_FOR_CARRIER,
475                 Cursor.FIELD_TYPE_INTEGER);
SIM_INFO_COLUMNS_TO_BACKUP.put( Telephony.SimInfo.COLUMN_IS_ONLY_NTN, Cursor.FIELD_TYPE_INTEGER)476         SIM_INFO_COLUMNS_TO_BACKUP.put(
477                 Telephony.SimInfo.COLUMN_IS_ONLY_NTN, Cursor.FIELD_TYPE_INTEGER);
SIM_INFO_COLUMNS_TO_BACKUP.put( Telephony.SimInfo.COLUMN_TRANSFER_STATUS, Cursor.FIELD_TYPE_INTEGER)478         SIM_INFO_COLUMNS_TO_BACKUP.put(
479                 Telephony.SimInfo.COLUMN_TRANSFER_STATUS, Cursor.FIELD_TYPE_INTEGER);
SIM_INFO_COLUMNS_TO_BACKUP.put( Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_STATUS, Cursor.FIELD_TYPE_INTEGER)480         SIM_INFO_COLUMNS_TO_BACKUP.put(
481                 Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_STATUS, Cursor.FIELD_TYPE_INTEGER);
SIM_INFO_COLUMNS_TO_BACKUP.put( Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_PLMNS, Cursor.FIELD_TYPE_STRING)482         SIM_INFO_COLUMNS_TO_BACKUP.put(
483                 Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_PLMNS,
484                 Cursor.FIELD_TYPE_STRING);
SIM_INFO_COLUMNS_TO_BACKUP.put( Telephony.SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS, Cursor.FIELD_TYPE_STRING)485         SIM_INFO_COLUMNS_TO_BACKUP.put(
486                 Telephony.SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS,
487                 Cursor.FIELD_TYPE_STRING);
SIM_INFO_COLUMNS_TO_BACKUP.put( Telephony.SimInfo.COLUMN_SATELLITE_ESOS_SUPPORTED, Cursor.FIELD_TYPE_INTEGER)488         SIM_INFO_COLUMNS_TO_BACKUP.put(
489                 Telephony.SimInfo.COLUMN_SATELLITE_ESOS_SUPPORTED, Cursor.FIELD_TYPE_INTEGER);
SIM_INFO_COLUMNS_TO_BACKUP.put( Telephony.SimInfo.COLUMN_IS_SATELLITE_PROVISIONED_FOR_NON_IP_DATAGRAM, Cursor.FIELD_TYPE_INTEGER)490         SIM_INFO_COLUMNS_TO_BACKUP.put(
491                 Telephony.SimInfo.COLUMN_IS_SATELLITE_PROVISIONED_FOR_NON_IP_DATAGRAM,
492                 Cursor.FIELD_TYPE_INTEGER);
SIM_INFO_COLUMNS_TO_BACKUP.put( Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_BARRED_PLMNS, Cursor.FIELD_TYPE_STRING)493         SIM_INFO_COLUMNS_TO_BACKUP.put(
494                 Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_BARRED_PLMNS,
495                 Cursor.FIELD_TYPE_STRING);
SIM_INFO_COLUMNS_TO_BACKUP.put( Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_DATA_PLAN_PLMNS, Cursor.FIELD_TYPE_STRING)496         SIM_INFO_COLUMNS_TO_BACKUP.put(
497                 Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_DATA_PLAN_PLMNS,
498                 Cursor.FIELD_TYPE_STRING);
SIM_INFO_COLUMNS_TO_BACKUP.put( Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_SERVICE_TYPE_MAP, Cursor.FIELD_TYPE_STRING)499         SIM_INFO_COLUMNS_TO_BACKUP.put(
500                 Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_SERVICE_TYPE_MAP,
501                 Cursor.FIELD_TYPE_STRING);
SIM_INFO_COLUMNS_TO_BACKUP.put( Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_DATA_SERVICE_POLICY, Cursor.FIELD_TYPE_STRING)502         SIM_INFO_COLUMNS_TO_BACKUP.put(
503                 Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_DATA_SERVICE_POLICY,
504                 Cursor.FIELD_TYPE_STRING);
SIM_INFO_COLUMNS_TO_BACKUP.put( Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_VOICE_SERVICE_POLICY, Cursor.FIELD_TYPE_STRING)505         SIM_INFO_COLUMNS_TO_BACKUP.put(
506                 Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_VOICE_SERVICE_POLICY,
507                 Cursor.FIELD_TYPE_STRING);
508     }
509 
510     @VisibleForTesting
getStringForCarrierTableCreation(String tableName)511     public static String getStringForCarrierTableCreation(String tableName) {
512         return "CREATE TABLE " + tableName +
513                 "(_id INTEGER PRIMARY KEY," +
514                 NAME + " TEXT DEFAULT ''," +
515                 NUMERIC + " TEXT DEFAULT ''," +
516                 MCC + " TEXT DEFAULT ''," +
517                 MNC + " TEXT DEFAULT ''," +
518                 CARRIER_ID + " INTEGER DEFAULT " + TelephonyManager.UNKNOWN_CARRIER_ID  + "," +
519                 APN + " TEXT DEFAULT ''," +
520                 USER + " TEXT DEFAULT ''," +
521                 SERVER + " TEXT DEFAULT ''," +
522                 PASSWORD + " TEXT DEFAULT ''," +
523                 PROXY + " TEXT DEFAULT ''," +
524                 PORT + " TEXT DEFAULT ''," +
525                 MMSPROXY + " TEXT DEFAULT ''," +
526                 MMSPORT + " TEXT DEFAULT ''," +
527                 MMSC + " TEXT DEFAULT ''," +
528                 AUTH_TYPE + " INTEGER DEFAULT -1," +
529                 TYPE + " TEXT DEFAULT ''," +
530                 CURRENT + " INTEGER," +
531                 PROTOCOL + " TEXT DEFAULT " + DEFAULT_PROTOCOL + "," +
532                 ROAMING_PROTOCOL + " TEXT DEFAULT " + DEFAULT_ROAMING_PROTOCOL + "," +
533                 CARRIER_ENABLED + " BOOLEAN DEFAULT 1," + // SQLite databases store bools as ints
534                 BEARER + " INTEGER DEFAULT 0," +
535                 BEARER_BITMASK + " INTEGER DEFAULT 0," +
536                 NETWORK_TYPE_BITMASK + " INTEGER DEFAULT 0," +
537                 LINGERING_NETWORK_TYPE_BITMASK + " INTEGER DEFAULT 0," +
538                 MVNO_TYPE + " TEXT DEFAULT ''," +
539                 MVNO_MATCH_DATA + " TEXT DEFAULT ''," +
540                 SUBSCRIPTION_ID + " INTEGER DEFAULT " +
541                 SubscriptionManager.INVALID_SUBSCRIPTION_ID + "," +
542                 PROFILE_ID + " INTEGER DEFAULT 0," +
543                 MODEM_PERSIST + " BOOLEAN DEFAULT 0," +
544                 MAX_CONNECTIONS + " INTEGER DEFAULT 0," +
545                 WAIT_TIME_RETRY + " INTEGER DEFAULT 0," +
546                 TIME_LIMIT_FOR_MAX_CONNECTIONS + " INTEGER DEFAULT 0," +
547                 MTU + " INTEGER DEFAULT 0," +
548                 MTU_V4 + " INTEGER DEFAULT 0," +
549                 MTU_V6 + " INTEGER DEFAULT 0," +
550                 EDITED_STATUS + " INTEGER DEFAULT " + UNEDITED + "," +
551                 USER_VISIBLE + " BOOLEAN DEFAULT 1," +
552                 USER_EDITABLE + " BOOLEAN DEFAULT 1," +
553                 OWNED_BY + " INTEGER DEFAULT " + OWNED_BY_OTHERS + "," +
554                 APN_SET_ID + " INTEGER DEFAULT " + NO_APN_SET_ID + "," +
555                 SKIP_464XLAT + " INTEGER DEFAULT " + SKIP_464XLAT_DEFAULT + "," +
556                 ALWAYS_ON + " INTEGER DEFAULT 0," +
557                 INFRASTRUCTURE_BITMASK + " INTEGER DEFAULT 3," +
558                 ESIM_BOOTSTRAP_PROVISIONING + " BOOLEAN DEFAULT 0," +
559                 // Uniqueness collisions are used to trigger merge code so if a field is listed
560                 // here it means we will accept both (user edited + new apn_conf definition)
561                 // Columns not included in UNIQUE constraint: name, current, edited,
562                 // user, server, password, authtype, type, sub_id, modem_cognitive, max_conns,
563                 // wait_time, max_conns_time, mtu, mtu_v4, mtu_v6, bearer_bitmask, user_visible,
564                 // network_type_bitmask, skip_464xlat, lingering_network_type_bitmask, always_on.
565                 "UNIQUE (" + TextUtils.join(", ", CARRIERS_UNIQUE_FIELDS) + "));";
566     }
567 
568     @VisibleForTesting
getStringForSimInfoTableCreation(String tableName)569     public static String getStringForSimInfoTableCreation(String tableName) {
570         return "CREATE TABLE " + tableName + "("
571                 + Telephony.SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID
572                 + " INTEGER PRIMARY KEY AUTOINCREMENT,"
573                 + Telephony.SimInfo.COLUMN_ICC_ID + " TEXT NOT NULL,"
574                 + Telephony.SimInfo.COLUMN_SIM_SLOT_INDEX
575                 + " INTEGER DEFAULT " + Telephony.SimInfo.SIM_NOT_INSERTED + ","
576                 + Telephony.SimInfo.COLUMN_DISPLAY_NAME + " TEXT,"
577                 + Telephony.SimInfo.COLUMN_CARRIER_NAME + " TEXT,"
578                 + Telephony.SimInfo.COLUMN_NAME_SOURCE
579                 + " INTEGER DEFAULT " + Telephony.SimInfo.NAME_SOURCE_CARRIER_ID + ","
580                 + Telephony.SimInfo.COLUMN_COLOR + " INTEGER DEFAULT "
581                 + Telephony.SimInfo.COLOR_DEFAULT + ","
582                 + Telephony.SimInfo.COLUMN_NUMBER + " TEXT,"
583                 + Telephony.SimInfo.COLUMN_DISPLAY_NUMBER_FORMAT
584                 + " INTEGER NOT NULL DEFAULT " + Telephony.SimInfo.DISPLAY_NUMBER_DEFAULT + ","
585                 + Telephony.SimInfo.COLUMN_DATA_ROAMING
586                 + " INTEGER DEFAULT " + Telephony.SimInfo.DATA_ROAMING_DISABLE + ","
587                 + Telephony.SimInfo.COLUMN_MCC + " INTEGER DEFAULT 0,"
588                 + Telephony.SimInfo.COLUMN_MNC + " INTEGER DEFAULT 0,"
589                 + Telephony.SimInfo.COLUMN_MCC_STRING + " TEXT,"
590                 + Telephony.SimInfo.COLUMN_MNC_STRING + " TEXT,"
591                 + Telephony.SimInfo.COLUMN_EHPLMNS + " TEXT,"
592                 + Telephony.SimInfo.COLUMN_HPLMNS + " TEXT,"
593                 + Telephony.SimInfo.COLUMN_SIM_PROVISIONING_STATUS
594                 + " INTEGER DEFAULT " + Telephony.SimInfo.SIM_PROVISIONED + ","
595                 + Telephony.SimInfo.COLUMN_IS_EMBEDDED + " INTEGER DEFAULT 0,"
596                 + Telephony.SimInfo.COLUMN_CARD_ID + " TEXT NOT NULL,"
597                 + Telephony.SimInfo.COLUMN_ACCESS_RULES + " BLOB,"
598                 + Telephony.SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS + " BLOB,"
599                 + Telephony.SimInfo.COLUMN_IS_REMOVABLE + " INTEGER DEFAULT 0,"
600                 + Telephony.SimInfo.COLUMN_CB_EXTREME_THREAT_ALERT + " INTEGER DEFAULT 1,"
601                 + Telephony.SimInfo.COLUMN_CB_SEVERE_THREAT_ALERT + " INTEGER DEFAULT 1,"
602                 + Telephony.SimInfo.COLUMN_CB_AMBER_ALERT + " INTEGER DEFAULT 1,"
603                 + Telephony.SimInfo.COLUMN_CB_EMERGENCY_ALERT + " INTEGER DEFAULT 1,"
604                 + Telephony.SimInfo.COLUMN_CB_ALERT_SOUND_DURATION + " INTEGER DEFAULT 4,"
605                 + Telephony.SimInfo.COLUMN_CB_ALERT_REMINDER_INTERVAL + " INTEGER DEFAULT 0,"
606                 + Telephony.SimInfo.COLUMN_CB_ALERT_VIBRATE + " INTEGER DEFAULT 1,"
607                 + Telephony.SimInfo.COLUMN_CB_ALERT_SPEECH + " INTEGER DEFAULT 1,"
608                 + Telephony.SimInfo.COLUMN_CB_ETWS_TEST_ALERT + " INTEGER DEFAULT 0,"
609                 + Telephony.SimInfo.COLUMN_CB_CHANNEL_50_ALERT + " INTEGER DEFAULT 1,"
610                 + Telephony.SimInfo.COLUMN_CB_CMAS_TEST_ALERT + " INTEGER DEFAULT 0,"
611                 + Telephony.SimInfo.COLUMN_CB_OPT_OUT_DIALOG + " INTEGER DEFAULT 1,"
612                 + Telephony.SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED + " INTEGER DEFAULT -1,"
613                 + Telephony.SimInfo.COLUMN_VT_IMS_ENABLED + " INTEGER DEFAULT -1,"
614                 + Telephony.SimInfo.COLUMN_WFC_IMS_ENABLED + " INTEGER DEFAULT -1,"
615                 + Telephony.SimInfo.COLUMN_WFC_IMS_MODE + " INTEGER DEFAULT -1,"
616                 + Telephony.SimInfo.COLUMN_WFC_IMS_ROAMING_MODE + " INTEGER DEFAULT -1,"
617                 + Telephony.SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED + " INTEGER DEFAULT -1,"
618                 + Telephony.SimInfo.COLUMN_IS_OPPORTUNISTIC + " INTEGER DEFAULT 0,"
619                 + Telephony.SimInfo.COLUMN_GROUP_UUID + " TEXT,"
620                 + Telephony.SimInfo.COLUMN_IS_METERED + " INTEGER DEFAULT 1,"
621                 + Telephony.SimInfo.COLUMN_ISO_COUNTRY_CODE + " TEXT,"
622                 + Telephony.SimInfo.COLUMN_CARRIER_ID + " INTEGER DEFAULT -1,"
623                 + Telephony.SimInfo.COLUMN_PROFILE_CLASS + " INTEGER DEFAULT "
624                 + Telephony.SimInfo.PROFILE_CLASS_UNSET + ","
625                 + Telephony.SimInfo.COLUMN_SUBSCRIPTION_TYPE + " INTEGER DEFAULT "
626                 + Telephony.SimInfo.SUBSCRIPTION_TYPE_LOCAL_SIM + ","
627                 + Telephony.SimInfo.COLUMN_GROUP_OWNER + " TEXT,"
628                 + Telephony.SimInfo.COLUMN_DATA_ENABLED_OVERRIDE_RULES + " TEXT,"
629                 + Telephony.SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES + " TEXT,"
630                 + Telephony.SimInfo.COLUMN_IMSI + " TEXT,"
631                 + Telephony.SimInfo.COLUMN_UICC_APPLICATIONS_ENABLED + " INTEGER DEFAULT 1,"
632                 + Telephony.SimInfo.COLUMN_ALLOWED_NETWORK_TYPES + " BIGINT DEFAULT -1,"
633                 + Telephony.SimInfo.COLUMN_IMS_RCS_UCE_ENABLED + " INTEGER DEFAULT 0,"
634                 + Telephony.SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED + " INTEGER DEFAULT 0,"
635                 + Telephony.SimInfo.COLUMN_RCS_CONFIG + " BLOB,"
636                 + Telephony.SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS + " TEXT,"
637                 + Telephony.SimInfo.COLUMN_D2D_STATUS_SHARING + " INTEGER DEFAULT 0,"
638                 + Telephony.SimInfo.COLUMN_VOIMS_OPT_IN_STATUS + " INTEGER DEFAULT 0,"
639                 + Telephony.SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS + " TEXT,"
640                 + Telephony.SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED + " INTEGER DEFAULT -1,"
641                 + Telephony.SimInfo.COLUMN_PHONE_NUMBER_SOURCE_CARRIER + " TEXT,"
642                 + Telephony.SimInfo.COLUMN_PHONE_NUMBER_SOURCE_IMS + " TEXT,"
643                 + Telephony.SimInfo.COLUMN_PORT_INDEX + "  INTEGER DEFAULT -1,"
644                 + Telephony.SimInfo.COLUMN_USAGE_SETTING + " INTEGER DEFAULT "
645                 + SubscriptionManager.USAGE_SETTING_UNKNOWN + ","
646                 + Telephony.SimInfo.COLUMN_TP_MESSAGE_REF +
647                 "  INTEGER DEFAULT -1,"
648                 + Telephony.SimInfo.COLUMN_USER_HANDLE + " INTEGER DEFAULT "
649                 + UserHandle.USER_NULL + ","
650                 + Telephony.SimInfo.COLUMN_SATELLITE_ENABLED + " INTEGER DEFAULT 0,"
651                 + Telephony.SimInfo.COLUMN_SATELLITE_ATTACH_ENABLED_FOR_CARRIER
652                 + " INTEGER DEFAULT 1, "
653                 + Telephony.SimInfo.COLUMN_IS_ONLY_NTN + " INTEGER DEFAULT 0, "
654                 + Telephony.SimInfo.COLUMN_SERVICE_CAPABILITIES + " INTEGER DEFAULT "
655                 + SubscriptionManager.getAllServiceCapabilityBitmasks() + ","
656                 + Telephony.SimInfo.COLUMN_TRANSFER_STATUS + " INTEGER DEFAULT 0,"
657                 + Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_STATUS + " INTEGER DEFAULT 0,"
658                 + Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_PLMNS + " TEXT,"
659                 + Telephony.SimInfo.COLUMN_SATELLITE_ESOS_SUPPORTED + " INTEGER DEFAULT 0,"
660                 + Telephony.SimInfo.COLUMN_IS_SATELLITE_PROVISIONED_FOR_NON_IP_DATAGRAM
661                 + " INTEGER DEFAULT 0,"
662                 + Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_BARRED_PLMNS + " TEXT,"
663                 + Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_DATA_PLAN_PLMNS + " TEXT,"
664                 + Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_SERVICE_TYPE_MAP + " TEXT,"
665                 + Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_DATA_SERVICE_POLICY + " TEXT,"
666                 + Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_VOICE_SERVICE_POLICY + " TEXT"
667                 + ");";
668     }
669 
670     static {
671         s_urlMatcher.addURI("telephony", "carriers", URL_TELEPHONY);
672         s_urlMatcher.addURI("telephony", "carriers/current", URL_CURRENT);
673         s_urlMatcher.addURI("telephony", "carriers/#", URL_ID);
674         s_urlMatcher.addURI("telephony", "carriers/restore", URL_RESTOREAPN);
675         s_urlMatcher.addURI("telephony", "carriers/preferapn", URL_PREFERAPN);
676         s_urlMatcher.addURI("telephony", "carriers/preferapn_no_update", URL_PREFERAPN_NO_UPDATE);
677         s_urlMatcher.addURI("telephony", "carriers/preferapnset", URL_PREFERAPNSET);
678 
679         s_urlMatcher.addURI("telephony", "siminfo", URL_SIMINFO);
680         s_urlMatcher.addURI("telephony", "siminfo/#", URL_SIMINFO_USING_SUBID);
681         s_urlMatcher.addURI("telephony", "siminfo/backup_and_restore/suw_restore",
682                 URL_SIMINFO_SUW_RESTORE);
683         s_urlMatcher.addURI("telephony", "siminfo/backup_and_restore/" +
684                 SIM_INSERTED_RESTORE_URI_SUFFIX,
685                 URL_SIMINFO_SIM_INSERTED_RESTORE);
686 
687         s_urlMatcher.addURI("telephony", "carriers/subId/*", URL_TELEPHONY_USING_SUBID);
688         s_urlMatcher.addURI("telephony", "carriers/current/subId/*", URL_CURRENT_USING_SUBID);
689         s_urlMatcher.addURI("telephony", "carriers/restore/subId/*", URL_RESTOREAPN_USING_SUBID);
690         s_urlMatcher.addURI("telephony", "carriers/preferapn/subId/*", URL_PREFERAPN_USING_SUBID);
691         s_urlMatcher.addURI("telephony", "carriers/preferapn_no_update/subId/*",
692                 URL_PREFERAPN_NO_UPDATE_USING_SUBID);
693         s_urlMatcher.addURI("telephony", "carriers/preferapnset/subId/*",
694                 URL_PREFERAPNSET_USING_SUBID);
695 
696         s_urlMatcher.addURI("telephony", "carriers/update_db", URL_UPDATE_DB);
697         s_urlMatcher.addURI("telephony", "carriers/delete", URL_DELETE);
698 
699         // Only called by DevicePolicyManager to manipulate DPC records.
700         s_urlMatcher.addURI("telephony", "carriers/dpc", URL_DPC);
701         // Only called by DevicePolicyManager to manipulate a DPC record with certain _ID.
702         s_urlMatcher.addURI("telephony", "carriers/dpc/#", URL_DPC_ID);
703         // Only called by Settings app, DcTracker and other telephony components to get APN list
704         // according to whether DPC records are enforced.
705         s_urlMatcher.addURI("telephony", "carriers/filtered", URL_FILTERED);
706         // Only called by Settings app, DcTracker and other telephony components to get a
707         // single APN according to whether DPC records are enforced.
708         s_urlMatcher.addURI("telephony", "carriers/filtered/#", URL_FILTERED_ID);
709         // Used by DcTracker to pass a subId.
710         s_urlMatcher.addURI("telephony", "carriers/filtered/subId/*", URL_FILTERED_USING_SUBID);
711 
712         // Only Called by DevicePolicyManager to enforce DPC records.
713         s_urlMatcher.addURI("telephony", "carriers/enforce_managed", URL_ENFORCE_MANAGED);
714         s_urlMatcher.addURI("telephony", "carriers/sim_apn_list", URL_SIM_APN_LIST);
715         s_urlMatcher.addURI("telephony", "carriers/sim_apn_list/#", URL_SIM_APN_LIST_ID);
716         s_urlMatcher.addURI("telephony", "carriers/sim_apn_list/filtered",
717             URL_SIM_APN_LIST_FILTERED);
718         s_urlMatcher.addURI("telephony", "carriers/sim_apn_list/filtered/subId/*",
719                 URL_SIM_APN_LIST_FILTERED_ID);
720 
721         s_currentNullMap = new ContentValues(1);
s_currentNullMap.put(CURRENT, "0")722         s_currentNullMap.put(CURRENT, "0");
723 
724         s_currentSetMap = new ContentValues(1);
s_currentSetMap.put(CURRENT, "1")725         s_currentSetMap.put(CURRENT, "1");
726     }
727 
728     /**
729      * Unit test will subclass it to inject mocks.
730      */
731     @VisibleForTesting
732     static class Injector {
binderGetCallingUid()733         int binderGetCallingUid() {
734             return Binder.getCallingUid();
735         }
736     }
737 
TelephonyProvider()738     public TelephonyProvider() {
739         this(new Injector());
740     }
741 
742     @VisibleForTesting
TelephonyProvider(Injector injector)743     public TelephonyProvider(Injector injector) {
744         mInjector = injector;
745     }
746 
747     @VisibleForTesting
getVersion(Context context)748     public static int getVersion(Context context) {
749         if (VDBG) log("getVersion:+");
750         // Get the database version, combining a static schema version and the XML version
751         Resources r = context.getResources();
752         if (r == null) {
753             loge("resources=null, return version=" + Integer.toHexString(DATABASE_VERSION));
754             return DATABASE_VERSION;
755         }
756         XmlResourceParser parser = r.getXml(com.android.internal.R.xml.apns);
757 
758         if (parser == null) {
759             loge("Null parser");
760             return DATABASE_VERSION;
761         }
762 
763         try {
764             XmlUtils.beginDocument(parser, "apns");
765             int publicversion = Integer.parseInt(parser.getAttributeValue(null, "version"));
766             int version = DATABASE_VERSION | publicversion;
767             if (VDBG) log("getVersion:- version=0x" + Integer.toHexString(version));
768             return version;
769         } catch (Exception e) {
770             loge("Can't get version of APN database" + e + " return version=" +
771                     Integer.toHexString(DATABASE_VERSION));
772             return DATABASE_VERSION;
773         } finally {
774             parser.close();
775         }
776     }
777 
778 
779     /**
780      * Put the default subscription Id into the provided convent values.
781      * @param values The content values to populate.
782      * @return The populated content values.
783      */
setDefaultValue(ContentValues values)784     public ContentValues setDefaultValue(ContentValues values) {
785         if (!values.containsKey(SUBSCRIPTION_ID)) {
786             values.put(SUBSCRIPTION_ID, mDefaultSubId);
787         }
788 
789         return values;
790     }
791 
792     @VisibleForTesting
793     public class DatabaseHelper extends SQLiteOpenHelper {
794         // Context to access resources with
795         private Context mContext;
796 
797         /**
798          * DatabaseHelper helper class for loading apns into a database.
799          *
800          * @param context of the user.
801          */
DatabaseHelper(Context context)802         public DatabaseHelper(Context context) {
803             super(context, DATABASE_NAME, null, getVersion(context));
804             mContext = context;
805             // Memory optimization - close idle connections after 30s of inactivity
806             setIdleConnectionTimeout(IDLE_CONNECTION_TIMEOUT_MS);
807             setWriteAheadLoggingEnabled(false);
808         }
809 
810         @Override
onCreate(SQLiteDatabase db)811         public void onCreate(SQLiteDatabase db) {
812             if (DBG) log("dbh.onCreate:+ db=" + db);
813             createSimInfoTable(db, SIMINFO_TABLE);
814             createCarriersTable(db, CARRIERS_TABLE);
815             // if CarrierSettings app is installed, we expect it to do the initializiation instead
816             if (apnSourceServiceExists(mContext)) {
817                 log("dbh.onCreate: Skipping apply APNs from xml.");
818             } else {
819                 log("dbh.onCreate: Apply apns from xml.");
820                 initDatabase(db);
821                 // Notify listeners of DB change since DB has been updated
822                 mContext.getContentResolver().notifyChange(
823                         CONTENT_URI, null, true, UserHandle.USER_ALL);
824             }
825             if (DBG) log("dbh.onCreate:- db=" + db);
826         }
827 
828         @Override
onOpen(SQLiteDatabase db)829         public void onOpen(SQLiteDatabase db) {
830             if (VDBG) log("dbh.onOpen:+ db=" + db);
831             try {
832                 // Try to access the table and create it if "no such table"
833                 db.query(SIMINFO_TABLE, null, null, null, null, null, null);
834                 if (DBG) log("dbh.onOpen: ok, queried table=" + SIMINFO_TABLE);
835             } catch (SQLiteException e) {
836                 loge("Exception " + SIMINFO_TABLE + "e=" + e);
837                 if (e.getMessage().startsWith("no such table")) {
838                     createSimInfoTable(db, SIMINFO_TABLE);
839                 }
840             }
841             try {
842                 db.query(CARRIERS_TABLE, null, null, null, null, null, null);
843                 if (DBG) log("dbh.onOpen: ok, queried table=" + CARRIERS_TABLE);
844             } catch (SQLiteException e) {
845                 loge("Exception " + CARRIERS_TABLE + " e=" + e);
846                 if (e.getMessage().startsWith("no such table")) {
847                     createCarriersTable(db, CARRIERS_TABLE);
848                 }
849             }
850             if (VDBG) log("dbh.onOpen:- db=" + db);
851         }
852 
createSimInfoTable(SQLiteDatabase db, String tableName)853         private void createSimInfoTable(SQLiteDatabase db, String tableName) {
854             if (DBG) log("dbh.createSimInfoTable:+ " + tableName);
855             db.execSQL(getStringForSimInfoTableCreation(tableName));
856             if (DBG) log("dbh.createSimInfoTable:-");
857         }
858 
createCarriersTable(SQLiteDatabase db, String tableName)859         private void createCarriersTable(SQLiteDatabase db, String tableName) {
860             // Set up the database schema
861             if (DBG) log("dbh.createCarriersTable: " + tableName);
862             db.execSQL(getStringForCarrierTableCreation(tableName));
863             if (DBG) log("dbh.createCarriersTable:-");
864         }
865 
getChecksum(File file)866         private long getChecksum(File file) {
867             CRC32 checkSummer = new CRC32();
868             long checkSum = -1;
869             try (CheckedInputStream cis =
870                 new CheckedInputStream(new FileInputStream(file), checkSummer)){
871                 byte[] buf = new byte[128];
872                 if(cis != null) {
873                     while(cis.read(buf) >= 0) {
874                         // Just read for checksum to get calculated.
875                     }
876                 }
877                 checkSum = checkSummer.getValue();
878                 if (DBG) log("Checksum for " + file.getAbsolutePath() + " is " + checkSum);
879             } catch (FileNotFoundException e) {
880                 loge("FileNotFoundException for " + file.getAbsolutePath() + ":" + e);
881             } catch (IOException e) {
882                 loge("IOException for " + file.getAbsolutePath() + ":" + e);
883             }
884 
885             // The RRO may have been updated in a firmware upgrade. Add checksum for the
886             // resources to the total checksum so that apns in an RRO update is not missed.
887             try (InputStream inputStream = mContext.getResources().
888                         openRawResource(com.android.internal.R.xml.apns)) {
889                 byte[] array = toByteArray(inputStream);
890                 checkSummer.reset();
891                 checkSummer.update(array);
892                 checkSum += checkSummer.getValue();
893                 if (DBG) log("Checksum after adding resource is " + checkSummer.getValue());
894             } catch (IOException | Resources.NotFoundException e) {
895                 loge("Exception when calculating checksum for internal apn resources: " + e);
896             }
897             return checkSum;
898         }
899 
toByteArray(InputStream input)900         private byte[] toByteArray(InputStream input) throws IOException {
901             byte[] buffer = new byte[128];
902             int bytesRead;
903             ByteArrayOutputStream output = new ByteArrayOutputStream();
904             while ((bytesRead = input.read(buffer)) != -1) {
905                 output.write(buffer, 0, bytesRead);
906             }
907             return output.toByteArray();
908         }
909 
getApnConfChecksum()910         private long getApnConfChecksum() {
911             SharedPreferences sp = mContext.getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE);
912             return sp.getLong(APN_CONF_CHECKSUM, -1);
913         }
914 
setApnConfChecksum(long checksum)915         private void setApnConfChecksum(long checksum) {
916             SharedPreferences sp = mContext.getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE);
917             SharedPreferences.Editor editor = sp.edit();
918             editor.putLong(APN_CONF_CHECKSUM, checksum);
919             editor.apply();
920         }
921 
getApnConfFile()922         private File getApnConfFile() {
923             // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
924             File confFile = new File(Environment.getRootDirectory(), PARTNER_APNS_PATH);
925             File oemConfFile =  new File(Environment.getOemDirectory(), OEM_APNS_PATH);
926             File updatedConfFile = new File(Environment.getDataDirectory(), OTA_UPDATED_APNS_PATH);
927             File productConfFile = new File(Environment.getProductDirectory(), PARTNER_APNS_PATH);
928             confFile = pickSecondIfExists(confFile, oemConfFile);
929             confFile = pickSecondIfExists(confFile, productConfFile);
930             confFile = pickSecondIfExists(confFile, updatedConfFile);
931             return confFile;
932         }
933 
934         /**
935          * This function computes checksum for the file to be read and compares it against the
936          * last read file. DB needs to be updated only if checksum has changed, or old checksum does
937          * not exist.
938          * @return true if DB should be updated with new conf file, false otherwise
939          */
apnDbUpdateNeeded()940         private boolean apnDbUpdateNeeded() {
941             File confFile = getApnConfFile();
942             long newChecksum = getChecksum(confFile);
943             long oldChecksum = getApnConfChecksum();
944             if (DBG) log("newChecksum: " + newChecksum);
945             if (DBG) log("oldChecksum: " + oldChecksum);
946             return newChecksum != oldChecksum;
947         }
948 
949         /**
950          *  This function adds APNs from xml file(s) to db. The db may or may not be empty to begin
951          *  with.
952          */
initDatabase(SQLiteDatabase db)953         private void initDatabase(SQLiteDatabase db) {
954             if (VDBG) log("dbh.initDatabase:+ db=" + db);
955             // Read internal APNS data
956             Resources r = mContext.getResources();
957             int publicversion = -1;
958             if (r != null) {
959                 XmlResourceParser parser = r.getXml(com.android.internal.R.xml.apns);
960                 try {
961                     XmlUtils.beginDocument(parser, "apns");
962                     publicversion = Integer.parseInt(parser.getAttributeValue(null, "version"));
963                     loadApns(db, parser, true);
964                 } catch (Exception e) {
965                     loge("Got exception while loading APN database." + e);
966                 } finally {
967                     parser.close();
968                 }
969             } else {
970                 loge("initDatabase: resources=null");
971             }
972 
973             // Read external APNS data (partner-provided)
974             XmlPullParser confparser = null;
975             File confFile = getApnConfFile();
976 
977             FileReader confreader = null;
978             if (DBG) log("confFile = " + confFile);
979             try {
980                 confreader = new FileReader(confFile);
981                 confparser = Xml.newPullParser();
982                 confparser.setInput(confreader);
983                 XmlUtils.beginDocument(confparser, "apns");
984 
985                 // Correctness check. Force internal version and confidential versions to agree
986                 int confversion = Integer.parseInt(confparser.getAttributeValue(null, "version"));
987                 if (publicversion != confversion) {
988                     log("initDatabase: throwing exception due to version mismatch");
989                     throw new IllegalStateException("Internal APNS file version doesn't match "
990                             + confFile.getAbsolutePath());
991                 }
992 
993                 loadApns(db, confparser, false);
994             } catch (FileNotFoundException e) {
995                 // It's ok if the file isn't found. It means there isn't a confidential file
996                 // Log.e(TAG, "File not found: '" + confFile.getAbsolutePath() + "'");
997             } catch (Exception e) {
998                 loge("initDatabase: Exception while parsing '" + confFile.getAbsolutePath() + "'" +
999                         e);
1000             } finally {
1001                 // Get rid of user/carrier deleted entries that are not present in apn xml file.
1002                 // Those entries have edited value USER_DELETED/CARRIER_DELETED.
1003                 if (VDBG) {
1004                     log("initDatabase: deleting USER_DELETED and replacing "
1005                             + "DELETED_BUT_PRESENT_IN_XML with DELETED");
1006                 }
1007 
1008                 // Delete USER_DELETED
1009                 db.delete(CARRIERS_TABLE, IS_USER_DELETED + " or " + IS_CARRIER_DELETED, null);
1010 
1011                 // Change USER_DELETED_BUT_PRESENT_IN_XML to USER_DELETED
1012                 ContentValues cv = new ContentValues();
1013                 cv.put(EDITED_STATUS, USER_DELETED);
1014                 db.update(CARRIERS_TABLE, cv, IS_USER_DELETED_BUT_PRESENT_IN_XML, null);
1015 
1016                 // Change CARRIER_DELETED_BUT_PRESENT_IN_XML to CARRIER_DELETED
1017                 cv = new ContentValues();
1018                 cv.put(EDITED_STATUS, CARRIER_DELETED);
1019                 db.update(CARRIERS_TABLE, cv, IS_CARRIER_DELETED_BUT_PRESENT_IN_XML, null);
1020 
1021                 if (confreader != null) {
1022                     try {
1023                         confreader.close();
1024                     } catch (IOException e) {
1025                         // do nothing
1026                     }
1027                 }
1028 
1029                 // Update the stored checksum
1030                 setApnConfChecksum(getChecksum(confFile));
1031             }
1032             if (VDBG) log("dbh.initDatabase:- db=" + db);
1033 
1034         }
1035 
pickSecondIfExists(File sysApnFile, File altApnFile)1036         private File pickSecondIfExists(File sysApnFile, File altApnFile) {
1037             if (altApnFile.exists()) {
1038                 if (DBG) log("Load APNs from " + altApnFile.getPath() +
1039                         " instead of " + sysApnFile.getPath());
1040                 return altApnFile;
1041             } else {
1042                 if (DBG) log("Load APNs from " + sysApnFile.getPath() +
1043                         " instead of " + altApnFile.getPath());
1044                 return sysApnFile;
1045             }
1046         }
1047 
1048         @Override
onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion)1049         public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
1050             String msg = "dbh.onDowngrade: TelephonyProvider database downgraded from version "
1051                     + oldVersion + " to " + newVersion + ". Some user settings might be lost!";
1052             loge(msg);
1053             mLocalLog.log(msg);
1054 
1055             try {
1056                 // Delete the database entirely so it can be rebuilt from scratch.
1057                 db.execSQL("DROP TABLE IF EXISTS " + CARRIERS_TABLE);
1058                 db.execSQL("DROP TABLE IF EXISTS " + SIMINFO_TABLE);
1059                 onCreate(db);
1060             } catch (SQLiteException e) {
1061                 loge("Failed to recreate the table " + CARRIERS_TABLE + " and " + SIMINFO_TABLE
1062                         + ". e=" + e);
1063             }
1064         }
1065 
1066         @Override
onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)1067         public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
1068             if (DBG) {
1069                 log("dbh.onUpgrade:+ db=" + db + " oldV=" + oldVersion + " newV=" + newVersion);
1070             }
1071 
1072             deletePreferredApnId(mContext);
1073 
1074             if (oldVersion < (5 << 16 | 6)) {
1075                 // 5 << 16 is the Database version and 6 in the xml version.
1076 
1077                 // This change adds a new authtype column to the database.
1078                 // The auth type column can have 4 values: 0 (None), 1 (PAP), 2 (CHAP)
1079                 // 3 (PAP or CHAP). To avoid breaking compatibility, with already working
1080                 // APNs, the unset value (-1) will be used. If the value is -1.
1081                 // the authentication will default to 0 (if no user / password) is specified
1082                 // or to 3. Currently, there have been no reported problems with
1083                 // pre-configured APNs and hence it is set to -1 for them. Similarly,
1084                 // if the user, has added a new APN, we set the authentication type
1085                 // to -1.
1086 
1087                 db.execSQL("ALTER TABLE " + CARRIERS_TABLE +
1088                         " ADD COLUMN authtype INTEGER DEFAULT -1;");
1089 
1090                 oldVersion = 5 << 16 | 6;
1091             }
1092             if (oldVersion < (6 << 16 | 6)) {
1093                 // Add protcol fields to the APN. The XML file does not change.
1094                 db.execSQL("ALTER TABLE " + CARRIERS_TABLE +
1095                         " ADD COLUMN protocol TEXT DEFAULT IP;");
1096                 db.execSQL("ALTER TABLE " + CARRIERS_TABLE +
1097                         " ADD COLUMN roaming_protocol TEXT DEFAULT IP;");
1098                 oldVersion = 6 << 16 | 6;
1099             }
1100             if (oldVersion < (7 << 16 | 6)) {
1101                 // Add carrier_enabled, bearer fields to the APN. The XML file does not change.
1102                 db.execSQL("ALTER TABLE " + CARRIERS_TABLE +
1103                         " ADD COLUMN carrier_enabled BOOLEAN DEFAULT 1;");
1104                 db.execSQL("ALTER TABLE " + CARRIERS_TABLE +
1105                         " ADD COLUMN bearer INTEGER DEFAULT 0;");
1106                 oldVersion = 7 << 16 | 6;
1107             }
1108             if (oldVersion < (8 << 16 | 6)) {
1109                 // Add mvno_type, mvno_match_data fields to the APN.
1110                 // The XML file does not change.
1111                 db.execSQL("ALTER TABLE " + CARRIERS_TABLE +
1112                         " ADD COLUMN mvno_type TEXT DEFAULT '';");
1113                 db.execSQL("ALTER TABLE " + CARRIERS_TABLE +
1114                         " ADD COLUMN mvno_match_data TEXT DEFAULT '';");
1115                 oldVersion = 8 << 16 | 6;
1116             }
1117             if (oldVersion < (9 << 16 | 6)) {
1118                 db.execSQL("ALTER TABLE " + CARRIERS_TABLE +
1119                         " ADD COLUMN sub_id INTEGER DEFAULT " +
1120                         SubscriptionManager.INVALID_SUBSCRIPTION_ID + ";");
1121                 oldVersion = 9 << 16 | 6;
1122             }
1123             if (oldVersion < (10 << 16 | 6)) {
1124                 db.execSQL("ALTER TABLE " + CARRIERS_TABLE +
1125                         " ADD COLUMN profile_id INTEGER DEFAULT 0;");
1126                 db.execSQL("ALTER TABLE " + CARRIERS_TABLE +
1127                         " ADD COLUMN modem_cognitive BOOLEAN DEFAULT 0;");
1128                 db.execSQL("ALTER TABLE " + CARRIERS_TABLE +
1129                         " ADD COLUMN max_conns INTEGER DEFAULT 0;");
1130                 db.execSQL("ALTER TABLE " + CARRIERS_TABLE +
1131                         " ADD COLUMN wait_time INTEGER DEFAULT 0;");
1132                 db.execSQL("ALTER TABLE " + CARRIERS_TABLE +
1133                         " ADD COLUMN max_conns_time INTEGER DEFAULT 0;");
1134                 oldVersion = 10 << 16 | 6;
1135             }
1136             if (oldVersion < (11 << 16 | 6)) {
1137                 db.execSQL("ALTER TABLE " + CARRIERS_TABLE +
1138                         " ADD COLUMN mtu INTEGER DEFAULT 0;");
1139                 oldVersion = 11 << 16 | 6;
1140             }
1141             if (oldVersion < (12 << 16 | 6)) {
1142                 try {
1143                     // Try to update the siminfo table. It might not be there.
1144                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE +
1145                             " ADD COLUMN " + Telephony.SimInfo.COLUMN_MCC + " INTEGER DEFAULT 0;");
1146                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE +
1147                             " ADD COLUMN " + Telephony.SimInfo.COLUMN_MNC + " INTEGER DEFAULT 0;");
1148                 } catch (SQLiteException e) {
1149                     if (DBG) {
1150                         log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
1151                                 " The table will get created in onOpen.");
1152                     }
1153                 }
1154                 oldVersion = 12 << 16 | 6;
1155             }
1156             if (oldVersion < (13 << 16 | 6)) {
1157                 try {
1158                     // Try to update the siminfo table. It might not be there.
1159                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " +
1160                             Telephony.SimInfo.COLUMN_CARRIER_NAME + " TEXT DEFAULT '';");
1161                 } catch (SQLiteException e) {
1162                     if (DBG) {
1163                         log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
1164                                 " The table will get created in onOpen.");
1165                     }
1166                 }
1167                 oldVersion = 13 << 16 | 6;
1168             }
1169             if (oldVersion < (14 << 16 | 6)) {
1170                 // Do nothing. This is to avoid recreating table twice. Table is anyway recreated
1171                 // for next version and that takes care of updates for this version as well.
1172                 // This version added a new column user_edited to carriers db.
1173             }
1174             if (oldVersion < (15 << 16 | 6)) {
1175                 // Most devices should be upgrading from version 13. On upgrade new db will be
1176                 // populated from the xml included in OTA but user and carrier edited/added entries
1177                 // need to be preserved. This new version also adds new columns EDITED and
1178                 // BEARER_BITMASK to the table. Upgrade steps from version 13 are:
1179                 // 1. preserve user and carrier added/edited APNs (by comparing against
1180                 // old-apns-conf.xml included in OTA) - done in preserveUserAndCarrierApns()
1181                 // 2. add new columns EDITED and BEARER_BITMASK (create a new table for that) - done
1182                 // in createCarriersTable()
1183                 // 3. copy over preserved APNs from old table to new table - done in
1184                 // copyPreservedApnsToNewTable()
1185                 // The only exception if upgrading from version 14 is that EDITED field is already
1186                 // present (but is called USER_EDITED)
1187                 /*********************************************************************************
1188                  * IMPORTANT NOTE: SINCE CARRIERS TABLE IS RECREATED HERE, IT WILL BE THE LATEST
1189                  * VERSION AFTER THIS. AS A RESULT ANY SUBSEQUENT UPDATES TO THE TABLE WILL FAIL
1190                  * (DUE TO COLUMN-ALREADY-EXISTS KIND OF EXCEPTION). ALL SUBSEQUENT UPDATES SHOULD
1191                  * HANDLE THAT GRACEFULLY.
1192                  *********************************************************************************/
1193                 Cursor c;
1194                 String[] proj = {"_id"};
1195                 if (VDBG) {
1196                     c = db.query(CARRIERS_TABLE, proj, null, null, null, null, null);
1197                     log("dbh.onUpgrade:- before upgrading total number of rows: " + c.getCount());
1198                 }
1199 
1200                 // Compare db with old apns xml file so that any user or carrier edited/added
1201                 // entries can be preserved across upgrade
1202                 preserveUserAndCarrierApns(db);
1203 
1204                 c = db.query(CARRIERS_TABLE, null, null, null, null, null, null);
1205 
1206                 if (VDBG) {
1207                     log("dbh.onUpgrade:- after preserveUserAndCarrierApns() total number of " +
1208                             "rows: " + ((c == null) ? 0 : c.getCount()));
1209                 }
1210 
1211                 createCarriersTable(db, CARRIERS_TABLE_TMP);
1212 
1213                 copyPreservedApnsToNewTable(db, c);
1214                 c.close();
1215 
1216                 db.execSQL("DROP TABLE IF EXISTS " + CARRIERS_TABLE);
1217 
1218                 db.execSQL("ALTER TABLE " + CARRIERS_TABLE_TMP + " rename to " + CARRIERS_TABLE +
1219                         ";");
1220 
1221                 if (VDBG) {
1222                     c = db.query(CARRIERS_TABLE, proj, null, null, null, null, null);
1223                     log("dbh.onUpgrade:- after upgrading total number of rows: " + c.getCount());
1224                     c.close();
1225                     c = db.query(CARRIERS_TABLE, proj, IS_UNEDITED, null, null, null, null);
1226                     log("dbh.onUpgrade:- after upgrading total number of rows with " + IS_UNEDITED +
1227                             ": " + c.getCount());
1228                     c.close();
1229                     c = db.query(CARRIERS_TABLE, proj, IS_EDITED, null, null, null, null);
1230                     log("dbh.onUpgrade:- after upgrading total number of rows with " + IS_EDITED +
1231                             ": " + c.getCount());
1232                     c.close();
1233                 }
1234 
1235                 oldVersion = 15 << 16 | 6;
1236             }
1237             if (oldVersion < (16 << 16 | 6)) {
1238                 try {
1239                     // Try to update the siminfo table. It might not be there.
1240                     // These columns may already be present in which case execSQL will throw an
1241                     // exception
1242                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1243                             + Telephony.SimInfo.COLUMN_CB_EXTREME_THREAT_ALERT
1244                             + " INTEGER DEFAULT 1;");
1245                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1246                             + Telephony.SimInfo.COLUMN_CB_SEVERE_THREAT_ALERT
1247                             + " INTEGER DEFAULT 1;");
1248                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1249                             + Telephony.SimInfo.COLUMN_CB_AMBER_ALERT + " INTEGER DEFAULT 1;");
1250                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1251                             + Telephony.SimInfo.COLUMN_CB_EMERGENCY_ALERT + " INTEGER DEFAULT 1;");
1252                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1253                             + Telephony.SimInfo.COLUMN_CB_ALERT_SOUND_DURATION
1254                             + " INTEGER DEFAULT 4;");
1255                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1256                             + Telephony.SimInfo.COLUMN_CB_ALERT_REMINDER_INTERVAL
1257                             + " INTEGER DEFAULT 0;");
1258                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1259                             + Telephony.SimInfo.COLUMN_CB_ALERT_VIBRATE + " INTEGER DEFAULT 1;");
1260                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1261                             + Telephony.SimInfo.COLUMN_CB_ALERT_SPEECH + " INTEGER DEFAULT 1;");
1262                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1263                             + Telephony.SimInfo.COLUMN_CB_ETWS_TEST_ALERT + " INTEGER DEFAULT 0;");
1264                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1265                             + Telephony.SimInfo.COLUMN_CB_CHANNEL_50_ALERT + " INTEGER DEFAULT 1;");
1266                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1267                             + Telephony.SimInfo.COLUMN_CB_CMAS_TEST_ALERT + " INTEGER DEFAULT 0;");
1268                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1269                             + Telephony.SimInfo.COLUMN_CB_OPT_OUT_DIALOG + " INTEGER DEFAULT 1;");
1270                 } catch (SQLiteException e) {
1271                     if (DBG) {
1272                         log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
1273                                 " The table will get created in onOpen.");
1274                     }
1275                 }
1276                 oldVersion = 16 << 16 | 6;
1277             }
1278             if (oldVersion < (17 << 16 | 6)) {
1279                 Cursor c = null;
1280                 try {
1281                     c = db.query(CARRIERS_TABLE, null, null, null, null, null, null,
1282                             String.valueOf(1));
1283                     if (c == null || c.getColumnIndex(USER_VISIBLE) == -1) {
1284                         db.execSQL("ALTER TABLE " + CARRIERS_TABLE + " ADD COLUMN " +
1285                                 USER_VISIBLE + " BOOLEAN DEFAULT 1;");
1286                     } else {
1287                         if (DBG) {
1288                             log("onUpgrade skipping " + CARRIERS_TABLE + " upgrade.  Column " +
1289                                     USER_VISIBLE + " already exists.");
1290                         }
1291                     }
1292                 } finally {
1293                     if (c != null) {
1294                         c.close();
1295                     }
1296                 }
1297                 oldVersion = 17 << 16 | 6;
1298             }
1299             if (oldVersion < (18 << 16 | 6)) {
1300                 try {
1301                     // Try to update the siminfo table. It might not be there.
1302                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " +
1303                             Telephony.SimInfo.COLUMN_SIM_PROVISIONING_STATUS + " INTEGER DEFAULT " +
1304                             Telephony.SimInfo.SIM_PROVISIONED + ";");
1305                 } catch (SQLiteException e) {
1306                     if (DBG) {
1307                         log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
1308                                 " The table will get created in onOpen.");
1309                     }
1310                 }
1311                 oldVersion = 18 << 16 | 6;
1312             }
1313             if (oldVersion < (19 << 16 | 6)) {
1314                 // Do nothing. This is to avoid recreating table twice. Table is anyway recreated
1315                 // for version 24 and that takes care of updates for this version as well.
1316                 // This version added more fields protocol and roaming protocol to the primary key.
1317             }
1318             if (oldVersion < (20 << 16 | 6)) {
1319                 try {
1320                     // Try to update the siminfo table. It might not be there.
1321                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " +
1322                             Telephony.SimInfo.COLUMN_IS_EMBEDDED + " INTEGER DEFAULT 0;");
1323                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " +
1324                             Telephony.SimInfo.COLUMN_ACCESS_RULES + " BLOB;");
1325                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " +
1326                             Telephony.SimInfo.COLUMN_IS_REMOVABLE + " INTEGER DEFAULT 0;");
1327                 } catch (SQLiteException e) {
1328                     if (DBG) {
1329                         log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
1330                                 "The table will get created in onOpen.");
1331                     }
1332                 }
1333                 oldVersion = 20 << 16 | 6;
1334             }
1335             if (oldVersion < (21 << 16 | 6)) {
1336                 try {
1337                     // Try to update the carriers table. It might not be there.
1338                     db.execSQL("ALTER TABLE " + CARRIERS_TABLE + " ADD COLUMN " +
1339                             USER_EDITABLE + " INTEGER DEFAULT 1;");
1340                 } catch (SQLiteException e) {
1341                     // This is possible if the column already exists which may be the case if the
1342                     // table was just created as part of upgrade to version 19
1343                     if (DBG) {
1344                         log("onUpgrade skipping " + CARRIERS_TABLE + " upgrade. " +
1345                                 "The table will get created in onOpen.");
1346                     }
1347                 }
1348                 oldVersion = 21 << 16 | 6;
1349             }
1350             if (oldVersion < (22 << 16 | 6)) {
1351                 try {
1352                     // Try to update the siminfo table. It might not be there.
1353                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1354                             + Telephony.SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED
1355                             + " INTEGER DEFAULT -1;");
1356                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1357                             + Telephony.SimInfo.COLUMN_VT_IMS_ENABLED + " INTEGER DEFAULT -1;");
1358                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1359                             + Telephony.SimInfo.COLUMN_WFC_IMS_ENABLED + " INTEGER DEFAULT -1;");
1360                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1361                             + Telephony.SimInfo.COLUMN_WFC_IMS_MODE + " INTEGER DEFAULT -1;");
1362                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1363                             + Telephony.SimInfo.COLUMN_WFC_IMS_ROAMING_MODE + " INTEGER DEFAULT -1;");
1364                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1365                             + Telephony.SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED + " INTEGER DEFAULT -1;");
1366                 } catch (SQLiteException e) {
1367                     if (DBG) {
1368                         log("onUpgrade skipping " + CARRIERS_TABLE + " upgrade. " +
1369                                 "The table will get created in onOpen.");
1370                     }
1371                 }
1372                 oldVersion = 22 << 16 | 6;
1373             }
1374             if (oldVersion < (23 << 16 | 6)) {
1375                 try {
1376                     db.execSQL("ALTER TABLE " + CARRIERS_TABLE + " ADD COLUMN " +
1377                             OWNED_BY + " INTEGER DEFAULT " + OWNED_BY_OTHERS + ";");
1378                 } catch (SQLiteException e) {
1379                     if (DBG) {
1380                         log("onUpgrade skipping " + CARRIERS_TABLE + " upgrade. " +
1381                                 "The table will get created in onOpen.");
1382                     }
1383                 }
1384                 oldVersion = 23 << 16 | 6;
1385             }
1386             if (oldVersion < (24 << 16 | 6)) {
1387                 Cursor c = null;
1388                 String[] proj = {"_id"};
1389                 recreateDB(db, proj, /* version */24);
1390                 if (VDBG) {
1391                     c = db.query(CARRIERS_TABLE, proj, null, null, null, null, null);
1392                     log("dbh.onUpgrade:- after upgrading total number of rows: " + c.getCount());
1393                     c.close();
1394                     c = db.query(
1395                             CARRIERS_TABLE, proj, NETWORK_TYPE_BITMASK, null, null, null, null);
1396                     log("dbh.onUpgrade:- after upgrading total number of rows with "
1397                             + NETWORK_TYPE_BITMASK + ": " + c.getCount());
1398                     c.close();
1399                 }
1400                 oldVersion = 24 << 16 | 6;
1401             }
1402             if (oldVersion < (25 << 16 | 6)) {
1403                 // Add a new column SubscriptionManager.CARD_ID into the database and set the value
1404                 // to be the same as the existing column SubscriptionManager.ICC_ID. In order to do
1405                 // this, we need to first make a copy of the existing SIMINFO_TABLE, set the value
1406                 // of the new column SubscriptionManager.CARD_ID, and replace the SIMINFO_TABLE with
1407                 // the new table.
1408                 Cursor c = null;
1409                 String[] proj = {Telephony.SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID};
1410                 recreateSimInfoDB(c, db, proj);
1411                 if (VDBG) {
1412                     c = db.query(SIMINFO_TABLE, proj, null, null, null, null, null);
1413                     log("dbh.onUpgrade:- after upgrading " + SIMINFO_TABLE
1414                             + " total number of rows: " + c.getCount());
1415                     c.close();
1416                     c = db.query(SIMINFO_TABLE, proj, Telephony.SimInfo.COLUMN_CARD_ID
1417                                     + " IS NOT NULL", null, null, null, null);
1418                     log("dbh.onUpgrade:- after upgrading total number of rows with "
1419                             + Telephony.SimInfo.COLUMN_CARD_ID + ": " + c.getCount());
1420                     c.close();
1421                 }
1422                 oldVersion = 25 << 16 | 6;
1423             }
1424             if (oldVersion < (26 << 16 | 6)) {
1425                 // Add a new column Carriers.APN_SET_ID into the database and set the value to
1426                 // Carriers.NO_SET_SET by default.
1427                 try {
1428                     db.execSQL("ALTER TABLE " + CARRIERS_TABLE + " ADD COLUMN " +
1429                             APN_SET_ID + " INTEGER DEFAULT " + NO_APN_SET_ID + ";");
1430                 } catch (SQLiteException e) {
1431                     if (DBG) {
1432                         log("onUpgrade skipping " + CARRIERS_TABLE + " upgrade. " +
1433                                 "The table will get created in onOpen.");
1434                     }
1435                 }
1436                 oldVersion = 26 << 16 | 6;
1437             }
1438 
1439             if (oldVersion < (27 << 16 | 6)) {
1440                 // Add the new MCC_STRING and MNC_STRING columns into the subscription table,
1441                 // and attempt to populate them.
1442                 try {
1443                     // Try to update the siminfo table. It might not be there.
1444                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE +
1445                             " ADD COLUMN " + Telephony.SimInfo.COLUMN_MCC_STRING + " TEXT;");
1446                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE +
1447                             " ADD COLUMN " + Telephony.SimInfo.COLUMN_MNC_STRING + " TEXT;");
1448                 } catch (SQLiteException e) {
1449                     if (DBG) {
1450                         log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
1451                                 " The table will get created in onOpen.");
1452                     }
1453                 }
1454                 // Migrate the old integer values over to strings
1455                 String[] proj = {Telephony.SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID,
1456                         Telephony.SimInfo.COLUMN_MCC, Telephony.SimInfo.COLUMN_MNC};
1457                 try (Cursor c = db.query(SIMINFO_TABLE, proj, null, null, null, null, null)) {
1458                     while (c.moveToNext()) {
1459                         fillInMccMncStringAtCursor(mContext, db, c);
1460                     }
1461                 }
1462                 oldVersion = 27 << 16 | 6;
1463             }
1464 
1465             if (oldVersion < (28 << 16 | 6)) {
1466                 try {
1467                     // Try to update the siminfo table. It might not be there.
1468                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1469                             + Telephony.SimInfo.COLUMN_IS_OPPORTUNISTIC + " INTEGER DEFAULT 0;");
1470                 } catch (SQLiteException e) {
1471                     if (DBG) {
1472                         log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
1473                                 "The table will get created in onOpen.");
1474                     }
1475                 }
1476                 oldVersion = 28 << 16 | 6;
1477             }
1478 
1479             if (oldVersion < (29 << 16 | 6)) {
1480                 try {
1481                     // Add a new column Telephony.CARRIER_ID into the database and add UNIQUE
1482                     // constraint into table. However, sqlite cannot add constraints to an existing
1483                     // table, so recreate the table.
1484                     String[] proj = {"_id"};
1485                     recreateDB(db, proj,  /* version */29);
1486                 } catch (SQLiteException e) {
1487                     if (DBG) {
1488                         log("onUpgrade skipping " + CARRIERS_TABLE + " upgrade. " +
1489                                 "The table will get created in onOpen.");
1490                     }
1491                 }
1492                 oldVersion = 29 << 16 | 6;
1493             }
1494 
1495             if (oldVersion < (30 << 16 | 6)) {
1496                 try {
1497                     // Try to update the siminfo table. It might not be there.
1498                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1499                         + Telephony.SimInfo.COLUMN_GROUP_UUID + " TEXT;");
1500                 } catch (SQLiteException e) {
1501                     if (DBG) {
1502                         log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
1503                             "The table will get created in onOpen.");
1504                     }
1505                 }
1506                 oldVersion = 30 << 16 | 6;
1507             }
1508 
1509             if (oldVersion < (31 << 16 | 6)) {
1510                 try {
1511                     // Try to update the siminfo table. It might not be there.
1512                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1513                             + Telephony.SimInfo.COLUMN_IS_METERED + " INTEGER DEFAULT 1;");
1514                 } catch (SQLiteException e) {
1515                     if (DBG) {
1516                         log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
1517                                 "The table will get created in onOpen.");
1518                     }
1519                 }
1520                 oldVersion = 31 << 16 | 6;
1521             }
1522 
1523             if (oldVersion < (32 << 16 | 6)) {
1524                 try {
1525                     // Try to update the siminfo table. It might not be there.
1526                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1527                             + Telephony.SimInfo.COLUMN_ISO_COUNTRY_CODE + " TEXT;");
1528                 } catch (SQLiteException e) {
1529                     if (DBG) {
1530                         log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
1531                                 "The table will get created in onOpen.");
1532                     }
1533                 }
1534                 oldVersion = 32 << 16 | 6;
1535             }
1536 
1537             if (oldVersion < (33 << 16 | 6)) {
1538                 try {
1539                     // Try to update the siminfo table. It might not be there.
1540                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1541                             + Telephony.SimInfo.COLUMN_CARRIER_ID + " INTEGER DEFAULT -1;");
1542                 } catch (SQLiteException e) {
1543                     if (DBG) {
1544                         log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
1545                                 "The table will get created in onOpen.");
1546                     }
1547                 }
1548                 oldVersion = 33 << 16 | 6;
1549             }
1550 
1551             if (oldVersion < (34 << 16 | 6)) {
1552                 try {
1553                     // Try to update the siminfo table. It might not be there.
1554                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " +
1555                             Telephony.SimInfo.COLUMN_PROFILE_CLASS + " INTEGER DEFAULT " +
1556                             Telephony.SimInfo.PROFILE_CLASS_UNSET + ";");
1557                 } catch (SQLiteException e) {
1558                     if (DBG) {
1559                         log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
1560                                 "The table will get created in onOpen.");
1561                     }
1562                 }
1563                 oldVersion = 34 << 16 | 6;
1564             }
1565 
1566             if (oldVersion < (35 << 16 | 6)) {
1567                 try {
1568                     // Try to update the siminfo table. It might not be there.
1569                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1570                         + Telephony.SimInfo.COLUMN_SUBSCRIPTION_TYPE + " INTEGER DEFAULT "
1571                         + Telephony.SimInfo.SUBSCRIPTION_TYPE_LOCAL_SIM + ";");
1572                 } catch (SQLiteException e) {
1573                     if (DBG) {
1574                         log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
1575                             "The table will get created in onOpen.");
1576                     }
1577                 }
1578                 oldVersion = 35 << 16 | 6;
1579             }
1580 
1581             if (oldVersion < (36 << 16 | 6)) {
1582                 // Add a new column Carriers.SKIP_464XLAT into the database and set the value to
1583                 // SKIP_464XLAT_DEFAULT.
1584                 try {
1585                     db.execSQL("ALTER TABLE " + CARRIERS_TABLE + " ADD COLUMN " +
1586                             SKIP_464XLAT + " INTEGER DEFAULT " + SKIP_464XLAT_DEFAULT + ";");
1587                 } catch (SQLiteException e) {
1588                     if (DBG) {
1589                         log("onUpgrade skipping " + CARRIERS_TABLE + " upgrade. " +
1590                                 "The table will get created in onOpen.");
1591                     }
1592                 }
1593                 oldVersion = 36 << 16 | 6;
1594             }
1595 
1596             if (oldVersion < (37 << 16 | 6)) {
1597                 // Add new columns Telephony.SimInfo.EHPLMNS and Telephony.SimInfo.HPLMNS into
1598                 // the database.
1599                 try {
1600                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE +
1601                             " ADD COLUMN " + Telephony.SimInfo.COLUMN_EHPLMNS + " TEXT;");
1602                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE +
1603                             " ADD COLUMN " + Telephony.SimInfo.COLUMN_HPLMNS + " TEXT;");
1604                 } catch (SQLiteException e) {
1605                     if (DBG) {
1606                         log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade for ehplmns. " +
1607                                 "The table will get created in onOpen.");
1608                     }
1609                 }
1610                 oldVersion = 37 << 16 | 6;
1611             }
1612 
1613             if (oldVersion < (39 << 16 | 6)) {
1614                 try {
1615                     // Try to update the siminfo table. It might not be there.
1616                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1617                             + Telephony.SimInfo.COLUMN_GROUP_OWNER + " TEXT;");
1618                 } catch (SQLiteException e) {
1619                     if (DBG) {
1620                         log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
1621                                 "The table will get created in onOpen.");
1622                     }
1623                 }
1624                 oldVersion = 39 << 16 | 6;
1625             }
1626 
1627             if (oldVersion < (40 << 16 | 6)) {
1628                 try {
1629                     // Try to update the siminfo table. It might not be there.
1630                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1631                             + Telephony.SimInfo.COLUMN_DATA_ENABLED_OVERRIDE_RULES + " TEXT;");
1632                 } catch (SQLiteException e) {
1633                     if (DBG) {
1634                         log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
1635                                 "The table will get created in onOpen.");
1636                     }
1637                 }
1638                 oldVersion = 40 << 16 | 6;
1639             }
1640 
1641             if (oldVersion < (41 << 16 | 6)) {
1642                 try {
1643                     // Try to update the siminfo table. It might not be there.
1644                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1645                             + Telephony.SimInfo.COLUMN_IMSI + " TEXT;");
1646                 } catch (SQLiteException e) {
1647                     if (DBG) {
1648                         log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
1649                                 "The table will get created in onOpen.");
1650                     }
1651                 }
1652                 oldVersion = 41 << 16 | 6;
1653             }
1654 
1655             if (oldVersion < (42 << 16 | 6)) {
1656                 try {
1657                     // Try to update the siminfo table. It might not be there.
1658                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " +
1659                             Telephony.SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS + " BLOB;");
1660                 } catch (SQLiteException e) {
1661                     if (DBG) {
1662                         log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
1663                                 "The table will get created in onOpen.");
1664                     }
1665                 }
1666             }
1667 
1668             if (oldVersion < (43 << 16 | 6)) {
1669                 try {
1670                     // Try to update the siminfo table. It might not be there.
1671                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1672                             + Telephony.SimInfo.COLUMN_UICC_APPLICATIONS_ENABLED
1673                             + " INTEGER DEFAULT 1;");
1674                 } catch (SQLiteException e) {
1675                     if (DBG) {
1676                         log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
1677                                 "The table will get created in onOpen.");
1678                     }
1679                 }
1680                 oldVersion = 43 << 16 | 6;
1681             }
1682 
1683             if (oldVersion < (44 << 16 | 6)) {
1684                 try {
1685                     // Try to update the siminfo table. It might not be there.
1686                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1687                             + Telephony.SimInfo.COLUMN_ALLOWED_NETWORK_TYPES
1688                             + " BIGINT DEFAULT -1;");
1689                 } catch (SQLiteException e) {
1690                     if (DBG) {
1691                         log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
1692                                 "The table will get created in onOpen.");
1693                     }
1694                 }
1695                 oldVersion = 44 << 16 | 6;
1696             }
1697 
1698             if (oldVersion < (45 << 16 | 6)) {
1699                 try {
1700                     // Try to update the siminfo table. It might not be there.
1701                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1702                             + Telephony.SimInfo.COLUMN_IMS_RCS_UCE_ENABLED
1703                             + " INTEGER DEFAULT 0;");
1704                 } catch (SQLiteException e) {
1705                     if (DBG) {
1706                         log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
1707                                 "The table will get created in onOpen.");
1708                     }
1709                 }
1710                 oldVersion = 45 << 16 | 6;
1711             }
1712 
1713             if (oldVersion < (46 << 16 | 6)) {
1714                 try {
1715                     // Try to update the siminfo table. It might not be there.
1716                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1717                             + Telephony.SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED
1718                             + " INTEGER DEFAULT 0;");
1719                 } catch (SQLiteException e) {
1720                     if (DBG) {
1721                         log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
1722                                 "The table will get created in onOpen.");
1723                     }
1724                 }
1725                 oldVersion = 46 << 16 | 6;
1726             }
1727 
1728             if (oldVersion < (47 << 16 | 6)) {
1729                 try {
1730                     // Try to update the siminfo table. It might not be there.
1731                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1732                             + Telephony.SimInfo.COLUMN_RCS_CONFIG
1733                             + " BLOB;");
1734                 } catch (SQLiteException e) {
1735                     if (DBG) {
1736                         log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
1737                                 "The table will get created in onOpen.");
1738                     }
1739                 }
1740                 oldVersion = 47 << 16 | 6;
1741             }
1742 
1743             if (oldVersion < (48 << 16 | 6)) {
1744                 try {
1745                     // Try to update the siminfo table. It might not be there.
1746                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1747                             + Telephony.SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS
1748                             + " TEXT;");
1749                 } catch (SQLiteException e) {
1750                     if (DBG) {
1751                         log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
1752                                 "The table will get created in onOpen.");
1753                     }
1754                 }
1755                 try {
1756                     // Migrate the old Long values over to String
1757                     String[] proj = {Telephony.SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID,
1758                             Telephony.SimInfo.COLUMN_ALLOWED_NETWORK_TYPES};
1759                     try (Cursor c = db.query(SIMINFO_TABLE, proj, null, null, null, null, null)) {
1760                         while (c.moveToNext()) {
1761                             fillInAllowedNetworkTypesStringAtCursor(db, c);
1762                         }
1763                     }
1764 
1765                 } catch (SQLiteException e) {
1766                     if (DBG) {
1767                         log("can't migrate value from COLUMN_ALLOWED_NETWORK_TYPES to "
1768                                 + "COLUMN_ALLOWED_NETWORK_TYPES_ALL_REASON");
1769                     }
1770                 }
1771                 oldVersion = 48 << 16 | 6;
1772             }
1773 
1774             if (oldVersion < (49 << 16 | 6)) {
1775                 try {
1776                     // Try to update the siminfo table. It might not be there.
1777                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1778                             + Telephony.SimInfo.COLUMN_D2D_STATUS_SHARING
1779                             + " INTEGER DEFAULT 0;");
1780                 } catch (SQLiteException e) {
1781                     if (DBG) {
1782                         log("onUpgrade failed to updated " + SIMINFO_TABLE
1783                                 + " to add d2d status sharing column. ");
1784                     }
1785                 }
1786             }
1787 
1788             if (oldVersion < (50 << 16 | 6)) {
1789                 try {
1790                     // Try to update the siminfo table. It might not be there.
1791                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1792                             + Telephony.SimInfo.COLUMN_VOIMS_OPT_IN_STATUS
1793                             + " INTEGER DEFAULT 0;");
1794                 } catch (SQLiteException e) {
1795                     if (DBG) {
1796                         log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
1797                                 "The table will get created in onOpen.");
1798                     }
1799                 }
1800                 oldVersion = 50 << 16 | 6;
1801             }
1802 
1803             if (oldVersion < (51 << 16 | 6)) {
1804                 try {
1805                     // Try to update the siminfo table. It might not be there.
1806                     db.execSQL("ALERT TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1807                             + Telephony.SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS
1808                             + " TEXT;");
1809                 } catch (SQLiteException e) {
1810                     if (DBG) {
1811                         log("onUpgrade failed to updated " + SIMINFO_TABLE
1812                                 + " to add d2d status sharing contacts. ");
1813                     }
1814                 }
1815                 oldVersion = 51 << 16 | 6;
1816             }
1817 
1818             if (oldVersion < (52 << 16 | 6)) {
1819                 try {
1820                     // Try to update the siminfo table. It might not be there.
1821                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1822                             + Telephony.SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED
1823                             + " INTEGER DEFAULT -1;");
1824                 } catch (SQLiteException e) {
1825                     if (DBG) {
1826                         log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
1827                                 "The table will get created in onOpen.");
1828                     }
1829                 }
1830                 oldVersion = 52 << 16 | 6;
1831             }
1832 
1833             if (oldVersion < (53 << 16 | 6)) {
1834                 try {
1835                     // Try to update the siminfo table. Fix typo error in version 51.
1836                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1837                             + Telephony.SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS
1838                             + " TEXT;");
1839                 } catch (SQLiteException e) {
1840                     if (DBG) {
1841                         log("onUpgrade failed to updated " + SIMINFO_TABLE
1842                                 + " to add d2d status sharing contacts. ");
1843                     }
1844                 }
1845                 oldVersion = 53 << 16 | 6;
1846             }
1847 
1848             if (oldVersion < (54 << 16 | 6)) {
1849                 try {
1850                     // Try to update the siminfo table with new columns.
1851                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1852                             + Telephony.SimInfo.COLUMN_PHONE_NUMBER_SOURCE_CARRIER
1853                             + " TEXT;");
1854                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1855                             + Telephony.SimInfo.COLUMN_PHONE_NUMBER_SOURCE_IMS
1856                             + " TEXT;");
1857                 } catch (SQLiteException e) {
1858                     if (DBG) {
1859                         log("onUpgrade failed to update " + SIMINFO_TABLE
1860                                 + " to add phone numbers. ");
1861                     }
1862                 }
1863                 oldVersion = 54 << 16 | 6;
1864             }
1865 
1866             if (oldVersion < (55 << 16 | 6)) {
1867                 try {
1868                     // Try to add new fields LINGERING_NETWORK_TYPE_BITMASK, ALWAYS_ON,
1869                     // MTU_V4, and MTU_V6
1870                     db.execSQL("ALTER TABLE " + CARRIERS_TABLE + " ADD COLUMN "
1871                             + LINGERING_NETWORK_TYPE_BITMASK + " INTEGER DEFAULT 0;");
1872                     db.execSQL("ALTER TABLE " + CARRIERS_TABLE + " ADD COLUMN "
1873                             + ALWAYS_ON + " INTEGER DEFAULT 0;");
1874                     db.execSQL("ALTER TABLE " + CARRIERS_TABLE + " ADD COLUMN "
1875                             + MTU_V4 + " INTEGER DEFAULT 0;");
1876                     db.execSQL("ALTER TABLE " + CARRIERS_TABLE + " ADD COLUMN "
1877                             + MTU_V6 + " INTEGER DEFAULT 0;");
1878                     // Populate MTU_V4 with MTU values
1879                     db.execSQL("UPDATE " + CARRIERS_TABLE + " SET " + MTU_V4 + " = "
1880                             + MTU + " WHERE " + MTU + " != 0;");
1881                 } catch (SQLiteException e) {
1882                     if (DBG) {
1883                         log("onUpgrade failed to update " + CARRIERS_TABLE
1884                                 + " to add lingering network type bitmask, always on flag,"
1885                                 + " and MTU v4 and v6 values.");
1886                     }
1887                 }
1888                 oldVersion = 55 << 16 | 6;
1889             }
1890 
1891             if (oldVersion < (56 << 16 | 6)) {
1892                 try {
1893                     // Try to update the siminfo table. It might not be there.
1894                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1895                             + Telephony.SimInfo.COLUMN_PORT_INDEX
1896                             + " INTEGER DEFAULT -1;");
1897                 } catch (SQLiteException e) {
1898                     if (DBG) {
1899                         log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
1900                                 "The table will get created in onOpen.");
1901                     }
1902                 }
1903                 oldVersion = 56 << 16 | 6;
1904             }
1905 
1906             if (oldVersion < (57 << 16 | 6)) {
1907                 try {
1908                     // Try to update the siminfo table. It might not be there.
1909                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1910                             + Telephony.SimInfo.COLUMN_USAGE_SETTING
1911                             + " INTEGER DEFAULT " + SubscriptionManager.USAGE_SETTING_UNKNOWN
1912                             + ";");
1913                 } catch (SQLiteException e) {
1914                     if (DBG) {
1915                         log("onUpgrade failed to updated " + SIMINFO_TABLE
1916                                 + " to add preferred usage setting");
1917                     }
1918                 }
1919                 oldVersion = 57 << 16 | 6;
1920             }
1921 
1922             if (oldVersion < (58 << 16 | 6)) {
1923                 try {
1924                     // Try to update the siminfo table with new columns.
1925                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1926                             + Telephony.SimInfo.COLUMN_TP_MESSAGE_REF
1927                             + "  INTEGER DEFAULT -1;");
1928                 } catch (SQLiteException e) {
1929                     if (DBG) {
1930                         log("onUpgrade failed to update " + SIMINFO_TABLE
1931                                 + " to add message Reference. ");
1932                     }
1933                 }
1934                 oldVersion = 58 << 16 | 6;
1935             }
1936 
1937             if (oldVersion < (59 << 16 | 6)) {
1938                 try {
1939                     // Try to update the siminfo table with new columns.
1940                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1941                             + Telephony.SimInfo.COLUMN_USER_HANDLE
1942                             + "  INTEGER DEFAULT " + UserHandle.USER_NULL +";");
1943                 } catch (SQLiteException e) {
1944                     if (DBG) {
1945                         log("onUpgrade failed to update " + SIMINFO_TABLE
1946                                 + " to add message Reference. ");
1947                     }
1948                 }
1949                 oldVersion = 59 << 16 | 6;
1950             }
1951             if (oldVersion < (60 << 16 | 6)) {
1952                 // Update the siminfo table with new column enabled_data_mobile_policies
1953                 // and set its value to be a copy of data_enabled_override_rules.
1954                 try {
1955                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
1956                             + Telephony.SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES
1957                             + " TEXT;");
1958                 } catch (SQLiteException e) {
1959                     if (DBG) {
1960                         log("onUpgrade failed to insert "
1961                                 +Telephony.SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES +" to "
1962                                 + SIMINFO_TABLE);
1963                     }
1964                 }
1965                 // Migrate the old Long values over to String
1966                 String[] proj = {Telephony.SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID,
1967                         Telephony.SimInfo.COLUMN_DATA_ENABLED_OVERRIDE_RULES};
1968                 try (Cursor c = db.query(SIMINFO_TABLE, proj, null, null, null, null, null)) {
1969                     while (c.moveToNext()) {
1970                         fillInEnabledMobileDataPoliciesAtCursor(db, c);
1971                     }
1972                 } catch (SQLiteException e) {
1973                     if (DBG) {
1974                         log("can't migrate value from COLUMN_DATA_ENABLED_OVERRIDE_RULES to "
1975                                 + "COLUMN_ENABLED_MOBILE_DATA_POLICIES");
1976                     }
1977                 }
1978                 oldVersion = 60 << 16 | 6;
1979             }
1980 
1981             if (oldVersion < (61 << 16 | 6)) {
1982                 try {
1983                     // If default value of USER_HANDLE column is set to -1, then update it to -10000
1984                     db.execSQL("UPDATE " + SIMINFO_TABLE + " SET "
1985                             + Telephony.SimInfo.COLUMN_USER_HANDLE + "=" + UserHandle.USER_NULL
1986                             + "  WHERE " + Telephony.SimInfo.COLUMN_USER_HANDLE + "=-1;");
1987                 } catch (SQLiteException e) {
1988                     if (DBG) {
1989                         log("onUpgrade failed to update " + SIMINFO_TABLE
1990                                 + " to add message Reference. ");
1991                     }
1992                 }
1993                 oldVersion = 61 << 16 | 6;
1994             }
1995 
1996             if (oldVersion < (62 << 16 | 6)) {
1997                 try {
1998                     // Try to update the siminfo table with new columns.
1999                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
2000                             + Telephony.SimInfo.COLUMN_SATELLITE_ENABLED
2001                             + "  INTEGER DEFAULT 0;");
2002                 } catch (SQLiteException e) {
2003                     if (DBG) {
2004                         log("onUpgrade failed to update " + SIMINFO_TABLE
2005                                 + " to add satellite enabled. ");
2006                     }
2007                 }
2008                 oldVersion = 62 << 16 | 6;
2009             }
2010 
2011             if (oldVersion < (63 << 16 | 6)) {
2012                 try {
2013                     // Try to update the siminfo table with new columns.
2014                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
2015                             + Telephony.SimInfo.COLUMN_SATELLITE_ATTACH_ENABLED_FOR_CARRIER
2016                             + "  INTEGER DEFAULT 0;");
2017                 } catch (SQLiteException e) {
2018                     if (DBG) {
2019                         log("onUpgrade failed to update " + SIMINFO_TABLE
2020                                 + " to add satellite attach for carrier enabled by user. ");
2021                     }
2022                 }
2023                 oldVersion = 63 << 16 | 6;
2024             }
2025 
2026             if (oldVersion < (64 << 16 | 6)) {
2027                 try {
2028                     /* If default value of COLUMN_SATELLITE_ENABLED column is set to -1, then update
2029                      it to 0 */
2030                     db.execSQL("UPDATE " + SIMINFO_TABLE + " SET "
2031                             + Telephony.SimInfo.COLUMN_SATELLITE_ENABLED + "=0"
2032                             + "  WHERE " + Telephony.SimInfo.COLUMN_SATELLITE_ENABLED + "=-1;");
2033                     /* If default value of COLUMN_SATELLITE_ATTACH_ENABLED_FOR_CARRIER column is set
2034                      to -1, then update it to 0 */
2035                     db.execSQL("UPDATE " + SIMINFO_TABLE + " SET "
2036                             + Telephony.SimInfo.COLUMN_SATELLITE_ATTACH_ENABLED_FOR_CARRIER + "=0"
2037                             + "  WHERE "
2038                             + Telephony.SimInfo.COLUMN_SATELLITE_ATTACH_ENABLED_FOR_CARRIER
2039                             + "=-1;");
2040 
2041                     // Try to update the siminfo table with new columns.
2042                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
2043                             + Telephony.SimInfo.COLUMN_IS_ONLY_NTN
2044                             + "  INTEGER DEFAULT 0;");
2045                 } catch (SQLiteException e) {
2046                     if (DBG) {
2047                         log("onUpgrade failed to update " + SIMINFO_TABLE
2048                                 + " to add satellite is ntn. ");
2049                     }
2050                 }
2051                 oldVersion = 64 << 16 | 6;
2052             }
2053 
2054             if (oldVersion < (65 << 16 | 6)) {
2055                 try {
2056                     db.execSQL("ALTER TABLE " + CARRIERS_TABLE + " ADD COLUMN "
2057                             + INFRASTRUCTURE_BITMASK + " INTEGER DEFAULT 1;");
2058                 } catch (SQLiteException e) {
2059                     if (DBG) {
2060                         log("onUpgrade failed to update " + CARRIERS_TABLE
2061                                 + " to add infrastructure bitmask value.");
2062                     }
2063                 }
2064                 oldVersion = 65 << 16 | 6;
2065             }
2066 
2067             if (oldVersion < (66 << 16 | 6)) {
2068                 try {
2069                     // Try to add new field ESIM_BOOTSTRAP_PROVISIONING
2070                     db.execSQL("ALTER TABLE " + CARRIERS_TABLE + " ADD COLUMN "
2071                             + ESIM_BOOTSTRAP_PROVISIONING + " INTEGER DEFAULT 0;");
2072                 } catch (SQLiteException e) {
2073                     if (DBG) {
2074                         log("onUpgrade failed to update " + CARRIERS_TABLE
2075                                     + " to add esim bootstrap provisioning flag");
2076                     }
2077 
2078                 }
2079                 oldVersion = 66 << 16 | 6;
2080             }
2081 
2082             if (oldVersion < (67 << 16 | 6)) {
2083                 try {
2084                     // If default value of infrastructure_bitmask column is set to 1, then update
2085                     // it to 3
2086                     db.execSQL("UPDATE " + CARRIERS_TABLE + " SET " + INFRASTRUCTURE_BITMASK + "=3"
2087                             + "  WHERE " + INFRASTRUCTURE_BITMASK + "=1;");
2088                 } catch (SQLiteException e) {
2089                     if (DBG) {
2090                         log("onUpgrade failed to update " + CARRIERS_TABLE
2091                                 + " to add infrastructure bitmask value.");
2092                     }
2093                 }
2094                 oldVersion = 67 << 16 | 6;
2095             }
2096 
2097             if (oldVersion < (68 << 16 | 6)) {
2098                 try {
2099                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
2100                             + Telephony.SimInfo.COLUMN_SERVICE_CAPABILITIES
2101                             + " INTEGER DEFAULT 7;");
2102                 } catch (SQLiteException e) {
2103                     if (DBG) {
2104                         log("onUpgrade failed to update " + SIMINFO_TABLE
2105                                 + " to add cellular service capabilities");
2106                     }
2107 
2108                 }
2109                 oldVersion = 68 << 16 | 6;
2110             }
2111 
2112             if (oldVersion < (69 << 16 | 6)) {
2113                 try {
2114                     // If default value of COLUMN_SATELLITE_ATTACH_ENABLED_FOR_CARRIER column is
2115                     // set to 0, then update it to 1
2116                     db.execSQL("UPDATE " + SIMINFO_TABLE + " SET "
2117                             + Telephony.SimInfo.COLUMN_SATELLITE_ATTACH_ENABLED_FOR_CARRIER + "=1"
2118                             + "  WHERE "
2119                             + Telephony.SimInfo.COLUMN_SATELLITE_ATTACH_ENABLED_FOR_CARRIER
2120                             + "=0;");
2121                 } catch (SQLiteException e) {
2122                     if (DBG) {
2123                         log("onUpgrade failed to update " + SIMINFO_TABLE
2124                                 + " to add cellular service capabilities");
2125                     }
2126                 }
2127                 oldVersion = 69 << 16 | 6;
2128             }
2129             if (oldVersion < (70 << 16 | 6)) {
2130                 try {
2131                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
2132                             + Telephony.SimInfo.COLUMN_TRANSFER_STATUS
2133                             + " INTEGER DEFAULT 0;");
2134                 } catch (SQLiteException e) {
2135                     if (DBG) {
2136                         log("onUpgrade failed to update " + SIMINFO_TABLE
2137                                 + " to add transfer status");
2138                     }
2139 
2140                 }
2141                 oldVersion = 70 << 16 | 6;
2142             }
2143 
2144             if (oldVersion < (71 << 16 | 6)) {
2145                 try {
2146                     // Try to update the siminfo table with new columns.
2147                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
2148                             + Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_STATUS
2149                             + "  INTEGER DEFAULT 0;");
2150                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
2151                             + Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_PLMNS
2152                             + " TEXT DEFAULT '';");
2153                 } catch (SQLiteException e) {
2154                     if (DBG) {
2155                         log("onUpgrade failed to update " + SIMINFO_TABLE
2156                                 + " to add satellite entitlement status and plmns");
2157                     }
2158                 }
2159                 oldVersion = 71 << 16 | 6;
2160             }
2161 
2162             if (oldVersion < (72 << 16 | 6)) {
2163                 try {
2164                     // Try to update the siminfo table with new columns.
2165                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
2166                             + Telephony.SimInfo.COLUMN_SATELLITE_ESOS_SUPPORTED
2167                             + " INTEGER DEFAULT 0;");
2168                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
2169                             + Telephony.SimInfo.COLUMN_IS_ONLY_NTN + " INTEGER DEFAULT 0;");
2170 
2171                     // Copy the value of the previous column (COLUMN_IS_NTN) to the new column
2172                     // (COLUMN_IS_ONLY_NTN) for all rows in the sim_info table.
2173                     final String columnIsNtn = "is_ntn";
2174                     db.execSQL("UPDATE " + SIMINFO_TABLE + " SET "
2175                             + Telephony.SimInfo.COLUMN_IS_ONLY_NTN + " = " + columnIsNtn + ";");
2176 
2177                     // ALTER TABLE siminfo DROP is_ntn;
2178                     db.execSQL(
2179                             "ALTER TABLE " + SIMINFO_TABLE + " DROP COLUMN " + columnIsNtn + ";");
2180                 } catch (SQLiteException e) {
2181                     if (DBG) {
2182                         log("onUpgrade failed to update " + SIMINFO_TABLE
2183                                 + " to add is satellite esos supported");
2184                     }
2185                 }
2186                 oldVersion = 72 << 16 | 6;
2187             }
2188 
2189             if (oldVersion < (73 << 16 | 6)) {
2190                 try {
2191                     // Try to update the siminfo table with new columns.
2192                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
2193                             + Telephony.SimInfo.COLUMN_IS_SATELLITE_PROVISIONED_FOR_NON_IP_DATAGRAM
2194                             + "  INTEGER DEFAULT 0;");
2195                 } catch (SQLiteException e) {
2196                     if (DBG) {
2197                         log("onUpgrade failed to update " + SIMINFO_TABLE
2198                                 + " to add satellite is provisioned");
2199                     }
2200                 }
2201                 oldVersion = 73 << 16 | 6;
2202             }
2203 
2204             if (oldVersion < (74 << 16 | 6)) {
2205                 try {
2206                     // Try to update the siminfo table with new columns.
2207                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
2208                             + Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_BARRED_PLMNS
2209                             + " TEXT DEFAULT '';");
2210                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
2211                             + Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_DATA_PLAN_PLMNS
2212                             + " TEXT DEFAULT '';");
2213                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
2214                             + Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_SERVICE_TYPE_MAP
2215                             + " TEXT DEFAULT '';");
2216                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
2217                             + Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_DATA_SERVICE_POLICY
2218                             + " TEXT DEFAULT '';");
2219                     db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
2220                             + Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_VOICE_SERVICE_POLICY
2221                             + " TEXT DEFAULT '';");
2222                 } catch (SQLiteException e) {
2223                     if (DBG) {
2224                         log("onUpgrade failed to update " + SIMINFO_TABLE
2225                                 + " to add satellite entitlement data");
2226                     }
2227                 }
2228                 oldVersion = 74 << 16 | 6;
2229             }
2230             if (DBG) {
2231                 log("dbh.onUpgrade:- db=" + db + " oldV=" + oldVersion + " newV=" + newVersion);
2232             }
2233             // when adding fields to onUpgrade, also add a unit test to TelephonyDatabaseHelperTest
2234             // and update the DATABASE_VERSION field and add a column in copyAllApnValues
2235         }
2236 
recreateSimInfoDB(Cursor c, SQLiteDatabase db, String[] proj)2237         private void recreateSimInfoDB(Cursor c, SQLiteDatabase db, String[] proj) {
2238             if (VDBG) {
2239                 c = db.query(SIMINFO_TABLE, proj, null, null, null, null, null);
2240                 log("dbh.onUpgrade:+ before upgrading " + SIMINFO_TABLE +
2241                         " total number of rows: " + c.getCount());
2242                 c.close();
2243             }
2244 
2245             // Sort in ascending order by subscription id to make sure the rows do not get flipped
2246             // during the query and added in the new sim info table in another order (sub id is
2247             // stored in settings between migrations).
2248             c = db.query(SIMINFO_TABLE, null, null, null, null, null, ORDER_BY_SUB_ID);
2249 
2250             db.execSQL("DROP TABLE IF EXISTS " + SIMINFO_TABLE_TMP);
2251 
2252             createSimInfoTable(db, SIMINFO_TABLE_TMP);
2253 
2254             copySimInfoDataToTmpTable(db, c);
2255             c.close();
2256 
2257             db.execSQL("DROP TABLE IF EXISTS " + SIMINFO_TABLE);
2258 
2259             db.execSQL("ALTER TABLE " + SIMINFO_TABLE_TMP + " rename to " + SIMINFO_TABLE + ";");
2260 
2261         }
2262 
copySimInfoDataToTmpTable(SQLiteDatabase db, Cursor c)2263         private void copySimInfoDataToTmpTable(SQLiteDatabase db, Cursor c) {
2264             // Move entries from SIMINFO_TABLE to SIMINFO_TABLE_TMP
2265             if (c != null) {
2266                 while (c.moveToNext()) {
2267                     ContentValues cv = new ContentValues();
2268                     copySimInfoValuesV24(cv, c);
2269                     // The card ID is supposed to be the ICCID of the profile for UICC card, and
2270                     // the EID of the card for eUICC card. Since EID is unknown for old entries in
2271                     // SIMINFO_TABLE, we use ICCID as the card ID for all the old entries while
2272                     // upgrading the SIMINFO_TABLE. In UiccController, both the card ID and ICCID
2273                     // will be checked when user queries the slot information using the card ID
2274                     // from the database.
2275                     getCardIdfromIccid(cv, c);
2276                     try {
2277                         db.insert(SIMINFO_TABLE_TMP, null, cv);
2278                         if (VDBG) {
2279                             log("dbh.copySimInfoDataToTmpTable: db.insert returned >= 0; " +
2280                                 "insert successful for cv " + cv);
2281                         }
2282                     } catch (SQLException e) {
2283                         if (VDBG)
2284                             log("dbh.copySimInfoDataToTmpTable insertWithOnConflict exception " +
2285                                 e + " for cv " + cv);
2286                     }
2287                 }
2288             }
2289         }
2290 
copySimInfoValuesV24(ContentValues cv, Cursor c)2291         private void copySimInfoValuesV24(ContentValues cv, Cursor c) {
2292             // String vals
2293             getStringValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_ICC_ID);
2294             getStringValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_DISPLAY_NAME);
2295             getStringValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_CARRIER_NAME);
2296             getStringValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_NUMBER);
2297 
2298             // bool/int vals
2299             getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_SIM_SLOT_INDEX);
2300             getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_NAME_SOURCE);
2301             getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_COLOR);
2302             getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_DISPLAY_NUMBER_FORMAT);
2303             getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_DATA_ROAMING);
2304             getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_MCC);
2305             getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_MNC);
2306             getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_SIM_PROVISIONING_STATUS);
2307             getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_IS_EMBEDDED);
2308             getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_IS_REMOVABLE);
2309             getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_CB_EXTREME_THREAT_ALERT);
2310             getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_CB_SEVERE_THREAT_ALERT);
2311             getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_CB_AMBER_ALERT);
2312             getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_CB_EMERGENCY_ALERT);
2313             getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_CB_ALERT_SOUND_DURATION);
2314             getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_CB_ALERT_REMINDER_INTERVAL);
2315             getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_CB_ALERT_VIBRATE);
2316             getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_CB_ALERT_SPEECH);
2317             getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_CB_ETWS_TEST_ALERT);
2318             getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_CB_CHANNEL_50_ALERT);
2319             getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_CB_CMAS_TEST_ALERT);
2320             getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_CB_OPT_OUT_DIALOG);
2321             getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED);
2322             getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_VT_IMS_ENABLED);
2323             getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_WFC_IMS_ENABLED);
2324             getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_WFC_IMS_MODE);
2325             getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_WFC_IMS_ROAMING_MODE);
2326             getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED);
2327 
2328             // Blob vals
2329             getBlobValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_ACCESS_RULES);
2330         }
2331 
getCardIdfromIccid(ContentValues cv, Cursor c)2332         private void getCardIdfromIccid(ContentValues cv, Cursor c) {
2333             int columnIndex = c.getColumnIndex(Telephony.SimInfo.COLUMN_ICC_ID);
2334             if (columnIndex != -1) {
2335                 String fromCursor = c.getString(columnIndex);
2336                 if (!TextUtils.isEmpty(fromCursor)) {
2337                     cv.put(Telephony.SimInfo.COLUMN_CARD_ID, fromCursor);
2338                 }
2339             }
2340         }
2341 
recreateDB(SQLiteDatabase db, String[] proj, int version)2342         private void recreateDB(SQLiteDatabase db, String[] proj, int version) {
2343             // Upgrade steps are:
2344             // 1. Create a temp table- done in createCarriersTable()
2345             // 2. copy over APNs from old table to new table - done in copyDataToTmpTable()
2346             // 3. Drop the existing table.
2347             // 4. Copy over the tmp table.
2348             Cursor c;
2349             if (VDBG) {
2350                 c = db.query(CARRIERS_TABLE, proj, null, null, null, null, null);
2351                 log("dbh.onUpgrade:- before upgrading total number of rows: " + c.getCount());
2352                 c.close();
2353             }
2354 
2355             c = db.query(CARRIERS_TABLE, null, null, null, null, null, null);
2356 
2357             if (VDBG) {
2358                 log("dbh.onUpgrade:- starting data copy of existing rows: " +
2359                         + ((c == null) ? 0 : c.getCount()));
2360             }
2361 
2362             db.execSQL("DROP TABLE IF EXISTS " + CARRIERS_TABLE_TMP);
2363 
2364             createCarriersTable(db, CARRIERS_TABLE_TMP);
2365 
2366             copyDataToTmpTable(db, c, version);
2367             c.close();
2368 
2369             db.execSQL("DROP TABLE IF EXISTS " + CARRIERS_TABLE);
2370 
2371             db.execSQL("ALTER TABLE " + CARRIERS_TABLE_TMP + " rename to " + CARRIERS_TABLE + ";");
2372         }
2373 
preserveUserAndCarrierApns(SQLiteDatabase db)2374         private void preserveUserAndCarrierApns(SQLiteDatabase db) {
2375             if (VDBG) log("preserveUserAndCarrierApns");
2376             XmlPullParser confparser;
2377             File confFile = new File(Environment.getRootDirectory(), OLD_APNS_PATH);
2378             FileReader confreader = null;
2379             try {
2380                 confreader = new FileReader(confFile);
2381                 confparser = Xml.newPullParser();
2382                 confparser.setInput(confreader);
2383                 XmlUtils.beginDocument(confparser, "apns");
2384 
2385                 deleteMatchingApns(db, confparser);
2386             } catch (FileNotFoundException e) {
2387                 // This function is called only when upgrading db to version 15. Details about the
2388                 // upgrade are mentioned in onUpgrade(). This file missing means user/carrier added
2389                 // APNs cannot be preserved. Log an error message so that OEMs know they need to
2390                 // include old apns file for comparison.
2391                 loge("PRESERVEUSERANDCARRIERAPNS: " + OLD_APNS_PATH +
2392                         " NOT FOUND. IT IS NEEDED TO UPGRADE FROM OLDER VERSIONS OF APN " +
2393                         "DB WHILE PRESERVING USER/CARRIER ADDED/EDITED ENTRIES.");
2394             } catch (Exception e) {
2395                 loge("preserveUserAndCarrierApns: Exception while parsing '" +
2396                         confFile.getAbsolutePath() + "'" + e);
2397             } finally {
2398                 if (confreader != null) {
2399                     try {
2400                         confreader.close();
2401                     } catch (IOException e) {
2402                         // do nothing
2403                     }
2404                 }
2405             }
2406         }
2407 
deleteMatchingApns(SQLiteDatabase db, XmlPullParser parser)2408         private void deleteMatchingApns(SQLiteDatabase db, XmlPullParser parser) {
2409             if (VDBG) log("deleteMatchingApns");
2410             if (parser != null) {
2411                 if (VDBG) log("deleteMatchingApns: parser != null");
2412                 try {
2413                     XmlUtils.nextElement(parser);
2414                     while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
2415                         ContentValues row = getRow(parser, false);
2416                         if (row == null) {
2417                             throw new XmlPullParserException("Expected 'apn' tag", parser, null);
2418                         }
2419                         deleteRow(db, row);
2420                         XmlUtils.nextElement(parser);
2421                     }
2422                 } catch (XmlPullParserException e) {
2423                     loge("deleteMatchingApns: Got XmlPullParserException while deleting apns." + e);
2424                 } catch (IOException e) {
2425                     loge("deleteMatchingApns: Got IOException while deleting apns." + e);
2426                 } catch (SQLException e) {
2427                     loge("deleteMatchingApns: Got SQLException while deleting apns." + e);
2428                 }
2429             }
2430         }
2431 
queryValFirst(String field)2432         private String queryValFirst(String field) {
2433             return field + "=?";
2434         }
2435 
queryVal(String field)2436         private String queryVal(String field) {
2437             return " and " + field + "=?";
2438         }
2439 
queryValOrNull(String field)2440         private String queryValOrNull(String field) {
2441             return " and (" + field + "=? or " + field + " is null)";
2442         }
2443 
queryVal2OrNull(String field)2444         private String queryVal2OrNull(String field) {
2445             return " and (" + field + "=? or " + field + "=? or " + field + " is null)";
2446         }
2447 
deleteRow(SQLiteDatabase db, ContentValues values)2448         private void deleteRow(SQLiteDatabase db, ContentValues values) {
2449             if (VDBG) log("deleteRow");
2450             String where = queryValFirst(NUMERIC) +
2451                     queryVal(MNC) +
2452                     queryVal(MNC) +
2453                     queryValOrNull(APN) +
2454                     queryValOrNull(USER) +
2455                     queryValOrNull(SERVER) +
2456                     queryValOrNull(PASSWORD) +
2457                     queryValOrNull(PROXY) +
2458                     queryValOrNull(PORT) +
2459                     queryValOrNull(MMSPROXY) +
2460                     queryValOrNull(MMSPORT) +
2461                     queryValOrNull(MMSC) +
2462                     queryValOrNull(AUTH_TYPE) +
2463                     queryValOrNull(TYPE) +
2464                     queryValOrNull(PROTOCOL) +
2465                     queryValOrNull(ROAMING_PROTOCOL) +
2466                     queryVal2OrNull(CARRIER_ENABLED) +
2467                     queryValOrNull(BEARER) +
2468                     queryValOrNull(MVNO_TYPE) +
2469                     queryValOrNull(MVNO_MATCH_DATA) +
2470                     queryValOrNull(PROFILE_ID) +
2471                     queryVal2OrNull(MODEM_PERSIST) +
2472                     queryValOrNull(MAX_CONNECTIONS) +
2473                     queryValOrNull(WAIT_TIME_RETRY) +
2474                     queryValOrNull(TIME_LIMIT_FOR_MAX_CONNECTIONS) +
2475                     queryValOrNull(MTU) +
2476                     queryValOrNull(MTU_V4) +
2477                     queryValOrNull(MTU_V6);
2478             String[] whereArgs = new String[31];
2479             int i = 0;
2480             whereArgs[i++] = values.getAsString(NUMERIC);
2481             whereArgs[i++] = values.getAsString(MCC);
2482             whereArgs[i++] = values.getAsString(MNC);
2483             whereArgs[i++] = values.getAsString(NAME);
2484             whereArgs[i++] = values.containsKey(APN) ?
2485                     values.getAsString(APN) : "";
2486             whereArgs[i++] = values.containsKey(USER) ?
2487                     values.getAsString(USER) : "";
2488             whereArgs[i++] = values.containsKey(SERVER) ?
2489                     values.getAsString(SERVER) : "";
2490             whereArgs[i++] = values.containsKey(PASSWORD) ?
2491                     values.getAsString(PASSWORD) : "";
2492             whereArgs[i++] = values.containsKey(PROXY) ?
2493                     values.getAsString(PROXY) : "";
2494             whereArgs[i++] = values.containsKey(PORT) ?
2495                     values.getAsString(PORT) : "";
2496             whereArgs[i++] = values.containsKey(MMSPROXY) ?
2497                     values.getAsString(MMSPROXY) : "";
2498             whereArgs[i++] = values.containsKey(MMSPORT) ?
2499                     values.getAsString(MMSPORT) : "";
2500             whereArgs[i++] = values.containsKey(MMSC) ?
2501                     values.getAsString(MMSC) : "";
2502             whereArgs[i++] = values.containsKey(AUTH_TYPE) ?
2503                     values.getAsString(AUTH_TYPE) : "-1";
2504             whereArgs[i++] = values.containsKey(TYPE) ?
2505                     values.getAsString(TYPE) : "";
2506             whereArgs[i++] = values.containsKey(PROTOCOL) ?
2507                     values.getAsString(PROTOCOL) : DEFAULT_PROTOCOL;
2508             whereArgs[i++] = values.containsKey(ROAMING_PROTOCOL) ?
2509                     values.getAsString(ROAMING_PROTOCOL) : DEFAULT_ROAMING_PROTOCOL;
2510 
2511             if (values.containsKey(CARRIER_ENABLED)) {
2512                 whereArgs[i++] = convertStringToBoolString(values.getAsString(CARRIER_ENABLED));
2513                 whereArgs[i++] = convertStringToIntString(values.getAsString(CARRIER_ENABLED));
2514             } else {
2515                 String defaultIntString = CARRIERS_UNIQUE_FIELDS_DEFAULTS.get(CARRIER_ENABLED);
2516                 whereArgs[i++] = convertStringToBoolString(defaultIntString);
2517                 whereArgs[i++] = defaultIntString;
2518             }
2519 
2520             whereArgs[i++] = values.containsKey(BEARER) ?
2521                     values.getAsString(BEARER) : "0";
2522             whereArgs[i++] = values.containsKey(MVNO_TYPE) ?
2523                     values.getAsString(MVNO_TYPE) : "";
2524             whereArgs[i++] = values.containsKey(MVNO_MATCH_DATA) ?
2525                     values.getAsString(MVNO_MATCH_DATA) : "";
2526             whereArgs[i++] = values.containsKey(PROFILE_ID) ?
2527                     values.getAsString(PROFILE_ID) : "0";
2528 
2529             if (values.containsKey(MODEM_PERSIST) &&
2530                     (values.getAsString(MODEM_PERSIST).
2531                             equalsIgnoreCase("true") ||
2532                             values.getAsString(MODEM_PERSIST).equals("1"))) {
2533                 whereArgs[i++] = "true";
2534                 whereArgs[i++] = "1";
2535             } else {
2536                 whereArgs[i++] = "false";
2537                 whereArgs[i++] = "0";
2538             }
2539 
2540             whereArgs[i++] = values.containsKey(MAX_CONNECTIONS) ?
2541                     values.getAsString(MAX_CONNECTIONS) : "0";
2542             whereArgs[i++] = values.containsKey(WAIT_TIME_RETRY) ?
2543                     values.getAsString(WAIT_TIME_RETRY) : "0";
2544             whereArgs[i++] = values.containsKey(TIME_LIMIT_FOR_MAX_CONNECTIONS) ?
2545                     values.getAsString(TIME_LIMIT_FOR_MAX_CONNECTIONS) : "0";
2546             whereArgs[i++] = values.containsKey(MTU) ?
2547                     values.getAsString(MTU) : "0";
2548             whereArgs[i++] = values.containsKey(MTU_V4) ?
2549                     values.getAsString(MTU_V4) : "0";
2550             whereArgs[i++] = values.containsKey(MTU_V6) ?
2551                     values.getAsString(MTU_V6) : "0";
2552 
2553             if (VDBG) {
2554                 log("deleteRow: where: " + where);
2555 
2556                 StringBuilder builder = new StringBuilder();
2557                 for (String s : whereArgs) {
2558                     builder.append(s + ", ");
2559                 }
2560 
2561                 log("deleteRow: whereArgs: " + builder.toString());
2562             }
2563             db.delete(CARRIERS_TABLE, where, whereArgs);
2564         }
2565 
copyDataToTmpTable(SQLiteDatabase db, Cursor c, int version)2566         private void copyDataToTmpTable(SQLiteDatabase db, Cursor c, int version) {
2567             // Move entries from CARRIERS_TABLE to CARRIERS_TABLE_TMP
2568             if (c != null) {
2569                 while (c.moveToNext()) {
2570                     ContentValues cv = new ContentValues();
2571                     copyAllApnValues(cv, c);
2572                     if (version == 24) {
2573                         // Sync bearer bitmask and network type bitmask
2574                         getNetworkTypeBitmaskFromCursor(cv, c);
2575                     }
2576                     try {
2577                         db.insertWithOnConflict(CARRIERS_TABLE_TMP, null, cv,
2578                                 SQLiteDatabase.CONFLICT_ABORT);
2579                         if (VDBG) {
2580                             log("dbh.copyPreservedApnsToNewTable: db.insert returned >= 0; " +
2581                                     "insert successful for cv " + cv);
2582                         }
2583                     } catch (SQLException e) {
2584                         if (VDBG)
2585                             log("dbh.copyPreservedApnsToNewTable insertWithOnConflict exception " +
2586                                     e + " for cv " + cv);
2587                     }
2588                 }
2589             }
2590         }
2591 
copyApnValuesV17(ContentValues cv, Cursor c)2592         private void copyApnValuesV17(ContentValues cv, Cursor c) {
2593             // Include only non-null values in cv so that null values can be replaced
2594             // with default if there's a default value for the field
2595 
2596             // String vals
2597             getStringValueFromCursor(cv, c, NAME);
2598             getStringValueFromCursor(cv, c, NUMERIC);
2599             getStringValueFromCursor(cv, c, MCC);
2600             getStringValueFromCursor(cv, c, MNC);
2601             getStringValueFromCursor(cv, c, APN);
2602             getStringValueFromCursor(cv, c, USER);
2603             getStringValueFromCursor(cv, c, SERVER);
2604             getStringValueFromCursor(cv, c, PASSWORD);
2605             getStringValueFromCursor(cv, c, PROXY);
2606             getStringValueFromCursor(cv, c, PORT);
2607             getStringValueFromCursor(cv, c, MMSPROXY);
2608             getStringValueFromCursor(cv, c, MMSPORT);
2609             getStringValueFromCursor(cv, c, MMSC);
2610             getStringValueFromCursor(cv, c, TYPE);
2611             getStringValueFromCursor(cv, c, PROTOCOL);
2612             getStringValueFromCursor(cv, c, ROAMING_PROTOCOL);
2613             getStringValueFromCursor(cv, c, MVNO_TYPE);
2614             getStringValueFromCursor(cv, c, MVNO_MATCH_DATA);
2615 
2616             // bool/int vals
2617             getIntValueFromCursor(cv, c, AUTH_TYPE);
2618             getIntValueFromCursor(cv, c, CURRENT);
2619             getIntValueFromCursor(cv, c, CARRIER_ENABLED);
2620             getIntValueFromCursor(cv, c, BEARER);
2621             getIntValueFromCursor(cv, c, SUBSCRIPTION_ID);
2622             getIntValueFromCursor(cv, c, PROFILE_ID);
2623             getIntValueFromCursor(cv, c, MODEM_PERSIST);
2624             getIntValueFromCursor(cv, c, MAX_CONNECTIONS);
2625             getIntValueFromCursor(cv, c, WAIT_TIME_RETRY);
2626             getIntValueFromCursor(cv, c, TIME_LIMIT_FOR_MAX_CONNECTIONS);
2627             getIntValueFromCursor(cv, c, MTU);
2628             getIntValueFromCursor(cv, c, BEARER_BITMASK);
2629             getIntValueFromCursor(cv, c, EDITED_STATUS);
2630             getIntValueFromCursor(cv, c, USER_VISIBLE);
2631         }
2632 
copyAllApnValues(ContentValues cv, Cursor c)2633         private void copyAllApnValues(ContentValues cv, Cursor c) {
2634             // String vals
2635             getStringValueFromCursor(cv, c, NAME);
2636             getStringValueFromCursor(cv, c, NUMERIC);
2637             getStringValueFromCursor(cv, c, MCC);
2638             getStringValueFromCursor(cv, c, MNC);
2639             getStringValueFromCursor(cv, c, APN);
2640             getStringValueFromCursor(cv, c, USER);
2641             getStringValueFromCursor(cv, c, SERVER);
2642             getStringValueFromCursor(cv, c, PASSWORD);
2643             getStringValueFromCursor(cv, c, PROXY);
2644             getStringValueFromCursor(cv, c, PORT);
2645             getStringValueFromCursor(cv, c, MMSPROXY);
2646             getStringValueFromCursor(cv, c, MMSPORT);
2647             getStringValueFromCursor(cv, c, MMSC);
2648             getStringValueFromCursor(cv, c, TYPE);
2649             getStringValueFromCursor(cv, c, PROTOCOL);
2650             getStringValueFromCursor(cv, c, ROAMING_PROTOCOL);
2651             getStringValueFromCursor(cv, c, MVNO_TYPE);
2652             getStringValueFromCursor(cv, c, MVNO_MATCH_DATA);
2653 
2654             // bool/int vals
2655             getIntValueFromCursor(cv, c, AUTH_TYPE);
2656             getIntValueFromCursor(cv, c, CURRENT);
2657             getIntValueFromCursor(cv, c, CARRIER_ENABLED);
2658             getIntValueFromCursor(cv, c, BEARER);
2659             getIntValueFromCursor(cv, c, SUBSCRIPTION_ID);
2660             getIntValueFromCursor(cv, c, PROFILE_ID);
2661             getIntValueFromCursor(cv, c, MODEM_PERSIST);
2662             getIntValueFromCursor(cv, c, MAX_CONNECTIONS);
2663             getIntValueFromCursor(cv, c, WAIT_TIME_RETRY);
2664             getIntValueFromCursor(cv, c, TIME_LIMIT_FOR_MAX_CONNECTIONS);
2665             getIntValueFromCursor(cv, c, MTU);
2666             getIntValueFromCursor(cv, c, MTU_V4);
2667             getIntValueFromCursor(cv, c, MTU_V6);
2668             getIntValueFromCursor(cv, c, NETWORK_TYPE_BITMASK);
2669             getIntValueFromCursor(cv, c, LINGERING_NETWORK_TYPE_BITMASK);
2670             getIntValueFromCursor(cv, c, BEARER_BITMASK);
2671             getIntValueFromCursor(cv, c, EDITED_STATUS);
2672             getIntValueFromCursor(cv, c, USER_VISIBLE);
2673             getIntValueFromCursor(cv, c, USER_EDITABLE);
2674             getIntValueFromCursor(cv, c, OWNED_BY);
2675             getIntValueFromCursor(cv, c, APN_SET_ID);
2676             getIntValueFromCursor(cv, c, SKIP_464XLAT);
2677             getIntValueFromCursor(cv, c, ALWAYS_ON);
2678             getIntValueFromCursor(cv, c, INFRASTRUCTURE_BITMASK);
2679             getIntValueFromCursor(cv, c, ESIM_BOOTSTRAP_PROVISIONING);
2680         }
2681 
copyPreservedApnsToNewTable(SQLiteDatabase db, Cursor c)2682         private void copyPreservedApnsToNewTable(SQLiteDatabase db, Cursor c) {
2683             // Move entries from CARRIERS_TABLE to CARRIERS_TABLE_TMP
2684             if (c != null && mContext.getResources() != null) {
2685                 try {
2686                     String[] persistApnsForPlmns = mContext.getResources().getStringArray(
2687                             R.array.persist_apns_for_plmn);
2688                     while (c.moveToNext()) {
2689                         ContentValues cv = new ContentValues();
2690                         String val;
2691                         // Using V17 copy function for V15 upgrade. This should be fine since it
2692                         // handles columns that may not exist properly (getStringValueFromCursor()
2693                         // and getIntValueFromCursor() handle column index -1)
2694                         copyApnValuesV17(cv, c);
2695                         // Change bearer to a bitmask
2696                         String bearerStr = c.getString(c.getColumnIndex(BEARER));
2697                         if (!TextUtils.isEmpty(bearerStr)) {
2698                             int bearer_bitmask = getBitmaskForTech(Integer.parseInt(bearerStr));
2699                             cv.put(BEARER_BITMASK, bearer_bitmask);
2700 
2701                             int networkTypeBitmask = rilRadioTechnologyToNetworkTypeBitmask(
2702                                     Integer.parseInt(bearerStr));
2703                             cv.put(NETWORK_TYPE_BITMASK, networkTypeBitmask);
2704                         }
2705 
2706                         int userEditedColumnIdx = c.getColumnIndex("user_edited");
2707                         if (userEditedColumnIdx != -1) {
2708                             String user_edited = c.getString(userEditedColumnIdx);
2709                             if (!TextUtils.isEmpty(user_edited)) {
2710                                 cv.put(EDITED_STATUS, new Integer(user_edited));
2711                             }
2712                         } else {
2713                             cv.put(EDITED_STATUS, CARRIER_EDITED);
2714                         }
2715 
2716                         // New EDITED column. Default value (UNEDITED) will
2717                         // be used for all rows except for non-mvno entries for plmns indicated
2718                         // by resource: those will be set to CARRIER_EDITED to preserve
2719                         // their current values
2720                         val = c.getString(c.getColumnIndex(NUMERIC));
2721                         for (String s : persistApnsForPlmns) {
2722                             if (!TextUtils.isEmpty(val) && val.equals(s) &&
2723                                     (!cv.containsKey(MVNO_TYPE) ||
2724                                             TextUtils.isEmpty(cv.getAsString(MVNO_TYPE)))) {
2725                                 if (userEditedColumnIdx == -1) {
2726                                     cv.put(EDITED_STATUS, CARRIER_EDITED);
2727                                 } else { // if (oldVersion == 14) -- if db had user_edited column
2728                                     if (cv.getAsInteger(EDITED_STATUS) == USER_EDITED) {
2729                                         cv.put(EDITED_STATUS, CARRIER_EDITED);
2730                                     }
2731                                 }
2732 
2733                                 break;
2734                             }
2735                         }
2736 
2737                         try {
2738                             db.insertWithOnConflict(CARRIERS_TABLE_TMP, null, cv,
2739                                     SQLiteDatabase.CONFLICT_ABORT);
2740                             if (VDBG) {
2741                                 log("dbh.copyPreservedApnsToNewTable: db.insert returned >= 0; " +
2742                                         "insert successful for cv " + cv);
2743                             }
2744                         } catch (SQLException e) {
2745                             if (VDBG)
2746                                 log("dbh.copyPreservedApnsToNewTable insertWithOnConflict exception " +
2747                                         e + " for cv " + cv);
2748                             // Insertion failed which could be due to a conflict. Check if that is
2749                             // the case and merge the entries
2750                             Cursor oldRow = selectConflictingRow(db,
2751                                     CARRIERS_TABLE_TMP, cv);
2752                             if (oldRow != null) {
2753                                 ContentValues mergedValues = new ContentValues();
2754                                 mergeFieldsAndUpdateDb(db, CARRIERS_TABLE_TMP, oldRow, cv,
2755                                         mergedValues, true, mContext);
2756                                 oldRow.close();
2757                             }
2758                         }
2759                     }
2760                 } catch (Resources.NotFoundException e) {
2761                     loge("array.persist_apns_for_plmn is not found");
2762                     return;
2763                 }
2764             }
2765         }
2766 
getStringValueFromCursor(ContentValues cv, Cursor c, String key)2767         private void getStringValueFromCursor(ContentValues cv, Cursor c, String key) {
2768             int columnIndex = c.getColumnIndex(key);
2769             if (columnIndex != -1) {
2770                 String fromCursor = c.getString(columnIndex);
2771                 if (fromCursor != null) {
2772                     cv.put(key, fromCursor);
2773                 }
2774             }
2775         }
2776 
2777         /**
2778          * If NETWORK_TYPE_BITMASK does not exist (upgrade from version 23 to version 24), generate
2779          * NETWORK_TYPE_BITMASK with the use of BEARER_BITMASK. If NETWORK_TYPE_BITMASK existed
2780          * (upgrade from version 24 to forward), always map NETWORK_TYPE_BITMASK to BEARER_BITMASK.
2781          */
getNetworkTypeBitmaskFromCursor(ContentValues cv, Cursor c)2782         private void getNetworkTypeBitmaskFromCursor(ContentValues cv, Cursor c) {
2783             int columnIndex = c.getColumnIndex(NETWORK_TYPE_BITMASK);
2784             if (columnIndex != -1) {
2785                 getStringValueFromCursor(cv, c, NETWORK_TYPE_BITMASK);
2786                 // Map NETWORK_TYPE_BITMASK to BEARER_BITMASK if NETWORK_TYPE_BITMASK existed;
2787                 String fromCursor = c.getString(columnIndex);
2788                 if (!TextUtils.isEmpty(fromCursor) && fromCursor.matches("\\d+")) {
2789                     int networkBitmask = Integer.valueOf(fromCursor);
2790                     int bearerBitmask = convertNetworkTypeBitmaskToBearerBitmask(networkBitmask);
2791                     cv.put(BEARER_BITMASK, String.valueOf(bearerBitmask));
2792                 }
2793                 return;
2794             }
2795             columnIndex = c.getColumnIndex(BEARER_BITMASK);
2796             if (columnIndex != -1) {
2797                 String fromCursor = c.getString(columnIndex);
2798                 if (!TextUtils.isEmpty(fromCursor) && fromCursor.matches("\\d+")) {
2799                     int bearerBitmask = Integer.valueOf(fromCursor);
2800                     int networkBitmask = convertBearerBitmaskToNetworkTypeBitmask(bearerBitmask);
2801                     cv.put(NETWORK_TYPE_BITMASK, String.valueOf(networkBitmask));
2802                 }
2803             }
2804         }
2805 
getIntValueFromCursor(ContentValues cv, Cursor c, String key)2806         private void getIntValueFromCursor(ContentValues cv, Cursor c, String key) {
2807             int columnIndex = c.getColumnIndex(key);
2808             if (columnIndex != -1) {
2809                 String fromCursor = c.getString(columnIndex);
2810                 if (!TextUtils.isEmpty(fromCursor)) {
2811                     try {
2812                         cv.put(key, new Integer(fromCursor));
2813                     } catch (NumberFormatException nfe) {
2814                         // do nothing
2815                     }
2816                 }
2817             }
2818         }
2819 
getBlobValueFromCursor(ContentValues cv, Cursor c, String key)2820         private void getBlobValueFromCursor(ContentValues cv, Cursor c, String key) {
2821             int columnIndex = c.getColumnIndex(key);
2822             if (columnIndex != -1) {
2823                 byte[] fromCursor = c.getBlob(columnIndex);
2824                 if (fromCursor != null) {
2825                     cv.put(key, fromCursor);
2826                 }
2827             }
2828         }
2829 
2830         /**
2831          * Gets the next row of apn values.
2832          *
2833          * @param parser the parser
2834          * @param isOverlay If the xml file comes from an overlay MCC/MNC are treated as integers
2835          * @return the row or null if it's not an apn
2836          */
getRow(XmlPullParser parser, boolean isOverlay)2837         private ContentValues getRow(XmlPullParser parser, boolean isOverlay) {
2838             if (!"apn".equals(parser.getName())) {
2839                 return null;
2840             }
2841 
2842             ContentValues map = new ContentValues();
2843 
2844             String mcc = parser.getAttributeValue(null, "mcc");
2845             String mnc = parser.getAttributeValue(null, "mnc");
2846             String mccString = mcc;
2847             String mncString = mnc;
2848             // Since an mnc can have both two and three digits and it is hard to verify
2849             // all OEM's Global APN lists we only do this for overlays.
2850             if (isOverlay && mcc !=null && mnc != null) {
2851                 mccString = String.format("%03d", Integer.parseInt(mcc));
2852                 // Looks up a two digit mnc in the carrier id DB
2853                 // if not found a three digit mnc value is chosen
2854                 mncString = getBestStringMnc(mContext, mccString, Integer.parseInt(mnc));
2855             }
2856             // Make sure to set default values for numeric, mcc and mnc. This is the empty string.
2857             // If default is not set here, a duplicate of each carrier id APN will be created next
2858             // time the apn list is read. This happens at OTA or at restore.
2859             String numeric = (mccString == null | mncString == null) ? "" : mccString + mncString;
2860             map.put(NUMERIC, numeric);
2861             map.put(MCC, mccString != null ? mccString : "");
2862             map.put(MNC, mncString != null ? mncString : "");
2863             map.put(NAME, parser.getAttributeValue(null, "carrier"));
2864 
2865             // do not add NULL to the map so that default values can be inserted in db
2866             addStringAttribute(parser, "apn", map, APN);
2867             addStringAttribute(parser, "user", map, USER);
2868             addStringAttribute(parser, "server", map, SERVER);
2869             addStringAttribute(parser, "password", map, PASSWORD);
2870             addStringAttribute(parser, "proxy", map, PROXY);
2871             addStringAttribute(parser, "port", map, PORT);
2872             addStringAttribute(parser, "mmsproxy", map, MMSPROXY);
2873             addStringAttribute(parser, "mmsport", map, MMSPORT);
2874             addStringAttribute(parser, "mmsc", map, MMSC);
2875 
2876             String apnType = parser.getAttributeValue(null, "type");
2877             if (apnType != null) {
2878                 // Remove spaces before putting it in the map.
2879                 apnType = apnType.replaceAll("\\s+", "");
2880                 map.put(TYPE, apnType);
2881             }
2882 
2883             addStringAttribute(parser, "protocol", map, PROTOCOL);
2884             addStringAttribute(parser, "roaming_protocol", map, ROAMING_PROTOCOL);
2885 
2886             addIntAttribute(parser, "authtype", map, AUTH_TYPE);
2887             addIntAttribute(parser, "bearer", map, BEARER);
2888             addIntAttribute(parser, "profile_id", map, PROFILE_ID);
2889             addIntAttribute(parser, "max_conns", map, MAX_CONNECTIONS);
2890             addIntAttribute(parser, "wait_time", map, WAIT_TIME_RETRY);
2891             addIntAttribute(parser, "max_conns_time", map, TIME_LIMIT_FOR_MAX_CONNECTIONS);
2892             addIntAttribute(parser, "mtu", map, MTU);
2893             addIntAttribute(parser, "mtu_v4", map, MTU_V4);
2894             addIntAttribute(parser, "mtu_v6", map, MTU_V6);
2895             addIntAttribute(parser, "apn_set_id", map, APN_SET_ID);
2896             addIntAttribute(parser, "carrier_id", map, CARRIER_ID);
2897             addIntAttribute(parser, "skip_464xlat", map, SKIP_464XLAT);
2898 
2899             addBoolAttribute(parser, "carrier_enabled", map, CARRIER_ENABLED);
2900             addBoolAttribute(parser, "modem_cognitive", map, MODEM_PERSIST);
2901             addBoolAttribute(parser, "user_visible", map, USER_VISIBLE);
2902             addBoolAttribute(parser, "user_editable", map, USER_EDITABLE);
2903             addBoolAttribute(parser, "always_on", map, ALWAYS_ON);
2904             addBoolAttribute(parser, "esim_bootstrap_provisioning", map,
2905                     ESIM_BOOTSTRAP_PROVISIONING);
2906 
2907             int infrastructureBitmask =
2908                     ApnSetting.INFRASTRUCTURE_CELLULAR | ApnSetting.INFRASTRUCTURE_SATELLITE;
2909             String infrastructureList = parser.getAttributeValue(null, "infrastructure_bitmask");
2910             if (infrastructureList != null) {
2911                 infrastructureBitmask = getInfrastructureListFromString(infrastructureList);
2912             }
2913             map.put(INFRASTRUCTURE_BITMASK, infrastructureBitmask);
2914 
2915             int networkTypeBitmask = 0;
2916             String networkTypeList = parser.getAttributeValue(null, "network_type_bitmask");
2917             if (networkTypeList != null) {
2918                 networkTypeBitmask = getBitmaskFromString(networkTypeList);
2919             }
2920             map.put(NETWORK_TYPE_BITMASK, networkTypeBitmask);
2921 
2922             int lingeringNetworkTypeBitmask = 0;
2923             String lingeringNetworkTypeList =
2924                     parser.getAttributeValue(null, "lingering_network_type_bitmask");
2925             if (lingeringNetworkTypeList != null) {
2926                 lingeringNetworkTypeBitmask = getBitmaskFromString(lingeringNetworkTypeList);
2927             }
2928             map.put(LINGERING_NETWORK_TYPE_BITMASK, lingeringNetworkTypeBitmask);
2929 
2930             int bearerBitmask = 0;
2931             if (networkTypeList != null) {
2932                 bearerBitmask = convertNetworkTypeBitmaskToBearerBitmask(networkTypeBitmask);
2933             } else {
2934                 String bearerList = parser.getAttributeValue(null, "bearer_bitmask");
2935                 if (bearerList != null) {
2936                     bearerBitmask = getBitmaskFromString(bearerList);
2937                 }
2938                 // Update the network type bitmask to keep them sync.
2939                 networkTypeBitmask = convertBearerBitmaskToNetworkTypeBitmask(bearerBitmask);
2940                 map.put(NETWORK_TYPE_BITMASK, networkTypeBitmask);
2941             }
2942             map.put(BEARER_BITMASK, bearerBitmask);
2943 
2944             String mvno_type = parser.getAttributeValue(null, "mvno_type");
2945             if (mvno_type != null) {
2946                 String mvno_match_data = parser.getAttributeValue(null, "mvno_match_data");
2947                 if (mvno_match_data != null) {
2948                     map.put(MVNO_TYPE, mvno_type);
2949                     map.put(MVNO_MATCH_DATA, mvno_match_data);
2950                 }
2951             }
2952             return map;
2953         }
2954 
addStringAttribute(XmlPullParser parser, String att, ContentValues map, String key)2955         private void addStringAttribute(XmlPullParser parser, String att,
2956                                         ContentValues map, String key) {
2957             String val = parser.getAttributeValue(null, att);
2958             if (val != null) {
2959                 map.put(key, val);
2960             }
2961         }
2962 
addIntAttribute(XmlPullParser parser, String att, ContentValues map, String key)2963         private void addIntAttribute(XmlPullParser parser, String att,
2964                                      ContentValues map, String key) {
2965             String val = parser.getAttributeValue(null, att);
2966             if (val != null) {
2967                 map.put(key, Integer.parseInt(val));
2968             }
2969         }
2970 
addBoolAttribute(XmlPullParser parser, String att, ContentValues map, String key)2971         private void addBoolAttribute(XmlPullParser parser, String att,
2972                                       ContentValues map, String key) {
2973             String val = parser.getAttributeValue(null, att);
2974             if (val != null) {
2975                 map.put(key, Boolean.parseBoolean(val));
2976             }
2977         }
2978 
2979         /*
2980          * Loads apns from xml file into the database
2981          *
2982          * @param db the sqlite database to write to
2983          * @param parser the xml parser
2984          * @param isOverlay, if we are parsing an xml in an overlay
2985          */
loadApns(SQLiteDatabase db, XmlPullParser parser, boolean isOverlay)2986         private void loadApns(SQLiteDatabase db, XmlPullParser parser, boolean isOverlay) {
2987             if (parser != null) {
2988                 try {
2989                     db.beginTransaction();
2990                     XmlUtils.nextElement(parser);
2991                     while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
2992                         ContentValues row = getRow(parser, isOverlay);
2993                         if (row == null) {
2994                             throw new XmlPullParserException("Expected 'apn' tag", parser, null);
2995                         }
2996                         insertAddingDefaults(db, row);
2997                         XmlUtils.nextElement(parser);
2998                     }
2999                     db.setTransactionSuccessful();
3000                 } catch (XmlPullParserException e) {
3001                     loge("Got XmlPullParserException while loading apns." + e);
3002                 } catch (IOException e) {
3003                     loge("Got IOException while loading apns." + e);
3004                 } catch (SQLException e) {
3005                     loge("Got SQLException while loading apns." + e);
3006                 } finally {
3007                     db.endTransaction();
3008                 }
3009             }
3010         }
3011 
insertAddingDefaults(SQLiteDatabase db, ContentValues row)3012         private void insertAddingDefaults(SQLiteDatabase db, ContentValues row) {
3013             row = setDefaultValue(row);
3014             try {
3015                 db.insertWithOnConflict(CARRIERS_TABLE, null, row, SQLiteDatabase.CONFLICT_ABORT);
3016                 if (VDBG) log("dbh.insertAddingDefaults: db.insert returned >= 0; insert " +
3017                         "successful for cv " + row);
3018             } catch (SQLException e) {
3019                 if (VDBG) log("dbh.insertAddingDefaults: exception " + e);
3020                 // Insertion failed which could be due to a conflict. Check if that is the case and
3021                 // update edited field accordingly.
3022                 // Search for the exact same entry and update edited field.
3023                 // If it is USER_EDITED/CARRIER_EDITED change it to UNEDITED,
3024                 // and if USER/CARRIER_DELETED change it to USER/CARRIER_DELETED_BUT_PRESENT_IN_XML.
3025                 Cursor oldRow = selectConflictingRow(db, CARRIERS_TABLE, row);
3026                 if (oldRow != null) {
3027                     // Update the row
3028                     ContentValues mergedValues = new ContentValues();
3029                     int edited = oldRow.getInt(oldRow.getColumnIndex(EDITED_STATUS));
3030                     int old_edited = edited;
3031                     if (edited != UNEDITED) {
3032                         if (edited == USER_DELETED) {
3033                             // USER_DELETED_BUT_PRESENT_IN_XML indicates entry has been deleted
3034                             // by user but present in apn xml file.
3035                             edited = USER_DELETED_BUT_PRESENT_IN_XML;
3036                         } else if (edited == CARRIER_DELETED) {
3037                             // CARRIER_DELETED_BUT_PRESENT_IN_XML indicates entry has been deleted
3038                             // by user but present in apn xml file.
3039                             edited = CARRIER_DELETED_BUT_PRESENT_IN_XML;
3040                         }
3041                         mergedValues.put(EDITED_STATUS, edited);
3042                     }
3043 
3044                     mergeFieldsAndUpdateDb(db, CARRIERS_TABLE, oldRow, row, mergedValues, false,
3045                             mContext);
3046 
3047                     if (VDBG) log("dbh.insertAddingDefaults: old edited = " + old_edited
3048                             + " new edited = " + edited);
3049 
3050                     oldRow.close();
3051                 }
3052             }
3053         }
3054     }
3055 
mergeFieldsAndUpdateDb(SQLiteDatabase db, String table, Cursor oldRow, ContentValues newRow, ContentValues mergedValues, boolean onUpgrade, Context context)3056     public static void mergeFieldsAndUpdateDb(SQLiteDatabase db, String table, Cursor oldRow,
3057             ContentValues newRow, ContentValues mergedValues,
3058             boolean onUpgrade, Context context) {
3059         if (newRow.containsKey(TYPE)) {
3060             // Merge the types
3061             String oldType = oldRow.getString(oldRow.getColumnIndex(TYPE));
3062             String newType = newRow.getAsString(TYPE);
3063 
3064             if (!oldType.equalsIgnoreCase(newType)) {
3065                 if (oldType.equals("") || newType.equals("")) {
3066                     newRow.put(TYPE, "");
3067                 } else {
3068                     String[] oldTypes = oldType.toLowerCase(Locale.ROOT).split(",");
3069                     String[] newTypes = newType.toLowerCase(Locale.ROOT).split(",");
3070 
3071                     if (VDBG) {
3072                         log("mergeFieldsAndUpdateDb: Calling separateRowsNeeded() oldType=" +
3073                                 oldType + " old bearer=" + oldRow.getInt(oldRow.getColumnIndex(
3074                                 BEARER_BITMASK)) +  " old networkType=" +
3075                                 oldRow.getInt(oldRow.getColumnIndex(NETWORK_TYPE_BITMASK)) +
3076                                 " old profile_id=" + oldRow.getInt(oldRow.getColumnIndex(
3077                                 PROFILE_ID)) + " newRow " + newRow);
3078                     }
3079 
3080                     // If separate rows are needed, do not need to merge any further
3081                     if (separateRowsNeeded(db, table, oldRow, newRow, context, oldTypes,
3082                             newTypes)) {
3083                         if (VDBG) log("mergeFieldsAndUpdateDb: separateRowsNeeded() returned " +
3084                                 "true");
3085                         return;
3086                     }
3087 
3088                     // Merge the 2 types
3089                     ArrayList<String> mergedTypes = new ArrayList<String>();
3090                     mergedTypes.addAll(Arrays.asList(oldTypes));
3091                     for (String s : newTypes) {
3092                         if (!mergedTypes.contains(s.trim())) {
3093                             mergedTypes.add(s);
3094                         }
3095                     }
3096                     StringBuilder mergedType = new StringBuilder();
3097                     for (int i = 0; i < mergedTypes.size(); i++) {
3098                         mergedType.append((i == 0 ? "" : ",") + mergedTypes.get(i));
3099                     }
3100                     newRow.put(TYPE, mergedType.toString());
3101                 }
3102             }
3103             mergedValues.put(TYPE, newRow.getAsString(TYPE));
3104         }
3105 
3106         if (newRow.containsKey(BEARER_BITMASK)) {
3107             int oldBearer = oldRow.getInt(oldRow.getColumnIndex(BEARER_BITMASK));
3108             int newBearer = newRow.getAsInteger(BEARER_BITMASK);
3109             if (oldBearer != newBearer) {
3110                 if (oldBearer == 0 || newBearer == 0) {
3111                     newRow.put(BEARER_BITMASK, 0);
3112                 } else {
3113                     newRow.put(BEARER_BITMASK, (oldBearer | newBearer));
3114                 }
3115             }
3116             mergedValues.put(BEARER_BITMASK, newRow.getAsInteger(BEARER_BITMASK));
3117         }
3118 
3119         if (newRow.containsKey(NETWORK_TYPE_BITMASK)) {
3120             int oldBitmask = oldRow.getInt(oldRow.getColumnIndex(NETWORK_TYPE_BITMASK));
3121             int newBitmask = newRow.getAsInteger(NETWORK_TYPE_BITMASK);
3122             if (oldBitmask != newBitmask) {
3123                 if (oldBitmask == 0 || newBitmask == 0) {
3124                     newRow.put(NETWORK_TYPE_BITMASK, 0);
3125                 } else {
3126                     newRow.put(NETWORK_TYPE_BITMASK, (oldBitmask | newBitmask));
3127                 }
3128             }
3129             mergedValues.put(NETWORK_TYPE_BITMASK, newRow.getAsInteger(NETWORK_TYPE_BITMASK));
3130         }
3131 
3132         if (newRow.containsKey(BEARER_BITMASK)
3133                 && newRow.containsKey(NETWORK_TYPE_BITMASK)) {
3134             syncBearerBitmaskAndNetworkTypeBitmask(mergedValues);
3135         }
3136 
3137         if (!onUpgrade) {
3138             // Do not overwrite a carrier or user edit with EDITED=UNEDITED
3139             if (newRow.containsKey(EDITED_STATUS)) {
3140                 int oldEdited = oldRow.getInt(oldRow.getColumnIndex(EDITED_STATUS));
3141                 int newEdited = newRow.getAsInteger(EDITED_STATUS);
3142                 if (newEdited == UNEDITED && (oldEdited == CARRIER_EDITED
3143                         || oldEdited == CARRIER_DELETED
3144                         || oldEdited == CARRIER_DELETED_BUT_PRESENT_IN_XML
3145                         || oldEdited == USER_EDITED
3146                         || oldEdited == USER_DELETED
3147                         || oldEdited == USER_DELETED_BUT_PRESENT_IN_XML)) {
3148                     newRow.remove(EDITED_STATUS);
3149                 }
3150             }
3151             mergedValues.putAll(newRow);
3152         }
3153 
3154         if (mergedValues.size() > 0) {
3155             db.update(table, mergedValues, "_id=" + oldRow.getInt(oldRow.getColumnIndex("_id")),
3156                     null);
3157         }
3158     }
3159 
separateRowsNeeded(SQLiteDatabase db, String table, Cursor oldRow, ContentValues newRow, Context context, String[] oldTypes, String[] newTypes)3160     private static boolean separateRowsNeeded(SQLiteDatabase db, String table, Cursor oldRow,
3161             ContentValues newRow, Context context,
3162             String[] oldTypes, String[] newTypes) {
3163         // If this APN falls under persist_apns_for_plmn, and the
3164         // only difference between old type and new type is that one has dun, and
3165         // the APNs have profile_id 0 or not set, then set the profile_id to 1 for
3166         // the dun APN/remove dun from type. This will ensure both oldRow and newRow exist
3167         // separately in db.
3168 
3169         boolean match = false;
3170 
3171         // Check if APN falls under persist_apns_for_plmn
3172         if (context.getResources() != null) {
3173             String[] persistApnsForPlmns = context.getResources().getStringArray(
3174                     R.array.persist_apns_for_plmn);
3175             for (String s : persistApnsForPlmns) {
3176                 if (s.equalsIgnoreCase(newRow.getAsString(NUMERIC))) {
3177                     match = true;
3178                     break;
3179                 }
3180             }
3181         } else {
3182             loge("separateRowsNeeded: resources=null");
3183         }
3184 
3185         if (!match) return false;
3186 
3187         // APN falls under persist_apns_for_plmn
3188         // Check if only difference between old type and new type is that
3189         // one has dun
3190         ArrayList<String> oldTypesAl = new ArrayList<String>(Arrays.asList(oldTypes));
3191         ArrayList<String> newTypesAl = new ArrayList<String>(Arrays.asList(newTypes));
3192         ArrayList<String> listWithDun = null;
3193         ArrayList<String> listWithoutDun = null;
3194         boolean dunInOld = false;
3195         if (oldTypesAl.size() == newTypesAl.size() + 1) {
3196             listWithDun = oldTypesAl;
3197             listWithoutDun = newTypesAl;
3198             dunInOld = true;
3199         } else if (oldTypesAl.size() + 1 == newTypesAl.size()) {
3200             listWithDun = newTypesAl;
3201             listWithoutDun = oldTypesAl;
3202         } else {
3203             return false;
3204         }
3205 
3206         if (listWithDun.contains("dun") && !listWithoutDun.contains("dun")) {
3207             listWithoutDun.add("dun");
3208             if (!listWithDun.containsAll(listWithoutDun)) {
3209                 return false;
3210             }
3211 
3212             // Only difference between old type and new type is that
3213             // one has dun
3214             // Check if profile_id is 0/not set
3215             if (oldRow.getInt(oldRow.getColumnIndex(PROFILE_ID)) == 0) {
3216                 if (dunInOld) {
3217                     // Update oldRow to remove dun from its type field
3218                     ContentValues updateOldRow = new ContentValues();
3219                     StringBuilder sb = new StringBuilder();
3220                     boolean first = true;
3221                     for (String s : listWithDun) {
3222                         if (!s.equalsIgnoreCase("dun")) {
3223                             sb.append(first ? s : "," + s);
3224                             first = false;
3225                         }
3226                     }
3227                     String updatedType = sb.toString();
3228                     if (VDBG) {
3229                         log("separateRowsNeeded: updating type in oldRow to " + updatedType);
3230                     }
3231                     updateOldRow.put(TYPE, updatedType);
3232                     db.update(table, updateOldRow,
3233                             "_id=" + oldRow.getInt(oldRow.getColumnIndex("_id")), null);
3234                     return true;
3235                 } else {
3236                     if (VDBG) log("separateRowsNeeded: adding profile id 1 to newRow");
3237                     // Update newRow to set profile_id to 1
3238                     newRow.put(PROFILE_ID, new Integer(1));
3239                 }
3240             } else {
3241                 return false;
3242             }
3243 
3244             // If match was found, both oldRow and newRow need to exist
3245             // separately in db. Add newRow to db.
3246             try {
3247                 db.insertWithOnConflict(table, null, newRow, SQLiteDatabase.CONFLICT_REPLACE);
3248                 if (VDBG) log("separateRowsNeeded: added newRow with profile id 1 to db");
3249                 return true;
3250             } catch (SQLException e) {
3251                 loge("Exception on trying to add new row after updating profile_id");
3252             }
3253         }
3254 
3255         return false;
3256     }
3257 
selectConflictingRow(SQLiteDatabase db, String table, ContentValues row)3258     public static Cursor selectConflictingRow(SQLiteDatabase db, String table,
3259             ContentValues row) {
3260         // Conflict is possible only when numeric, mcc, mnc (fields without any default value)
3261         // are set in the new row
3262         if (!row.containsKey(NUMERIC) || !row.containsKey(MCC) || !row.containsKey(MNC)) {
3263             loge("dbh.selectConflictingRow: called for non-conflicting row: " + row);
3264             return null;
3265         }
3266 
3267         String[] columns = { "_id",
3268                 TYPE,
3269                 EDITED_STATUS,
3270                 BEARER_BITMASK,
3271                 NETWORK_TYPE_BITMASK,
3272                 PROFILE_ID };
3273         String selection = TextUtils.join("=? AND ", CARRIERS_UNIQUE_FIELDS) + "=?";
3274         int i = 0;
3275         String[] selectionArgs = new String[CARRIERS_UNIQUE_FIELDS.size()];
3276         for (String field : CARRIERS_UNIQUE_FIELDS) {
3277             if (!row.containsKey(field)) {
3278                 selectionArgs[i++] = CARRIERS_UNIQUE_FIELDS_DEFAULTS.get(field);
3279             } else {
3280                 if (CARRIERS_BOOLEAN_FIELDS.contains(field)) {
3281                     // for boolean fields we overwrite the strings "true" and "false" with "1"
3282                     // and "0"
3283                     selectionArgs[i++] = convertStringToIntString(row.getAsString(field));
3284                 } else {
3285                     selectionArgs[i++] = row.getAsString(field);
3286                 }
3287             }
3288         }
3289 
3290         Cursor c = db.query(table, columns, selection, selectionArgs, null, null, null);
3291 
3292         if (c != null) {
3293             if (c.getCount() == 1) {
3294                 if (VDBG) log("dbh.selectConflictingRow: " + c.getCount() + " conflicting " +
3295                         "row found");
3296                 if (c.moveToFirst()) {
3297                     return c;
3298                 } else {
3299                     loge("dbh.selectConflictingRow: moveToFirst() failed");
3300                 }
3301             } else {
3302                 loge("dbh.selectConflictingRow: Expected 1 but found " + c.getCount() +
3303                         " matching rows found for cv " + row);
3304             }
3305             c.close();
3306         } else {
3307             loge("dbh.selectConflictingRow: Error - c is null; no matching row found for " +
3308                     "cv " + row);
3309         }
3310 
3311         return null;
3312     }
3313 
3314     /**
3315      * Convert "true" and "false" to "1" and "0".
3316      * If the passed in string is already "1" or "0" returns the passed in string.
3317      */
convertStringToIntString(String boolString)3318     private static String convertStringToIntString(String boolString) {
3319         if ("0".equals(boolString) || "false".equalsIgnoreCase(boolString)) return "0";
3320         return "1";
3321     }
3322 
3323     /**
3324      * Convert "1" and "0" to "true" and "false".
3325      * If the passed in string is already "true" or "false" returns the passed in string.
3326      */
convertStringToBoolString(String intString)3327     private static String convertStringToBoolString(String intString) {
3328         if ("0".equals(intString) || "false".equalsIgnoreCase(intString)) return "false";
3329         return "true";
3330     }
3331 
3332     /**
3333      * These methods can be overridden in a subclass for testing TelephonyProvider using an
3334      * in-memory database.
3335      */
getReadableDatabase()3336     SQLiteDatabase getReadableDatabase() {
3337         return mOpenHelper.getReadableDatabase();
3338     }
getWritableDatabase()3339     SQLiteDatabase getWritableDatabase() {
3340         return mOpenHelper.getWritableDatabase();
3341     }
initDatabaseWithDatabaseHelper(SQLiteDatabase db)3342     void initDatabaseWithDatabaseHelper(SQLiteDatabase db) {
3343         mOpenHelper.initDatabase(db);
3344     }
needApnDbUpdate()3345     boolean needApnDbUpdate() {
3346         return mOpenHelper.apnDbUpdateNeeded();
3347     }
3348 
apnSourceServiceExists(Context context)3349     private static boolean apnSourceServiceExists(Context context) {
3350         if (s_apnSourceServiceExists != null) {
3351             return s_apnSourceServiceExists;
3352         }
3353         try {
3354             String service = context.getResources().getString(R.string.apn_source_service);
3355             if (TextUtils.isEmpty(service)) {
3356                 s_apnSourceServiceExists = false;
3357             } else {
3358                 s_apnSourceServiceExists = context.getPackageManager().getServiceInfo(
3359                         ComponentName.unflattenFromString(service), 0)
3360                         != null;
3361             }
3362         } catch (PackageManager.NameNotFoundException e) {
3363             s_apnSourceServiceExists = false;
3364         }
3365         return s_apnSourceServiceExists;
3366     }
3367 
restoreApnsWithService(int subId)3368     private void restoreApnsWithService(int subId) {
3369         Context context = getContext();
3370         Resources r = context.getResources();
3371         AtomicBoolean connectionBindingInvalid = new AtomicBoolean(false);
3372         ServiceConnection connection = new ServiceConnection() {
3373             @Override
3374             public void onServiceConnected(ComponentName className,
3375                     IBinder service) {
3376                 log("restoreApnsWithService: onServiceConnected");
3377                 synchronized (mLock) {
3378                     mIApnSourceService = IApnSourceService.Stub.asInterface(service);
3379                     mLock.notifyAll();
3380                 }
3381             }
3382 
3383             @Override
3384             public void onServiceDisconnected(ComponentName arg0) {
3385                 loge("mIApnSourceService has disconnected unexpectedly");
3386                 synchronized (mLock) {
3387                     mIApnSourceService = null;
3388                 }
3389             }
3390 
3391             @Override
3392             public void onBindingDied(ComponentName name) {
3393                 loge("The binding to the apn service connection is dead: " + name);
3394                 synchronized (mLock) {
3395                     connectionBindingInvalid.set(true);
3396                     mLock.notifyAll();
3397                 }
3398             }
3399 
3400             @Override
3401             public void onNullBinding(ComponentName name) {
3402                 loge("Null binding: " + name);
3403                 synchronized (mLock) {
3404                     connectionBindingInvalid.set(true);
3405                     mLock.notifyAll();
3406                 }
3407             }
3408         };
3409 
3410         Intent intent = new Intent(IApnSourceService.class.getName());
3411         intent.setComponent(ComponentName.unflattenFromString(
3412                 r.getString(R.string.apn_source_service)));
3413         log("binding to service to restore apns, intent=" + intent);
3414         try {
3415             if (context.bindService(intent,
3416                     Context.BIND_IMPORTANT | Context.BIND_AUTO_CREATE,
3417                     runnable -> new Thread(runnable).start(),
3418                     connection)) {
3419                 synchronized (mLock) {
3420                     while (mIApnSourceService == null && !connectionBindingInvalid.get()) {
3421                         try {
3422                             mLock.wait();
3423                         } catch (InterruptedException e) {
3424                             loge("Error while waiting for service connection: " + e);
3425                         }
3426                     }
3427                     if (connectionBindingInvalid.get()) {
3428                         loge("The binding is invalid.");
3429                         return;
3430                     }
3431                     try {
3432                         ContentValues[] values = mIApnSourceService.getApns(subId);
3433                         if (values != null) {
3434                             // we use the unsynchronized insert because this function is called
3435                             // within the syncrhonized function delete()
3436                             unsynchronizedBulkInsert(CONTENT_URI, values);
3437                             log("restoreApnsWithService: restored");
3438                         }
3439                     } catch (RemoteException e) {
3440                         loge("Error applying apns from service: " + e);
3441                     }
3442                 }
3443             } else {
3444                 loge("unable to bind to service from intent=" + intent);
3445             }
3446         } catch (SecurityException e) {
3447             loge("Error applying apns from service: " + e);
3448         } finally {
3449             if (connection != null) {
3450                 context.unbindService(connection);
3451             }
3452             synchronized (mLock) {
3453                 mIApnSourceService = null;
3454             }
3455         }
3456     }
3457 
3458 
3459     @Override
onCreate()3460     public boolean onCreate() {
3461         mOpenHelper = new DatabaseHelper(getContext());
3462         mDefaultSubId = SubscriptionManager.getDefaultSubscriptionId();
3463         boolean isNewBuild = false;
3464         String newBuildId = SystemProperties.get("ro.build.id", null);
3465         SharedPreferences sp = getContext().getSharedPreferences(BUILD_ID_FILE,
3466                 Context.MODE_PRIVATE);
3467         if (!TextUtils.isEmpty(newBuildId)) {
3468             // Check if build id has changed
3469             String oldBuildId = sp.getString(RO_BUILD_ID, "");
3470             if (!newBuildId.equals(oldBuildId)) {
3471                 localLog("onCreate: build id changed from " + oldBuildId + " to " + newBuildId);
3472                 isNewBuild = true;
3473             } else {
3474                 if (VDBG) log("onCreate: build id did not change: " + oldBuildId);
3475             }
3476         } else {
3477             if (VDBG) log("onCreate: newBuildId is empty");
3478         }
3479 
3480         if (isNewBuild) {
3481             if (!apnSourceServiceExists(getContext())) {
3482                 // Update APN DB
3483                 updateApnDb();
3484             }
3485 
3486             // Add all APN related shared prefs to local log for dumpsys
3487             if (DBG) addAllApnSharedPrefToLocalLog();
3488         }
3489 
3490         // Write build id to SharedPreferences after APNs have been updated above by updateApnDb()
3491         if (!TextUtils.isEmpty(newBuildId)) {
3492             if (isNewBuild) log("onCreate: updating build id to " + newBuildId);
3493             sp.edit().putString(RO_BUILD_ID, newBuildId).apply();
3494         }
3495 
3496         SharedPreferences spEnforcedFile = getContext().getSharedPreferences(ENFORCED_FILE,
3497                 Context.MODE_PRIVATE);
3498         mManagedApnEnforced = spEnforcedFile.getBoolean(ENFORCED_KEY, false);
3499 
3500         ProviderUtil.logRunningTelephonyProviderProcesses(getContext());
3501         if (VDBG) log("onCreate:- ret true");
3502         return true;
3503     }
3504 
addAllApnSharedPrefToLocalLog()3505     private void addAllApnSharedPrefToLocalLog() {
3506         localLog("addAllApnSharedPrefToLocalLog");
3507         SharedPreferences spApn = getContext().getSharedPreferences(PREF_FILE_APN,
3508                 Context.MODE_PRIVATE);
3509 
3510         Map<String, ?> allPrefApnId = spApn.getAll();
3511         for (String key : allPrefApnId.keySet()) {
3512             try {
3513                 localLog(key + ":" + allPrefApnId.get(key).toString());
3514             } catch (Exception e) {
3515                 localLog("Skipping over key " + key + " due to exception " + e);
3516             }
3517         }
3518 
3519         SharedPreferences spFullApn = getContext().getSharedPreferences(PREF_FILE_FULL_APN,
3520                 Context.MODE_PRIVATE);
3521 
3522         Map<String, ?> allPrefFullApn = spFullApn.getAll();
3523         for (String key : allPrefFullApn.keySet()) {
3524             try {
3525                 localLog(key + ":" + allPrefFullApn.get(key).toString());
3526             } catch (Exception e) {
3527                 localLog("Skipping over key " + key + " due to exception " + e);
3528             }
3529         }
3530     }
3531 
localLog(String logMsg)3532     private void localLog(String logMsg) {
3533         Log.d(TAG, logMsg);
3534         mLocalLog.log(logMsg);
3535     }
3536 
isManagedApnEnforced()3537     private synchronized boolean isManagedApnEnforced() {
3538         return mManagedApnEnforced;
3539     }
3540 
setManagedApnEnforced(boolean enforced)3541     private void setManagedApnEnforced(boolean enforced) {
3542         SharedPreferences sp = getContext().getSharedPreferences(ENFORCED_FILE,
3543                 Context.MODE_PRIVATE);
3544         SharedPreferences.Editor editor = sp.edit();
3545         editor.putBoolean(ENFORCED_KEY, enforced);
3546         editor.apply();
3547         synchronized (this) {
3548             mManagedApnEnforced = enforced;
3549         }
3550     }
3551 
setPreferredApnId(Long id, int subId, boolean saveApn)3552     private void setPreferredApnId(Long id, int subId, boolean saveApn) {
3553         SharedPreferences sp = getContext().getSharedPreferences(PREF_FILE_APN,
3554                 Context.MODE_PRIVATE);
3555         SharedPreferences.Editor editor = sp.edit();
3556         editor.putLong(COLUMN_APN_ID + subId, id != null ? id : INVALID_APN_ID);
3557         localLog("setPreferredApnId: " + COLUMN_APN_ID + subId + ":"
3558                 + (id != null ? id : INVALID_APN_ID));
3559         // This is for debug purposes. It indicates if this APN was set by DcTracker or user (true)
3560         // or if this was restored from APN saved in PREF_FILE_FULL_APN (false).
3561         editor.putBoolean(EXPLICIT_SET_CALLED + subId, saveApn);
3562         localLog("setPreferredApnId: " + EXPLICIT_SET_CALLED + subId + ":" + saveApn);
3563         editor.apply();
3564         if (id == null || id.longValue() == INVALID_APN_ID) {
3565             deletePreferredApn(subId);
3566         } else {
3567             // If id is not invalid, and saveApn is true, save the actual APN in PREF_FILE_FULL_APN
3568             // too.
3569             if (saveApn) {
3570                 setPreferredApn(id, subId);
3571             }
3572         }
3573     }
3574 
getPreferredApnId(int subId, boolean checkApnSp)3575     private long getPreferredApnId(int subId, boolean checkApnSp) {
3576         SharedPreferences sp = getContext().getSharedPreferences(PREF_FILE_APN,
3577                 Context.MODE_PRIVATE);
3578         long apnId = sp.getLong(COLUMN_APN_ID + subId, INVALID_APN_ID);
3579         if (apnId == INVALID_APN_ID && checkApnSp) {
3580             apnId = getPreferredApnIdFromApn(subId);
3581             if (apnId != INVALID_APN_ID) {
3582                 setPreferredApnId(apnId, subId, false);
3583             }
3584         }
3585         return apnId;
3586     }
3587 
getPreferredApnSetId(int subId)3588     private int getPreferredApnSetId(int subId) {
3589         SharedPreferences sp = getContext().getSharedPreferences(PREF_FILE_FULL_APN,
3590                 Context.MODE_PRIVATE);
3591         try {
3592             return Integer.parseInt(sp.getString(APN_SET_ID + subId, null));
3593         } catch (NumberFormatException e) {
3594             return NO_APN_SET_ID;
3595         }
3596     }
3597 
deletePreferredApnId(Context context)3598     private void deletePreferredApnId(Context context) {
3599         SharedPreferences sp = context.getSharedPreferences(PREF_FILE_APN,
3600                 Context.MODE_PRIVATE);
3601         SharedPreferences.Editor editor = sp.edit();
3602         editor.clear();
3603         editor.apply();
3604     }
3605 
setPreferredApn(Long id, int subId)3606     private void setPreferredApn(Long id, int subId) {
3607         localLog("setPreferredApn: _id " + id + " subId " + subId);
3608         SQLiteDatabase db = getWritableDatabase();
3609         // query all unique fields from id
3610         String[] proj = CARRIERS_UNIQUE_FIELDS.toArray(new String[CARRIERS_UNIQUE_FIELDS.size()]);
3611 
3612         Cursor c = db.query(CARRIERS_TABLE, proj, "_id=" + id, null, null, null, null);
3613         if (c != null) {
3614             if (c.getCount() == 1) {
3615                 c.moveToFirst();
3616                 SharedPreferences sp = getContext().getSharedPreferences(PREF_FILE_FULL_APN,
3617                         Context.MODE_PRIVATE);
3618                 SharedPreferences.Editor editor = sp.edit();
3619                 // store values of all unique fields to SP
3620                 for (String key : CARRIERS_UNIQUE_FIELDS) {
3621                     editor.putString(key + subId, c.getString(c.getColumnIndex(key)));
3622                     localLog("setPreferredApn: " + key + subId + ":"
3623                             + c.getString(c.getColumnIndex(key)));
3624                 }
3625                 // also store the version number
3626                 editor.putString(DB_VERSION_KEY + subId, "" + DATABASE_VERSION);
3627                 localLog("setPreferredApn: " + DB_VERSION_KEY + subId + ":" + DATABASE_VERSION);
3628                 editor.apply();
3629             } else {
3630                 log("setPreferredApn: # matching APNs found " + c.getCount());
3631             }
3632             c.close();
3633         } else {
3634             log("setPreferredApn: No matching APN found");
3635         }
3636     }
3637 
getPreferredApnIdFromApn(int subId)3638     private long getPreferredApnIdFromApn(int subId) {
3639         log("getPreferredApnIdFromApn: for subId " + subId);
3640         SQLiteDatabase db = getReadableDatabase();
3641 
3642         List<String> whereList = new ArrayList<>();
3643         List<String> whereArgsList = new ArrayList<>();
3644         SharedPreferences sp = getContext().getSharedPreferences(PREF_FILE_FULL_APN,
3645                 Context.MODE_PRIVATE);
3646         for (String key : CARRIERS_UNIQUE_FIELDS) {
3647             String value = sp.getString(key + subId, null);
3648             if (value == null) {
3649                 continue;
3650             } else {
3651                 whereList.add(key);
3652                 whereArgsList.add(value);
3653             }
3654         }
3655         if (whereList.size() == 0) return INVALID_APN_ID;
3656 
3657         String where = TextUtils.join("=? and ", whereList) + "=?";
3658         String[] whereArgs = new String[whereArgsList.size()];
3659         whereArgs = whereArgsList.toArray(whereArgs);
3660 
3661         long apnId = INVALID_APN_ID;
3662         Cursor c = db.query(CARRIERS_TABLE, new String[]{"_id"}, where, whereArgs, null, null,
3663                 null);
3664         if (c != null) {
3665             if (c.getCount() == 1) {
3666                 c.moveToFirst();
3667                 apnId = c.getInt(c.getColumnIndex("_id"));
3668             } else {
3669                 log("getPreferredApnIdFromApn: returning INVALID. # matching APNs found " +
3670                         c.getCount());
3671             }
3672             c.close();
3673         } else {
3674             log("getPreferredApnIdFromApn: returning INVALID. No matching APN found");
3675         }
3676         return apnId;
3677     }
3678 
deletePreferredApn(int subId)3679     private void deletePreferredApn(int subId) {
3680         log("deletePreferredApn: for subId " + subId);
3681         SharedPreferences sp = getContext().getSharedPreferences(PREF_FILE_FULL_APN,
3682                 Context.MODE_PRIVATE);
3683         if (sp.contains(DB_VERSION_KEY + subId)) {
3684             log("deletePreferredApn: apn is stored. Deleting it now for subId " + subId);
3685             SharedPreferences.Editor editor = sp.edit();
3686             editor.remove(DB_VERSION_KEY + subId);
3687             for (String key : CARRIERS_UNIQUE_FIELDS) {
3688                 editor.remove(key + subId);
3689             }
3690             editor.apply();
3691         }
3692     }
3693 
isCallingFromSystemOrPhoneUid()3694     boolean isCallingFromSystemOrPhoneUid() {
3695         int callingUid = mInjector.binderGetCallingUid();
3696         return TelephonyPermissions.isSystemOrPhone(callingUid)
3697                 // Allow ROOT for testing. ROOT can access underlying DB files anyways.
3698                 || UserHandle.isSameApp(callingUid, Process.ROOT_UID);
3699     }
3700 
ensureCallingFromSystemOrPhoneUid(String message)3701     void ensureCallingFromSystemOrPhoneUid(String message) {
3702         if (!isCallingFromSystemOrPhoneUid()) {
3703             throw new SecurityException(message);
3704         }
3705     }
3706 
3707     @Override
call(String method, @Nullable String args, @Nullable Bundle bundle)3708     public synchronized Bundle call(String method, @Nullable String args, @Nullable Bundle bundle) {
3709         if (SubscriptionManager.GET_SIM_SPECIFIC_SETTINGS_METHOD_NAME.equals(method)) {
3710             getContext().enforceCallingOrSelfPermission(
3711                     android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, TAG);
3712             final long identity = Binder.clearCallingIdentity();
3713             try {
3714                 return retrieveSimSpecificSettings();
3715             } finally {
3716                 Binder.restoreCallingIdentity(identity);
3717             }
3718         } else if (SubscriptionManager.RESTORE_SIM_SPECIFIC_SETTINGS_METHOD_NAME.equals(method)) {
3719             getContext().enforceCallingOrSelfPermission(
3720                     android.Manifest.permission.MODIFY_PHONE_STATE, TAG);
3721             final long identity = Binder.clearCallingIdentity();
3722             try {
3723                 Bundle resultBundle = new Bundle();
3724                 boolean changed = restoreSimSpecificSettings(bundle, args);
3725                 if (changed) {
3726                     mLocalLog.log("Restoration changed the subscription database.");
3727                     log("Restoration changed the subscription database.");
3728                 }
3729                 resultBundle.putBoolean(
3730                         SubscriptionManager.RESTORE_SIM_SPECIFIC_SETTINGS_DATABASE_UPDATED,
3731                         changed);
3732                 return resultBundle;
3733             } finally {
3734                 Binder.restoreCallingIdentity(identity);
3735             }
3736         } else {
3737             loge("method is not recognized");
3738         }
3739 
3740         return null;
3741     }
3742 
3743     /**
3744      * See {@link SubscriptionController#GET_SIM_SPECIFIC_SETTINGS_METHOD_NAME} for details
3745      */
retrieveSimSpecificSettings()3746     private Bundle retrieveSimSpecificSettings() {
3747         Bundle resultBundle = new Bundle();
3748         resultBundle.putByteArray(SubscriptionManager.KEY_SIM_SPECIFIC_SETTINGS_DATA,
3749                 getSimSpecificDataToBackUp());
3750 
3751         return resultBundle;
3752     }
3753 
3754     /**
3755      * Attempts to restore the backed up sim-specific configs to device. End result is SimInfoDB is
3756      * modified to match any backed up configs for the appropriate inserted sims.
3757      *
3758      * @param bundle containing the data to be restored. If {@code null}, then backed up
3759      * data should already be in internal storage and will be retrieved from there.
3760      * @param iccId of the SIM that a restore is being attempted for. If {@code null}, then try to
3761      * restore for all simInfo entries in SimInfoDB
3762      *
3763      * @return {@code true} if the restoration changed the subscription database.
3764      */
restoreSimSpecificSettings(@ullable Bundle bundle, @Nullable String iccId)3765     private boolean restoreSimSpecificSettings(@Nullable Bundle bundle, @Nullable String iccId) {
3766         int restoreCase = TelephonyProtoEnums.SIM_RESTORE_CASE_UNDEFINED_USE_CASE;
3767         if (bundle != null) {
3768             restoreCase = TelephonyProtoEnums.SIM_RESTORE_CASE_SUW;
3769             if (!writeSimSettingsToInternalStorage(
3770                     bundle.getByteArray(SubscriptionManager.KEY_SIM_SPECIFIC_SETTINGS_DATA))) {
3771                 return false;
3772             }
3773         } else if (iccId != null){
3774             restoreCase = TelephonyProtoEnums.SIM_RESTORE_CASE_SIM_INSERTED;
3775         }
3776         return mergeBackedUpDataToSimInfoDb(restoreCase, iccId);
3777     }
3778 
3779     @VisibleForTesting
writeSimSettingsToInternalStorage(byte[] data)3780     boolean writeSimSettingsToInternalStorage(byte[] data) {
3781         AtomicFile atomicFile = new AtomicFile(
3782                 new File(getContext().getFilesDir(), BACKED_UP_SIM_SPECIFIC_SETTINGS_FILE));
3783         FileOutputStream fos = null;
3784         try {
3785             fos = atomicFile.startWrite();
3786             fos.write(data);
3787             atomicFile.finishWrite(fos);
3788         } catch (IOException e) {
3789             if (fos != null) {
3790                 atomicFile.failWrite(fos);
3791             }
3792             loge("Not able to create internal file with per-sim configs. Failed with error "
3793                     + e);
3794             return false;
3795         }
3796 
3797         return true;
3798     }
3799 
3800     /**
3801      * Attempt to match any SimInfoDB entries to what is in the internal backup data file and
3802      * update DB entry with the adequate backed up data.
3803      *
3804      * @param restoreCase one of the SimSpecificSettingsRestoreMatchingCriteria values defined in
3805      * frameworks/proto_logging/stats/enums/telephony/enums.proto
3806      * @param iccId of the SIM that a restore is being attempted for. If {@code null}, then try to
3807      * restore for all simInfo entries in SimInfoDB
3808      *
3809      * @return {@code true} if the restoration changed the subscription database.
3810      */
mergeBackedUpDataToSimInfoDb(int restoreCase, @Nullable String iccId)3811     private boolean mergeBackedUpDataToSimInfoDb(int restoreCase, @Nullable String iccId) {
3812         // Get data stored in internal file
3813         File file = new File(getContext().getFilesDir(), BACKED_UP_SIM_SPECIFIC_SETTINGS_FILE);
3814         if (!file.exists()) {
3815             loge("internal sim-specific settings backup data file does not exist. "
3816                 + "Aborting restore");
3817             return false;
3818         }
3819 
3820         AtomicFile atomicFile = new AtomicFile(file);
3821         PersistableBundle bundle = null;
3822         try (FileInputStream fis = atomicFile.openRead()) {
3823             bundle = PersistableBundle.readFromStream(fis);
3824         } catch (IOException e) {
3825             loge("Failed to convert backed up per-sim configs to bundle. Stopping restore. "
3826                 + "Failed with error " + e);
3827             return false;
3828         }
3829 
3830         String selection = null;
3831         String[] selectionArgs = null;
3832         if (iccId != null) {
3833             selection = Telephony.SimInfo.COLUMN_ICC_ID + "=?";
3834             selectionArgs = new String[]{iccId};
3835         }
3836         try (Cursor cursor = query(
3837                 SubscriptionManager.CONTENT_URI,
3838                 new String[] {
3839                         Telephony.SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID,
3840                         Telephony.SimInfo.COLUMN_ICC_ID,
3841                         Telephony.SimInfo.COLUMN_NUMBER,
3842                         Telephony.SimInfo.COLUMN_CARRIER_ID,
3843                         Telephony.SimInfo.COLUMN_ISO_COUNTRY_CODE,
3844                         Telephony.SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS,
3845                 },
3846                 selection,
3847                 selectionArgs,
3848                 ORDER_BY_SUB_ID)) {
3849             return findAndRestoreAllMatches(bundle.deepCopy(), cursor, restoreCase);
3850         }
3851     }
3852 
3853     /**
3854      * Find the matched subscription and restore SIM specific settings to them.
3855      *
3856      * @param backedUpDataBundle The backed-up data to be restored.
3857      * @param cursor The database cursor.
3858      * @param restoreCase one of the SimSpecificSettingsRestoreMatchingCriteria values defined in
3859      * frameworks/proto_logging/stats/enums/telephony/enums.proto
3860      *
3861      * @return {@code true} if the restoration changed the subscription database.
3862      */
findAndRestoreAllMatches(PersistableBundle backedUpDataBundle, Cursor cursor, int restoreCase)3863     private boolean findAndRestoreAllMatches(PersistableBundle backedUpDataBundle, Cursor cursor,
3864             int restoreCase) {
3865         boolean changed = false;
3866         int[] previouslyRestoredSubIdsArray =
3867                 backedUpDataBundle.getIntArray(KEY_PREVIOUSLY_RESTORED_SUB_IDS);
3868         List<Integer> previouslyRestoredSubIdsList = previouslyRestoredSubIdsArray != null
3869                 ? Arrays.stream(previouslyRestoredSubIdsArray).boxed().collect(Collectors.toList())
3870                 : new ArrayList<>();
3871         List<Integer> newlyRestoredSubIds = new ArrayList<>();
3872         int backupDataFormatVersion = backedUpDataBundle
3873                 .getInt(KEY_BACKUP_DATA_FORMAT_VERSION, -1);
3874 
3875         Resources r = getContext().getResources();
3876         List<String> wfcRestoreBlockedCountries = Arrays.asList(r.getStringArray(
3877                     R.array.wfc_restore_blocked_countries));
3878 
3879         while (cursor != null && cursor.moveToNext()) {
3880             // Get all the possible matching criteria.
3881             int subIdColumnIndex = cursor.getColumnIndex(
3882                     Telephony.SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID);
3883             int currSubIdFromDb = cursor.getInt(subIdColumnIndex);
3884 
3885             if (previouslyRestoredSubIdsList.contains(currSubIdFromDb)) {
3886                 // Abort restore for any sims that were previously restored.
3887                 continue;
3888             }
3889 
3890             int iccIdColumnIndex = cursor.getColumnIndex(Telephony.SimInfo.COLUMN_ICC_ID);
3891             String currIccIdFromDb = cursor.getString(iccIdColumnIndex);
3892 
3893             int phoneNumberColumnIndex = cursor.getColumnIndex(Telephony.SimInfo.COLUMN_NUMBER);
3894             String currPhoneNumberFromDb = cursor.getString(phoneNumberColumnIndex);
3895 
3896             int carrierIdColumnIndex = cursor.getColumnIndex(Telephony.SimInfo.COLUMN_CARRIER_ID);
3897             int currCarrierIdFromDb = cursor.getInt(carrierIdColumnIndex);
3898 
3899             int isoCountryCodeColumnIndex = cursor.getColumnIndex(
3900                     Telephony.SimInfo.COLUMN_ISO_COUNTRY_CODE);
3901             String isoCountryCodeFromDb = cursor.getString(isoCountryCodeColumnIndex);
3902 
3903             int allowedNetworkTypesForReasonsIndex = cursor.getColumnIndex(
3904                     Telephony.SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS);
3905             String allowedNetworkTypesForReasonsFromDb =
3906                     cursor.getString(allowedNetworkTypesForReasonsIndex);
3907 
3908             // Find the best match from backed up data.
3909             SimRestoreMatch bestRestoreMatch = null;
3910             for (int rowNum = 0; true; rowNum++) {
3911                 PersistableBundle currRow = backedUpDataBundle.getPersistableBundle(
3912                         KEY_SIMINFO_DB_ROW_PREFIX + rowNum);
3913                 if (currRow == null) {
3914                     break;
3915                 }
3916 
3917                 SimRestoreMatch currSimRestoreMatch = new SimRestoreMatch(
3918                         currIccIdFromDb, currCarrierIdFromDb, currPhoneNumberFromDb,
3919                         isoCountryCodeFromDb, allowedNetworkTypesForReasonsFromDb,
3920                         wfcRestoreBlockedCountries, currRow,
3921                         backupDataFormatVersion);
3922 
3923                 if (currSimRestoreMatch == null) {
3924                     continue;
3925                 }
3926 
3927                 /*
3928                  * The three following match cases are ordered by descending priority:
3929                  *   - Match by iccId: If iccId of backup data matches iccId of any inserted sims,
3930                  *       we confidently restore all configs.
3931                  *   - Match phone number and carrierId: If both of these values match, we
3932                  *       confidently restore all configs.
3933                  *   - Match only carrierId: If only carrierId of backup data matches an inserted
3934                  *       sim, we only restore non-sensitive configs.
3935                  *
3936                  * Having a matchScore value for each match allows us to control these priorities.
3937                  */
3938                 if (bestRestoreMatch == null || (currSimRestoreMatch.getMatchScore()
3939                         >= bestRestoreMatch.getMatchScore()
3940                         && currSimRestoreMatch.getContentValues() != null)) {
3941                     bestRestoreMatch = currSimRestoreMatch;
3942                 }
3943             }
3944 
3945             if (bestRestoreMatch != null) {
3946                 ContentValues newContentValues = bestRestoreMatch.getContentValues();
3947                 if (bestRestoreMatch.getMatchScore() != 0 && newContentValues != null) {
3948                     if (restoreCase == TelephonyProtoEnums.SIM_RESTORE_CASE_SUW) {
3949                         if (update(SubscriptionManager.SIM_INFO_SUW_RESTORE_CONTENT_URI,
3950                                 newContentValues,
3951                                 Telephony.SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID + "=?",
3952                                 new String[]{Integer.toString(currSubIdFromDb)}) > 0) {
3953                             mLocalLog.log("Restored sub " + currSubIdFromDb + " from backup"
3954                                     + ". case=SUW");
3955                             log("Restored sub " + currSubIdFromDb + " from backup. case=SUW");
3956                             changed = true;
3957                         }
3958                     } else if (restoreCase == TelephonyProtoEnums.SIM_RESTORE_CASE_SIM_INSERTED) {
3959                         Uri simInsertedRestoreUri = Uri.withAppendedPath(
3960                                 SubscriptionManager.SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI,
3961                                 SIM_INSERTED_RESTORE_URI_SUFFIX);
3962                         if (update(simInsertedRestoreUri,
3963                                 newContentValues,
3964                                 Telephony.SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID + "=?",
3965                                 new String[]{Integer.toString(currSubIdFromDb)}) > 0) {
3966                             mLocalLog.log("Restored sub " + currSubIdFromDb + " from backup. "
3967                                     + "case=SIM inserted.");
3968                             log("Restored sub " + currSubIdFromDb + " from backup. "
3969                                     + "case=SIM inserted.");
3970                             changed = true;
3971                         }
3972                     }
3973                     log("Restore of inserted SIM's sim-specific settings has been successfully "
3974                             + "completed.");
3975                     TelephonyStatsLog.write(TelephonyStatsLog.SIM_SPECIFIC_SETTINGS_RESTORED,
3976                             TelephonyProtoEnums.SIM_RESTORE_RESULT_SUCCESS,
3977                             restoreCase, bestRestoreMatch.getMatchingCriteriaForLogging());
3978                     newlyRestoredSubIds.add(currSubIdFromDb);
3979                 } else {
3980                     /* If this block was reached because ContentValues was null, that means the
3981                     database schema was newer during backup than during restore. We consider this
3982                     a no-match to avoid updating columns that don't exist */
3983                     TelephonyStatsLog.write(TelephonyStatsLog.SIM_SPECIFIC_SETTINGS_RESTORED,
3984                             TelephonyProtoEnums.SIM_RESTORE_RESULT_NONE_MATCH,
3985                             restoreCase, bestRestoreMatch.getMatchingCriteriaForLogging());
3986                 }
3987             } else {
3988                 log("No matching SIM in backup data. SIM-specific settings not restored.");
3989                 TelephonyStatsLog.write(TelephonyStatsLog.SIM_SPECIFIC_SETTINGS_RESTORED,
3990                         TelephonyProtoEnums.SIM_RESTORE_RESULT_ZERO_SIM_IN_BACKUP,
3991                         restoreCase, TelephonyProtoEnums.SIM_RESTORE_MATCHING_CRITERIA_NONE);
3992             }
3993         }
3994 
3995         // Update the internal file with subIds that we just restored.
3996         previouslyRestoredSubIdsList.addAll(newlyRestoredSubIds);
3997         backedUpDataBundle.putIntArray(
3998                 KEY_PREVIOUSLY_RESTORED_SUB_IDS,
3999                 previouslyRestoredSubIdsList.stream().mapToInt(i -> i).toArray());
4000         try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
4001             backedUpDataBundle.writeToStream(outputStream);
4002             writeSimSettingsToInternalStorage(outputStream.toByteArray());
4003         } catch (IOException e) {
4004             loge("Not able to convert SimInfoDB to byte array. Not storing which subIds were "
4005                     + "restored");
4006         }
4007         return changed;
4008     }
4009 
4010     private static class SimRestoreMatch {
4011 
4012         private Set<Integer> matches = new ArraySet<>();
4013         private int subId;
4014         private ContentValues contentValues;
4015         private int matchingCriteria;
4016         private int matchScore;
4017 
4018         private static final int ICCID_MATCH = 1;
4019         private static final int PHONE_NUMBER_MATCH = 2;
4020         private static final int CARRIER_ID_MATCH = 3;
4021 
SimRestoreMatch(String iccIdFromDb, int carrierIdFromDb, String phoneNumberFromDb, String isoCountryCodeFromDb, String allowedNetworkTypesForReasonsFromDb, List<String> wfcRestoreBlockedCountries, PersistableBundle backedUpSimInfoEntry, int backupDataFormatVersion)4022         public SimRestoreMatch(String iccIdFromDb, int carrierIdFromDb,
4023                 String phoneNumberFromDb, String isoCountryCodeFromDb,
4024                 String allowedNetworkTypesForReasonsFromDb,
4025                 List<String> wfcRestoreBlockedCountries,
4026                 PersistableBundle backedUpSimInfoEntry, int backupDataFormatVersion) {
4027             subId = backedUpSimInfoEntry.getInt(
4028                 Telephony.SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID,
4029                 DEFAULT_INT_COLUMN_VALUE);
4030             String iccIdFromBackup = backedUpSimInfoEntry.getString(Telephony.SimInfo.COLUMN_ICC_ID,
4031                   "");
4032             String phoneNumberFromBackup = backedUpSimInfoEntry.getString(
4033                   Telephony.SimInfo.COLUMN_NUMBER, "");
4034             int carrierIdFromBackup = backedUpSimInfoEntry.getInt(
4035                   Telephony.SimInfo.COLUMN_CARRIER_ID,
4036                   TelephonyManager.UNKNOWN_CARRIER_ID);
4037 
4038 
4039             // find all matching fields
4040             if (iccIdFromDb != null && iccIdFromDb.equals(iccIdFromBackup)
4041                     && !iccIdFromBackup.isEmpty()) {
4042                 matches.add(ICCID_MATCH);
4043             }
4044             if (carrierIdFromDb == carrierIdFromBackup
4045                     && carrierIdFromBackup != TelephonyManager.UNKNOWN_CARRIER_ID) {
4046                 matches.add(CARRIER_ID_MATCH);
4047             }
4048             if (phoneNumberFromDb != null && phoneNumberFromDb.equals(phoneNumberFromBackup)
4049                     && !phoneNumberFromBackup.isEmpty()) {
4050                 matches.add(PHONE_NUMBER_MATCH);
4051             }
4052 
4053             contentValues = convertBackedUpDataToContentValues(
4054                     backedUpSimInfoEntry, backupDataFormatVersion, isoCountryCodeFromDb,
4055                     allowedNetworkTypesForReasonsFromDb, wfcRestoreBlockedCountries);
4056             matchScore = calculateMatchScore();
4057             matchingCriteria = calculateMatchingCriteria();
4058         }
4059 
getSubId()4060         public int getSubId() {
4061             return subId;
4062         }
4063 
getContentValues()4064         public ContentValues getContentValues() {
4065             return contentValues;
4066         }
4067 
getMatchScore()4068         public int getMatchScore() {
4069             return matchScore;
4070         }
4071 
calculateMatchScore()4072         private int calculateMatchScore() {
4073             int score = 0;
4074 
4075             if (matches.contains(ICCID_MATCH)) {
4076                 score += 100;
4077             }
4078             if (matches.contains(CARRIER_ID_MATCH)) {
4079                 if (matches.contains(PHONE_NUMBER_MATCH)) {
4080                     score += 10;
4081                 } else {
4082                     score += 1;
4083                 }
4084             }
4085 
4086             return score;
4087         }
4088 
getMatchingCriteriaForLogging()4089         public int getMatchingCriteriaForLogging() {
4090             return matchingCriteria;
4091         }
4092 
calculateMatchingCriteria()4093         private int calculateMatchingCriteria() {
4094             if (matches.contains(ICCID_MATCH)) {
4095                 return TelephonyProtoEnums.SIM_RESTORE_MATCHING_CRITERIA_ICCID;
4096             }
4097             if (matches.contains(CARRIER_ID_MATCH)) {
4098                 if (matches.contains(PHONE_NUMBER_MATCH)) {
4099                     return TelephonyProtoEnums
4100                         .SIM_RESTORE_MATCHING_CRITERIA_CARRIER_ID_AND_PHONE_NUMBER;
4101                 } else {
4102                     return TelephonyProtoEnums.SIM_RESTORE_MATCHING_CRITERIA_CARRIER_ID_ONLY;
4103                 }
4104             }
4105             return TelephonyProtoEnums.SIM_RESTORE_MATCHING_CRITERIA_NONE;
4106         }
4107 
convertBackedUpDataToContentValues( PersistableBundle backedUpSimInfoEntry, int backupDataFormatVersion, String isoCountryCodeFromDb, String allowedNetworkTypesForReasonsFromDb, List<String> wfcRestoreBlockedCountries)4108         private ContentValues convertBackedUpDataToContentValues(
4109                 PersistableBundle backedUpSimInfoEntry, int backupDataFormatVersion,
4110                 String isoCountryCodeFromDb, String allowedNetworkTypesForReasonsFromDb,
4111                 List<String> wfcRestoreBlockedCountries) {
4112             if (DATABASE_VERSION != 74 << 16) {
4113                 throw new AssertionError("The database schema has been updated which might make "
4114                     + "the format of #BACKED_UP_SIM_SPECIFIC_SETTINGS_FILE outdated. Make sure to "
4115                     + "1) review whether any of the columns in #SIM_INFO_COLUMNS_TO_BACKUP have "
4116                     + "been migrated or deleted, 2) add the new column name into one of those "
4117                     + "maps, 3) add migration code in this method as necessary, and 4) update the "
4118                     + "version check in this if statement.");
4119             }
4120             ContentValues contentValues = new ContentValues();
4121             // Don't restore anything if restoring from a newer version of the current database.
4122             if (backupDataFormatVersion > DATABASE_VERSION) {
4123                 return null;
4124             }
4125 
4126             /* Any migration logic should be placed under this comment block.
4127              * ex:
4128              *   if (backupDataFormatVersion >= 48 << 19) {
4129              *     contentValues.put(NEW_COLUMN_NAME_2,
4130              *         backedUpSimInfoEntry.getInt( OLD_COLUMN_NAME, DEFAULT_INT_COLUMN_VALUE));
4131              *     ...
4132              *   } else if (backupDataFormatVersion >= 48 << 17) {
4133              *     contentValues.put(NEW_COLUMN_NAME_1,
4134              *         backedUpSimInfoEntry.getInt(OLD_COLUMN_NAME, DEFAULT_INT_COLUMN_VALUE));
4135              *     ...
4136              *   } else {
4137              *     // The values from the first format of backup ever available.
4138              *     contentValues.put(Telephony.SimInfo.COLUMN_IMS_RCS_UCE_ENABLED,
4139              *         backedUpSimInfoEntry.getInt(
4140              *             Telephony.SimInfo.COLUMN_IMS_RCS_UCE_ENABLED,
4141              *             DEFAULT_INT_COLUMN_VALUE));
4142              *     contentValues.put(Telephony.SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED,
4143              *         backedUpSimInfoEntry.getString(
4144              *              Telephony.SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED, ""));
4145              *     contentValues.put(Telephony.SimInfo.COLUMN_VT_IMS_ENABLED,
4146              *               backedUpSimInfoEntry.getString(Telephony.SimInfo.COLUMN_VT_IMS_ENABLED,
4147              *               ""));
4148              *     ...
4149              *   }
4150              *
4151              * Also make sure to add necessary removal of sensitive settings in
4152              * polishContentValues(ContentValues contentValues).
4153              */
4154             if (backupDataFormatVersion >= 74 << 16) {
4155                 contentValues.put(Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_BARRED_PLMNS,
4156                         backedUpSimInfoEntry.getString(
4157                                 Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_BARRED_PLMNS,
4158                                 DEFAULT_STRING_COLUMN_VALUE));
4159                 contentValues.put(Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_DATA_PLAN_PLMNS,
4160                         backedUpSimInfoEntry.getString(
4161                                 Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_DATA_PLAN_PLMNS,
4162                                 DEFAULT_STRING_COLUMN_VALUE));
4163                 contentValues.put(Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_SERVICE_TYPE_MAP,
4164                         backedUpSimInfoEntry.getString(
4165                                 Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_SERVICE_TYPE_MAP,
4166                                 DEFAULT_STRING_COLUMN_VALUE));
4167                 contentValues.put(
4168                         Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_DATA_SERVICE_POLICY,
4169                         backedUpSimInfoEntry.getString(
4170                                 Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_DATA_SERVICE_POLICY,
4171                                 DEFAULT_STRING_COLUMN_VALUE));
4172                 contentValues.put(
4173                         Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_VOICE_SERVICE_POLICY,
4174                         backedUpSimInfoEntry.getString(
4175                                 Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_VOICE_SERVICE_POLICY,
4176                                 DEFAULT_STRING_COLUMN_VALUE));
4177 
4178             }
4179             if (backupDataFormatVersion >= 73 << 16) {
4180                 contentValues.put(
4181                         Telephony.SimInfo.COLUMN_IS_SATELLITE_PROVISIONED_FOR_NON_IP_DATAGRAM,
4182                         backedUpSimInfoEntry.getInt(
4183                                 Telephony.SimInfo
4184                                         .COLUMN_IS_SATELLITE_PROVISIONED_FOR_NON_IP_DATAGRAM,
4185                                 DEFAULT_INT_COLUMN_VALUE));
4186             }
4187             if (backupDataFormatVersion >= 72 << 16) {
4188                 contentValues.put(Telephony.SimInfo.COLUMN_SATELLITE_ESOS_SUPPORTED,
4189                         backedUpSimInfoEntry.getInt(
4190                                 Telephony.SimInfo.COLUMN_SATELLITE_ESOS_SUPPORTED,
4191                                 DEFAULT_INT_COLUMN_VALUE));
4192             }
4193             if (backupDataFormatVersion >= 71 << 16) {
4194                 contentValues.put(Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_STATUS,
4195                         backedUpSimInfoEntry.getInt(
4196                                 Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_STATUS,
4197                                 DEFAULT_INT_COLUMN_VALUE));
4198                 contentValues.put(Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_PLMNS,
4199                         backedUpSimInfoEntry.getString(
4200                                 Telephony.SimInfo.COLUMN_SATELLITE_ENTITLEMENT_PLMNS,
4201                                 DEFAULT_STRING_COLUMN_VALUE));
4202                 contentValues.put(Telephony.SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS,
4203                         replaceEnable2g(
4204                                 allowedNetworkTypesForReasonsFromDb,
4205                                 backedUpSimInfoEntry.getString(Telephony.SimInfo
4206                                                 .COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS),
4207                                 DEFAULT_STRING_COLUMN_VALUE));
4208             }
4209             if (backupDataFormatVersion >= 70 << 16) {
4210                 contentValues.put(Telephony.SimInfo.COLUMN_TRANSFER_STATUS,
4211                         backedUpSimInfoEntry.getInt(Telephony.SimInfo.COLUMN_TRANSFER_STATUS,
4212                                 DEFAULT_INT_COLUMN_VALUE));
4213             }
4214             if (backupDataFormatVersion >= 64 << 16) {
4215                 contentValues.put(Telephony.SimInfo.COLUMN_IS_ONLY_NTN,
4216                         backedUpSimInfoEntry.getInt(Telephony.SimInfo.COLUMN_IS_ONLY_NTN,
4217                                 DEFAULT_INT_COLUMN_VALUE));
4218             }
4219             if (backupDataFormatVersion >= 63 << 16) {
4220                 contentValues.put(Telephony.SimInfo.COLUMN_SATELLITE_ATTACH_ENABLED_FOR_CARRIER,
4221                         backedUpSimInfoEntry.getInt(
4222                                 Telephony.SimInfo.COLUMN_SATELLITE_ATTACH_ENABLED_FOR_CARRIER,
4223                                 DEFAULT_INT_COLUMN_VALUE));
4224             }
4225             if (backupDataFormatVersion >= 62 << 16) {
4226                 contentValues.put(Telephony.SimInfo.COLUMN_SATELLITE_ENABLED,
4227                         backedUpSimInfoEntry.getInt(
4228                                 Telephony.SimInfo.COLUMN_SATELLITE_ENABLED,
4229                                 DEFAULT_INT_COLUMN_VALUE));
4230             }
4231             if (backupDataFormatVersion >= 60 << 16) {
4232                 contentValues.put(Telephony.SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES,
4233                         backedUpSimInfoEntry.getString(
4234                                 Telephony.SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES,
4235                                 DEFAULT_STRING_COLUMN_VALUE));
4236             }
4237             if (backupDataFormatVersion >= 57 << 16) {
4238                 contentValues.put(Telephony.SimInfo.COLUMN_USAGE_SETTING,
4239                         backedUpSimInfoEntry.getInt(
4240                                 Telephony.SimInfo.COLUMN_USAGE_SETTING,
4241                                 DEFAULT_INT_COLUMN_VALUE));
4242             }
4243             if (backupDataFormatVersion >= 52 << 16) {
4244                 contentValues.put(Telephony.SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED,
4245                         backedUpSimInfoEntry.getInt(
4246                                 Telephony.SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED,
4247                                 DEFAULT_INT_COLUMN_VALUE));
4248             }
4249             if (backupDataFormatVersion >= 51 << 16) {
4250                 contentValues.put(Telephony.SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS,
4251                         backedUpSimInfoEntry.getString(
4252                                 Telephony.SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS,
4253                                 DEFAULT_STRING_COLUMN_VALUE));
4254             }
4255             if (backupDataFormatVersion >= 50 << 16) {
4256                 contentValues.put(Telephony.SimInfo.COLUMN_D2D_STATUS_SHARING,
4257                         backedUpSimInfoEntry.getInt(
4258                                 Telephony.SimInfo.COLUMN_D2D_STATUS_SHARING,
4259                                 DEFAULT_INT_COLUMN_VALUE));
4260             }
4261             contentValues.put(Telephony.SimInfo.COLUMN_IMS_RCS_UCE_ENABLED,
4262                     backedUpSimInfoEntry.getInt(
4263                             Telephony.SimInfo.COLUMN_IMS_RCS_UCE_ENABLED,
4264                             DEFAULT_INT_COLUMN_VALUE));
4265             contentValues.put(Telephony.SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED,
4266                     backedUpSimInfoEntry.getInt(
4267                             Telephony.SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED,
4268                             DEFAULT_INT_COLUMN_VALUE));
4269             contentValues.put(Telephony.SimInfo.COLUMN_VT_IMS_ENABLED,
4270                     backedUpSimInfoEntry.getInt(
4271                             Telephony.SimInfo.COLUMN_VT_IMS_ENABLED,
4272                             DEFAULT_INT_COLUMN_VALUE));
4273             if (isoCountryCodeFromDb != null
4274                     && !wfcRestoreBlockedCountries
4275                             .contains(isoCountryCodeFromDb.toLowerCase(Locale.ROOT))) {
4276                 // Don't restore COLUMN_WFC_IMS_ENABLED if the sim is from one of the countries that
4277                 // requires WFC entitlement.
4278                 contentValues.put(Telephony.SimInfo.COLUMN_WFC_IMS_ENABLED,
4279                         backedUpSimInfoEntry.getInt(
4280                                 Telephony.SimInfo.COLUMN_WFC_IMS_ENABLED,
4281                                 DEFAULT_INT_COLUMN_VALUE));
4282             }
4283             contentValues.put(Telephony.SimInfo.COLUMN_WFC_IMS_MODE,
4284                     backedUpSimInfoEntry.getInt(
4285                             Telephony.SimInfo.COLUMN_WFC_IMS_MODE,
4286                             DEFAULT_INT_COLUMN_VALUE));
4287             contentValues.put(Telephony.SimInfo.COLUMN_WFC_IMS_ROAMING_MODE,
4288                     backedUpSimInfoEntry.getInt(
4289                             Telephony.SimInfo.COLUMN_WFC_IMS_ROAMING_MODE,
4290                             DEFAULT_INT_COLUMN_VALUE));
4291 
4292             return polishContentValues(contentValues);
4293         }
4294 
4295         /**
4296          * Replaces the value of the "enable_2g" key-value pair in the given input string with the
4297          * new "enable_2g key-value provided.
4298          *
4299          * @param input The input string to modify.
4300          * @param newEnable2g The new value for the "enable_2g" key-value pair.
4301          * @param defaultValue default value to return if replacement is not possible.
4302          * @return The modified input string with the updated "enable_2g" value.
4303          */
replaceEnable2g( @ullable String input, @Nullable String newEnable2g, String defaultValue)4304         private static @Nullable String replaceEnable2g(
4305                 @Nullable String input, @Nullable String newEnable2g, String defaultValue) {
4306             if (newEnable2g == null
4307                     || !newEnable2g.startsWith(ALLOWED_NETWORK_TYPES_TEXT_ENABLE_2G)) {
4308                 return defaultValue;
4309             } else if (input == null || input.isBlank()) {
4310                 return newEnable2g;
4311             }
4312 
4313             String delimiter = ",";
4314             String[] parts = input.trim().split(delimiter);
4315 
4316             // Finding and replacing the "enable_2g" value
4317             for (int i = 0; i < parts.length; i++) {
4318                 if (parts[i].startsWith(ALLOWED_NETWORK_TYPES_TEXT_ENABLE_2G)) {
4319                     parts[i] = newEnable2g;
4320                     return String.join(delimiter, parts);
4321                 }
4322             }
4323 
4324             // Adding the "enable_2g" value if not found
4325             if (parts.length == 0) {
4326                 return newEnable2g;
4327             }
4328             return input + "," + newEnable2g;
4329         }
4330 
polishContentValues(ContentValues contentValues)4331         private ContentValues polishContentValues(ContentValues contentValues) {
4332             /* Remove any values that weren't found in the backup file. These were set to defaults
4333             in #convertBackedUpDataToContentValues(). */
4334             for (Map.Entry<String, Integer> column : SIM_INFO_COLUMNS_TO_BACKUP.entrySet()) {
4335                 String columnName = column.getKey();
4336 
4337                 if (!contentValues.containsKey(columnName)) {
4338                     continue;
4339                 }
4340 
4341                 int columnType = column.getValue();
4342                 if (columnType == Cursor.FIELD_TYPE_INTEGER
4343                         && DEFAULT_INT_COLUMN_VALUE == contentValues.getAsInteger(columnName)) {
4344                     contentValues.remove(columnName);
4345                 } else if (columnType == Cursor.FIELD_TYPE_STRING && contentValues
4346                         .getAsString(columnName).equals(DEFAULT_STRING_COLUMN_VALUE)) {
4347                     contentValues.remove(columnName);
4348                 }
4349             }
4350 
4351             if (matches.contains(ICCID_MATCH)) {
4352                 return contentValues;
4353             } else if (matches.contains(CARRIER_ID_MATCH)) {
4354                 if (!matches.contains(PHONE_NUMBER_MATCH)) {
4355                     // Low confidence match should not restore sensitive configs.
4356                     if (contentValues.containsKey(Telephony.SimInfo.COLUMN_IMS_RCS_UCE_ENABLED)) {
4357                         contentValues.remove(Telephony.SimInfo.COLUMN_IMS_RCS_UCE_ENABLED);
4358                     }
4359                 }
4360                 return contentValues;
4361             }
4362             return null;
4363         }
4364 
4365     }
4366 
4367     /**
4368      * Retrieves data from all columns in SimInfoDB of backup/restore interest.
4369      *
4370      * @return data of interest from SimInfoDB as a byte array.
4371      */
getSimSpecificDataToBackUp()4372     private byte[] getSimSpecificDataToBackUp() {
4373         Map<String, Integer> simInfoColumnsToBackup = SIM_INFO_COLUMNS_TO_BACKUP;
4374         String[] projection = simInfoColumnsToBackup.keySet()
4375                 .toArray(new String[simInfoColumnsToBackup.size()]);
4376 
4377         try (Cursor cursor = query(SubscriptionManager.CONTENT_URI, projection, null, null, null);
4378                 ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
4379             PersistableBundle topLevelBundle = new PersistableBundle();
4380             topLevelBundle.putInt(KEY_BACKUP_DATA_FORMAT_VERSION, DATABASE_VERSION);
4381             for (int rowNum = 0; cursor != null && cursor.moveToNext(); rowNum++) {
4382                 PersistableBundle rowBundle = convertSimInfoDbEntryToPersistableBundle(cursor);
4383                 topLevelBundle.putPersistableBundle(KEY_SIMINFO_DB_ROW_PREFIX + rowNum, rowBundle);
4384             }
4385             topLevelBundle.writeToStream(outputStream);
4386             return outputStream.toByteArray();
4387         } catch (IOException e) {
4388             loge("Not able to convert SimInfoDB to byte array. Returning empty byte array");
4389             return new byte[0];
4390         }
4391     }
4392 
convertSimInfoDbEntryToPersistableBundle(Cursor cursor)4393     private static PersistableBundle convertSimInfoDbEntryToPersistableBundle(Cursor cursor) {
4394         PersistableBundle bundle = new PersistableBundle();
4395         for (Map.Entry<String, Integer> column : SIM_INFO_COLUMNS_TO_BACKUP.entrySet()) {
4396             String columnName = column.getKey();
4397             int columnType = column.getValue();
4398             int columnIndex = cursor.getColumnIndex(columnName);
4399             if (Telephony.SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS
4400                             .equals(columnName)) {
4401                 bundle.putString(columnName,
4402                         filteredAllowedNetworkTypesForBackup(cursor.getString(columnIndex)));
4403             } else if (columnType == Cursor.FIELD_TYPE_INTEGER) {
4404                 bundle.putInt(columnName, cursor.getInt(columnIndex));
4405             } else if (columnType == Cursor.FIELD_TYPE_STRING) {
4406                 bundle.putString(columnName, cursor.getString(columnIndex));
4407             } else {
4408                 throw new AssertionError("SimInfoDB column to be backed up is not recognized. Make "
4409                     + "sure to properly add the desired colum name and value type to "
4410                     + "SIM_INFO_COLUMNS_TO_BACKUP.");
4411             }
4412         }
4413 
4414         return bundle;
4415     }
4416 
4417     /**
4418      * Returns filtered allowed network types for backup.
4419      *
4420      * Filters and returns only {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G} for
4421      * the TelephonyProvider column value for network types allowed with all reasons.
4422      *
4423      * @param networkTypeValues String Value for network types allowed with all reasons
4424      * @return String of "enable_2g=VALUE" format. if no reasons to backup returns null.
4425      */
filteredAllowedNetworkTypesForBackup(String networkTypeValues)4426     private static String filteredAllowedNetworkTypesForBackup(String networkTypeValues) {
4427         return networkTypeValues == null ? null :
4428                 Arrays.stream(networkTypeValues.trim().split(","))
4429                         .filter(r -> r.startsWith(ALLOWED_NETWORK_TYPES_TEXT_ENABLE_2G))
4430                         .findFirst()
4431                         .orElse(null);
4432     }
4433 
4434     @Override
query(Uri url, String[] projectionIn, String selection, String[] selectionArgs, String sort)4435     public Cursor query(Uri url, String[] projectionIn, String selection,  String[] selectionArgs,
4436             String sort) {
4437         if (VDBG) log("query: url=" + url + ", projectionIn=" + Arrays.toString(projectionIn)
4438                 + ", selection=" + selection + "selectionArgs=" + Arrays.toString(selectionArgs)
4439                 + ", sort=" + sort);
4440         int match = s_urlMatcher.match(url);
4441         checkPermissionCompat(match, projectionIn);
4442 
4443         mDefaultSubId = SubscriptionManager.getDefaultSubscriptionId();
4444         return queryInternal(url, projectionIn, selection, selectionArgs, sort);
4445     }
4446 
4447     /**
4448      * Internally queries the database.
4449      *
4450      * Things to keep in mind when writing code for this function:
4451      *   - Must be wrapped in synchronized before quering database.
4452      *   - Please call external APIs, that use locks, outside of synchronized.
4453      */
queryInternal(Uri url, String[] projectionIn, String selection, String[] selectionArgs, String sort)4454     private Cursor queryInternal(Uri url, String[] projectionIn, String selection,
4455             String[] selectionArgs, String sort) {
4456         int subId = mDefaultSubId;
4457         String subIdString;
4458         SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
4459         qb.setStrict(true); // a little protection from injection attacks
4460         qb.setTables(CARRIERS_TABLE);
4461 
4462         List<String> constraints = new ArrayList<String>();
4463 
4464         int match = s_urlMatcher.match(url);
4465         switch (match) {
4466             case URL_TELEPHONY_USING_SUBID: {
4467                 // The behaves exactly same as URL_SIM_APN_LIST_ID.
4468                 subIdString = url.getLastPathSegment();
4469                 try {
4470                     subId = Integer.parseInt(subIdString);
4471                 } catch (NumberFormatException e) {
4472                     loge("NumberFormatException" + e);
4473                     return null;
4474                 }
4475                 qb.appendWhereStandalone(IS_NOT_OWNED_BY_DPC);
4476                 return getSubscriptionMatchingAPNList(qb, projectionIn, selection, selectionArgs,
4477                         sort, subId);
4478 
4479                 // TODO b/74213956 turn this back on once insertion includes correct sub id
4480                 // constraints.add(SUBSCRIPTION_ID + "=" + subIdString);
4481             }
4482             case URL_TELEPHONY: {
4483                 constraints.add(IS_NOT_OWNED_BY_DPC);
4484                 break;
4485             }
4486 
4487             case URL_CURRENT_USING_SUBID: {
4488                 subIdString = url.getLastPathSegment();
4489                 try {
4490                     subId = Integer.parseInt(subIdString);
4491                 } catch (NumberFormatException e) {
4492                     loge("NumberFormatException" + e);
4493                     return null;
4494                 }
4495                 // TODO b/74213956 turn this back on once insertion includes correct sub id
4496                 // constraints.add(SUBSCRIPTION_ID + "=" + subIdString);
4497             }
4498             //intentional fall through from above case
4499             case URL_CURRENT: {
4500                 constraints.add("current IS NOT NULL");
4501                 constraints.add(IS_NOT_OWNED_BY_DPC);
4502                 // do not ignore the selection since MMS may use it.
4503                 //selection = null;
4504                 break;
4505             }
4506 
4507             case URL_ID: {
4508                 constraints.add("_id = " + url.getPathSegments().get(1));
4509                 constraints.add(IS_NOT_OWNED_BY_DPC);
4510                 break;
4511             }
4512 
4513             case URL_PREFERAPN_USING_SUBID:
4514             case URL_PREFERAPN_NO_UPDATE_USING_SUBID: {
4515                 subIdString = url.getLastPathSegment();
4516                 try {
4517                     subId = Integer.parseInt(subIdString);
4518                 } catch (NumberFormatException e) {
4519                     loge("NumberFormatException" + e);
4520                     return null;
4521                 }
4522                 // TODO b/74213956 turn this back on once insertion includes correct sub id
4523                 // constraints.add(SUBSCRIPTION_ID + "=" + subIdString);
4524             }
4525             //intentional fall through from above case
4526             case URL_PREFERAPN:
4527             case URL_PREFERAPN_NO_UPDATE: {
4528                 constraints.add("_id = " + getPreferredApnId(subId, true));
4529                 break;
4530             }
4531 
4532             case URL_PREFERAPNSET_USING_SUBID: {
4533                 subIdString = url.getLastPathSegment();
4534                 try {
4535                     subId = Integer.parseInt(subIdString);
4536                 } catch (NumberFormatException e) {
4537                     loge("NumberFormatException" + e);
4538                     return null;
4539                 }
4540                 // TODO b/74213956 turn this back on once insertion includes correct sub id
4541                 // constraints.add(SUBSCRIPTION_ID + "=" + subIdString);
4542             }
4543             // intentional fall through from above case
4544             case URL_PREFERAPNSET: {
4545                 final int set = getPreferredApnSetId(subId);
4546                 if (set == NO_APN_SET_ID) {
4547                     return null;
4548                 }
4549                 constraints.add(APN_SET_ID + "=" + set);
4550                 qb.appendWhere(TextUtils.join(" AND ", constraints));
4551                 return getSubscriptionMatchingAPNList(qb, projectionIn, selection, selectionArgs,
4552                         sort, subId);
4553             }
4554 
4555             case URL_DPC: {
4556                 ensureCallingFromSystemOrPhoneUid("URL_DPC called from non SYSTEM_UID.");
4557                 // DPC query only returns DPC records.
4558                 constraints.add(IS_OWNED_BY_DPC);
4559                 break;
4560             }
4561 
4562             case URL_DPC_ID: {
4563                 constraints.add("_id = " + url.getLastPathSegment());
4564                 ensureCallingFromSystemOrPhoneUid("URL_DPC called from non SYSTEM_UID.");
4565                 // DPC query only returns DPC records.
4566                 constraints.add(IS_OWNED_BY_DPC);
4567                 break;
4568             }
4569 
4570             case URL_FILTERED_ID:
4571             case URL_FILTERED_USING_SUBID: {
4572                 String idString = url.getLastPathSegment();
4573                 if (match == URL_FILTERED_ID) {
4574                     constraints.add("_id = " + idString);
4575                 } else {
4576                     try {
4577                         subId = Integer.parseInt(idString);
4578                         // TODO b/74213956 turn this back on once insertion includes correct sub id
4579                         // constraints.add(SUBSCRIPTION_ID + "=" + subIdString);
4580                     } catch (NumberFormatException e) {
4581                         loge("NumberFormatException" + e);
4582                         return null;
4583                     }
4584                 }
4585             }
4586             //intentional fall through from above case
4587             case URL_FILTERED: {
4588                 if (isManagedApnEnforced()) {
4589                     // If enforced, return DPC records only.
4590                     constraints.add(IS_OWNED_BY_DPC);
4591                 } else {
4592                     // Otherwise return non-DPC records only.
4593                     constraints.add(IS_NOT_OWNED_BY_DPC);
4594                 }
4595                 break;
4596             }
4597 
4598             case URL_ENFORCE_MANAGED: {
4599                 ensureCallingFromSystemOrPhoneUid(
4600                         "URL_ENFORCE_MANAGED called from non SYSTEM_UID.");
4601                 MatrixCursor cursor = new MatrixCursor(new String[]{ENFORCED_KEY});
4602                 cursor.addRow(new Object[]{isManagedApnEnforced() ? 1 : 0});
4603                 return cursor;
4604             }
4605 
4606             case URL_SIMINFO: {
4607                 qb.setTables(SIMINFO_TABLE);
4608                 break;
4609             }
4610             case URL_SIM_APN_LIST_ID: {
4611                 subIdString = url.getLastPathSegment();
4612                 try {
4613                     subId = Integer.parseInt(subIdString);
4614                 } catch (NumberFormatException e) {
4615                     loge("NumberFormatException" + e);
4616                     return null;
4617                 }
4618             }
4619             //intentional fall through from above case
4620             case URL_SIM_APN_LIST: {
4621                 qb.appendWhere(IS_NOT_OWNED_BY_DPC);
4622                 return getSubscriptionMatchingAPNList(qb, projectionIn, selection, selectionArgs,
4623                         sort, subId);
4624             }
4625 
4626             case URL_SIM_APN_LIST_FILTERED_ID: {
4627                 subIdString = url.getLastPathSegment();
4628                 try {
4629                     subId = Integer.parseInt(subIdString);
4630                 } catch (NumberFormatException e) {
4631                     loge("NumberFormatException" + e);
4632                     return null;
4633                 }
4634             }
4635             //intentional fall through from above case
4636             case URL_SIM_APN_LIST_FILTERED: {
4637                 if (isManagedApnEnforced()) {
4638                     // If enforced, return DPC records only.
4639                     qb.appendWhereStandalone(IS_OWNED_BY_DPC);
4640                 } else {
4641                     // Otherwise return non-DPC records only.
4642                     qb.appendWhereStandalone(IS_NOT_OWNED_BY_DPC);
4643                 }
4644                 return getSubscriptionMatchingAPNList(qb, projectionIn, selection, selectionArgs,
4645                         sort, subId);
4646             }
4647 
4648             default: {
4649                 return null;
4650             }
4651         }
4652 
4653         // appendWhere doesn't add ANDs so we do it ourselves
4654         if (constraints.size() > 0) {
4655             qb.appendWhere(TextUtils.join(" AND ", constraints));
4656         }
4657 
4658         synchronized (this) {
4659             SQLiteDatabase db = getReadableDatabase();
4660             Cursor ret = null;
4661             try {
4662                 // Exclude entries marked deleted
4663                 if (CARRIERS_TABLE.equals(qb.getTables())) {
4664                     if (TextUtils.isEmpty(selection)) {
4665                         selection = "";
4666                     } else {
4667                         selection += " and ";
4668                     }
4669                     selection += IS_NOT_USER_DELETED + " and "
4670                             + IS_NOT_USER_DELETED_BUT_PRESENT_IN_XML + " and "
4671                             + IS_NOT_CARRIER_DELETED + " and "
4672                             + IS_NOT_CARRIER_DELETED_BUT_PRESENT_IN_XML;
4673                     if (VDBG) log("query: selection modified to " + selection);
4674                 }
4675                 ret = qb.query(db, projectionIn, selection, selectionArgs, null, null, sort);
4676             } catch (SQLException e) {
4677                 loge("got exception when querying: " + e);
4678             }
4679             if (ret != null) {
4680                 ret.setNotificationUri(getContext().getContentResolver(), url);
4681             }
4682             return ret;
4683         }
4684     }
4685 
4686     /**
4687      * This method syncs PREF_FILE_FULL_APN with the db based on the current preferred apn ids.
4688      */
updatePreferredApns()4689     private void updatePreferredApns() {
4690         SharedPreferences spApn = getContext().getSharedPreferences(PREF_FILE_APN,
4691                 Context.MODE_PRIVATE);
4692 
4693         Map<String, ?> allPrefApnId = spApn.getAll();
4694         for (String key : allPrefApnId.keySet()) {
4695             if (key.startsWith(COLUMN_APN_ID)) {
4696                 int subId;
4697                 try {
4698                     subId = Integer.parseInt(key.substring(COLUMN_APN_ID.length()));
4699                 } catch (NumberFormatException e) {
4700                     loge("updatePreferredApns: NumberFormatException for key=" + key);
4701                     continue;
4702                 }
4703                 long preferredApnId = getPreferredApnId(subId, false);
4704                 if (preferredApnId != INVALID_APN_ID) {
4705                     setPreferredApn(preferredApnId, subId);
4706                 }
4707             }
4708         }
4709     }
4710 
4711     /**
4712      * To find the current sim APN. Query APN based on {MCC, MNC, MVNO} and {Carrier_ID}.
4713      *
4714      * There has three steps:
4715      * 1. Query the APN based on { MCC, MNC, MVNO } and if has results jump to step 3, else jump to
4716      *    step 2.
4717      * 2. Fallback to query the parent APN that query based on { MCC, MNC }.
4718      * 3. Append the result with the APN that query based on { Carrier_ID }
4719      */
getSubscriptionMatchingAPNList(SQLiteQueryBuilder qb, String[] projectionIn, String selection, String[] selectionArgs, String sort, int subId)4720     private Cursor getSubscriptionMatchingAPNList(SQLiteQueryBuilder qb, String[] projectionIn,
4721             String selection, String[] selectionArgs, String sort, int subId) {
4722         Context context = getContext();
4723 
4724         // The SubscriptionManager can use the lock to query tables such as sim_info again, so
4725         // calling subscriptionManager should be performed outside of synchronized.
4726         final SubscriptionManager subscriptionManager = (SubscriptionManager) context
4727                 .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
4728         if (!subscriptionManager.isActiveSubscriptionId(subId)) {
4729             return null;
4730         }
4731 
4732         return getSubscriptionMatchingAPNListSynchronized(qb, projectionIn, selection,
4733                 selectionArgs, sort, subId);
4734     }
4735 
getSubscriptionMatchingAPNListSynchronized( SQLiteQueryBuilder qb, String[] projectionIn, String selection, String[] selectionArgs, String sort, int subId)4736     private synchronized Cursor getSubscriptionMatchingAPNListSynchronized(
4737             SQLiteQueryBuilder qb, String[] projectionIn, String selection, String[] selectionArgs,
4738             String sort, int subId) {
4739         Cursor ret;
4740         Context context = getContext();
4741         final TelephonyManager tm = ((TelephonyManager) context
4742                 .getSystemService(Context.TELEPHONY_SERVICE))
4743                 .createForSubscriptionId(subId);
4744         SQLiteDatabase db = getReadableDatabase();
4745         String mccmnc = tm.getSimOperator();
4746         int carrierId = tm.getSimSpecificCarrierId();
4747 
4748         qb.appendWhereStandalone(IS_NOT_USER_DELETED + " and " +
4749                 IS_NOT_USER_DELETED_BUT_PRESENT_IN_XML + " and " +
4750                 IS_NOT_CARRIER_DELETED + " and " +
4751                 IS_NOT_CARRIER_DELETED_BUT_PRESENT_IN_XML);
4752 
4753         // For query db one time, append all conditions in one selection and separate results after
4754         // the query is completed. IMSI has special match rule, so just query the MCC / MNC and
4755         // filter the MVNO by ourselves
4756         qb.appendWhereStandalone(NUMERIC + " = '" + mccmnc + "' OR " +
4757                 CARRIER_ID + " = '" + carrierId + "'");
4758 
4759         ret = qb.query(db, null, selection, selectionArgs, null, null, sort);
4760         if (ret == null) {
4761             loge("subId:" + subId + " query current APN but cursor is null.");
4762             return null;
4763         }
4764 
4765         if (DBG) log("subId:" + subId + " mccmnc=" + mccmnc + " carrierId=" + carrierId +
4766                 ", match current APN size:  " + ret.getCount());
4767 
4768         String[] columnNames = projectionIn != null ? projectionIn : ret.getColumnNames();
4769         MatrixCursor currentCursor = new MatrixCursor(columnNames);
4770         MatrixCursor parentCursor = new MatrixCursor(columnNames);
4771         MatrixCursor carrierIdCursor = new MatrixCursor(columnNames);
4772         MatrixCursor carrierIdNonMatchingMNOCursor = new MatrixCursor(columnNames);
4773 
4774         int numericIndex = ret.getColumnIndex(NUMERIC);
4775         int mvnoIndex = ret.getColumnIndex(MVNO_TYPE);
4776         int mvnoDataIndex = ret.getColumnIndex(MVNO_MATCH_DATA);
4777         int carrierIdIndex = ret.getColumnIndex(CARRIER_ID);
4778 
4779         // Separate the result into MatrixCursor
4780         while (ret.moveToNext()) {
4781             List<String> data = new ArrayList<>();
4782             for (String column : columnNames) {
4783                 data.add(ret.getString(ret.getColumnIndex(column)));
4784             }
4785 
4786             boolean isCurrentSimOperator = false;
4787             if (!TextUtils.isEmpty(ret.getString(numericIndex))) {
4788                 final long identity = Binder.clearCallingIdentity();
4789                 try {
4790                     isCurrentSimOperator = tm.matchesCurrentSimOperator(
4791                             ret.getString(numericIndex),
4792                             getMvnoTypeIntFromString(ret.getString(mvnoIndex)),
4793                             ret.getString(mvnoDataIndex));
4794                 } finally {
4795                     Binder.restoreCallingIdentity(identity);
4796                 }
4797             }
4798 
4799             boolean isMVNOAPN = !TextUtils.isEmpty(ret.getString(numericIndex))
4800                     && isCurrentSimOperator;
4801             boolean isMNOAPN = !TextUtils.isEmpty(ret.getString(numericIndex))
4802                     && ret.getString(numericIndex).equals(mccmnc)
4803                     && TextUtils.isEmpty(ret.getString(mvnoIndex));
4804             boolean isCarrierIdAPN = !TextUtils.isEmpty(ret.getString(carrierIdIndex))
4805                     && ret.getString(carrierIdIndex).equals(String.valueOf(carrierId))
4806                     && carrierId != TelephonyManager.UNKNOWN_CARRIER_ID;
4807 
4808             if (isMVNOAPN) {
4809                 // 1. The APN that query based on legacy SIM MCC/MCC and MVNO
4810                 currentCursor.addRow(data);
4811             } else if (isMNOAPN) {
4812                 // 2. The APN that query based on SIM MCC/MNC
4813                 parentCursor.addRow(data);
4814             } else if (isCarrierIdAPN) {
4815                 // The APN that query based on carrier Id (not include the MVNO or MNO APN)
4816                 if (TextUtils.isEmpty(ret.getString(numericIndex))) {
4817                     carrierIdCursor.addRow(data);
4818                 } else {
4819                     carrierIdNonMatchingMNOCursor.addRow(data);
4820                 }
4821             }
4822         }
4823         ret.close();
4824 
4825         MatrixCursor result;
4826         if (currentCursor.getCount() > 0) {
4827             if (DBG) log("match MVNO APN: " + currentCursor.getCount());
4828             result = currentCursor;
4829         } else if (parentCursor.getCount() > 0) {
4830             if (DBG) log("match MNO APN: " + parentCursor.getCount());
4831             result = parentCursor;
4832         } else {
4833             if (DBG) {
4834                 log("No MVNO, MNO and no MCC/MNC match, but we have match/matches with the " +
4835                         "same carrier id, count: " + carrierIdNonMatchingMNOCursor.getCount());
4836             }
4837             result = carrierIdNonMatchingMNOCursor;
4838         }
4839 
4840         if (DBG) log("match carrier id APN: " + carrierIdCursor.getCount());
4841         appendCursorData(result, carrierIdCursor);
4842         return result;
4843     }
4844 
appendCursorData(@onNull MatrixCursor from, @NonNull MatrixCursor to)4845     private static void appendCursorData(@NonNull MatrixCursor from, @NonNull MatrixCursor to) {
4846         while (to.moveToNext()) {
4847             List<Object> data = new ArrayList<>();
4848             for (String column : to.getColumnNames()) {
4849                 int index = to.getColumnIndex(column);
4850                 switch (to.getType(index)) {
4851                     case Cursor.FIELD_TYPE_INTEGER:
4852                         data.add(to.getInt(index));
4853                         break;
4854                     case Cursor.FIELD_TYPE_FLOAT:
4855                         data.add(to.getFloat(index));
4856                         break;
4857                     case Cursor.FIELD_TYPE_BLOB:
4858                         data.add(to.getBlob(index));
4859                         break;
4860                     case Cursor.FIELD_TYPE_STRING:
4861                     case Cursor.FIELD_TYPE_NULL:
4862                         data.add(to.getString(index));
4863                         break;
4864                 }
4865             }
4866             from.addRow(data);
4867         }
4868     }
4869 
4870     @Override
getType(Uri url)4871     public String getType(Uri url)
4872     {
4873         switch (s_urlMatcher.match(url)) {
4874         case URL_TELEPHONY:
4875         case URL_TELEPHONY_USING_SUBID:
4876             return "vnd.android.cursor.dir/telephony-carrier";
4877 
4878         case URL_ID:
4879         case URL_FILTERED_ID:
4880         case URL_FILTERED_USING_SUBID:
4881             return "vnd.android.cursor.item/telephony-carrier";
4882 
4883         case URL_PREFERAPN_USING_SUBID:
4884         case URL_PREFERAPN_NO_UPDATE_USING_SUBID:
4885         case URL_PREFERAPN:
4886         case URL_PREFERAPN_NO_UPDATE:
4887         case URL_PREFERAPNSET:
4888         case URL_PREFERAPNSET_USING_SUBID:
4889             return "vnd.android.cursor.item/telephony-carrier";
4890 
4891         default:
4892             throw new IllegalArgumentException("Unknown URL " + url);
4893         }
4894     }
4895 
4896     /**
4897      * Insert an array of ContentValues and call notifyChange at the end.
4898      */
4899     @Override
bulkInsert(Uri url, ContentValues[] values)4900     public int bulkInsert(Uri url, ContentValues[] values) {
4901         mDefaultSubId = SubscriptionManager.getDefaultSubscriptionId();
4902         synchronized (this) {
4903             return unsynchronizedBulkInsert(url, values);
4904         }
4905     }
4906 
4907     /**
4908      * Do a bulk insert while inside a synchronized function. This is typically not safe and should
4909      * only be done when you are sure there will be no conflict.
4910      */
unsynchronizedBulkInsert(Uri url, ContentValues[] values)4911     private int unsynchronizedBulkInsert(Uri url, ContentValues[] values) {
4912         int count = 0;
4913         boolean notify = false;
4914         for (ContentValues value : values) {
4915             Pair<Uri, Boolean> rowAndNotify = insertSingleRow(url, value);
4916             if (rowAndNotify.first != null) {
4917                 count++;
4918             }
4919             if (rowAndNotify.second == true) {
4920                 notify = true;
4921             }
4922         }
4923         if (notify) {
4924             getContext().getContentResolver().notifyChange(CONTENT_URI, null,
4925                     true, UserHandle.USER_ALL);
4926         }
4927         return count;
4928     }
4929 
4930     @Override
insert(Uri url, ContentValues initialValues)4931     public Uri insert(Uri url, ContentValues initialValues) {
4932         mDefaultSubId = SubscriptionManager.getDefaultSubscriptionId();
4933         return insertSynchronized(url, initialValues);
4934     }
4935 
insertSynchronized(Uri url, ContentValues initialValues)4936     private synchronized Uri insertSynchronized(Uri url, ContentValues initialValues) {
4937         Pair<Uri, Boolean> rowAndNotify = insertSingleRow(url, initialValues);
4938         if (rowAndNotify.second) {
4939             getContext().getContentResolver().notifyChange(CONTENT_URI, null,
4940                     true, UserHandle.USER_ALL);
4941         }
4942         return rowAndNotify.first;
4943     }
4944 
4945     /**
4946      * Internal insert function to prevent code duplication for URL_TELEPHONY and URL_DPC.
4947      *
4948      * @param values the value that caller wants to insert
4949      * @return a pair in which the first element refers to the Uri for the row inserted, the second
4950      *         element refers to whether sends out notification.
4951      */
insertRowWithValue(ContentValues values)4952     private Pair<Uri, Boolean> insertRowWithValue(ContentValues values) {
4953         Uri result = null;
4954         boolean notify = false;
4955         SQLiteDatabase db = getWritableDatabase();
4956 
4957         try {
4958             // Abort on conflict of unique fields and attempt merge
4959             long rowID = db.insertWithOnConflict(CARRIERS_TABLE, null, values,
4960                     SQLiteDatabase.CONFLICT_ABORT);
4961             if (rowID >= 0) {
4962                 result = ContentUris.withAppendedId(CONTENT_URI, rowID);
4963                 notify = true;
4964             }
4965             if (DBG) log("insert: inserted " + values + ", rowID = " + rowID);
4966         } catch (SQLException e) {
4967             log("insert: exception " + e);
4968             // Insertion failed which could be due to a conflict. Check if that is the case
4969             // and merge the entries
4970             Cursor oldRow = selectConflictingRow(db, CARRIERS_TABLE, values);
4971             if (oldRow != null) {
4972                 ContentValues mergedValues = new ContentValues();
4973                 mergeFieldsAndUpdateDb(db, CARRIERS_TABLE, oldRow, values,
4974                         mergedValues, false, getContext());
4975                 oldRow.close();
4976                 notify = true;
4977             }
4978         }
4979         return Pair.create(result, notify);
4980     }
4981 
insertSingleRow(Uri url, ContentValues initialValues)4982     private Pair<Uri, Boolean> insertSingleRow(Uri url, ContentValues initialValues) {
4983         Uri result = null;
4984         int subId = mDefaultSubId;
4985 
4986         int match = s_urlMatcher.match(url);
4987         checkPermission(match);
4988         syncBearerBitmaskAndNetworkTypeBitmask(initialValues);
4989 
4990         boolean notify = false;
4991         SQLiteDatabase db = getWritableDatabase();
4992         switch (match)
4993         {
4994             case URL_TELEPHONY_USING_SUBID:
4995             {
4996                 loge("insert carriers/subId/* is not supported, treat as carriers");
4997             }
4998             //intentional fall through from above case
4999 
5000             case URL_TELEPHONY:
5001             {
5002                 ContentValues values;
5003                 if (initialValues != null) {
5004                     values = new ContentValues(initialValues);
5005                 } else {
5006                     values = new ContentValues();
5007                 }
5008 
5009                 values = setDefaultValue(values);
5010                 if (!values.containsKey(EDITED_STATUS)) {
5011                     values.put(EDITED_STATUS, CARRIER_EDITED);
5012                 }
5013                 // Owned_by should be others if inserted via general uri.
5014                 values.put(OWNED_BY, OWNED_BY_OTHERS);
5015 
5016                 Pair<Uri, Boolean> ret = insertRowWithValue(values);
5017                 result = ret.first;
5018                 notify = ret.second;
5019                 break;
5020             }
5021 
5022             case URL_CURRENT_USING_SUBID:
5023             {
5024                 loge("insert carriers/current/subId/* is not supported, treat as carriers/current");
5025             }
5026             //intentional fall through from above case
5027 
5028             case URL_CURRENT:
5029             {
5030                 // zero out the previous operator
5031                 db.update(CARRIERS_TABLE, s_currentNullMap, CURRENT + "!=0", null);
5032 
5033                 String numeric = initialValues.getAsString(NUMERIC);
5034                 int updated = db.update(CARRIERS_TABLE, s_currentSetMap,
5035                         NUMERIC + " = '" + numeric + "'", null);
5036 
5037                 if (updated > 0)
5038                 {
5039                     if (VDBG) log("Setting numeric '" + numeric + "' to be the current operator");
5040                 }
5041                 else
5042                 {
5043                     loge("Failed setting numeric '" + numeric + "' to the current operator");
5044                 }
5045                 break;
5046             }
5047 
5048             case URL_PREFERAPN_USING_SUBID:
5049             case URL_PREFERAPN_NO_UPDATE_USING_SUBID:
5050             {
5051                 String subIdString = url.getLastPathSegment();
5052                 try {
5053                     subId = Integer.parseInt(subIdString);
5054                 } catch (NumberFormatException e) {
5055                     loge("NumberFormatException" + e);
5056                     return Pair.create(result, notify);
5057                 }
5058             }
5059             //intentional fall through from above case
5060 
5061             case URL_PREFERAPN:
5062             case URL_PREFERAPN_NO_UPDATE:
5063             {
5064                 if (initialValues != null) {
5065                     if(initialValues.containsKey(COLUMN_APN_ID)) {
5066                         setPreferredApnId(initialValues.getAsLong(COLUMN_APN_ID), subId, true);
5067                         notify = true;
5068                     }
5069                 }
5070                 break;
5071             }
5072 
5073             case URL_DPC: {
5074                 ensureCallingFromSystemOrPhoneUid("URL_DPC called from non SYSTEM_UID.");
5075 
5076                 ContentValues values;
5077                 if (initialValues != null) {
5078                     values = new ContentValues(initialValues);
5079                 } else {
5080                     values = new ContentValues();
5081                 }
5082 
5083                 // Owned_by should be DPC if inserted via URL_DPC.
5084                 values.put(OWNED_BY, OWNED_BY_DPC);
5085                 // DPC records should not be user editable.
5086                 values.put(USER_EDITABLE, false);
5087 
5088                 final long rowID = db.insertWithOnConflict(CARRIERS_TABLE, null, values,
5089                         SQLiteDatabase.CONFLICT_IGNORE);
5090                 if (rowID >= 0) {
5091                     result = ContentUris.withAppendedId(CONTENT_URI, rowID);
5092                     notify = true;
5093                 }
5094                 if (VDBG) log("insert: inserted " + values.toString() + " rowID = " + rowID);
5095 
5096                 break;
5097             }
5098 
5099             case URL_SIMINFO: {
5100                long id = db.insert(SIMINFO_TABLE, null, initialValues);
5101                result = ContentUris.withAppendedId(Telephony.SimInfo.CONTENT_URI, id);
5102                break;
5103             }
5104         }
5105 
5106         return Pair.create(result, notify);
5107     }
5108 
5109     @Override
delete(Uri url, String where, String[] whereArgs)5110     public int delete(Uri url, String where, String[] whereArgs) {
5111         mDefaultSubId = SubscriptionManager.getDefaultSubscriptionId();
5112         return deleteSynchronized(url, where, whereArgs);
5113     }
5114 
deleteSynchronized(Uri url, String where, String[] whereArgs)5115     private synchronized int deleteSynchronized(Uri url, String where, String[] whereArgs) {
5116         int count = 0;
5117         int subId = mDefaultSubId;
5118         String userOrCarrierEdited = ") and (" +
5119                 IS_USER_EDITED +  " or " +
5120                 IS_CARRIER_EDITED + ")";
5121         String notUserOrCarrierEdited = ") and (" +
5122                 IS_NOT_USER_EDITED +  " and " +
5123                 IS_NOT_CARRIER_EDITED + ")";
5124         String unedited = ") and " + IS_UNEDITED;
5125         ContentValues cv = new ContentValues();
5126         cv.put(EDITED_STATUS, USER_DELETED);
5127 
5128         int match = s_urlMatcher.match(url);
5129         checkPermission(match);
5130 
5131         SQLiteDatabase db = getWritableDatabase();
5132         switch (match)
5133         {
5134             case URL_DELETE:
5135             {
5136                 // Delete preferred APN for all subIds
5137                 deletePreferredApnId(getContext());
5138                 // Delete unedited entries
5139                 count = db.delete(CARRIERS_TABLE, "(" + where + unedited + " and " +
5140                         IS_NOT_OWNED_BY_DPC, whereArgs);
5141                 break;
5142             }
5143 
5144             case URL_TELEPHONY_USING_SUBID:
5145             {
5146                 loge("delete carriers/subId/* is not supported, treat as carriers");
5147             }
5148             //intentional fall through from above case
5149 
5150             case URL_TELEPHONY:
5151             {
5152                 // Delete user/carrier edited entries
5153                 count = db.delete(CARRIERS_TABLE, "(" + where + userOrCarrierEdited
5154                         + " and " + IS_NOT_OWNED_BY_DPC, whereArgs);
5155                 // Otherwise mark as user deleted instead of deleting
5156                 count += db.update(CARRIERS_TABLE, cv, "(" + where +
5157                         notUserOrCarrierEdited + " and " + IS_NOT_OWNED_BY_DPC, whereArgs);
5158                 break;
5159             }
5160 
5161             case URL_CURRENT_USING_SUBID: {
5162                 loge("delete carriers/current/subId/* is not supported, treat as carriers/current");
5163             }
5164             //intentional fall through from above case
5165 
5166             case URL_CURRENT:
5167             {
5168                 // Delete user/carrier edited entries
5169                 count = db.delete(CARRIERS_TABLE, "(" + where + userOrCarrierEdited
5170                         + " and " + IS_NOT_OWNED_BY_DPC, whereArgs);
5171                 // Otherwise mark as user deleted instead of deleting
5172                 count += db.update(CARRIERS_TABLE, cv, "(" + where +
5173                         notUserOrCarrierEdited + " and " + IS_NOT_OWNED_BY_DPC, whereArgs);
5174                 break;
5175             }
5176 
5177             case URL_ID:
5178             {
5179                 // Delete user/carrier edited entries
5180                 count = db.delete(CARRIERS_TABLE,
5181                         "(" + _ID + "=?" + userOrCarrierEdited +
5182                                 " and " + IS_NOT_OWNED_BY_DPC,
5183                         new String[] { url.getLastPathSegment() });
5184                 // Otherwise mark as user deleted instead of deleting
5185                 count += db.update(CARRIERS_TABLE, cv,
5186                         "(" + _ID + "=?" + notUserOrCarrierEdited +
5187                                 " and " + IS_NOT_OWNED_BY_DPC,
5188                         new String[]{url.getLastPathSegment() });
5189                 break;
5190             }
5191 
5192             case URL_RESTOREAPN_USING_SUBID: {
5193                 String subIdString = url.getLastPathSegment();
5194                 try {
5195                     subId = Integer.parseInt(subIdString);
5196                 } catch (NumberFormatException e) {
5197                     loge("NumberFormatException" + e);
5198                     throw new IllegalArgumentException("Invalid subId " + url);
5199                 }
5200             }
5201             // intentional fall through from above case
5202 
5203             case URL_RESTOREAPN: {
5204                 count = 1;
5205                 restoreDefaultAPN(subId);
5206                 getContext().getContentResolver().notifyChange(
5207                         Uri.withAppendedPath(CONTENT_URI, "restore/subId/" + subId), null,
5208                         true, UserHandle.USER_ALL);
5209                 break;
5210             }
5211 
5212             case URL_PREFERAPN_USING_SUBID:
5213             case URL_PREFERAPN_NO_UPDATE_USING_SUBID: {
5214                 String subIdString = url.getLastPathSegment();
5215                 try {
5216                     subId = Integer.parseInt(subIdString);
5217                 } catch (NumberFormatException e) {
5218                     loge("NumberFormatException" + e);
5219                     throw new IllegalArgumentException("Invalid subId " + url);
5220                 }
5221             }
5222             //intentional fall through from above case
5223 
5224             case URL_PREFERAPN:
5225             case URL_PREFERAPN_NO_UPDATE:
5226             {
5227                 setPreferredApnId((long)INVALID_APN_ID, subId, true);
5228                 if ((match == URL_PREFERAPN) || (match == URL_PREFERAPN_USING_SUBID)) count = 1;
5229                 break;
5230             }
5231 
5232             case URL_DPC_ID: {
5233                 ensureCallingFromSystemOrPhoneUid("URL_DPC_ID called from non SYSTEM_UID.");
5234 
5235                 // Only delete if owned by DPC.
5236                 count = db.delete(CARRIERS_TABLE, "(" + _ID + "=?)" + " and " + IS_OWNED_BY_DPC,
5237                         new String[] { url.getLastPathSegment() });
5238                 break;
5239             }
5240 
5241             case URL_SIMINFO: {
5242                 count = db.delete(SIMINFO_TABLE, where, whereArgs);
5243                 break;
5244             }
5245 
5246             case URL_UPDATE_DB: {
5247                 updateApnDb();
5248                 count = 1;
5249                 break;
5250             }
5251 
5252             default: {
5253                 throw new UnsupportedOperationException("Cannot delete that URL: " + url);
5254             }
5255         }
5256 
5257         if (count > 0) {
5258             getContext().getContentResolver().notifyChange(CONTENT_URI, null,
5259                     true, UserHandle.USER_ALL);
5260         }
5261 
5262         return count;
5263     }
5264 
5265     @Override
update(Uri url, ContentValues values, String where, String[] whereArgs)5266     public int update(Uri url, ContentValues values, String where, String[] whereArgs)
5267     {
5268         mDefaultSubId = SubscriptionManager.getDefaultSubscriptionId();
5269         return updateSynchronized(url, values, where, whereArgs);
5270     }
5271 
updateSynchronized(Uri url, ContentValues values, String where, String[] whereArgs)5272     private synchronized int updateSynchronized(Uri url, ContentValues values, String where,
5273             String[] whereArgs) {
5274         int count = 0;
5275         int uriType = URL_UNKNOWN;
5276         int subId = mDefaultSubId;
5277 
5278         int match = s_urlMatcher.match(url);
5279         checkPermission(match);
5280         syncBearerBitmaskAndNetworkTypeBitmask(values);
5281 
5282         SQLiteDatabase db = getWritableDatabase();
5283         switch (match)
5284         {
5285             case URL_TELEPHONY_USING_SUBID:
5286             {
5287                 loge("insert carriers/subId/* is not supported, treat as carriers");
5288             }
5289             //intentional fall through from above case
5290 
5291             case URL_TELEPHONY:
5292             {
5293                 if (!values.containsKey(EDITED_STATUS)) {
5294                     values.put(EDITED_STATUS, CARRIER_EDITED);
5295                 }
5296 
5297                 // Replace on conflict so that if same APN is present in db with edited
5298                 // as UNEDITED or USER/CARRIER_DELETED, it is replaced with
5299                 // edited USER/CARRIER_EDITED
5300                 count = db.updateWithOnConflict(CARRIERS_TABLE, values, where +
5301                                 " and " + IS_NOT_OWNED_BY_DPC, whereArgs,
5302                         SQLiteDatabase.CONFLICT_REPLACE);
5303                 break;
5304             }
5305 
5306             case URL_CURRENT_USING_SUBID:
5307             {
5308                 loge("insert carriers/current/subId/* is not supported, treat as carriers/current");
5309             }
5310             //intentional fall through from above case
5311 
5312             case URL_CURRENT:
5313             {
5314                 if (!values.containsKey(EDITED_STATUS)) {
5315                     values.put(EDITED_STATUS, CARRIER_EDITED);
5316                 }
5317                 // Replace on conflict so that if same APN is present in db with edited
5318                 // as UNEDITED or USER/CARRIER_DELETED, it is replaced with
5319                 // edited USER/CARRIER_EDITED
5320                 count = db.updateWithOnConflict(CARRIERS_TABLE, values, where +
5321                                 " and " + IS_NOT_OWNED_BY_DPC,
5322                         whereArgs, SQLiteDatabase.CONFLICT_REPLACE);
5323                 break;
5324             }
5325 
5326             case URL_ID:
5327             {
5328                 String rowID = url.getLastPathSegment();
5329                 if (where != null || whereArgs != null) {
5330                     throw new UnsupportedOperationException(
5331                             "Cannot update URL " + url + " with a where clause");
5332                 }
5333                 if (!values.containsKey(EDITED_STATUS)) {
5334                     values.put(EDITED_STATUS, CARRIER_EDITED);
5335                 }
5336 
5337                 try {
5338                     count = db.updateWithOnConflict(CARRIERS_TABLE, values, _ID + "=?" + " and " +
5339                                     IS_NOT_OWNED_BY_DPC, new String[] { rowID },
5340                             SQLiteDatabase.CONFLICT_ABORT);
5341                 } catch (SQLException e) {
5342                     // Update failed which could be due to a conflict. Check if that is
5343                     // the case and merge the entries
5344                     log("update: exception " + e);
5345                     Cursor oldRow = selectConflictingRow(db, CARRIERS_TABLE, values);
5346                     if (oldRow != null) {
5347                         ContentValues mergedValues = new ContentValues();
5348                         mergeFieldsAndUpdateDb(db, CARRIERS_TABLE, oldRow, values,
5349                                 mergedValues, false, getContext());
5350                         oldRow.close();
5351                         db.delete(CARRIERS_TABLE, _ID + "=?" + " and " + IS_NOT_OWNED_BY_DPC,
5352                                 new String[] { rowID });
5353                     }
5354                 }
5355                 break;
5356             }
5357 
5358             case URL_PREFERAPN_USING_SUBID:
5359             case URL_PREFERAPN_NO_UPDATE_USING_SUBID:
5360             {
5361                 String subIdString = url.getLastPathSegment();
5362                 try {
5363                     subId = Integer.parseInt(subIdString);
5364                 } catch (NumberFormatException e) {
5365                     loge("NumberFormatException" + e);
5366                     throw new IllegalArgumentException("Invalid subId " + url);
5367                 }
5368             }
5369 
5370             case URL_PREFERAPN:
5371             case URL_PREFERAPN_NO_UPDATE:
5372             {
5373                 if (values != null) {
5374                     if (values.containsKey(COLUMN_APN_ID)) {
5375                         setPreferredApnId(values.getAsLong(COLUMN_APN_ID), subId, true);
5376                         if ((match == URL_PREFERAPN) ||
5377                                 (match == URL_PREFERAPN_USING_SUBID)) {
5378                             count = 1;
5379                         }
5380                     }
5381                 }
5382                 break;
5383             }
5384 
5385             case URL_DPC_ID:
5386             {
5387                 ensureCallingFromSystemOrPhoneUid("URL_DPC_ID called from non SYSTEM_UID.");
5388 
5389                 if (where != null || whereArgs != null) {
5390                     throw new UnsupportedOperationException(
5391                             "Cannot update URL " + url + " with a where clause");
5392                 }
5393                 count = db.updateWithOnConflict(CARRIERS_TABLE, values,
5394                         _ID + "=?" + " and " + IS_OWNED_BY_DPC,
5395                         new String[] { url.getLastPathSegment() }, SQLiteDatabase.CONFLICT_IGNORE);
5396                 break;
5397             }
5398 
5399             case URL_ENFORCE_MANAGED: {
5400                 ensureCallingFromSystemOrPhoneUid(
5401                         "URL_ENFORCE_MANAGED called from non SYSTEM_UID.");
5402                 if (values != null) {
5403                     if (values.containsKey(ENFORCED_KEY)) {
5404                         setManagedApnEnforced(values.getAsBoolean(ENFORCED_KEY));
5405                         count = 1;
5406                     }
5407                 }
5408                 break;
5409             }
5410 
5411             case URL_SIMINFO_USING_SUBID:
5412                 String subIdString = url.getLastPathSegment();
5413                 try {
5414                     subId = Integer.parseInt(subIdString);
5415                 } catch (NumberFormatException e) {
5416                     loge("NumberFormatException" + e);
5417                     throw new IllegalArgumentException("Invalid subId " + url);
5418                 }
5419                 if (where != null || whereArgs != null) {
5420                     throw new UnsupportedOperationException(
5421                             "Cannot update URL " + url + " with a where clause");
5422                 }
5423                 count = db.update(SIMINFO_TABLE, values, _ID + "=?",
5424                         new String[] { subIdString});
5425                 uriType = URL_SIMINFO_USING_SUBID;
5426                 break;
5427 
5428             case URL_SIMINFO: {
5429                 count = db.update(SIMINFO_TABLE, values, where, whereArgs);
5430                 uriType = URL_SIMINFO;
5431                 break;
5432             }
5433 
5434             case URL_SIMINFO_SUW_RESTORE:
5435                 count = db.update(SIMINFO_TABLE, values, where, whereArgs);
5436                 uriType = URL_SIMINFO_SUW_RESTORE;
5437                 break;
5438 
5439             case URL_SIMINFO_SIM_INSERTED_RESTORE:
5440                 count = db.update(SIMINFO_TABLE, values, where, whereArgs);
5441                 break;
5442 
5443             default: {
5444                 throw new UnsupportedOperationException("Cannot update that URL: " + url);
5445             }
5446         }
5447 
5448         // if APNs (CARRIERS_TABLE) have been updated, some of them may be preferred APN for
5449         // different subs. So update the APN field values saved in SharedPref for all subIds.
5450         switch (match) {
5451             case URL_TELEPHONY_USING_SUBID:
5452             case URL_TELEPHONY:
5453             case URL_CURRENT_USING_SUBID:
5454             case URL_CURRENT:
5455             case URL_ID:
5456             case URL_DPC_ID:
5457                 updatePreferredApns();
5458                 break;
5459         }
5460 
5461         if (count > 0) {
5462             boolean usingSubId = false;
5463             switch (uriType) {
5464                 case URL_SIMINFO_SIM_INSERTED_RESTORE:
5465                     break;
5466                 case URL_SIMINFO_SUW_RESTORE:
5467                     getContext().getContentResolver().notifyChange(
5468                             SubscriptionManager.SIM_INFO_SUW_RESTORE_CONTENT_URI, null);
5469                     // intentional fall through from above case
5470                 case URL_SIMINFO_USING_SUBID:
5471                     usingSubId = true;
5472                     // intentional fall through from above case
5473                 case URL_SIMINFO:
5474                     // skip notifying descendant URLs to avoid unneccessary wake up.
5475                     // If not set, any change to SIMINFO will notify observers which listens to
5476                     // specific field of SIMINFO.
5477                     getContext().getContentResolver().notifyChange(
5478                         Telephony.SimInfo.CONTENT_URI, null,
5479                             ContentResolver.NOTIFY_SYNC_TO_NETWORK
5480                                     | ContentResolver.NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS,
5481                             UserHandle.USER_ALL);
5482                     // notify observers on specific user settings changes.
5483                     if (values.containsKey(Telephony.SimInfo.COLUMN_WFC_IMS_ENABLED)) {
5484                         getContext().getContentResolver().notifyChange(
5485                                 getNotifyContentUri(SubscriptionManager.WFC_ENABLED_CONTENT_URI,
5486                                         usingSubId, subId), null, true, UserHandle.USER_ALL);
5487                     }
5488                     if (values.containsKey(Telephony.SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED)) {
5489                         getContext().getContentResolver().notifyChange(
5490                                 getNotifyContentUri(SubscriptionManager
5491                                                 .ADVANCED_CALLING_ENABLED_CONTENT_URI,
5492                                         usingSubId, subId), null, true, UserHandle.USER_ALL);
5493                     }
5494                     if (values.containsKey(Telephony.SimInfo.COLUMN_VT_IMS_ENABLED)) {
5495                         getContext().getContentResolver().notifyChange(
5496                                 getNotifyContentUri(SubscriptionManager.VT_ENABLED_CONTENT_URI,
5497                                         usingSubId, subId), null, true, UserHandle.USER_ALL);
5498                     }
5499                     if (values.containsKey(Telephony.SimInfo.COLUMN_WFC_IMS_MODE)) {
5500                         getContext().getContentResolver().notifyChange(
5501                                 getNotifyContentUri(SubscriptionManager.WFC_MODE_CONTENT_URI,
5502                                         usingSubId, subId), null, true, UserHandle.USER_ALL);
5503                     }
5504                     if (values.containsKey(Telephony.SimInfo.COLUMN_WFC_IMS_ROAMING_MODE)) {
5505                         getContext().getContentResolver().notifyChange(getNotifyContentUri(
5506                                 SubscriptionManager.WFC_ROAMING_MODE_CONTENT_URI,
5507                                 usingSubId, subId), null, true, UserHandle.USER_ALL);
5508                     }
5509                     if (values.containsKey(Telephony.SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED)) {
5510                         getContext().getContentResolver().notifyChange(getNotifyContentUri(
5511                                 SubscriptionManager.WFC_ROAMING_ENABLED_CONTENT_URI,
5512                                 usingSubId, subId), null, true, UserHandle.USER_ALL);
5513                     }
5514                     if (values.containsKey(Telephony.SimInfo.COLUMN_IMS_RCS_UCE_ENABLED)) {
5515                         getContext().getContentResolver().notifyChange(getNotifyContentUri(
5516                                         Uri.withAppendedPath(Telephony.SimInfo.CONTENT_URI,
5517                                                 Telephony.SimInfo.COLUMN_IMS_RCS_UCE_ENABLED),
5518                                         usingSubId, subId), null, true, UserHandle.USER_ALL);
5519                     }
5520                     if (values.containsKey(Telephony.SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED)) {
5521                         getContext().getContentResolver().notifyChange(getNotifyContentUri(
5522                                 Uri.withAppendedPath(Telephony.SimInfo.CONTENT_URI,
5523                                         Telephony.SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED),
5524                                 usingSubId, subId), null, true, UserHandle.USER_ALL);
5525                     }
5526                     if (values.containsKey(Telephony.SimInfo.COLUMN_VOIMS_OPT_IN_STATUS)) {
5527                         getContext().getContentResolver().notifyChange(getNotifyContentUri(
5528                                 Uri.withAppendedPath(Telephony.SimInfo.CONTENT_URI,
5529                                         Telephony.SimInfo.COLUMN_VOIMS_OPT_IN_STATUS),
5530                                 usingSubId, subId), null, true, UserHandle.USER_ALL);
5531                     }
5532                     if (values.containsKey(Telephony.SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED)) {
5533                         getContext().getContentResolver().notifyChange(getNotifyContentUri(
5534                                 Uri.withAppendedPath(Telephony.SimInfo.CONTENT_URI,
5535                                         Telephony.SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED),
5536                                 usingSubId, subId), null, true, UserHandle.USER_ALL);
5537                     }
5538                     if (values.containsKey(Telephony.SimInfo.COLUMN_USAGE_SETTING)) {
5539                         getContext().getContentResolver().notifyChange(getNotifyContentUri(
5540                                 Uri.withAppendedPath(Telephony.SimInfo.CONTENT_URI,
5541                                         Telephony.SimInfo.COLUMN_USAGE_SETTING),
5542                                 usingSubId, subId), null, true, UserHandle.USER_ALL);
5543                     }
5544                     if (values.containsKey(Telephony.SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES)) {
5545                         getContext().getContentResolver().notifyChange(getNotifyContentUri(
5546                                 Uri.withAppendedPath(Telephony.SimInfo.CONTENT_URI,
5547                                         Telephony.SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES),
5548                                 usingSubId, subId), null, true, UserHandle.USER_ALL);
5549                     }
5550                     if (values.containsKey(
5551                             Telephony.SimInfo.COLUMN_SERVICE_CAPABILITIES)) {
5552                         getContext().getContentResolver().notifyChange(getNotifyContentUri(
5553                                 Uri.withAppendedPath(Telephony.SimInfo.CONTENT_URI,
5554                                         Telephony.SimInfo.COLUMN_SERVICE_CAPABILITIES),
5555                                 usingSubId, subId), null, true, UserHandle.USER_ALL);
5556                     }
5557                     if (values.containsKey(
5558                             Telephony.SimInfo.COLUMN_TRANSFER_STATUS)) {
5559                         getContext().getContentResolver().notifyChange(getNotifyContentUri(
5560                                 Uri.withAppendedPath(Telephony.SimInfo.CONTENT_URI,
5561                                         Telephony.SimInfo.COLUMN_TRANSFER_STATUS),
5562                                 usingSubId, subId), null, true, UserHandle.USER_ALL);
5563                     }
5564                     break;
5565                 default:
5566                     getContext().getContentResolver().notifyChange(
5567                             CONTENT_URI, null, true, UserHandle.USER_ALL);
5568             }
5569         }
5570 
5571         return count;
5572     }
5573 
getNotifyContentUri(Uri uri, boolean usingSubId, int subId)5574     private static Uri getNotifyContentUri(Uri uri, boolean usingSubId, int subId) {
5575         return (usingSubId) ? Uri.withAppendedPath(uri, "" + subId) : uri;
5576     }
5577 
5578     /**
5579      * Checks permission to query or insert/update/delete the database. The permissions required
5580      * for APN DB and SIMINFO DB are different:
5581      * <ul>
5582      * <li>APN DB requires WRITE_APN_SETTINGS or carrier privileges
5583      * <li>SIMINFO DB requires phone UID; it's for phone internal usage only
5584      * </ul>
5585      */
checkPermission(int match)5586     private void checkPermission(int match) {
5587         switch (match) {
5588             case URL_SIMINFO:
5589             case URL_SIMINFO_USING_SUBID:
5590             case URL_SIMINFO_SUW_RESTORE:
5591             case URL_SIMINFO_SIM_INSERTED_RESTORE:
5592                 checkPermissionForSimInfoTable();
5593                 break;
5594             default:
5595                 checkPermissionForApnTable();
5596         }
5597     }
5598 
checkPermissionForApnTable()5599     private void checkPermissionForApnTable() {
5600         int status = getContext().checkCallingOrSelfPermission(
5601                 "android.permission.WRITE_APN_SETTINGS");
5602         if (status == PackageManager.PERMISSION_GRANTED) {
5603             return;
5604         }
5605 
5606         PackageManager packageManager = getContext().getPackageManager();
5607         if (Flags.hsumPackageManager()) {
5608             packageManager = getContext().createContextAsUser(Binder.getCallingUserHandle(), 0)
5609                     .getPackageManager();
5610         }
5611         String[] packages = packageManager.getPackagesForUid(Binder.getCallingUid());
5612 
5613         TelephonyManager telephonyManager =
5614                 (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
5615         final long token = Binder.clearCallingIdentity();
5616         try {
5617             for (String pkg : packages) {
5618                 if (telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(pkg) ==
5619                     TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
5620                     return;
5621                 }
5622             }
5623         } finally {
5624             Binder.restoreCallingIdentity(token);
5625         }
5626 
5627         throw new SecurityException("No permission to access APN settings");
5628     }
5629 
5630     /**
5631      * Check permission to query the database based on PlatformCompat settings -- if the compat
5632      * change is enabled, check WRITE_APN_SETTINGS or carrier privs for all queries. Otherwise,
5633      * use the legacy checkQueryPermission method to see if the query should be allowed.
5634      */
checkPermissionCompat(int match, String[] projectionIn)5635     private void checkPermissionCompat(int match, String[] projectionIn) {
5636         boolean useNewBehavior = CompatChanges.isChangeEnabled(
5637                 Telephony.Carriers.APN_READING_PERMISSION_CHANGE_ID,
5638                 Binder.getCallingUid());
5639 
5640         if (!useNewBehavior) {
5641             log("Using old permission behavior for telephony provider compat");
5642             checkQueryPermission(match, projectionIn);
5643         } else {
5644             checkPermission(match);
5645         }
5646     }
5647 
checkQueryPermission(int match, String[] projectionIn)5648     private void checkQueryPermission(int match, String[] projectionIn) {
5649         if (match == URL_SIMINFO) {
5650             checkPermissionForSimInfoTable();
5651         } else {
5652             if (projectionIn != null) {
5653                 for (String column : projectionIn) {
5654                     if (TYPE.equals(column) ||
5655                             MMSC.equals(column) ||
5656                             MMSPROXY.equals(column) ||
5657                             MMSPORT.equals(column) ||
5658                             MVNO_TYPE.equals(column) ||
5659                             MVNO_MATCH_DATA.equals(column) ||
5660                             APN.equals(column)) {
5661                         // noop
5662                     } else {
5663                         checkPermissionForApnTable();
5664                         break;
5665                     }
5666                 }
5667             } else {
5668                 // null returns all columns, so need permission check
5669                 checkPermissionForApnTable();
5670             }
5671         }
5672     }
5673 
checkPermissionForSimInfoTable()5674     private void checkPermissionForSimInfoTable() {
5675         ensureCallingFromSystemOrPhoneUid("Access SIMINFO table from not phone/system UID");
5676         if (getContext().checkCallingOrSelfPermission(
5677                     "android.permission.ACCESS_TELEPHONY_SIMINFO_DB")
5678                 == PackageManager.PERMISSION_GRANTED) {
5679             return;
5680         }
5681         throw new SecurityException("No permission to access SIMINFO table");
5682     }
5683 
5684     private DatabaseHelper mOpenHelper;
5685 
restoreDefaultAPN(int subId)5686     private void restoreDefaultAPN(int subId) {
5687         SQLiteDatabase db = getWritableDatabase();
5688         TelephonyManager telephonyManager =
5689                 (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
5690         String where = null;
5691         if (telephonyManager.getPhoneCount() > 1) {
5692             where = getWhereClauseForRestoreDefaultApn(db, subId);
5693         }
5694         if (TextUtils.isEmpty(where)) {
5695             where = IS_NOT_OWNED_BY_DPC;
5696         }
5697         log("restoreDefaultAPN: where: " + where);
5698 
5699         try {
5700             db.delete(CARRIERS_TABLE, where, null);
5701         } catch (SQLException e) {
5702             loge("got exception when deleting to restore: " + e);
5703         }
5704 
5705         // delete preferred apn ids and preferred apns (both stored in diff SharedPref) for all
5706         // subIds
5707         SharedPreferences spApnId = getContext().getSharedPreferences(PREF_FILE_APN,
5708                 Context.MODE_PRIVATE);
5709         SharedPreferences.Editor editorApnId = spApnId.edit();
5710         editorApnId.clear();
5711         editorApnId.apply();
5712 
5713         SharedPreferences spApn = getContext().getSharedPreferences(PREF_FILE_FULL_APN,
5714                 Context.MODE_PRIVATE);
5715         SharedPreferences.Editor editorApn = spApn.edit();
5716         editorApn.clear();
5717         editorApn.apply();
5718 
5719         if (apnSourceServiceExists(getContext())) {
5720             restoreApnsWithService(subId);
5721         } else {
5722             initDatabaseWithDatabaseHelper(db);
5723         }
5724     }
5725 
getWhereClauseForRestoreDefaultApn(SQLiteDatabase db, int subId)5726     private String getWhereClauseForRestoreDefaultApn(SQLiteDatabase db, int subId) {
5727         TelephonyManager telephonyManager =
5728             getContext().getSystemService(TelephonyManager.class).createForSubscriptionId(subId);
5729         String simOperator = telephonyManager.getSimOperator();
5730         int simCarrierId = telephonyManager.getSimSpecificCarrierId();
5731         Cursor cursor = db.query(CARRIERS_TABLE, new String[] {MVNO_TYPE, MVNO_MATCH_DATA},
5732                 NUMERIC + "='" + simOperator + "'", null, null, null, DEFAULT_SORT_ORDER);
5733         String where = null;
5734 
5735         if (cursor != null) {
5736             cursor.moveToFirst();
5737             while (!cursor.isAfterLast()) {
5738                 String mvnoType = cursor.getString(0 /* MVNO_TYPE index */);
5739                 String mvnoMatchData = cursor.getString(1 /* MVNO_MATCH_DATA index */);
5740                 if (!TextUtils.isEmpty(mvnoType) && !TextUtils.isEmpty(mvnoMatchData)
5741                         && telephonyManager.matchesCurrentSimOperator(simOperator,
5742                             getMvnoTypeIntFromString(mvnoType), mvnoMatchData)) {
5743                     where = NUMERIC + "='" + simOperator + "'"
5744                             + " AND " + MVNO_TYPE + "='" + mvnoType + "'"
5745                             + " AND " + MVNO_MATCH_DATA + "='" + mvnoMatchData + "'"
5746                             + " AND " + IS_NOT_OWNED_BY_DPC;
5747                     break;
5748                 }
5749                 cursor.moveToNext();
5750             }
5751             cursor.close();
5752 
5753             if (TextUtils.isEmpty(where)) {
5754                 where = NUMERIC + "='" + simOperator + "'"
5755                         + " AND (" + MVNO_TYPE + "='' OR " + MVNO_MATCH_DATA + "='')"
5756                         + " AND " + IS_NOT_OWNED_BY_DPC;
5757             }
5758             // Add carrier id APNs
5759             if (TelephonyManager.UNKNOWN_CARRIER_ID < simCarrierId) {
5760                 where = where.concat(" OR " + CARRIER_ID + " = '" + simCarrierId + "'" + " AND "
5761                         + IS_NOT_OWNED_BY_DPC);
5762             }
5763 
5764         }
5765         return where;
5766     }
5767 
updateApnDb()5768     private synchronized void updateApnDb() {
5769         if (apnSourceServiceExists(getContext())) {
5770             loge("called updateApnDb when apn source service exists");
5771             return;
5772         }
5773 
5774         // On first boot getWritableDatabase() triggers
5775         // DatabaseHelper.onCreate() which in turn will call initDatabase.
5776         // To avoid loading APNs twice call getWritableDatabase() before needApnDbUpdate()
5777         SQLiteDatabase db = getWritableDatabase();
5778 
5779         if (!needApnDbUpdate()) {
5780             log("Skipping apn db update since apn-conf has not changed.");
5781             return;
5782         }
5783 
5784         // Delete preferred APN for all subIds
5785         deletePreferredApnId(getContext());
5786 
5787         // Delete entries in db
5788         try {
5789             if (VDBG) log("updateApnDb: deleting edited=UNEDITED entries");
5790             db.delete(CARRIERS_TABLE, IS_UNEDITED + " and " + IS_NOT_OWNED_BY_DPC, null);
5791         } catch (SQLException e) {
5792             loge("got exception when deleting to update: " + e);
5793         }
5794 
5795         initDatabaseWithDatabaseHelper(db);
5796 
5797         // Notify listeners of DB change since DB has been updated
5798         getContext().getContentResolver().notifyChange(
5799                 CONTENT_URI, null, true, UserHandle.USER_ALL);
5800 
5801     }
5802 
fillInMccMncStringAtCursor(Context context, SQLiteDatabase db, Cursor c)5803     public static void fillInMccMncStringAtCursor(Context context, SQLiteDatabase db, Cursor c) {
5804         int mcc, mnc;
5805         String subId;
5806         try {
5807             mcc = c.getInt(c.getColumnIndexOrThrow(Telephony.SimInfo.COLUMN_MCC));
5808             mnc = c.getInt(c.getColumnIndexOrThrow(Telephony.SimInfo.COLUMN_MNC));
5809             subId = c.getString(c.getColumnIndexOrThrow(
5810                     Telephony.SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID));
5811         } catch (IllegalArgumentException e) {
5812             Log.e(TAG, "Possible database corruption -- some columns not found.");
5813             return;
5814         }
5815 
5816         String mccString = String.format(Locale.getDefault(), "%03d", mcc);
5817         String mncString = getBestStringMnc(context, mccString, mnc);
5818         ContentValues cv = new ContentValues(2);
5819         cv.put(Telephony.SimInfo.COLUMN_MCC_STRING, mccString);
5820         cv.put(Telephony.SimInfo.COLUMN_MNC_STRING, mncString);
5821         db.update(SIMINFO_TABLE, cv,
5822                 Telephony.SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID + "=?",
5823                 new String[]{subId});
5824     }
5825 
5826     /*
5827      * Find the best string-form mnc by looking up possibilities in the carrier id db.
5828      * Default to the three-digit version if neither/both are valid.
5829      */
getBestStringMnc(Context context, String mcc, int mnc)5830     private static String getBestStringMnc(Context context, String mcc, int mnc) {
5831         if (mnc >= 100 && mnc <= 999) {
5832             return String.valueOf(mnc);
5833         }
5834         String twoDigitMnc = String.format(Locale.getDefault(), "%02d", mnc);
5835         String threeDigitMnc = "0" + twoDigitMnc;
5836         boolean threeDigitNetworkCode =
5837                 Arrays.asList(COUNTRY_MCC_WITH_THREE_DIGIT_MNC).contains(mcc);
5838         int twoDigitResult = countMccMncInCarrierList(context, mcc + twoDigitMnc);
5839         int threeDigitResult = countMccMncInCarrierList(context, mcc + threeDigitMnc);
5840 
5841         if ((threeDigitResult > twoDigitResult) ||
5842                 (threeDigitNetworkCode && (twoDigitResult == threeDigitResult))) {
5843             return threeDigitMnc;
5844         } else {
5845             return twoDigitMnc;
5846         }
5847     }
5848 
5849     /**
5850      * Check carrier_list how many mcc mnc combo matches there are
5851      */
countMccMncInCarrierList(Context ctx, String mccMncCombo)5852     private static int countMccMncInCarrierList(Context ctx, String mccMncCombo) {
5853         try (
5854             Cursor mccMncCursor = ctx.getContentResolver().query(
5855                     Telephony.CarrierId.All.CONTENT_URI,
5856                     /* projection */ null,
5857                     /* selection */ Telephony.CarrierId.All.MCCMNC + "=?",
5858                     /* selectionArgs */ new String[]{mccMncCombo}, null);
5859         )
5860         {
5861             return mccMncCursor.getCount();
5862         }
5863     }
5864 
5865     /**
5866      * Sync the bearer bitmask and network type bitmask when inserting and updating.
5867      * Since bearerBitmask is deprecating, map the networkTypeBitmask to bearerBitmask if
5868      * networkTypeBitmask was provided. But if networkTypeBitmask was not provided, map the
5869      * bearerBitmask to networkTypeBitmask.
5870      */
syncBearerBitmaskAndNetworkTypeBitmask(ContentValues values)5871     private static void syncBearerBitmaskAndNetworkTypeBitmask(ContentValues values) {
5872         if (values.containsKey(NETWORK_TYPE_BITMASK)) {
5873             int convertedBitmask = convertNetworkTypeBitmaskToBearerBitmask(
5874                     values.getAsInteger(NETWORK_TYPE_BITMASK));
5875             if (values.containsKey(BEARER_BITMASK)
5876                     && convertedBitmask != values.getAsInteger(BEARER_BITMASK)) {
5877                 loge("Network type bitmask and bearer bitmask are not compatible.");
5878             }
5879             values.put(BEARER_BITMASK, convertNetworkTypeBitmaskToBearerBitmask(
5880                     values.getAsInteger(NETWORK_TYPE_BITMASK)));
5881         } else {
5882             if (values.containsKey(BEARER_BITMASK)) {
5883                 int convertedBitmask = convertBearerBitmaskToNetworkTypeBitmask(
5884                         values.getAsInteger(BEARER_BITMASK));
5885                 values.put(NETWORK_TYPE_BITMASK, convertedBitmask);
5886             }
5887         }
5888     }
5889 
5890     /**
5891      * Log with debug
5892      *
5893      * @param s is string log
5894      */
log(String s)5895     private static void log(String s) {
5896         Log.d(TAG, s);
5897     }
5898 
loge(String s)5899     private static void loge(String s) {
5900         Log.e(TAG, s);
5901     }
5902 
getMvnoTypeIntFromString(String mvnoType)5903     private static int getMvnoTypeIntFromString(String mvnoType) {
5904         String mvnoTypeString = TextUtils.isEmpty(mvnoType) ? mvnoType : mvnoType.toLowerCase(Locale.ROOT);
5905         Integer mvnoTypeInt = MVNO_TYPE_STRING_MAP.get(mvnoTypeString);
5906         return  mvnoTypeInt == null ? ApnSetting.MVNO_TYPE_UNKNOWN : mvnoTypeInt;
5907     }
5908 
getBitmaskFromString(String bearerList)5909     private static int getBitmaskFromString(String bearerList) {
5910         String[] bearers = bearerList.split("\\|");
5911         int bearerBitmask = 0;
5912         for (String bearer : bearers) {
5913             int bearerInt = 0;
5914             try {
5915                 bearerInt = Integer.parseInt(bearer.trim());
5916             } catch (NumberFormatException nfe) {
5917                 return 0;
5918             }
5919 
5920             if (bearerInt == 0) {
5921                 return 0;
5922             }
5923             bearerBitmask |= getBitmaskForTech(bearerInt);
5924         }
5925         return bearerBitmask;
5926     }
5927 
5928     /**
5929      * Get the infrastructure bitmask from string
5930      *
5931      * @param infrastructureString The infrastructure list in string format. For example
5932      * {@code "cellular|satellite"}.
5933      *
5934      * @return The infrastructure bitmask.
5935      */
getInfrastructureListFromString(@onNull String infrastructureString)5936     private static int getInfrastructureListFromString(@NonNull String infrastructureString) {
5937         String[] infras = infrastructureString.split("\\|");
5938         int infrastructureBitmask = 0;
5939         for (String infrastructure : infras) {
5940             switch (infrastructure.toLowerCase(Locale.ROOT)) {
5941                 case "cellular":
5942                     infrastructureBitmask |= ApnSetting.INFRASTRUCTURE_CELLULAR;
5943                     break;
5944                 case "satellite":
5945                     infrastructureBitmask |= ApnSetting.INFRASTRUCTURE_SATELLITE;
5946                     break;
5947             }
5948         }
5949         return infrastructureBitmask;
5950     }
5951 
5952     /**
5953      * Transform RIL radio technology value to Network
5954      * type bitmask{@link android.telephony.TelephonyManager.NetworkTypeBitMask}.
5955      *
5956      * @param rat The RIL radio technology.
5957      * @return The network type
5958      * bitmask{@link android.telephony.TelephonyManager.NetworkTypeBitMask}.
5959      */
rilRadioTechnologyToNetworkTypeBitmask(int rat)5960     private static int rilRadioTechnologyToNetworkTypeBitmask(int rat) {
5961         switch (rat) {
5962             case RIL_RADIO_TECHNOLOGY_GPRS:
5963                 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_GPRS;
5964             case RIL_RADIO_TECHNOLOGY_EDGE:
5965                 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_EDGE;
5966             case RIL_RADIO_TECHNOLOGY_UMTS:
5967                 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_UMTS;
5968             case RIL_RADIO_TECHNOLOGY_HSDPA:
5969                 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_HSDPA;
5970             case RIL_RADIO_TECHNOLOGY_HSUPA:
5971                 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_HSUPA;
5972             case RIL_RADIO_TECHNOLOGY_HSPA:
5973                 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_HSPA;
5974             case RIL_RADIO_TECHNOLOGY_IS95A:
5975             case RIL_RADIO_TECHNOLOGY_IS95B:
5976                 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_CDMA;
5977             case RIL_RADIO_TECHNOLOGY_1xRTT:
5978                 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_1xRTT;
5979             case RIL_RADIO_TECHNOLOGY_EVDO_0:
5980                 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_EVDO_0;
5981             case RIL_RADIO_TECHNOLOGY_EVDO_A:
5982                 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_EVDO_A;
5983             case RIL_RADIO_TECHNOLOGY_EVDO_B:
5984                 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_EVDO_B;
5985             case RIL_RADIO_TECHNOLOGY_EHRPD:
5986                 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_EHRPD;
5987             case RIL_RADIO_TECHNOLOGY_LTE:
5988                 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_LTE;
5989             case RIL_RADIO_TECHNOLOGY_HSPAP:
5990                 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_HSPAP;
5991             case RIL_RADIO_TECHNOLOGY_GSM:
5992                 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_GSM;
5993             case RIL_RADIO_TECHNOLOGY_TD_SCDMA:
5994                 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_TD_SCDMA;
5995             case RIL_RADIO_TECHNOLOGY_IWLAN:
5996                 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_IWLAN;
5997             case RIL_RADIO_TECHNOLOGY_LTE_CA:
5998                 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_LTE_CA;
5999             case RIL_RADIO_TECHNOLOGY_NR:
6000                 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_NR;
6001             default:
6002                 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_UNKNOWN;
6003         }
6004     }
6005 
6006     /**
6007      * Convert network type bitmask to bearer bitmask.
6008      *
6009      * @param networkTypeBitmask The network type bitmask value
6010      * @return The bearer bitmask value.
6011      */
convertNetworkTypeBitmaskToBearerBitmask(int networkTypeBitmask)6012     private static int convertNetworkTypeBitmaskToBearerBitmask(int networkTypeBitmask) {
6013         if (networkTypeBitmask == 0) {
6014             return 0;
6015         }
6016 
6017         int bearerBitmask = 0;
6018         for (int bearerInt = 0; bearerInt < NEXT_RIL_RADIO_TECHNOLOGY; bearerInt++) {
6019             if (bitmaskHasTarget(networkTypeBitmask,
6020                     rilRadioTechnologyToNetworkTypeBitmask(bearerInt))) {
6021                 bearerBitmask |= getBitmaskForTech(bearerInt);
6022             }
6023         }
6024         return bearerBitmask;
6025     }
6026 
6027     /**
6028      * Convert bearer bitmask to network type bitmask.
6029      *
6030      * @param bearerBitmask The bearer bitmask value.
6031      * @return The network type bitmask value.
6032      */
convertBearerBitmaskToNetworkTypeBitmask(int bearerBitmask)6033     private static int convertBearerBitmaskToNetworkTypeBitmask(int bearerBitmask) {
6034         if (bearerBitmask == 0) {
6035             return 0;
6036         }
6037 
6038         int networkTypeBitmask = 0;
6039         for (int bearerUnitInt = 0; bearerUnitInt < NEXT_RIL_RADIO_TECHNOLOGY; bearerUnitInt++) {
6040             int bearerUnitBitmask = getBitmaskForTech(bearerUnitInt);
6041             if (bitmaskHasTarget(bearerBitmask, bearerUnitBitmask)) {
6042                 networkTypeBitmask |= rilRadioTechnologyToNetworkTypeBitmask(bearerUnitInt);
6043             }
6044         }
6045         return networkTypeBitmask;
6046     }
6047 
bitmaskHasTarget(int bearerBitmask, int targetBitmask)6048     private static boolean bitmaskHasTarget(int bearerBitmask, int targetBitmask) {
6049         if (bearerBitmask == 0) {
6050             return true;
6051         } else if (targetBitmask != 0) {
6052             return ((bearerBitmask & targetBitmask) != 0);
6053         }
6054         return false;
6055     }
6056 
getBitmaskForTech(int radioTech)6057     private static int getBitmaskForTech(int radioTech) {
6058         if (radioTech >= 1) {
6059             return (1 << (radioTech - 1));
6060         }
6061         return 0;
6062     }
6063 
6064     /**
6065      * Migrate the old Long values{@link Telephony.SimInfo.COLUMN_ALLOWED_NETWORK_TYPES} over to
6066      * String{@link Telephony.SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_ALL_REASON}
6067      *
6068      * @param db The sqlite database to write to
6069      * @param c The {@link Telephony.SimInfo.COLUMN_ALLOWED_NETWORK_TYPES} values in the sim info
6070      *         table.
6071      */
fillInAllowedNetworkTypesStringAtCursor(SQLiteDatabase db, Cursor c)6072     public static void fillInAllowedNetworkTypesStringAtCursor(SQLiteDatabase db, Cursor c) {
6073         long allowedNetworkTypesReasonCarrier;
6074         String subId;
6075         try {
6076             allowedNetworkTypesReasonCarrier = c.getLong(
6077                     c.getColumnIndexOrThrow(Telephony.SimInfo.COLUMN_ALLOWED_NETWORK_TYPES));
6078             subId = c.getString(c.getColumnIndexOrThrow(
6079                     Telephony.SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID));
6080         } catch (IllegalArgumentException e) {
6081             Log.e(TAG, "Possible database corruption -- some columns not found.");
6082             return;
6083         }
6084 
6085         if (allowedNetworkTypesReasonCarrier != -1) {
6086             ContentValues cv = new ContentValues(1);
6087 
6088             cv.put(Telephony.SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS,
6089                     "carrier=" + allowedNetworkTypesReasonCarrier);
6090             db.update(SIMINFO_TABLE, cv,
6091                     Telephony.SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID + "=?",
6092                     new String[]{subId});
6093         }
6094     }
6095 
6096     /**
6097      * Migrate the old values{@link Telephony.SimInfo#COLUMN_DATA_ENABLED_OVERRIDE_RULES} over to
6098      * String{@link Telephony.SimInfo#COLUMN_ENABLED_MOBILE_DATA_POLICIES}
6099      *
6100      * @param db The sqlite database to write to
6101      * @param c The {@link Telephony.SimInfo#COLUMN_DATA_ENABLED_OVERRIDE_RULES} values in the sim info
6102      *         table.
6103      */
fillInEnabledMobileDataPoliciesAtCursor(SQLiteDatabase db, Cursor c)6104     public static void fillInEnabledMobileDataPoliciesAtCursor(SQLiteDatabase db, Cursor c) {
6105         String overrideRule;
6106         String subId;
6107         try {
6108             overrideRule = c.getString(
6109                     c.getColumnIndexOrThrow(Telephony.SimInfo.COLUMN_DATA_ENABLED_OVERRIDE_RULES));
6110             subId = c.getString(c.getColumnIndexOrThrow(
6111                     Telephony.SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID));
6112         } catch (IllegalArgumentException e) {
6113             Log.e(TAG, "COLUMN_DATA_ENABLED_OVERRIDE_RULES not found.");
6114             return;
6115         }
6116 
6117         if (overrideRule != null) {
6118             ContentValues cv = new ContentValues(1);
6119 
6120             // convert override rule to its corresponding mobile data policy
6121             overrideRule = overrideRule.contains("mms") ?
6122                     String.valueOf(TelephonyManager.MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED): "";
6123             cv.put(Telephony.SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES, overrideRule);
6124             db.update(SIMINFO_TABLE, cv,
6125                     Telephony.SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID + "=?",
6126                     new String[]{subId});
6127         }
6128     }
6129 
6130     /**
6131      * Dump the database table.
6132      *
6133      * @param tableName Table name.
6134      * @param pw Print writer.
6135      */
dumpTable(@onNull String tableName, @NonNull IndentingPrintWriter pw)6136     private void dumpTable(@NonNull String tableName, @NonNull IndentingPrintWriter pw) {
6137         try (Cursor cursor = getReadableDatabase().query(false, tableName, null,
6138                 null, null, null, null, null, null)) {
6139             pw.println(tableName + " table:");
6140             pw.increaseIndent();
6141             while (cursor != null && cursor.moveToNext()) {
6142                 List<String> columnStrings = new ArrayList<>();
6143                 String str = "";
6144                 for (int i = 0; i < cursor.getColumnCount(); i++) {
6145                     str = cursor.getColumnName(i) + "=";
6146                     int type = cursor.getType(i);
6147                     try {
6148                         switch (type) {
6149                             case 0 /*FIELD_TYPE_NULL*/:
6150                                 str += "null";
6151                                 break;
6152                             case 1 /*FIELD_TYPE_INTEGER*/:
6153                                 str += cursor.getInt(i);
6154                                 break;
6155                             case 2 /*FIELD_TYPE_FLOAT*/:
6156                                 str += cursor.getFloat(i);
6157                                 break;
6158                             case 3 /*FIELD_TYPE_STRING*/:
6159                                 String columnValue = cursor.getString(i);
6160                                 // Redact icc_id and card_id
6161                                 if (SIMINFO_TABLE.equals(tableName)
6162                                         && (Telephony.SimInfo.COLUMN_ICC_ID.equals(
6163                                                 cursor.getColumnName(i))
6164                                         || Telephony.SimInfo.COLUMN_CARD_ID.equals(
6165                                                 cursor.getColumnName(i)))) {
6166                                     columnValue = SubscriptionInfo.getPrintableId(columnValue);
6167                                 }
6168                                 str += columnValue;
6169                                 break;
6170                             case 4 /*FIELD_TYPE_BLOB*/:
6171                                 str += "[blob]";
6172                                 break;
6173                             default:
6174                                 str += "unknown";
6175                                 break;
6176                         }
6177                     } catch (Exception e) {
6178                         str += "exception";
6179                     }
6180                     columnStrings.add(str);
6181                 }
6182                 pw.println(TextUtils.join(", ", columnStrings));
6183             }
6184             pw.decreaseIndent();
6185         } catch (Exception ex) {
6186             pw.println("Exception while dumping the table " + tableName + ", ex=" + ex);
6187         }
6188     }
6189 
6190     @Override
dump(FileDescriptor fd, PrintWriter printWriter, String[] args)6191     public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) {
6192         IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, "  ");
6193         pw.println(TAG + ":");
6194         pw.increaseIndent();
6195         pw.println("Database:");
6196         pw.increaseIndent();
6197         dumpTable(SIMINFO_TABLE, pw);
6198         dumpTable(CARRIERS_TABLE, pw);
6199         pw.decreaseIndent();
6200         pw.println("Local log:");
6201         pw.increaseIndent();
6202         mLocalLog.dump(pw);
6203         pw.decreaseIndent();
6204         pw.decreaseIndent();
6205     }
6206 }
6207