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