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