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