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.APN; 21 import static android.provider.Telephony.Carriers.APN_SET_ID; 22 import static android.provider.Telephony.Carriers.AUTH_TYPE; 23 import static android.provider.Telephony.Carriers.BEARER; 24 import static android.provider.Telephony.Carriers.BEARER_BITMASK; 25 import static android.provider.Telephony.Carriers.CARRIER_DELETED; 26 import static android.provider.Telephony.Carriers.CARRIER_DELETED_BUT_PRESENT_IN_XML; 27 import static android.provider.Telephony.Carriers.CARRIER_EDITED; 28 import static android.provider.Telephony.Carriers.CARRIER_ENABLED; 29 import static android.provider.Telephony.Carriers.CARRIER_ID; 30 import static android.provider.Telephony.Carriers.CONTENT_URI; 31 import static android.provider.Telephony.Carriers.CURRENT; 32 import static android.provider.Telephony.Carriers.DEFAULT_SORT_ORDER; 33 import static android.provider.Telephony.Carriers.EDITED_STATUS; 34 import static android.provider.Telephony.Carriers.MAX_CONNECTIONS; 35 import static android.provider.Telephony.Carriers.TIME_LIMIT_FOR_MAX_CONNECTIONS; 36 import static android.provider.Telephony.Carriers.MCC; 37 import static android.provider.Telephony.Carriers.MMSC; 38 import static android.provider.Telephony.Carriers.MMSPORT; 39 import static android.provider.Telephony.Carriers.MMSPROXY; 40 import static android.provider.Telephony.Carriers.MNC; 41 import static android.provider.Telephony.Carriers.MODEM_PERSIST; 42 import static android.provider.Telephony.Carriers.MTU; 43 import static android.provider.Telephony.Carriers.MVNO_MATCH_DATA; 44 import static android.provider.Telephony.Carriers.MVNO_TYPE; 45 import static android.provider.Telephony.Carriers.NAME; 46 import static android.provider.Telephony.Carriers.NETWORK_TYPE_BITMASK; 47 import static android.provider.Telephony.Carriers.NO_APN_SET_ID; 48 import static android.provider.Telephony.Carriers.NUMERIC; 49 import static android.provider.Telephony.Carriers.OWNED_BY; 50 import static android.provider.Telephony.Carriers.OWNED_BY_DPC; 51 import static android.provider.Telephony.Carriers.OWNED_BY_OTHERS; 52 import static android.provider.Telephony.Carriers.PASSWORD; 53 import static android.provider.Telephony.Carriers.PORT; 54 import static android.provider.Telephony.Carriers.PROFILE_ID; 55 import static android.provider.Telephony.Carriers.PROTOCOL; 56 import static android.provider.Telephony.Carriers.PROXY; 57 import static android.provider.Telephony.Carriers.ROAMING_PROTOCOL; 58 import static android.provider.Telephony.Carriers.SERVER; 59 import static android.provider.Telephony.Carriers.SKIP_464XLAT; 60 import static android.provider.Telephony.Carriers.SKIP_464XLAT_DEFAULT; 61 import static android.provider.Telephony.Carriers.SUBSCRIPTION_ID; 62 import static android.provider.Telephony.Carriers.TYPE; 63 import static android.provider.Telephony.Carriers.UNEDITED; 64 import static android.provider.Telephony.Carriers.USER; 65 import static android.provider.Telephony.Carriers.USER_DELETED; 66 import static android.provider.Telephony.Carriers.USER_DELETED_BUT_PRESENT_IN_XML; 67 import static android.provider.Telephony.Carriers.USER_EDITABLE; 68 import static android.provider.Telephony.Carriers.USER_EDITED; 69 import static android.provider.Telephony.Carriers.USER_VISIBLE; 70 import static android.provider.Telephony.Carriers.WAIT_TIME_RETRY; 71 import static android.provider.Telephony.Carriers._ID; 72 73 import android.annotation.NonNull; 74 import android.content.ComponentName; 75 import android.content.ContentProvider; 76 import android.content.ContentResolver; 77 import android.content.ContentUris; 78 import android.content.ContentValues; 79 import android.content.Context; 80 import android.content.Intent; 81 import android.content.ServiceConnection; 82 import android.content.SharedPreferences; 83 import android.content.UriMatcher; 84 import android.content.pm.PackageManager; 85 import android.content.res.Resources; 86 import android.content.res.XmlResourceParser; 87 import android.database.Cursor; 88 import android.database.MatrixCursor; 89 import android.database.SQLException; 90 import android.database.sqlite.SQLiteDatabase; 91 import android.database.sqlite.SQLiteException; 92 import android.database.sqlite.SQLiteOpenHelper; 93 import android.database.sqlite.SQLiteQueryBuilder; 94 import android.net.Uri; 95 import android.os.Binder; 96 import android.os.Environment; 97 import android.os.FileUtils; 98 import android.os.IBinder; 99 import android.os.Process; 100 import android.os.RemoteException; 101 import android.os.SystemProperties; 102 import android.os.UserHandle; 103 import android.provider.Telephony; 104 import android.telephony.Annotation; 105 import android.telephony.SubscriptionInfo; 106 import android.telephony.SubscriptionManager; 107 import android.telephony.TelephonyManager; 108 import android.telephony.data.ApnSetting; 109 import android.text.TextUtils; 110 import android.util.ArrayMap; 111 import android.util.Log; 112 import android.util.Pair; 113 import android.util.Xml; 114 115 import com.android.internal.annotations.GuardedBy; 116 import com.android.internal.annotations.VisibleForTesting; 117 import com.android.internal.telephony.PhoneFactory; 118 import com.android.internal.util.XmlUtils; 119 import android.service.carrier.IApnSourceService; 120 121 import org.xmlpull.v1.XmlPullParser; 122 import org.xmlpull.v1.XmlPullParserException; 123 124 import java.io.ByteArrayOutputStream; 125 import java.io.File; 126 import java.io.FileNotFoundException; 127 import java.io.FileReader; 128 import java.io.IOException; 129 import java.io.InputStream; 130 import java.util.ArrayList; 131 import java.util.Arrays; 132 import java.util.HashMap; 133 import java.util.HashSet; 134 import java.util.List; 135 import java.util.Locale; 136 import java.util.Map; 137 import java.util.Set; 138 import java.util.zip.CRC32; 139 140 public class TelephonyProvider extends ContentProvider 141 { 142 private static final String DATABASE_NAME = "telephony.db"; 143 private static final int IDLE_CONNECTION_TIMEOUT_MS = 30000; 144 private static final boolean DBG = true; 145 private static final boolean VDBG = false; // STOPSHIP if true 146 147 private static final int DATABASE_VERSION = 45 << 16; 148 private static final int URL_UNKNOWN = 0; 149 private static final int URL_TELEPHONY = 1; 150 private static final int URL_CURRENT = 2; 151 private static final int URL_ID = 3; 152 private static final int URL_RESTOREAPN = 4; 153 private static final int URL_PREFERAPN = 5; 154 private static final int URL_PREFERAPN_NO_UPDATE = 6; 155 private static final int URL_SIMINFO = 7; 156 private static final int URL_TELEPHONY_USING_SUBID = 8; 157 private static final int URL_CURRENT_USING_SUBID = 9; 158 private static final int URL_RESTOREAPN_USING_SUBID = 10; 159 private static final int URL_PREFERAPN_USING_SUBID = 11; 160 private static final int URL_PREFERAPN_NO_UPDATE_USING_SUBID = 12; 161 private static final int URL_SIMINFO_USING_SUBID = 13; 162 private static final int URL_UPDATE_DB = 14; 163 private static final int URL_DELETE = 15; 164 private static final int URL_DPC = 16; 165 private static final int URL_DPC_ID = 17; 166 private static final int URL_FILTERED = 18; 167 private static final int URL_FILTERED_ID = 19; 168 private static final int URL_ENFORCE_MANAGED = 20; 169 // URL_PREFERAPNSET and URL_PREFERAPNSET_USING_SUBID return all APNs for the current 170 // carrier which have an apn_set_id equal to the preferred APN 171 // (if no preferred APN, or preferred APN has no set id, the query will return null) 172 private static final int URL_PREFERAPNSET = 21; 173 private static final int URL_PREFERAPNSET_USING_SUBID = 22; 174 private static final int URL_SIM_APN_LIST = 23; 175 private static final int URL_SIM_APN_LIST_ID = 24; 176 private static final int URL_FILTERED_USING_SUBID = 25; 177 private static final int URL_SIM_APN_LIST_FILTERED = 26; 178 private static final int URL_SIM_APN_LIST_FILTERED_ID = 27; 179 180 /** 181 * Default value for mtu if it's not set. Moved from PhoneConstants. 182 */ 183 private static final int UNSPECIFIED_INT = -1; 184 185 private static final String TAG = "TelephonyProvider"; 186 private static final String CARRIERS_TABLE = "carriers"; 187 private static final String CARRIERS_TABLE_TMP = "carriers_tmp"; 188 private static final String SIMINFO_TABLE = "siminfo"; 189 private static final String SIMINFO_TABLE_TMP = "siminfo_tmp"; 190 191 private static final String PREF_FILE_APN = "preferred-apn"; 192 private static final String COLUMN_APN_ID = "apn_id"; 193 private static final String EXPLICIT_SET_CALLED = "explicit_set_called"; 194 195 private static final String PREF_FILE_FULL_APN = "preferred-full-apn"; 196 private static final String DB_VERSION_KEY = "version"; 197 198 private static final String BUILD_ID_FILE = "build-id"; 199 private static final String RO_BUILD_ID = "ro_build_id"; 200 201 private static final String ENFORCED_FILE = "dpc-apn-enforced"; 202 private static final String ENFORCED_KEY = "enforced"; 203 204 private static final String PREF_FILE = "telephonyprovider"; 205 private static final String APN_CONF_CHECKSUM = "apn_conf_checksum"; 206 207 private static final String PARTNER_APNS_PATH = "etc/apns-conf.xml"; 208 private static final String OEM_APNS_PATH = "telephony/apns-conf.xml"; 209 private static final String OTA_UPDATED_APNS_PATH = "misc/apns/apns-conf.xml"; 210 private static final String OLD_APNS_PATH = "etc/old-apns-conf.xml"; 211 212 private static final String DEFAULT_PROTOCOL = "IP"; 213 private static final String DEFAULT_ROAMING_PROTOCOL = "IP"; 214 215 private static final UriMatcher s_urlMatcher = new UriMatcher(UriMatcher.NO_MATCH); 216 217 private static final ContentValues s_currentNullMap; 218 private static final ContentValues s_currentSetMap; 219 220 private static final String IS_UNEDITED = EDITED_STATUS + "=" + UNEDITED; 221 private static final String IS_EDITED = EDITED_STATUS + "!=" + UNEDITED; 222 private static final String IS_USER_EDITED = EDITED_STATUS + "=" + USER_EDITED; 223 private static final String IS_NOT_USER_EDITED = EDITED_STATUS + "!=" + USER_EDITED; 224 private static final String IS_USER_DELETED = EDITED_STATUS + "=" + USER_DELETED; 225 private static final String IS_NOT_USER_DELETED = EDITED_STATUS + "!=" + USER_DELETED; 226 private static final String IS_USER_DELETED_BUT_PRESENT_IN_XML = 227 EDITED_STATUS + "=" + USER_DELETED_BUT_PRESENT_IN_XML; 228 private static final String IS_NOT_USER_DELETED_BUT_PRESENT_IN_XML = 229 EDITED_STATUS + "!=" + USER_DELETED_BUT_PRESENT_IN_XML; 230 private static final String IS_CARRIER_EDITED = EDITED_STATUS + "=" + CARRIER_EDITED; 231 private static final String IS_NOT_CARRIER_EDITED = EDITED_STATUS + "!=" + CARRIER_EDITED; 232 private static final String IS_CARRIER_DELETED = EDITED_STATUS + "=" + CARRIER_DELETED; 233 private static final String IS_NOT_CARRIER_DELETED = EDITED_STATUS + "!=" + CARRIER_DELETED; 234 private static final String IS_CARRIER_DELETED_BUT_PRESENT_IN_XML = 235 EDITED_STATUS + "=" + CARRIER_DELETED_BUT_PRESENT_IN_XML; 236 private static final String IS_NOT_CARRIER_DELETED_BUT_PRESENT_IN_XML = 237 EDITED_STATUS + "!=" + CARRIER_DELETED_BUT_PRESENT_IN_XML; 238 private static final String IS_OWNED_BY_DPC = OWNED_BY + "=" + OWNED_BY_DPC; 239 private static final String IS_NOT_OWNED_BY_DPC = OWNED_BY + "!=" + OWNED_BY_DPC; 240 241 private static final String ORDER_BY_SUB_ID = 242 Telephony.SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID + " ASC"; 243 244 private static final int INVALID_APN_ID = -1; 245 private static final List<String> CARRIERS_UNIQUE_FIELDS = new ArrayList<String>(); 246 private static final Set<String> CARRIERS_BOOLEAN_FIELDS = new HashSet<String>(); 247 private static final Map<String, String> CARRIERS_UNIQUE_FIELDS_DEFAULTS = new HashMap(); 248 249 @VisibleForTesting 250 static Boolean s_apnSourceServiceExists; 251 252 protected final Object mLock = new Object(); 253 @GuardedBy("mLock") 254 private IApnSourceService mIApnSourceService; 255 private Injector mInjector; 256 257 private boolean mManagedApnEnforced; 258 259 /** 260 * Available radio technologies for GSM, UMTS and CDMA. 261 * Duplicates the constants from hardware/radio/include/ril.h 262 * This should only be used by agents working with the ril. Others 263 * should use the equivalent TelephonyManager.NETWORK_TYPE_* 264 */ 265 private static final int RIL_RADIO_TECHNOLOGY_UNKNOWN = 0; 266 private static final int RIL_RADIO_TECHNOLOGY_GPRS = 1; 267 private static final int RIL_RADIO_TECHNOLOGY_EDGE = 2; 268 private static final int RIL_RADIO_TECHNOLOGY_UMTS = 3; 269 private static final int RIL_RADIO_TECHNOLOGY_IS95A = 4; 270 private static final int RIL_RADIO_TECHNOLOGY_IS95B = 5; 271 private static final int RIL_RADIO_TECHNOLOGY_1xRTT = 6; 272 private static final int RIL_RADIO_TECHNOLOGY_EVDO_0 = 7; 273 private static final int RIL_RADIO_TECHNOLOGY_EVDO_A = 8; 274 private static final int RIL_RADIO_TECHNOLOGY_HSDPA = 9; 275 private static final int RIL_RADIO_TECHNOLOGY_HSUPA = 10; 276 private static final int RIL_RADIO_TECHNOLOGY_HSPA = 11; 277 private static final int RIL_RADIO_TECHNOLOGY_EVDO_B = 12; 278 private static final int RIL_RADIO_TECHNOLOGY_EHRPD = 13; 279 private static final int RIL_RADIO_TECHNOLOGY_LTE = 14; 280 private static final int RIL_RADIO_TECHNOLOGY_HSPAP = 15; 281 282 /** 283 * GSM radio technology only supports voice. It does not support data. 284 */ 285 private static final int RIL_RADIO_TECHNOLOGY_GSM = 16; 286 private static final int RIL_RADIO_TECHNOLOGY_TD_SCDMA = 17; 287 288 /** 289 * IWLAN 290 */ 291 private static final int RIL_RADIO_TECHNOLOGY_IWLAN = 18; 292 293 /** 294 * LTE_CA 295 */ 296 private static final int RIL_RADIO_TECHNOLOGY_LTE_CA = 19; 297 298 /** 299 * NR(New Radio) 5G. 300 */ 301 private static final int RIL_RADIO_TECHNOLOGY_NR = 20; 302 303 /** 304 * The number of the radio technologies. 305 */ 306 private static final int NEXT_RIL_RADIO_TECHNOLOGY = 21; 307 308 private static final Map<String, Integer> MVNO_TYPE_STRING_MAP; 309 310 static { 311 // Columns not included in UNIQUE constraint: name, current, edited, user, server, password, 312 // authtype, type, protocol, roaming_protocol, sub_id, modem_cognitive, max_conns, 313 // wait_time, max_conns_time, mtu, bearer_bitmask, user_visible, network_type_bitmask, 314 // skip_464xlat CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(NUMERIC, "")315 CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(NUMERIC, ""); CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(MCC, "")316 CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(MCC, ""); CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(MNC, "")317 CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(MNC, ""); CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(APN, "")318 CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(APN, ""); CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(PROXY, "")319 CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(PROXY, ""); CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(PORT, "")320 CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(PORT, ""); CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(MMSPROXY, "")321 CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(MMSPROXY, ""); CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(MMSPORT, "")322 CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(MMSPORT, ""); CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(MMSC, "")323 CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(MMSC, ""); CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(CARRIER_ENABLED, "1")324 CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(CARRIER_ENABLED, "1"); CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(BEARER, "0")325 CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(BEARER, "0"); CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(MVNO_TYPE, "")326 CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(MVNO_TYPE, ""); CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(MVNO_MATCH_DATA, "")327 CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(MVNO_MATCH_DATA, ""); CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(PROFILE_ID, "0")328 CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(PROFILE_ID, "0"); CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(PROTOCOL, "IP")329 CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(PROTOCOL, "IP"); CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(ROAMING_PROTOCOL, "IP")330 CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(ROAMING_PROTOCOL, "IP"); CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(USER_EDITABLE, "1")331 CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(USER_EDITABLE, "1"); CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(OWNED_BY, String.valueOf(OWNED_BY_OTHERS))332 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))333 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))334 CARRIERS_UNIQUE_FIELDS_DEFAULTS.put(CARRIER_ID, 335 String.valueOf(TelephonyManager.UNKNOWN_CARRIER_ID)); 336 CARRIERS_UNIQUE_FIELDS_DEFAULTS.keySet()337 CARRIERS_UNIQUE_FIELDS.addAll(CARRIERS_UNIQUE_FIELDS_DEFAULTS.keySet()); 338 339 // SQLite databases store bools as ints but the ContentValues objects passed in through 340 // queries use bools. As a result there is some special handling of boolean fields within 341 // the TelephonyProvider. 342 CARRIERS_BOOLEAN_FIELDS.add(CARRIER_ENABLED); 343 CARRIERS_BOOLEAN_FIELDS.add(MODEM_PERSIST); 344 CARRIERS_BOOLEAN_FIELDS.add(USER_VISIBLE); 345 CARRIERS_BOOLEAN_FIELDS.add(USER_EDITABLE); 346 347 MVNO_TYPE_STRING_MAP = new ArrayMap<String, Integer>(); 348 MVNO_TYPE_STRING_MAP.put("spn", ApnSetting.MVNO_TYPE_SPN); 349 MVNO_TYPE_STRING_MAP.put("imsi", ApnSetting.MVNO_TYPE_IMSI); 350 MVNO_TYPE_STRING_MAP.put("gid", ApnSetting.MVNO_TYPE_GID); 351 MVNO_TYPE_STRING_MAP.put("iccid", ApnSetting.MVNO_TYPE_ICCID); 352 } 353 354 @VisibleForTesting getStringForCarrierTableCreation(String tableName)355 public static String getStringForCarrierTableCreation(String tableName) { 356 return "CREATE TABLE " + tableName + 357 "(_id INTEGER PRIMARY KEY," + 358 NAME + " TEXT DEFAULT ''," + 359 NUMERIC + " TEXT DEFAULT ''," + 360 MCC + " TEXT DEFAULT ''," + 361 MNC + " TEXT DEFAULT ''," + 362 CARRIER_ID + " INTEGER DEFAULT " + TelephonyManager.UNKNOWN_CARRIER_ID + "," + 363 APN + " TEXT DEFAULT ''," + 364 USER + " TEXT DEFAULT ''," + 365 SERVER + " TEXT DEFAULT ''," + 366 PASSWORD + " TEXT DEFAULT ''," + 367 PROXY + " TEXT DEFAULT ''," + 368 PORT + " TEXT DEFAULT ''," + 369 MMSPROXY + " TEXT DEFAULT ''," + 370 MMSPORT + " TEXT DEFAULT ''," + 371 MMSC + " TEXT DEFAULT ''," + 372 AUTH_TYPE + " INTEGER DEFAULT -1," + 373 TYPE + " TEXT DEFAULT ''," + 374 CURRENT + " INTEGER," + 375 PROTOCOL + " TEXT DEFAULT " + DEFAULT_PROTOCOL + "," + 376 ROAMING_PROTOCOL + " TEXT DEFAULT " + DEFAULT_ROAMING_PROTOCOL + "," + 377 CARRIER_ENABLED + " BOOLEAN DEFAULT 1," + // SQLite databases store bools as ints 378 BEARER + " INTEGER DEFAULT 0," + 379 BEARER_BITMASK + " INTEGER DEFAULT 0," + 380 NETWORK_TYPE_BITMASK + " INTEGER DEFAULT 0," + 381 MVNO_TYPE + " TEXT DEFAULT ''," + 382 MVNO_MATCH_DATA + " TEXT DEFAULT ''," + 383 SUBSCRIPTION_ID + " INTEGER DEFAULT " + 384 SubscriptionManager.INVALID_SUBSCRIPTION_ID + "," + 385 PROFILE_ID + " INTEGER DEFAULT 0," + 386 MODEM_PERSIST + " BOOLEAN DEFAULT 0," + 387 MAX_CONNECTIONS + " INTEGER DEFAULT 0," + 388 WAIT_TIME_RETRY + " INTEGER DEFAULT 0," + 389 TIME_LIMIT_FOR_MAX_CONNECTIONS + " INTEGER DEFAULT 0," + 390 MTU + " INTEGER DEFAULT 0," + 391 EDITED_STATUS + " INTEGER DEFAULT " + UNEDITED + "," + 392 USER_VISIBLE + " BOOLEAN DEFAULT 1," + 393 USER_EDITABLE + " BOOLEAN DEFAULT 1," + 394 OWNED_BY + " INTEGER DEFAULT " + OWNED_BY_OTHERS + "," + 395 APN_SET_ID + " INTEGER DEFAULT " + NO_APN_SET_ID + "," + 396 SKIP_464XLAT + " INTEGER DEFAULT " + SKIP_464XLAT_DEFAULT + "," + 397 // Uniqueness collisions are used to trigger merge code so if a field is listed 398 // here it means we will accept both (user edited + new apn_conf definition) 399 // Columns not included in UNIQUE constraint: name, current, edited, 400 // user, server, password, authtype, type, sub_id, modem_cognitive, max_conns, 401 // wait_time, max_conns_time, mtu, bearer_bitmask, user_visible, 402 // network_type_bitmask, skip_464xlat. 403 "UNIQUE (" + TextUtils.join(", ", CARRIERS_UNIQUE_FIELDS) + "));"; 404 } 405 406 @VisibleForTesting getStringForSimInfoTableCreation(String tableName)407 public static String getStringForSimInfoTableCreation(String tableName) { 408 return "CREATE TABLE " + tableName + "(" 409 + Telephony.SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID 410 + " INTEGER PRIMARY KEY AUTOINCREMENT," 411 + Telephony.SimInfo.COLUMN_ICC_ID + " TEXT NOT NULL," 412 + Telephony.SimInfo.COLUMN_SIM_SLOT_INDEX 413 + " INTEGER DEFAULT " + Telephony.SimInfo.SIM_NOT_INSERTED + "," 414 + Telephony.SimInfo.COLUMN_DISPLAY_NAME + " TEXT," 415 + Telephony.SimInfo.COLUMN_CARRIER_NAME + " TEXT," 416 + Telephony.SimInfo.COLUMN_NAME_SOURCE 417 + " INTEGER DEFAULT " + Telephony.SimInfo.NAME_SOURCE_CARRIER_ID + "," 418 + Telephony.SimInfo.COLUMN_COLOR + " INTEGER DEFAULT " 419 + Telephony.SimInfo.COLOR_DEFAULT + "," 420 + Telephony.SimInfo.COLUMN_NUMBER + " TEXT," 421 + Telephony.SimInfo.COLUMN_DISPLAY_NUMBER_FORMAT 422 + " INTEGER NOT NULL DEFAULT " + Telephony.SimInfo.DISPLAY_NUMBER_DEFAULT + "," 423 + Telephony.SimInfo.COLUMN_DATA_ROAMING 424 + " INTEGER DEFAULT " + Telephony.SimInfo.DATA_ROAMING_DISABLE + "," 425 + Telephony.SimInfo.COLUMN_MCC + " INTEGER DEFAULT 0," 426 + Telephony.SimInfo.COLUMN_MNC + " INTEGER DEFAULT 0," 427 + Telephony.SimInfo.COLUMN_MCC_STRING + " TEXT," 428 + Telephony.SimInfo.COLUMN_MNC_STRING + " TEXT," 429 + Telephony.SimInfo.COLUMN_EHPLMNS + " TEXT," 430 + Telephony.SimInfo.COLUMN_HPLMNS + " TEXT," 431 + Telephony.SimInfo.COLUMN_SIM_PROVISIONING_STATUS 432 + " INTEGER DEFAULT " + Telephony.SimInfo.SIM_PROVISIONED + "," 433 + Telephony.SimInfo.COLUMN_IS_EMBEDDED + " INTEGER DEFAULT 0," 434 + Telephony.SimInfo.COLUMN_CARD_ID + " TEXT NOT NULL," 435 + Telephony.SimInfo.COLUMN_ACCESS_RULES + " BLOB," 436 + Telephony.SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS + " BLOB," 437 + Telephony.SimInfo.COLUMN_IS_REMOVABLE + " INTEGER DEFAULT 0," 438 + Telephony.SimInfo.COLUMN_CB_EXTREME_THREAT_ALERT + " INTEGER DEFAULT 1," 439 + Telephony.SimInfo.COLUMN_CB_SEVERE_THREAT_ALERT + " INTEGER DEFAULT 1," 440 + Telephony.SimInfo.COLUMN_CB_AMBER_ALERT + " INTEGER DEFAULT 1," 441 + Telephony.SimInfo.COLUMN_CB_EMERGENCY_ALERT + " INTEGER DEFAULT 1," 442 + Telephony.SimInfo.COLUMN_CB_ALERT_SOUND_DURATION + " INTEGER DEFAULT 4," 443 + Telephony.SimInfo.COLUMN_CB_ALERT_REMINDER_INTERVAL + " INTEGER DEFAULT 0," 444 + Telephony.SimInfo.COLUMN_CB_ALERT_VIBRATE + " INTEGER DEFAULT 1," 445 + Telephony.SimInfo.COLUMN_CB_ALERT_SPEECH + " INTEGER DEFAULT 1," 446 + Telephony.SimInfo.COLUMN_CB_ETWS_TEST_ALERT + " INTEGER DEFAULT 0," 447 + Telephony.SimInfo.COLUMN_CB_CHANNEL_50_ALERT + " INTEGER DEFAULT 1," 448 + Telephony.SimInfo.COLUMN_CB_CMAS_TEST_ALERT + " INTEGER DEFAULT 0," 449 + Telephony.SimInfo.COLUMN_CB_OPT_OUT_DIALOG + " INTEGER DEFAULT 1," 450 + Telephony.SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED + " INTEGER DEFAULT -1," 451 + Telephony.SimInfo.COLUMN_VT_IMS_ENABLED + " INTEGER DEFAULT -1," 452 + Telephony.SimInfo.COLUMN_WFC_IMS_ENABLED + " INTEGER DEFAULT -1," 453 + Telephony.SimInfo.COLUMN_WFC_IMS_MODE + " INTEGER DEFAULT -1," 454 + Telephony.SimInfo.COLUMN_WFC_IMS_ROAMING_MODE + " INTEGER DEFAULT -1," 455 + Telephony.SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED + " INTEGER DEFAULT -1," 456 + Telephony.SimInfo.COLUMN_IS_OPPORTUNISTIC + " INTEGER DEFAULT 0," 457 + Telephony.SimInfo.COLUMN_GROUP_UUID + " TEXT," 458 + Telephony.SimInfo.COLUMN_IS_METERED + " INTEGER DEFAULT 1," 459 + Telephony.SimInfo.COLUMN_ISO_COUNTRY_CODE + " TEXT," 460 + Telephony.SimInfo.COLUMN_CARRIER_ID + " INTEGER DEFAULT -1," 461 + Telephony.SimInfo.COLUMN_PROFILE_CLASS + " INTEGER DEFAULT " 462 + Telephony.SimInfo.PROFILE_CLASS_UNSET + "," 463 + Telephony.SimInfo.COLUMN_SUBSCRIPTION_TYPE + " INTEGER DEFAULT " 464 + Telephony.SimInfo.SUBSCRIPTION_TYPE_LOCAL_SIM + "," 465 + Telephony.SimInfo.COLUMN_GROUP_OWNER + " TEXT," 466 + Telephony.SimInfo.COLUMN_DATA_ENABLED_OVERRIDE_RULES + " TEXT," 467 + Telephony.SimInfo.COLUMN_IMSI + " TEXT," 468 + Telephony.SimInfo.COLUMN_UICC_APPLICATIONS_ENABLED + " INTEGER DEFAULT 1," 469 + Telephony.SimInfo.COLUMN_ALLOWED_NETWORK_TYPES + " BIGINT DEFAULT -1," 470 + Telephony.SimInfo.COLUMN_IMS_RCS_UCE_ENABLED + " INTEGER DEFAULT 0" 471 + ");"; 472 } 473 474 static { 475 s_urlMatcher.addURI("telephony", "carriers", URL_TELEPHONY); 476 s_urlMatcher.addURI("telephony", "carriers/current", URL_CURRENT); 477 s_urlMatcher.addURI("telephony", "carriers/#", URL_ID); 478 s_urlMatcher.addURI("telephony", "carriers/restore", URL_RESTOREAPN); 479 s_urlMatcher.addURI("telephony", "carriers/preferapn", URL_PREFERAPN); 480 s_urlMatcher.addURI("telephony", "carriers/preferapn_no_update", URL_PREFERAPN_NO_UPDATE); 481 s_urlMatcher.addURI("telephony", "carriers/preferapnset", URL_PREFERAPNSET); 482 483 s_urlMatcher.addURI("telephony", "siminfo", URL_SIMINFO); 484 s_urlMatcher.addURI("telephony", "siminfo/#", URL_SIMINFO_USING_SUBID); 485 486 s_urlMatcher.addURI("telephony", "carriers/subId/*", URL_TELEPHONY_USING_SUBID); 487 s_urlMatcher.addURI("telephony", "carriers/current/subId/*", URL_CURRENT_USING_SUBID); 488 s_urlMatcher.addURI("telephony", "carriers/restore/subId/*", URL_RESTOREAPN_USING_SUBID); 489 s_urlMatcher.addURI("telephony", "carriers/preferapn/subId/*", URL_PREFERAPN_USING_SUBID); 490 s_urlMatcher.addURI("telephony", "carriers/preferapn_no_update/subId/*", 491 URL_PREFERAPN_NO_UPDATE_USING_SUBID); 492 s_urlMatcher.addURI("telephony", "carriers/preferapnset/subId/*", 493 URL_PREFERAPNSET_USING_SUBID); 494 495 s_urlMatcher.addURI("telephony", "carriers/update_db", URL_UPDATE_DB); 496 s_urlMatcher.addURI("telephony", "carriers/delete", URL_DELETE); 497 498 // Only called by DevicePolicyManager to manipulate DPC records. 499 s_urlMatcher.addURI("telephony", "carriers/dpc", URL_DPC); 500 // Only called by DevicePolicyManager to manipulate a DPC record with certain _ID. 501 s_urlMatcher.addURI("telephony", "carriers/dpc/#", URL_DPC_ID); 502 // Only called by Settings app, DcTracker and other telephony components to get APN list 503 // according to whether DPC records are enforced. 504 s_urlMatcher.addURI("telephony", "carriers/filtered", URL_FILTERED); 505 // Only called by Settings app, DcTracker and other telephony components to get a 506 // single APN according to whether DPC records are enforced. 507 s_urlMatcher.addURI("telephony", "carriers/filtered/#", URL_FILTERED_ID); 508 // Used by DcTracker to pass a subId. 509 s_urlMatcher.addURI("telephony", "carriers/filtered/subId/*", URL_FILTERED_USING_SUBID); 510 511 // Only Called by DevicePolicyManager to enforce DPC records. 512 s_urlMatcher.addURI("telephony", "carriers/enforce_managed", URL_ENFORCE_MANAGED); 513 s_urlMatcher.addURI("telephony", "carriers/sim_apn_list", URL_SIM_APN_LIST); 514 s_urlMatcher.addURI("telephony", "carriers/sim_apn_list/#", URL_SIM_APN_LIST_ID); 515 s_urlMatcher.addURI("telephony", "carriers/sim_apn_list/filtered", 516 URL_SIM_APN_LIST_FILTERED); 517 s_urlMatcher.addURI("telephony", "carriers/sim_apn_list/filtered/subId/*", 518 URL_SIM_APN_LIST_FILTERED_ID); 519 520 s_currentNullMap = new ContentValues(1); s_currentNullMap.put(CURRENT, "0")521 s_currentNullMap.put(CURRENT, "0"); 522 523 s_currentSetMap = new ContentValues(1); s_currentSetMap.put(CURRENT, "1")524 s_currentSetMap.put(CURRENT, "1"); 525 } 526 527 /** 528 * Unit test will subclass it to inject mocks. 529 */ 530 @VisibleForTesting 531 static class Injector { binderGetCallingUid()532 int binderGetCallingUid() { 533 return Binder.getCallingUid(); 534 } 535 } 536 TelephonyProvider()537 public TelephonyProvider() { 538 this(new Injector()); 539 } 540 541 @VisibleForTesting TelephonyProvider(Injector injector)542 public TelephonyProvider(Injector injector) { 543 mInjector = injector; 544 } 545 546 @VisibleForTesting getVersion(Context context)547 public static int getVersion(Context context) { 548 if (VDBG) log("getVersion:+"); 549 // Get the database version, combining a static schema version and the XML version 550 Resources r = context.getResources(); 551 if (r == null) { 552 loge("resources=null, return version=" + Integer.toHexString(DATABASE_VERSION)); 553 return DATABASE_VERSION; 554 } 555 XmlResourceParser parser = r.getXml(com.android.internal.R.xml.apns); 556 try { 557 XmlUtils.beginDocument(parser, "apns"); 558 int publicversion = Integer.parseInt(parser.getAttributeValue(null, "version")); 559 int version = DATABASE_VERSION | publicversion; 560 if (VDBG) log("getVersion:- version=0x" + Integer.toHexString(version)); 561 return version; 562 } catch (Exception e) { 563 loge("Can't get version of APN database" + e + " return version=" + 564 Integer.toHexString(DATABASE_VERSION)); 565 return DATABASE_VERSION; 566 } finally { 567 parser.close(); 568 } 569 } 570 setDefaultValue(ContentValues values)571 static public ContentValues setDefaultValue(ContentValues values) { 572 if (!values.containsKey(SUBSCRIPTION_ID)) { 573 int subId = SubscriptionManager.getDefaultSubscriptionId(); 574 values.put(SUBSCRIPTION_ID, subId); 575 } 576 577 return values; 578 } 579 580 @VisibleForTesting 581 public class DatabaseHelper extends SQLiteOpenHelper { 582 // Context to access resources with 583 private Context mContext; 584 585 /** 586 * DatabaseHelper helper class for loading apns into a database. 587 * 588 * @param context of the user. 589 */ DatabaseHelper(Context context)590 public DatabaseHelper(Context context) { 591 super(context, DATABASE_NAME, null, getVersion(context)); 592 mContext = context; 593 // Memory optimization - close idle connections after 30s of inactivity 594 setIdleConnectionTimeout(IDLE_CONNECTION_TIMEOUT_MS); 595 setWriteAheadLoggingEnabled(false); 596 } 597 598 @Override onCreate(SQLiteDatabase db)599 public void onCreate(SQLiteDatabase db) { 600 if (DBG) log("dbh.onCreate:+ db=" + db); 601 createSimInfoTable(db, SIMINFO_TABLE); 602 createCarriersTable(db, CARRIERS_TABLE); 603 // if CarrierSettings app is installed, we expect it to do the initializiation instead 604 if (apnSourceServiceExists(mContext)) { 605 log("dbh.onCreate: Skipping apply APNs from xml."); 606 } else { 607 log("dbh.onCreate: Apply apns from xml."); 608 initDatabase(db); 609 } 610 if (DBG) log("dbh.onCreate:- db=" + db); 611 } 612 613 @Override onOpen(SQLiteDatabase db)614 public void onOpen(SQLiteDatabase db) { 615 if (VDBG) log("dbh.onOpen:+ db=" + db); 616 try { 617 // Try to access the table and create it if "no such table" 618 db.query(SIMINFO_TABLE, null, null, null, null, null, null); 619 if (DBG) log("dbh.onOpen: ok, queried table=" + SIMINFO_TABLE); 620 } catch (SQLiteException e) { 621 loge("Exception " + SIMINFO_TABLE + "e=" + e); 622 if (e.getMessage().startsWith("no such table")) { 623 createSimInfoTable(db, SIMINFO_TABLE); 624 } 625 } 626 try { 627 db.query(CARRIERS_TABLE, null, null, null, null, null, null); 628 if (DBG) log("dbh.onOpen: ok, queried table=" + CARRIERS_TABLE); 629 } catch (SQLiteException e) { 630 loge("Exception " + CARRIERS_TABLE + " e=" + e); 631 if (e.getMessage().startsWith("no such table")) { 632 createCarriersTable(db, CARRIERS_TABLE); 633 } 634 } 635 if (VDBG) log("dbh.onOpen:- db=" + db); 636 } 637 createSimInfoTable(SQLiteDatabase db, String tableName)638 private void createSimInfoTable(SQLiteDatabase db, String tableName) { 639 if (DBG) log("dbh.createSimInfoTable:+ " + tableName); 640 db.execSQL(getStringForSimInfoTableCreation(tableName)); 641 if (DBG) log("dbh.createSimInfoTable:-"); 642 } 643 createCarriersTable(SQLiteDatabase db, String tableName)644 private void createCarriersTable(SQLiteDatabase db, String tableName) { 645 // Set up the database schema 646 if (DBG) log("dbh.createCarriersTable: " + tableName); 647 db.execSQL(getStringForCarrierTableCreation(tableName)); 648 if (DBG) log("dbh.createCarriersTable:-"); 649 } 650 getChecksum(File file)651 private long getChecksum(File file) { 652 long checksum = -1; 653 try { 654 checksum = FileUtils.checksumCrc32(file); 655 if (DBG) log("Checksum for " + file.getAbsolutePath() + " is " + checksum); 656 } catch (FileNotFoundException e) { 657 loge("FileNotFoundException for " + file.getAbsolutePath() + ":" + e); 658 } catch (IOException e) { 659 loge("IOException for " + file.getAbsolutePath() + ":" + e); 660 } 661 662 // The RRO may have been updated in a firmware upgrade. Add checksum for the 663 // resources to the total checksum so that apns in an RRO update is not missed. 664 try (InputStream inputStream = mContext.getResources(). 665 openRawResource(com.android.internal.R.xml.apns)) { 666 byte[] array = toByteArray(inputStream); 667 CRC32 c = new CRC32(); 668 c.update(array); 669 checksum += c.getValue(); 670 if (DBG) log("Checksum after adding resource is " + checksum); 671 } catch (IOException | Resources.NotFoundException e) { 672 loge("Exception when calculating checksum for internal apn resources: " + e); 673 } 674 return checksum; 675 } 676 toByteArray(InputStream input)677 private byte[] toByteArray(InputStream input) throws IOException { 678 byte[] buffer = new byte[128]; 679 int bytesRead; 680 ByteArrayOutputStream output = new ByteArrayOutputStream(); 681 while ((bytesRead = input.read(buffer)) != -1) { 682 output.write(buffer, 0, bytesRead); 683 } 684 return output.toByteArray(); 685 } 686 getApnConfChecksum()687 private long getApnConfChecksum() { 688 SharedPreferences sp = mContext.getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE); 689 return sp.getLong(APN_CONF_CHECKSUM, -1); 690 } 691 setApnConfChecksum(long checksum)692 private void setApnConfChecksum(long checksum) { 693 SharedPreferences sp = mContext.getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE); 694 SharedPreferences.Editor editor = sp.edit(); 695 editor.putLong(APN_CONF_CHECKSUM, checksum); 696 editor.apply(); 697 } 698 getApnConfFile()699 private File getApnConfFile() { 700 // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system". 701 File confFile = new File(Environment.getRootDirectory(), PARTNER_APNS_PATH); 702 File oemConfFile = new File(Environment.getOemDirectory(), OEM_APNS_PATH); 703 File updatedConfFile = new File(Environment.getDataDirectory(), OTA_UPDATED_APNS_PATH); 704 File productConfFile = new File(Environment.getProductDirectory(), PARTNER_APNS_PATH); 705 confFile = pickSecondIfExists(confFile, oemConfFile); 706 confFile = pickSecondIfExists(confFile, productConfFile); 707 confFile = pickSecondIfExists(confFile, updatedConfFile); 708 return confFile; 709 } 710 711 /** 712 * This function computes checksum for the file to be read and compares it against the 713 * last read file. DB needs to be updated only if checksum has changed, or old checksum does 714 * not exist. 715 * @return true if DB should be updated with new conf file, false otherwise 716 */ apnDbUpdateNeeded()717 private boolean apnDbUpdateNeeded() { 718 File confFile = getApnConfFile(); 719 long newChecksum = getChecksum(confFile); 720 long oldChecksum = getApnConfChecksum(); 721 if (DBG) log("newChecksum: " + newChecksum); 722 if (DBG) log("oldChecksum: " + oldChecksum); 723 if (newChecksum == oldChecksum) { 724 return false; 725 } else { 726 return true; 727 } 728 } 729 730 /** 731 * This function adds APNs from xml file(s) to db. The db may or may not be empty to begin 732 * with. 733 */ initDatabase(SQLiteDatabase db)734 private void initDatabase(SQLiteDatabase db) { 735 if (VDBG) log("dbh.initDatabase:+ db=" + db); 736 // Read internal APNS data 737 Resources r = mContext.getResources(); 738 int publicversion = -1; 739 if (r != null) { 740 XmlResourceParser parser = r.getXml(com.android.internal.R.xml.apns); 741 try { 742 XmlUtils.beginDocument(parser, "apns"); 743 publicversion = Integer.parseInt(parser.getAttributeValue(null, "version")); 744 loadApns(db, parser); 745 } catch (Exception e) { 746 loge("Got exception while loading APN database." + e); 747 } finally { 748 parser.close(); 749 } 750 } else { 751 loge("initDatabase: resources=null"); 752 } 753 754 // Read external APNS data (partner-provided) 755 XmlPullParser confparser = null; 756 File confFile = getApnConfFile(); 757 758 FileReader confreader = null; 759 if (DBG) log("confFile = " + confFile); 760 try { 761 confreader = new FileReader(confFile); 762 confparser = Xml.newPullParser(); 763 confparser.setInput(confreader); 764 XmlUtils.beginDocument(confparser, "apns"); 765 766 // Sanity check. Force internal version and confidential versions to agree 767 int confversion = Integer.parseInt(confparser.getAttributeValue(null, "version")); 768 if (publicversion != confversion) { 769 log("initDatabase: throwing exception due to version mismatch"); 770 throw new IllegalStateException("Internal APNS file version doesn't match " 771 + confFile.getAbsolutePath()); 772 } 773 774 loadApns(db, confparser); 775 } catch (FileNotFoundException e) { 776 // It's ok if the file isn't found. It means there isn't a confidential file 777 // Log.e(TAG, "File not found: '" + confFile.getAbsolutePath() + "'"); 778 } catch (Exception e) { 779 loge("initDatabase: Exception while parsing '" + confFile.getAbsolutePath() + "'" + 780 e); 781 } finally { 782 // Get rid of user/carrier deleted entries that are not present in apn xml file. 783 // Those entries have edited value USER_DELETED/CARRIER_DELETED. 784 if (VDBG) { 785 log("initDatabase: deleting USER_DELETED and replacing " 786 + "DELETED_BUT_PRESENT_IN_XML with DELETED"); 787 } 788 789 // Delete USER_DELETED 790 db.delete(CARRIERS_TABLE, IS_USER_DELETED + " or " + IS_CARRIER_DELETED, null); 791 792 // Change USER_DELETED_BUT_PRESENT_IN_XML to USER_DELETED 793 ContentValues cv = new ContentValues(); 794 cv.put(EDITED_STATUS, USER_DELETED); 795 db.update(CARRIERS_TABLE, cv, IS_USER_DELETED_BUT_PRESENT_IN_XML, null); 796 797 // Change CARRIER_DELETED_BUT_PRESENT_IN_XML to CARRIER_DELETED 798 cv = new ContentValues(); 799 cv.put(EDITED_STATUS, CARRIER_DELETED); 800 db.update(CARRIERS_TABLE, cv, IS_CARRIER_DELETED_BUT_PRESENT_IN_XML, null); 801 802 if (confreader != null) { 803 try { 804 confreader.close(); 805 } catch (IOException e) { 806 // do nothing 807 } 808 } 809 810 // Update the stored checksum 811 setApnConfChecksum(getChecksum(confFile)); 812 } 813 if (VDBG) log("dbh.initDatabase:- db=" + db); 814 815 } 816 pickSecondIfExists(File sysApnFile, File altApnFile)817 private File pickSecondIfExists(File sysApnFile, File altApnFile) { 818 if (altApnFile.exists()) { 819 if (DBG) log("Load APNs from " + altApnFile.getPath() + 820 " instead of " + sysApnFile.getPath()); 821 return altApnFile; 822 } else { 823 if (DBG) log("Load APNs from " + sysApnFile.getPath() + 824 " instead of " + altApnFile.getPath()); 825 return sysApnFile; 826 } 827 } 828 829 @Override onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)830 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 831 if (DBG) { 832 log("dbh.onUpgrade:+ db=" + db + " oldV=" + oldVersion + " newV=" + newVersion); 833 } 834 835 deletePreferredApnId(mContext); 836 837 if (oldVersion < (5 << 16 | 6)) { 838 // 5 << 16 is the Database version and 6 in the xml version. 839 840 // This change adds a new authtype column to the database. 841 // The auth type column can have 4 values: 0 (None), 1 (PAP), 2 (CHAP) 842 // 3 (PAP or CHAP). To avoid breaking compatibility, with already working 843 // APNs, the unset value (-1) will be used. If the value is -1. 844 // the authentication will default to 0 (if no user / password) is specified 845 // or to 3. Currently, there have been no reported problems with 846 // pre-configured APNs and hence it is set to -1 for them. Similarly, 847 // if the user, has added a new APN, we set the authentication type 848 // to -1. 849 850 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + 851 " ADD COLUMN authtype INTEGER DEFAULT -1;"); 852 853 oldVersion = 5 << 16 | 6; 854 } 855 if (oldVersion < (6 << 16 | 6)) { 856 // Add protcol fields to the APN. The XML file does not change. 857 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + 858 " ADD COLUMN protocol TEXT DEFAULT IP;"); 859 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + 860 " ADD COLUMN roaming_protocol TEXT DEFAULT IP;"); 861 oldVersion = 6 << 16 | 6; 862 } 863 if (oldVersion < (7 << 16 | 6)) { 864 // Add carrier_enabled, bearer fields to the APN. The XML file does not change. 865 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + 866 " ADD COLUMN carrier_enabled BOOLEAN DEFAULT 1;"); 867 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + 868 " ADD COLUMN bearer INTEGER DEFAULT 0;"); 869 oldVersion = 7 << 16 | 6; 870 } 871 if (oldVersion < (8 << 16 | 6)) { 872 // Add mvno_type, mvno_match_data fields to the APN. 873 // The XML file does not change. 874 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + 875 " ADD COLUMN mvno_type TEXT DEFAULT '';"); 876 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + 877 " ADD COLUMN mvno_match_data TEXT DEFAULT '';"); 878 oldVersion = 8 << 16 | 6; 879 } 880 if (oldVersion < (9 << 16 | 6)) { 881 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + 882 " ADD COLUMN sub_id INTEGER DEFAULT " + 883 SubscriptionManager.INVALID_SUBSCRIPTION_ID + ";"); 884 oldVersion = 9 << 16 | 6; 885 } 886 if (oldVersion < (10 << 16 | 6)) { 887 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + 888 " ADD COLUMN profile_id INTEGER DEFAULT 0;"); 889 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + 890 " ADD COLUMN modem_cognitive BOOLEAN DEFAULT 0;"); 891 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + 892 " ADD COLUMN max_conns INTEGER DEFAULT 0;"); 893 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + 894 " ADD COLUMN wait_time INTEGER DEFAULT 0;"); 895 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + 896 " ADD COLUMN max_conns_time INTEGER DEFAULT 0;"); 897 oldVersion = 10 << 16 | 6; 898 } 899 if (oldVersion < (11 << 16 | 6)) { 900 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + 901 " ADD COLUMN mtu INTEGER DEFAULT 0;"); 902 oldVersion = 11 << 16 | 6; 903 } 904 if (oldVersion < (12 << 16 | 6)) { 905 try { 906 // Try to update the siminfo table. It might not be there. 907 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + 908 " ADD COLUMN " + Telephony.SimInfo.COLUMN_MCC + " INTEGER DEFAULT 0;"); 909 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + 910 " ADD COLUMN " + Telephony.SimInfo.COLUMN_MNC + " INTEGER DEFAULT 0;"); 911 } catch (SQLiteException e) { 912 if (DBG) { 913 log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " + 914 " The table will get created in onOpen."); 915 } 916 } 917 oldVersion = 12 << 16 | 6; 918 } 919 if (oldVersion < (13 << 16 | 6)) { 920 try { 921 // Try to update the siminfo table. It might not be there. 922 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " + 923 Telephony.SimInfo.COLUMN_CARRIER_NAME + " TEXT DEFAULT '';"); 924 } catch (SQLiteException e) { 925 if (DBG) { 926 log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " + 927 " The table will get created in onOpen."); 928 } 929 } 930 oldVersion = 13 << 16 | 6; 931 } 932 if (oldVersion < (14 << 16 | 6)) { 933 // Do nothing. This is to avoid recreating table twice. Table is anyway recreated 934 // for next version and that takes care of updates for this version as well. 935 // This version added a new column user_edited to carriers db. 936 } 937 if (oldVersion < (15 << 16 | 6)) { 938 // Most devices should be upgrading from version 13. On upgrade new db will be 939 // populated from the xml included in OTA but user and carrier edited/added entries 940 // need to be preserved. This new version also adds new columns EDITED and 941 // BEARER_BITMASK to the table. Upgrade steps from version 13 are: 942 // 1. preserve user and carrier added/edited APNs (by comparing against 943 // old-apns-conf.xml included in OTA) - done in preserveUserAndCarrierApns() 944 // 2. add new columns EDITED and BEARER_BITMASK (create a new table for that) - done 945 // in createCarriersTable() 946 // 3. copy over preserved APNs from old table to new table - done in 947 // copyPreservedApnsToNewTable() 948 // The only exception if upgrading from version 14 is that EDITED field is already 949 // present (but is called USER_EDITED) 950 /********************************************************************************* 951 * IMPORTANT NOTE: SINCE CARRIERS TABLE IS RECREATED HERE, IT WILL BE THE LATEST 952 * VERSION AFTER THIS. AS A RESULT ANY SUBSEQUENT UPDATES TO THE TABLE WILL FAIL 953 * (DUE TO COLUMN-ALREADY-EXISTS KIND OF EXCEPTION). ALL SUBSEQUENT UPDATES SHOULD 954 * HANDLE THAT GRACEFULLY. 955 *********************************************************************************/ 956 Cursor c; 957 String[] proj = {"_id"}; 958 if (VDBG) { 959 c = db.query(CARRIERS_TABLE, proj, null, null, null, null, null); 960 log("dbh.onUpgrade:- before upgrading total number of rows: " + c.getCount()); 961 } 962 963 // Compare db with old apns xml file so that any user or carrier edited/added 964 // entries can be preserved across upgrade 965 preserveUserAndCarrierApns(db); 966 967 c = db.query(CARRIERS_TABLE, null, null, null, null, null, null); 968 969 if (VDBG) { 970 log("dbh.onUpgrade:- after preserveUserAndCarrierApns() total number of " + 971 "rows: " + ((c == null) ? 0 : c.getCount())); 972 } 973 974 createCarriersTable(db, CARRIERS_TABLE_TMP); 975 976 copyPreservedApnsToNewTable(db, c); 977 c.close(); 978 979 db.execSQL("DROP TABLE IF EXISTS " + CARRIERS_TABLE); 980 981 db.execSQL("ALTER TABLE " + CARRIERS_TABLE_TMP + " rename to " + CARRIERS_TABLE + 982 ";"); 983 984 if (VDBG) { 985 c = db.query(CARRIERS_TABLE, proj, null, null, null, null, null); 986 log("dbh.onUpgrade:- after upgrading total number of rows: " + c.getCount()); 987 c.close(); 988 c = db.query(CARRIERS_TABLE, proj, IS_UNEDITED, null, null, null, null); 989 log("dbh.onUpgrade:- after upgrading total number of rows with " + IS_UNEDITED + 990 ": " + c.getCount()); 991 c.close(); 992 c = db.query(CARRIERS_TABLE, proj, IS_EDITED, null, null, null, null); 993 log("dbh.onUpgrade:- after upgrading total number of rows with " + IS_EDITED + 994 ": " + c.getCount()); 995 c.close(); 996 } 997 998 oldVersion = 15 << 16 | 6; 999 } 1000 if (oldVersion < (16 << 16 | 6)) { 1001 try { 1002 // Try to update the siminfo table. It might not be there. 1003 // These columns may already be present in which case execSQL will throw an 1004 // exception 1005 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " 1006 + Telephony.SimInfo.COLUMN_CB_EXTREME_THREAT_ALERT 1007 + " INTEGER DEFAULT 1;"); 1008 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " 1009 + Telephony.SimInfo.COLUMN_CB_SEVERE_THREAT_ALERT 1010 + " INTEGER DEFAULT 1;"); 1011 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " 1012 + Telephony.SimInfo.COLUMN_CB_AMBER_ALERT + " INTEGER DEFAULT 1;"); 1013 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " 1014 + Telephony.SimInfo.COLUMN_CB_EMERGENCY_ALERT + " INTEGER DEFAULT 1;"); 1015 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " 1016 + Telephony.SimInfo.COLUMN_CB_ALERT_SOUND_DURATION 1017 + " INTEGER DEFAULT 4;"); 1018 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " 1019 + Telephony.SimInfo.COLUMN_CB_ALERT_REMINDER_INTERVAL 1020 + " INTEGER DEFAULT 0;"); 1021 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " 1022 + Telephony.SimInfo.COLUMN_CB_ALERT_VIBRATE + " INTEGER DEFAULT 1;"); 1023 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " 1024 + Telephony.SimInfo.COLUMN_CB_ALERT_SPEECH + " INTEGER DEFAULT 1;"); 1025 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " 1026 + Telephony.SimInfo.COLUMN_CB_ETWS_TEST_ALERT + " INTEGER DEFAULT 0;"); 1027 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " 1028 + Telephony.SimInfo.COLUMN_CB_CHANNEL_50_ALERT + " INTEGER DEFAULT 1;"); 1029 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " 1030 + Telephony.SimInfo.COLUMN_CB_CMAS_TEST_ALERT + " INTEGER DEFAULT 0;"); 1031 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " 1032 + Telephony.SimInfo.COLUMN_CB_OPT_OUT_DIALOG + " INTEGER DEFAULT 1;"); 1033 } catch (SQLiteException e) { 1034 if (DBG) { 1035 log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " + 1036 " The table will get created in onOpen."); 1037 } 1038 } 1039 oldVersion = 16 << 16 | 6; 1040 } 1041 if (oldVersion < (17 << 16 | 6)) { 1042 Cursor c = null; 1043 try { 1044 c = db.query(CARRIERS_TABLE, null, null, null, null, null, null, 1045 String.valueOf(1)); 1046 if (c == null || c.getColumnIndex(USER_VISIBLE) == -1) { 1047 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + " ADD COLUMN " + 1048 USER_VISIBLE + " BOOLEAN DEFAULT 1;"); 1049 } else { 1050 if (DBG) { 1051 log("onUpgrade skipping " + CARRIERS_TABLE + " upgrade. Column " + 1052 USER_VISIBLE + " already exists."); 1053 } 1054 } 1055 } finally { 1056 if (c != null) { 1057 c.close(); 1058 } 1059 } 1060 oldVersion = 17 << 16 | 6; 1061 } 1062 if (oldVersion < (18 << 16 | 6)) { 1063 try { 1064 // Try to update the siminfo table. It might not be there. 1065 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " + 1066 Telephony.SimInfo.COLUMN_SIM_PROVISIONING_STATUS + " INTEGER DEFAULT " + 1067 Telephony.SimInfo.SIM_PROVISIONED + ";"); 1068 } catch (SQLiteException e) { 1069 if (DBG) { 1070 log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " + 1071 " The table will get created in onOpen."); 1072 } 1073 } 1074 oldVersion = 18 << 16 | 6; 1075 } 1076 if (oldVersion < (19 << 16 | 6)) { 1077 // Do nothing. This is to avoid recreating table twice. Table is anyway recreated 1078 // for version 24 and that takes care of updates for this version as well. 1079 // This version added more fields protocol and roaming protocol to the primary key. 1080 } 1081 if (oldVersion < (20 << 16 | 6)) { 1082 try { 1083 // Try to update the siminfo table. It might not be there. 1084 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " + 1085 Telephony.SimInfo.COLUMN_IS_EMBEDDED + " INTEGER DEFAULT 0;"); 1086 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " + 1087 Telephony.SimInfo.COLUMN_ACCESS_RULES + " BLOB;"); 1088 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " + 1089 Telephony.SimInfo.COLUMN_IS_REMOVABLE + " INTEGER DEFAULT 0;"); 1090 } catch (SQLiteException e) { 1091 if (DBG) { 1092 log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " + 1093 "The table will get created in onOpen."); 1094 } 1095 } 1096 oldVersion = 20 << 16 | 6; 1097 } 1098 if (oldVersion < (21 << 16 | 6)) { 1099 try { 1100 // Try to update the carriers table. It might not be there. 1101 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + " ADD COLUMN " + 1102 USER_EDITABLE + " INTEGER DEFAULT 1;"); 1103 } catch (SQLiteException e) { 1104 // This is possible if the column already exists which may be the case if the 1105 // table was just created as part of upgrade to version 19 1106 if (DBG) { 1107 log("onUpgrade skipping " + CARRIERS_TABLE + " upgrade. " + 1108 "The table will get created in onOpen."); 1109 } 1110 } 1111 oldVersion = 21 << 16 | 6; 1112 } 1113 if (oldVersion < (22 << 16 | 6)) { 1114 try { 1115 // Try to update the siminfo table. It might not be there. 1116 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " 1117 + Telephony.SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED 1118 + " INTEGER DEFAULT -1;"); 1119 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " 1120 + Telephony.SimInfo.COLUMN_VT_IMS_ENABLED + " INTEGER DEFAULT -1;"); 1121 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " 1122 + Telephony.SimInfo.COLUMN_WFC_IMS_ENABLED + " INTEGER DEFAULT -1;"); 1123 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " 1124 + Telephony.SimInfo.COLUMN_WFC_IMS_MODE + " INTEGER DEFAULT -1;"); 1125 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " 1126 + Telephony.SimInfo.COLUMN_WFC_IMS_ROAMING_MODE + " INTEGER DEFAULT -1;"); 1127 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " 1128 + Telephony.SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED + " INTEGER DEFAULT -1;"); 1129 } catch (SQLiteException e) { 1130 if (DBG) { 1131 log("onUpgrade skipping " + CARRIERS_TABLE + " upgrade. " + 1132 "The table will get created in onOpen."); 1133 } 1134 } 1135 oldVersion = 22 << 16 | 6; 1136 } 1137 if (oldVersion < (23 << 16 | 6)) { 1138 try { 1139 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + " ADD COLUMN " + 1140 OWNED_BY + " INTEGER DEFAULT " + OWNED_BY_OTHERS + ";"); 1141 } catch (SQLiteException e) { 1142 if (DBG) { 1143 log("onUpgrade skipping " + CARRIERS_TABLE + " upgrade. " + 1144 "The table will get created in onOpen."); 1145 } 1146 } 1147 oldVersion = 23 << 16 | 6; 1148 } 1149 if (oldVersion < (24 << 16 | 6)) { 1150 Cursor c = null; 1151 String[] proj = {"_id"}; 1152 recreateDB(db, proj, /* version */24); 1153 if (VDBG) { 1154 c = db.query(CARRIERS_TABLE, proj, null, null, null, null, null); 1155 log("dbh.onUpgrade:- after upgrading total number of rows: " + c.getCount()); 1156 c.close(); 1157 c = db.query( 1158 CARRIERS_TABLE, proj, NETWORK_TYPE_BITMASK, null, null, null, null); 1159 log("dbh.onUpgrade:- after upgrading total number of rows with " 1160 + NETWORK_TYPE_BITMASK + ": " + c.getCount()); 1161 c.close(); 1162 } 1163 oldVersion = 24 << 16 | 6; 1164 } 1165 if (oldVersion < (25 << 16 | 6)) { 1166 // Add a new column SubscriptionManager.CARD_ID into the database and set the value 1167 // to be the same as the existing column SubscriptionManager.ICC_ID. In order to do 1168 // this, we need to first make a copy of the existing SIMINFO_TABLE, set the value 1169 // of the new column SubscriptionManager.CARD_ID, and replace the SIMINFO_TABLE with 1170 // the new table. 1171 Cursor c = null; 1172 String[] proj = {Telephony.SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID}; 1173 recreateSimInfoDB(c, db, proj); 1174 if (VDBG) { 1175 c = db.query(SIMINFO_TABLE, proj, null, null, null, null, null); 1176 log("dbh.onUpgrade:- after upgrading " + SIMINFO_TABLE 1177 + " total number of rows: " + c.getCount()); 1178 c.close(); 1179 c = db.query(SIMINFO_TABLE, proj, Telephony.SimInfo.COLUMN_CARD_ID 1180 + " IS NOT NULL", null, null, null, null); 1181 log("dbh.onUpgrade:- after upgrading total number of rows with " 1182 + Telephony.SimInfo.COLUMN_CARD_ID + ": " + c.getCount()); 1183 c.close(); 1184 } 1185 oldVersion = 25 << 16 | 6; 1186 } 1187 if (oldVersion < (26 << 16 | 6)) { 1188 // Add a new column Carriers.APN_SET_ID into the database and set the value to 1189 // Carriers.NO_SET_SET by default. 1190 try { 1191 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + " ADD COLUMN " + 1192 APN_SET_ID + " INTEGER DEFAULT " + NO_APN_SET_ID + ";"); 1193 } catch (SQLiteException e) { 1194 if (DBG) { 1195 log("onUpgrade skipping " + CARRIERS_TABLE + " upgrade. " + 1196 "The table will get created in onOpen."); 1197 } 1198 } 1199 oldVersion = 26 << 16 | 6; 1200 } 1201 1202 if (oldVersion < (27 << 16 | 6)) { 1203 // Add the new MCC_STRING and MNC_STRING columns into the subscription table, 1204 // and attempt to populate them. 1205 try { 1206 // Try to update the siminfo table. It might not be there. 1207 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + 1208 " ADD COLUMN " + Telephony.SimInfo.COLUMN_MCC_STRING + " TEXT;"); 1209 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + 1210 " ADD COLUMN " + Telephony.SimInfo.COLUMN_MNC_STRING + " TEXT;"); 1211 } catch (SQLiteException e) { 1212 if (DBG) { 1213 log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " + 1214 " The table will get created in onOpen."); 1215 } 1216 } 1217 // Migrate the old integer values over to strings 1218 String[] proj = {Telephony.SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID, 1219 Telephony.SimInfo.COLUMN_MCC, Telephony.SimInfo.COLUMN_MNC}; 1220 try (Cursor c = db.query(SIMINFO_TABLE, proj, null, null, null, null, null)) { 1221 while (c.moveToNext()) { 1222 fillInMccMncStringAtCursor(mContext, db, c); 1223 } 1224 } 1225 oldVersion = 27 << 16 | 6; 1226 } 1227 1228 if (oldVersion < (28 << 16 | 6)) { 1229 try { 1230 // Try to update the siminfo table. It might not be there. 1231 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " 1232 + Telephony.SimInfo.COLUMN_IS_OPPORTUNISTIC + " INTEGER DEFAULT 0;"); 1233 } catch (SQLiteException e) { 1234 if (DBG) { 1235 log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " + 1236 "The table will get created in onOpen."); 1237 } 1238 } 1239 oldVersion = 28 << 16 | 6; 1240 } 1241 1242 if (oldVersion < (29 << 16 | 6)) { 1243 try { 1244 // Add a new column Telephony.CARRIER_ID into the database and add UNIQUE 1245 // constraint into table. However, sqlite cannot add constraints to an existing 1246 // table, so recreate the table. 1247 String[] proj = {"_id"}; 1248 recreateDB(db, proj, /* version */29); 1249 } catch (SQLiteException e) { 1250 if (DBG) { 1251 log("onUpgrade skipping " + CARRIERS_TABLE + " upgrade. " + 1252 "The table will get created in onOpen."); 1253 } 1254 } 1255 oldVersion = 29 << 16 | 6; 1256 } 1257 1258 if (oldVersion < (30 << 16 | 6)) { 1259 try { 1260 // Try to update the siminfo table. It might not be there. 1261 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " 1262 + Telephony.SimInfo.COLUMN_GROUP_UUID + " TEXT;"); 1263 } catch (SQLiteException e) { 1264 if (DBG) { 1265 log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " + 1266 "The table will get created in onOpen."); 1267 } 1268 } 1269 oldVersion = 30 << 16 | 6; 1270 } 1271 1272 if (oldVersion < (31 << 16 | 6)) { 1273 try { 1274 // Try to update the siminfo table. It might not be there. 1275 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " 1276 + Telephony.SimInfo.COLUMN_IS_METERED + " INTEGER DEFAULT 1;"); 1277 } catch (SQLiteException e) { 1278 if (DBG) { 1279 log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " + 1280 "The table will get created in onOpen."); 1281 } 1282 } 1283 oldVersion = 31 << 16 | 6; 1284 } 1285 1286 if (oldVersion < (32 << 16 | 6)) { 1287 try { 1288 // Try to update the siminfo table. It might not be there. 1289 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " 1290 + Telephony.SimInfo.COLUMN_ISO_COUNTRY_CODE + " TEXT;"); 1291 } catch (SQLiteException e) { 1292 if (DBG) { 1293 log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " + 1294 "The table will get created in onOpen."); 1295 } 1296 } 1297 oldVersion = 32 << 16 | 6; 1298 } 1299 1300 if (oldVersion < (33 << 16 | 6)) { 1301 try { 1302 // Try to update the siminfo table. It might not be there. 1303 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " 1304 + Telephony.SimInfo.COLUMN_CARRIER_ID + " INTEGER DEFAULT -1;"); 1305 } catch (SQLiteException e) { 1306 if (DBG) { 1307 log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " + 1308 "The table will get created in onOpen."); 1309 } 1310 } 1311 oldVersion = 33 << 16 | 6; 1312 } 1313 1314 if (oldVersion < (34 << 16 | 6)) { 1315 try { 1316 // Try to update the siminfo table. It might not be there. 1317 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " + 1318 Telephony.SimInfo.COLUMN_PROFILE_CLASS + " INTEGER DEFAULT " + 1319 Telephony.SimInfo.PROFILE_CLASS_UNSET + ";"); 1320 } catch (SQLiteException e) { 1321 if (DBG) { 1322 log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " + 1323 "The table will get created in onOpen."); 1324 } 1325 } 1326 oldVersion = 34 << 16 | 6; 1327 } 1328 1329 if (oldVersion < (35 << 16 | 6)) { 1330 try { 1331 // Try to update the siminfo table. It might not be there. 1332 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " 1333 + Telephony.SimInfo.COLUMN_SUBSCRIPTION_TYPE + " INTEGER DEFAULT " 1334 + Telephony.SimInfo.SUBSCRIPTION_TYPE_LOCAL_SIM + ";"); 1335 } catch (SQLiteException e) { 1336 if (DBG) { 1337 log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " + 1338 "The table will get created in onOpen."); 1339 } 1340 } 1341 oldVersion = 35 << 16 | 6; 1342 } 1343 1344 if (oldVersion < (36 << 16 | 6)) { 1345 // Add a new column Carriers.SKIP_464XLAT into the database and set the value to 1346 // SKIP_464XLAT_DEFAULT. 1347 try { 1348 db.execSQL("ALTER TABLE " + CARRIERS_TABLE + " ADD COLUMN " + 1349 SKIP_464XLAT + " INTEGER DEFAULT " + SKIP_464XLAT_DEFAULT + ";"); 1350 } catch (SQLiteException e) { 1351 if (DBG) { 1352 log("onUpgrade skipping " + CARRIERS_TABLE + " upgrade. " + 1353 "The table will get created in onOpen."); 1354 } 1355 } 1356 oldVersion = 36 << 16 | 6; 1357 } 1358 1359 if (oldVersion < (37 << 16 | 6)) { 1360 // Add new columns Telephony.SimInfo.EHPLMNS and Telephony.SimInfo.HPLMNS into 1361 // the database. 1362 try { 1363 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + 1364 " ADD COLUMN " + Telephony.SimInfo.COLUMN_EHPLMNS + " TEXT;"); 1365 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + 1366 " ADD COLUMN " + Telephony.SimInfo.COLUMN_HPLMNS + " TEXT;"); 1367 } catch (SQLiteException e) { 1368 if (DBG) { 1369 log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade for ehplmns. " + 1370 "The table will get created in onOpen."); 1371 } 1372 } 1373 oldVersion = 37 << 16 | 6; 1374 } 1375 1376 if (oldVersion < (39 << 16 | 6)) { 1377 try { 1378 // Try to update the siminfo table. It might not be there. 1379 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " 1380 + Telephony.SimInfo.COLUMN_GROUP_OWNER + " TEXT;"); 1381 } catch (SQLiteException e) { 1382 if (DBG) { 1383 log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " + 1384 "The table will get created in onOpen."); 1385 } 1386 } 1387 oldVersion = 39 << 16 | 6; 1388 } 1389 1390 if (oldVersion < (40 << 16 | 6)) { 1391 try { 1392 // Try to update the siminfo table. It might not be there. 1393 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " 1394 + Telephony.SimInfo.COLUMN_DATA_ENABLED_OVERRIDE_RULES + " TEXT;"); 1395 } catch (SQLiteException e) { 1396 if (DBG) { 1397 log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " + 1398 "The table will get created in onOpen."); 1399 } 1400 } 1401 oldVersion = 40 << 16 | 6; 1402 } 1403 1404 if (oldVersion < (41 << 16 | 6)) { 1405 try { 1406 // Try to update the siminfo table. It might not be there. 1407 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " 1408 + Telephony.SimInfo.COLUMN_IMSI + " TEXT;"); 1409 } catch (SQLiteException e) { 1410 if (DBG) { 1411 log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " + 1412 "The table will get created in onOpen."); 1413 } 1414 } 1415 oldVersion = 41 << 16 | 6; 1416 } 1417 1418 if (oldVersion < (42 << 16 | 6)) { 1419 try { 1420 // Try to update the siminfo table. It might not be there. 1421 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " + 1422 Telephony.SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS + " BLOB;"); 1423 } catch (SQLiteException e) { 1424 if (DBG) { 1425 log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " + 1426 "The table will get created in onOpen."); 1427 } 1428 } 1429 } 1430 1431 if (oldVersion < (43 << 16 | 6)) { 1432 try { 1433 // Try to update the siminfo table. It might not be there. 1434 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " 1435 + Telephony.SimInfo.COLUMN_UICC_APPLICATIONS_ENABLED 1436 + " INTEGER DEFAULT 1;"); 1437 } catch (SQLiteException e) { 1438 if (DBG) { 1439 log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " + 1440 "The table will get created in onOpen."); 1441 } 1442 } 1443 oldVersion = 43 << 16 | 6; 1444 } 1445 1446 if (oldVersion < (44 << 16 | 6)) { 1447 try { 1448 // Try to update the siminfo table. It might not be there. 1449 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " 1450 + Telephony.SimInfo.COLUMN_ALLOWED_NETWORK_TYPES 1451 + " BIGINT DEFAULT -1;"); 1452 } catch (SQLiteException e) { 1453 if (DBG) { 1454 log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " + 1455 "The table will get created in onOpen."); 1456 } 1457 } 1458 oldVersion = 44 << 16 | 6; 1459 } 1460 1461 if (oldVersion < (45 << 16 | 6)) { 1462 try { 1463 // Try to update the siminfo table. It might not be there. 1464 db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN " 1465 + Telephony.SimInfo.COLUMN_IMS_RCS_UCE_ENABLED 1466 + " INTEGER DEFAULT 0;"); 1467 } catch (SQLiteException e) { 1468 if (DBG) { 1469 log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " + 1470 "The table will get created in onOpen."); 1471 } 1472 } 1473 oldVersion = 45 << 16 | 6; 1474 } 1475 1476 if (DBG) { 1477 log("dbh.onUpgrade:- db=" + db + " oldV=" + oldVersion + " newV=" + newVersion); 1478 } 1479 // when adding fields to onUpgrade, also add a unit test to TelephonyDatabaseHelperTest 1480 // and update the DATABASE_VERSION field and add a column in copyAllApnValues 1481 } 1482 recreateSimInfoDB(Cursor c, SQLiteDatabase db, String[] proj)1483 private void recreateSimInfoDB(Cursor c, SQLiteDatabase db, String[] proj) { 1484 if (VDBG) { 1485 c = db.query(SIMINFO_TABLE, proj, null, null, null, null, null); 1486 log("dbh.onUpgrade:+ before upgrading " + SIMINFO_TABLE + 1487 " total number of rows: " + c.getCount()); 1488 c.close(); 1489 } 1490 1491 // Sort in ascending order by subscription id to make sure the rows do not get flipped 1492 // during the query and added in the new sim info table in another order (sub id is 1493 // stored in settings between migrations). 1494 c = db.query(SIMINFO_TABLE, null, null, null, null, null, ORDER_BY_SUB_ID); 1495 1496 db.execSQL("DROP TABLE IF EXISTS " + SIMINFO_TABLE_TMP); 1497 1498 createSimInfoTable(db, SIMINFO_TABLE_TMP); 1499 1500 copySimInfoDataToTmpTable(db, c); 1501 c.close(); 1502 1503 db.execSQL("DROP TABLE IF EXISTS " + SIMINFO_TABLE); 1504 1505 db.execSQL("ALTER TABLE " + SIMINFO_TABLE_TMP + " rename to " + SIMINFO_TABLE + ";"); 1506 1507 } 1508 copySimInfoDataToTmpTable(SQLiteDatabase db, Cursor c)1509 private void copySimInfoDataToTmpTable(SQLiteDatabase db, Cursor c) { 1510 // Move entries from SIMINFO_TABLE to SIMINFO_TABLE_TMP 1511 if (c != null) { 1512 while (c.moveToNext()) { 1513 ContentValues cv = new ContentValues(); 1514 copySimInfoValuesV24(cv, c); 1515 // The card ID is supposed to be the ICCID of the profile for UICC card, and 1516 // the EID of the card for eUICC card. Since EID is unknown for old entries in 1517 // SIMINFO_TABLE, we use ICCID as the card ID for all the old entries while 1518 // upgrading the SIMINFO_TABLE. In UiccController, both the card ID and ICCID 1519 // will be checked when user queries the slot information using the card ID 1520 // from the database. 1521 getCardIdfromIccid(cv, c); 1522 try { 1523 db.insert(SIMINFO_TABLE_TMP, null, cv); 1524 if (VDBG) { 1525 log("dbh.copySimInfoDataToTmpTable: db.insert returned >= 0; " + 1526 "insert successful for cv " + cv); 1527 } 1528 } catch (SQLException e) { 1529 if (VDBG) 1530 log("dbh.copySimInfoDataToTmpTable insertWithOnConflict exception " + 1531 e + " for cv " + cv); 1532 } 1533 } 1534 } 1535 } 1536 copySimInfoValuesV24(ContentValues cv, Cursor c)1537 private void copySimInfoValuesV24(ContentValues cv, Cursor c) { 1538 // String vals 1539 getStringValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_ICC_ID); 1540 getStringValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_DISPLAY_NAME); 1541 getStringValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_CARRIER_NAME); 1542 getStringValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_NUMBER); 1543 1544 // bool/int vals 1545 getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_SIM_SLOT_INDEX); 1546 getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_NAME_SOURCE); 1547 getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_COLOR); 1548 getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_DISPLAY_NUMBER_FORMAT); 1549 getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_DATA_ROAMING); 1550 getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_MCC); 1551 getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_MNC); 1552 getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_SIM_PROVISIONING_STATUS); 1553 getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_IS_EMBEDDED); 1554 getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_IS_REMOVABLE); 1555 getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_CB_EXTREME_THREAT_ALERT); 1556 getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_CB_SEVERE_THREAT_ALERT); 1557 getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_CB_AMBER_ALERT); 1558 getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_CB_EMERGENCY_ALERT); 1559 getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_CB_ALERT_SOUND_DURATION); 1560 getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_CB_ALERT_REMINDER_INTERVAL); 1561 getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_CB_ALERT_VIBRATE); 1562 getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_CB_ALERT_SPEECH); 1563 getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_CB_ETWS_TEST_ALERT); 1564 getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_CB_CHANNEL_50_ALERT); 1565 getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_CB_CMAS_TEST_ALERT); 1566 getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_CB_OPT_OUT_DIALOG); 1567 getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED); 1568 getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_VT_IMS_ENABLED); 1569 getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_WFC_IMS_ENABLED); 1570 getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_WFC_IMS_MODE); 1571 getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_WFC_IMS_ROAMING_MODE); 1572 getIntValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED); 1573 1574 // Blob vals 1575 getBlobValueFromCursor(cv, c, Telephony.SimInfo.COLUMN_ACCESS_RULES); 1576 } 1577 getCardIdfromIccid(ContentValues cv, Cursor c)1578 private void getCardIdfromIccid(ContentValues cv, Cursor c) { 1579 int columnIndex = c.getColumnIndex(Telephony.SimInfo.COLUMN_ICC_ID); 1580 if (columnIndex != -1) { 1581 String fromCursor = c.getString(columnIndex); 1582 if (!TextUtils.isEmpty(fromCursor)) { 1583 cv.put(Telephony.SimInfo.COLUMN_CARD_ID, fromCursor); 1584 } 1585 } 1586 } 1587 recreateDB(SQLiteDatabase db, String[] proj, int version)1588 private void recreateDB(SQLiteDatabase db, String[] proj, int version) { 1589 // Upgrade steps are: 1590 // 1. Create a temp table- done in createCarriersTable() 1591 // 2. copy over APNs from old table to new table - done in copyDataToTmpTable() 1592 // 3. Drop the existing table. 1593 // 4. Copy over the tmp table. 1594 Cursor c; 1595 if (VDBG) { 1596 c = db.query(CARRIERS_TABLE, proj, null, null, null, null, null); 1597 log("dbh.onUpgrade:- before upgrading total number of rows: " + c.getCount()); 1598 c.close(); 1599 } 1600 1601 c = db.query(CARRIERS_TABLE, null, null, null, null, null, null); 1602 1603 if (VDBG) { 1604 log("dbh.onUpgrade:- starting data copy of existing rows: " + 1605 + ((c == null) ? 0 : c.getCount())); 1606 } 1607 1608 db.execSQL("DROP TABLE IF EXISTS " + CARRIERS_TABLE_TMP); 1609 1610 createCarriersTable(db, CARRIERS_TABLE_TMP); 1611 1612 copyDataToTmpTable(db, c, version); 1613 c.close(); 1614 1615 db.execSQL("DROP TABLE IF EXISTS " + CARRIERS_TABLE); 1616 1617 db.execSQL("ALTER TABLE " + CARRIERS_TABLE_TMP + " rename to " + CARRIERS_TABLE + ";"); 1618 } 1619 preserveUserAndCarrierApns(SQLiteDatabase db)1620 private void preserveUserAndCarrierApns(SQLiteDatabase db) { 1621 if (VDBG) log("preserveUserAndCarrierApns"); 1622 XmlPullParser confparser; 1623 File confFile = new File(Environment.getRootDirectory(), OLD_APNS_PATH); 1624 FileReader confreader = null; 1625 try { 1626 confreader = new FileReader(confFile); 1627 confparser = Xml.newPullParser(); 1628 confparser.setInput(confreader); 1629 XmlUtils.beginDocument(confparser, "apns"); 1630 1631 deleteMatchingApns(db, confparser); 1632 } catch (FileNotFoundException e) { 1633 // This function is called only when upgrading db to version 15. Details about the 1634 // upgrade are mentioned in onUpgrade(). This file missing means user/carrier added 1635 // APNs cannot be preserved. Log an error message so that OEMs know they need to 1636 // include old apns file for comparison. 1637 loge("PRESERVEUSERANDCARRIERAPNS: " + OLD_APNS_PATH + 1638 " NOT FOUND. IT IS NEEDED TO UPGRADE FROM OLDER VERSIONS OF APN " + 1639 "DB WHILE PRESERVING USER/CARRIER ADDED/EDITED ENTRIES."); 1640 } catch (Exception e) { 1641 loge("preserveUserAndCarrierApns: Exception while parsing '" + 1642 confFile.getAbsolutePath() + "'" + e); 1643 } finally { 1644 if (confreader != null) { 1645 try { 1646 confreader.close(); 1647 } catch (IOException e) { 1648 // do nothing 1649 } 1650 } 1651 } 1652 } 1653 deleteMatchingApns(SQLiteDatabase db, XmlPullParser parser)1654 private void deleteMatchingApns(SQLiteDatabase db, XmlPullParser parser) { 1655 if (VDBG) log("deleteMatchingApns"); 1656 if (parser != null) { 1657 if (VDBG) log("deleteMatchingApns: parser != null"); 1658 try { 1659 XmlUtils.nextElement(parser); 1660 while (parser.getEventType() != XmlPullParser.END_DOCUMENT) { 1661 ContentValues row = getRow(parser); 1662 if (row == null) { 1663 throw new XmlPullParserException("Expected 'apn' tag", parser, null); 1664 } 1665 deleteRow(db, row); 1666 XmlUtils.nextElement(parser); 1667 } 1668 } catch (XmlPullParserException e) { 1669 loge("deleteMatchingApns: Got XmlPullParserException while deleting apns." + e); 1670 } catch (IOException e) { 1671 loge("deleteMatchingApns: Got IOException while deleting apns." + e); 1672 } catch (SQLException e) { 1673 loge("deleteMatchingApns: Got SQLException while deleting apns." + e); 1674 } 1675 } 1676 } 1677 queryValFirst(String field)1678 private String queryValFirst(String field) { 1679 return field + "=?"; 1680 } 1681 queryVal(String field)1682 private String queryVal(String field) { 1683 return " and " + field + "=?"; 1684 } 1685 queryValOrNull(String field)1686 private String queryValOrNull(String field) { 1687 return " and (" + field + "=? or " + field + " is null)"; 1688 } 1689 queryVal2OrNull(String field)1690 private String queryVal2OrNull(String field) { 1691 return " and (" + field + "=? or " + field + "=? or " + field + " is null)"; 1692 } 1693 deleteRow(SQLiteDatabase db, ContentValues values)1694 private void deleteRow(SQLiteDatabase db, ContentValues values) { 1695 if (VDBG) log("deleteRow"); 1696 String where = queryValFirst(NUMERIC) + 1697 queryVal(MNC) + 1698 queryVal(MNC) + 1699 queryValOrNull(APN) + 1700 queryValOrNull(USER) + 1701 queryValOrNull(SERVER) + 1702 queryValOrNull(PASSWORD) + 1703 queryValOrNull(PROXY) + 1704 queryValOrNull(PORT) + 1705 queryValOrNull(MMSPROXY) + 1706 queryValOrNull(MMSPORT) + 1707 queryValOrNull(MMSC) + 1708 queryValOrNull(AUTH_TYPE) + 1709 queryValOrNull(TYPE) + 1710 queryValOrNull(PROTOCOL) + 1711 queryValOrNull(ROAMING_PROTOCOL) + 1712 queryVal2OrNull(CARRIER_ENABLED) + 1713 queryValOrNull(BEARER) + 1714 queryValOrNull(MVNO_TYPE) + 1715 queryValOrNull(MVNO_MATCH_DATA) + 1716 queryValOrNull(PROFILE_ID) + 1717 queryVal2OrNull(MODEM_PERSIST) + 1718 queryValOrNull(MAX_CONNECTIONS) + 1719 queryValOrNull(WAIT_TIME_RETRY) + 1720 queryValOrNull(TIME_LIMIT_FOR_MAX_CONNECTIONS) + 1721 queryValOrNull(MTU); 1722 String[] whereArgs = new String[29]; 1723 int i = 0; 1724 whereArgs[i++] = values.getAsString(NUMERIC); 1725 whereArgs[i++] = values.getAsString(MCC); 1726 whereArgs[i++] = values.getAsString(MNC); 1727 whereArgs[i++] = values.getAsString(NAME); 1728 whereArgs[i++] = values.containsKey(APN) ? 1729 values.getAsString(APN) : ""; 1730 whereArgs[i++] = values.containsKey(USER) ? 1731 values.getAsString(USER) : ""; 1732 whereArgs[i++] = values.containsKey(SERVER) ? 1733 values.getAsString(SERVER) : ""; 1734 whereArgs[i++] = values.containsKey(PASSWORD) ? 1735 values.getAsString(PASSWORD) : ""; 1736 whereArgs[i++] = values.containsKey(PROXY) ? 1737 values.getAsString(PROXY) : ""; 1738 whereArgs[i++] = values.containsKey(PORT) ? 1739 values.getAsString(PORT) : ""; 1740 whereArgs[i++] = values.containsKey(MMSPROXY) ? 1741 values.getAsString(MMSPROXY) : ""; 1742 whereArgs[i++] = values.containsKey(MMSPORT) ? 1743 values.getAsString(MMSPORT) : ""; 1744 whereArgs[i++] = values.containsKey(MMSC) ? 1745 values.getAsString(MMSC) : ""; 1746 whereArgs[i++] = values.containsKey(AUTH_TYPE) ? 1747 values.getAsString(AUTH_TYPE) : "-1"; 1748 whereArgs[i++] = values.containsKey(TYPE) ? 1749 values.getAsString(TYPE) : ""; 1750 whereArgs[i++] = values.containsKey(PROTOCOL) ? 1751 values.getAsString(PROTOCOL) : DEFAULT_PROTOCOL; 1752 whereArgs[i++] = values.containsKey(ROAMING_PROTOCOL) ? 1753 values.getAsString(ROAMING_PROTOCOL) : DEFAULT_ROAMING_PROTOCOL; 1754 1755 if (values.containsKey(CARRIER_ENABLED)) { 1756 whereArgs[i++] = convertStringToBoolString(values.getAsString(CARRIER_ENABLED)); 1757 whereArgs[i++] = convertStringToIntString(values.getAsString(CARRIER_ENABLED)); 1758 } else { 1759 String defaultIntString = CARRIERS_UNIQUE_FIELDS_DEFAULTS.get(CARRIER_ENABLED); 1760 whereArgs[i++] = convertStringToBoolString(defaultIntString); 1761 whereArgs[i++] = defaultIntString; 1762 } 1763 1764 whereArgs[i++] = values.containsKey(BEARER) ? 1765 values.getAsString(BEARER) : "0"; 1766 whereArgs[i++] = values.containsKey(MVNO_TYPE) ? 1767 values.getAsString(MVNO_TYPE) : ""; 1768 whereArgs[i++] = values.containsKey(MVNO_MATCH_DATA) ? 1769 values.getAsString(MVNO_MATCH_DATA) : ""; 1770 whereArgs[i++] = values.containsKey(PROFILE_ID) ? 1771 values.getAsString(PROFILE_ID) : "0"; 1772 1773 if (values.containsKey(MODEM_PERSIST) && 1774 (values.getAsString(MODEM_PERSIST). 1775 equalsIgnoreCase("true") || 1776 values.getAsString(MODEM_PERSIST).equals("1"))) { 1777 whereArgs[i++] = "true"; 1778 whereArgs[i++] = "1"; 1779 } else { 1780 whereArgs[i++] = "false"; 1781 whereArgs[i++] = "0"; 1782 } 1783 1784 whereArgs[i++] = values.containsKey(MAX_CONNECTIONS) ? 1785 values.getAsString(MAX_CONNECTIONS) : "0"; 1786 whereArgs[i++] = values.containsKey(WAIT_TIME_RETRY) ? 1787 values.getAsString(WAIT_TIME_RETRY) : "0"; 1788 whereArgs[i++] = values.containsKey(TIME_LIMIT_FOR_MAX_CONNECTIONS) ? 1789 values.getAsString(TIME_LIMIT_FOR_MAX_CONNECTIONS) : "0"; 1790 whereArgs[i++] = values.containsKey(MTU) ? 1791 values.getAsString(MTU) : "0"; 1792 1793 if (VDBG) { 1794 log("deleteRow: where: " + where); 1795 1796 StringBuilder builder = new StringBuilder(); 1797 for (String s : whereArgs) { 1798 builder.append(s + ", "); 1799 } 1800 1801 log("deleteRow: whereArgs: " + builder.toString()); 1802 } 1803 db.delete(CARRIERS_TABLE, where, whereArgs); 1804 } 1805 copyDataToTmpTable(SQLiteDatabase db, Cursor c, int version)1806 private void copyDataToTmpTable(SQLiteDatabase db, Cursor c, int version) { 1807 // Move entries from CARRIERS_TABLE to CARRIERS_TABLE_TMP 1808 if (c != null) { 1809 while (c.moveToNext()) { 1810 ContentValues cv = new ContentValues(); 1811 copyAllApnValues(cv, c); 1812 if (version == 24) { 1813 // Sync bearer bitmask and network type bitmask 1814 getNetworkTypeBitmaskFromCursor(cv, c); 1815 } 1816 try { 1817 db.insertWithOnConflict(CARRIERS_TABLE_TMP, null, cv, 1818 SQLiteDatabase.CONFLICT_ABORT); 1819 if (VDBG) { 1820 log("dbh.copyPreservedApnsToNewTable: db.insert returned >= 0; " + 1821 "insert successful for cv " + cv); 1822 } 1823 } catch (SQLException e) { 1824 if (VDBG) 1825 log("dbh.copyPreservedApnsToNewTable insertWithOnConflict exception " + 1826 e + " for cv " + cv); 1827 } 1828 } 1829 } 1830 } 1831 copyApnValuesV17(ContentValues cv, Cursor c)1832 private void copyApnValuesV17(ContentValues cv, Cursor c) { 1833 // Include only non-null values in cv so that null values can be replaced 1834 // with default if there's a default value for the field 1835 1836 // String vals 1837 getStringValueFromCursor(cv, c, NAME); 1838 getStringValueFromCursor(cv, c, NUMERIC); 1839 getStringValueFromCursor(cv, c, MCC); 1840 getStringValueFromCursor(cv, c, MNC); 1841 getStringValueFromCursor(cv, c, APN); 1842 getStringValueFromCursor(cv, c, USER); 1843 getStringValueFromCursor(cv, c, SERVER); 1844 getStringValueFromCursor(cv, c, PASSWORD); 1845 getStringValueFromCursor(cv, c, PROXY); 1846 getStringValueFromCursor(cv, c, PORT); 1847 getStringValueFromCursor(cv, c, MMSPROXY); 1848 getStringValueFromCursor(cv, c, MMSPORT); 1849 getStringValueFromCursor(cv, c, MMSC); 1850 getStringValueFromCursor(cv, c, TYPE); 1851 getStringValueFromCursor(cv, c, PROTOCOL); 1852 getStringValueFromCursor(cv, c, ROAMING_PROTOCOL); 1853 getStringValueFromCursor(cv, c, MVNO_TYPE); 1854 getStringValueFromCursor(cv, c, MVNO_MATCH_DATA); 1855 1856 // bool/int vals 1857 getIntValueFromCursor(cv, c, AUTH_TYPE); 1858 getIntValueFromCursor(cv, c, CURRENT); 1859 getIntValueFromCursor(cv, c, CARRIER_ENABLED); 1860 getIntValueFromCursor(cv, c, BEARER); 1861 getIntValueFromCursor(cv, c, SUBSCRIPTION_ID); 1862 getIntValueFromCursor(cv, c, PROFILE_ID); 1863 getIntValueFromCursor(cv, c, MODEM_PERSIST); 1864 getIntValueFromCursor(cv, c, MAX_CONNECTIONS); 1865 getIntValueFromCursor(cv, c, WAIT_TIME_RETRY); 1866 getIntValueFromCursor(cv, c, TIME_LIMIT_FOR_MAX_CONNECTIONS); 1867 getIntValueFromCursor(cv, c, MTU); 1868 getIntValueFromCursor(cv, c, BEARER_BITMASK); 1869 getIntValueFromCursor(cv, c, EDITED_STATUS); 1870 getIntValueFromCursor(cv, c, USER_VISIBLE); 1871 } 1872 copyAllApnValues(ContentValues cv, Cursor c)1873 private void copyAllApnValues(ContentValues cv, Cursor c) { 1874 // String vals 1875 getStringValueFromCursor(cv, c, NAME); 1876 getStringValueFromCursor(cv, c, NUMERIC); 1877 getStringValueFromCursor(cv, c, MCC); 1878 getStringValueFromCursor(cv, c, MNC); 1879 getStringValueFromCursor(cv, c, APN); 1880 getStringValueFromCursor(cv, c, USER); 1881 getStringValueFromCursor(cv, c, SERVER); 1882 getStringValueFromCursor(cv, c, PASSWORD); 1883 getStringValueFromCursor(cv, c, PROXY); 1884 getStringValueFromCursor(cv, c, PORT); 1885 getStringValueFromCursor(cv, c, MMSPROXY); 1886 getStringValueFromCursor(cv, c, MMSPORT); 1887 getStringValueFromCursor(cv, c, MMSC); 1888 getStringValueFromCursor(cv, c, TYPE); 1889 getStringValueFromCursor(cv, c, PROTOCOL); 1890 getStringValueFromCursor(cv, c, ROAMING_PROTOCOL); 1891 getStringValueFromCursor(cv, c, MVNO_TYPE); 1892 getStringValueFromCursor(cv, c, MVNO_MATCH_DATA); 1893 1894 // bool/int vals 1895 getIntValueFromCursor(cv, c, AUTH_TYPE); 1896 getIntValueFromCursor(cv, c, CURRENT); 1897 getIntValueFromCursor(cv, c, CARRIER_ENABLED); 1898 getIntValueFromCursor(cv, c, BEARER); 1899 getIntValueFromCursor(cv, c, SUBSCRIPTION_ID); 1900 getIntValueFromCursor(cv, c, PROFILE_ID); 1901 getIntValueFromCursor(cv, c, MODEM_PERSIST); 1902 getIntValueFromCursor(cv, c, MAX_CONNECTIONS); 1903 getIntValueFromCursor(cv, c, WAIT_TIME_RETRY); 1904 getIntValueFromCursor(cv, c, TIME_LIMIT_FOR_MAX_CONNECTIONS); 1905 getIntValueFromCursor(cv, c, MTU); 1906 getIntValueFromCursor(cv, c, NETWORK_TYPE_BITMASK); 1907 getIntValueFromCursor(cv, c, BEARER_BITMASK); 1908 getIntValueFromCursor(cv, c, EDITED_STATUS); 1909 getIntValueFromCursor(cv, c, USER_VISIBLE); 1910 getIntValueFromCursor(cv, c, USER_EDITABLE); 1911 getIntValueFromCursor(cv, c, OWNED_BY); 1912 getIntValueFromCursor(cv, c, APN_SET_ID); 1913 getIntValueFromCursor(cv, c, SKIP_464XLAT); 1914 } 1915 copyPreservedApnsToNewTable(SQLiteDatabase db, Cursor c)1916 private void copyPreservedApnsToNewTable(SQLiteDatabase db, Cursor c) { 1917 // Move entries from CARRIERS_TABLE to CARRIERS_TABLE_TMP 1918 if (c != null && mContext.getResources() != null) { 1919 try { 1920 String[] persistApnsForPlmns = mContext.getResources().getStringArray( 1921 R.array.persist_apns_for_plmn); 1922 while (c.moveToNext()) { 1923 ContentValues cv = new ContentValues(); 1924 String val; 1925 // Using V17 copy function for V15 upgrade. This should be fine since it handles 1926 // columns that may not exist properly (getStringValueFromCursor() and 1927 // getIntValueFromCursor() handle column index -1) 1928 copyApnValuesV17(cv, c); 1929 // Change bearer to a bitmask 1930 String bearerStr = c.getString(c.getColumnIndex(BEARER)); 1931 if (!TextUtils.isEmpty(bearerStr)) { 1932 int bearer_bitmask = getBitmaskForTech(Integer.parseInt(bearerStr)); 1933 cv.put(BEARER_BITMASK, bearer_bitmask); 1934 1935 int networkTypeBitmask = rilRadioTechnologyToNetworkTypeBitmask( 1936 Integer.parseInt(bearerStr)); 1937 cv.put(NETWORK_TYPE_BITMASK, networkTypeBitmask); 1938 } 1939 1940 int userEditedColumnIdx = c.getColumnIndex("user_edited"); 1941 if (userEditedColumnIdx != -1) { 1942 String user_edited = c.getString(userEditedColumnIdx); 1943 if (!TextUtils.isEmpty(user_edited)) { 1944 cv.put(EDITED_STATUS, new Integer(user_edited)); 1945 } 1946 } else { 1947 cv.put(EDITED_STATUS, CARRIER_EDITED); 1948 } 1949 1950 // New EDITED column. Default value (UNEDITED) will 1951 // be used for all rows except for non-mvno entries for plmns indicated 1952 // by resource: those will be set to CARRIER_EDITED to preserve 1953 // their current values 1954 val = c.getString(c.getColumnIndex(NUMERIC)); 1955 for (String s : persistApnsForPlmns) { 1956 if (!TextUtils.isEmpty(val) && val.equals(s) && 1957 (!cv.containsKey(MVNO_TYPE) || 1958 TextUtils.isEmpty(cv.getAsString(MVNO_TYPE)))) { 1959 if (userEditedColumnIdx == -1) { 1960 cv.put(EDITED_STATUS, CARRIER_EDITED); 1961 } else { // if (oldVersion == 14) -- if db had user_edited column 1962 if (cv.getAsInteger(EDITED_STATUS) == USER_EDITED) { 1963 cv.put(EDITED_STATUS, CARRIER_EDITED); 1964 } 1965 } 1966 1967 break; 1968 } 1969 } 1970 1971 try { 1972 db.insertWithOnConflict(CARRIERS_TABLE_TMP, null, cv, 1973 SQLiteDatabase.CONFLICT_ABORT); 1974 if (VDBG) { 1975 log("dbh.copyPreservedApnsToNewTable: db.insert returned >= 0; " + 1976 "insert successful for cv " + cv); 1977 } 1978 } catch (SQLException e) { 1979 if (VDBG) 1980 log("dbh.copyPreservedApnsToNewTable insertWithOnConflict exception " + 1981 e + " for cv " + cv); 1982 // Insertion failed which could be due to a conflict. Check if that is 1983 // the case and merge the entries 1984 Cursor oldRow = selectConflictingRow(db, 1985 CARRIERS_TABLE_TMP, cv); 1986 if (oldRow != null) { 1987 ContentValues mergedValues = new ContentValues(); 1988 mergeFieldsAndUpdateDb(db, CARRIERS_TABLE_TMP, oldRow, cv, 1989 mergedValues, true, mContext); 1990 oldRow.close(); 1991 } 1992 } 1993 } 1994 } catch (Resources.NotFoundException e) { 1995 loge("array.persist_apns_for_plmn is not found"); 1996 return; 1997 } 1998 } 1999 } 2000 getStringValueFromCursor(ContentValues cv, Cursor c, String key)2001 private void getStringValueFromCursor(ContentValues cv, Cursor c, String key) { 2002 int columnIndex = c.getColumnIndex(key); 2003 if (columnIndex != -1) { 2004 String fromCursor = c.getString(columnIndex); 2005 if (fromCursor != null) { 2006 cv.put(key, fromCursor); 2007 } 2008 } 2009 } 2010 2011 /** 2012 * If NETWORK_TYPE_BITMASK does not exist (upgrade from version 23 to version 24), generate 2013 * NETWORK_TYPE_BITMASK with the use of BEARER_BITMASK. If NETWORK_TYPE_BITMASK existed 2014 * (upgrade from version 24 to forward), always map NETWORK_TYPE_BITMASK to BEARER_BITMASK. 2015 */ getNetworkTypeBitmaskFromCursor(ContentValues cv, Cursor c)2016 private void getNetworkTypeBitmaskFromCursor(ContentValues cv, Cursor c) { 2017 int columnIndex = c.getColumnIndex(NETWORK_TYPE_BITMASK); 2018 if (columnIndex != -1) { 2019 getStringValueFromCursor(cv, c, NETWORK_TYPE_BITMASK); 2020 // Map NETWORK_TYPE_BITMASK to BEARER_BITMASK if NETWORK_TYPE_BITMASK existed; 2021 String fromCursor = c.getString(columnIndex); 2022 if (!TextUtils.isEmpty(fromCursor) && fromCursor.matches("\\d+")) { 2023 int networkBitmask = Integer.valueOf(fromCursor); 2024 int bearerBitmask = convertNetworkTypeBitmaskToBearerBitmask(networkBitmask); 2025 cv.put(BEARER_BITMASK, String.valueOf(bearerBitmask)); 2026 } 2027 return; 2028 } 2029 columnIndex = c.getColumnIndex(BEARER_BITMASK); 2030 if (columnIndex != -1) { 2031 String fromCursor = c.getString(columnIndex); 2032 if (!TextUtils.isEmpty(fromCursor) && fromCursor.matches("\\d+")) { 2033 int bearerBitmask = Integer.valueOf(fromCursor); 2034 int networkBitmask = convertBearerBitmaskToNetworkTypeBitmask(bearerBitmask); 2035 cv.put(NETWORK_TYPE_BITMASK, String.valueOf(networkBitmask)); 2036 } 2037 } 2038 } 2039 getIntValueFromCursor(ContentValues cv, Cursor c, String key)2040 private void getIntValueFromCursor(ContentValues cv, Cursor c, String key) { 2041 int columnIndex = c.getColumnIndex(key); 2042 if (columnIndex != -1) { 2043 String fromCursor = c.getString(columnIndex); 2044 if (!TextUtils.isEmpty(fromCursor)) { 2045 try { 2046 cv.put(key, new Integer(fromCursor)); 2047 } catch (NumberFormatException nfe) { 2048 // do nothing 2049 } 2050 } 2051 } 2052 } 2053 getBlobValueFromCursor(ContentValues cv, Cursor c, String key)2054 private void getBlobValueFromCursor(ContentValues cv, Cursor c, String key) { 2055 int columnIndex = c.getColumnIndex(key); 2056 if (columnIndex != -1) { 2057 byte[] fromCursor = c.getBlob(columnIndex); 2058 if (fromCursor != null) { 2059 cv.put(key, fromCursor); 2060 } 2061 } 2062 } 2063 2064 /** 2065 * Gets the next row of apn values. 2066 * 2067 * @param parser the parser 2068 * @return the row or null if it's not an apn 2069 */ getRow(XmlPullParser parser)2070 private ContentValues getRow(XmlPullParser parser) { 2071 if (!"apn".equals(parser.getName())) { 2072 return null; 2073 } 2074 2075 ContentValues map = new ContentValues(); 2076 2077 String mcc = parser.getAttributeValue(null, "mcc"); 2078 String mnc = parser.getAttributeValue(null, "mnc"); 2079 String numeric = mcc + mnc; 2080 2081 map.put(NUMERIC, numeric); 2082 map.put(MCC, mcc); 2083 map.put(MNC, mnc); 2084 map.put(NAME, parser.getAttributeValue(null, "carrier")); 2085 2086 // do not add NULL to the map so that default values can be inserted in db 2087 addStringAttribute(parser, "apn", map, APN); 2088 addStringAttribute(parser, "user", map, USER); 2089 addStringAttribute(parser, "server", map, SERVER); 2090 addStringAttribute(parser, "password", map, PASSWORD); 2091 addStringAttribute(parser, "proxy", map, PROXY); 2092 addStringAttribute(parser, "port", map, PORT); 2093 addStringAttribute(parser, "mmsproxy", map, MMSPROXY); 2094 addStringAttribute(parser, "mmsport", map, MMSPORT); 2095 addStringAttribute(parser, "mmsc", map, MMSC); 2096 2097 String apnType = parser.getAttributeValue(null, "type"); 2098 if (apnType != null) { 2099 // Remove spaces before putting it in the map. 2100 apnType = apnType.replaceAll("\\s+", ""); 2101 map.put(TYPE, apnType); 2102 } 2103 2104 addStringAttribute(parser, "protocol", map, PROTOCOL); 2105 addStringAttribute(parser, "roaming_protocol", map, ROAMING_PROTOCOL); 2106 2107 addIntAttribute(parser, "authtype", map, AUTH_TYPE); 2108 addIntAttribute(parser, "bearer", map, BEARER); 2109 addIntAttribute(parser, "profile_id", map, PROFILE_ID); 2110 addIntAttribute(parser, "max_conns", map, MAX_CONNECTIONS); 2111 addIntAttribute(parser, "wait_time", map, WAIT_TIME_RETRY); 2112 addIntAttribute(parser, "max_conns_time", map, TIME_LIMIT_FOR_MAX_CONNECTIONS); 2113 addIntAttribute(parser, "mtu", map, MTU); 2114 addIntAttribute(parser, "apn_set_id", map, APN_SET_ID); 2115 addIntAttribute(parser, "carrier_id", map, CARRIER_ID); 2116 addIntAttribute(parser, "skip_464xlat", map, SKIP_464XLAT); 2117 2118 addBoolAttribute(parser, "carrier_enabled", map, CARRIER_ENABLED); 2119 addBoolAttribute(parser, "modem_cognitive", map, MODEM_PERSIST); 2120 addBoolAttribute(parser, "user_visible", map, USER_VISIBLE); 2121 addBoolAttribute(parser, "user_editable", map, USER_EDITABLE); 2122 2123 int networkTypeBitmask = 0; 2124 String networkTypeList = parser.getAttributeValue(null, "network_type_bitmask"); 2125 if (networkTypeList != null) { 2126 networkTypeBitmask = getBitmaskFromString(networkTypeList); 2127 } 2128 map.put(NETWORK_TYPE_BITMASK, networkTypeBitmask); 2129 2130 int bearerBitmask = 0; 2131 if (networkTypeList != null) { 2132 bearerBitmask = convertNetworkTypeBitmaskToBearerBitmask(networkTypeBitmask); 2133 } else { 2134 String bearerList = parser.getAttributeValue(null, "bearer_bitmask"); 2135 if (bearerList != null) { 2136 bearerBitmask = getBitmaskFromString(bearerList); 2137 } 2138 // Update the network type bitmask to keep them sync. 2139 networkTypeBitmask = convertBearerBitmaskToNetworkTypeBitmask(bearerBitmask); 2140 map.put(NETWORK_TYPE_BITMASK, networkTypeBitmask); 2141 } 2142 map.put(BEARER_BITMASK, bearerBitmask); 2143 2144 String mvno_type = parser.getAttributeValue(null, "mvno_type"); 2145 if (mvno_type != null) { 2146 String mvno_match_data = parser.getAttributeValue(null, "mvno_match_data"); 2147 if (mvno_match_data != null) { 2148 map.put(MVNO_TYPE, mvno_type); 2149 map.put(MVNO_MATCH_DATA, mvno_match_data); 2150 } 2151 } 2152 2153 return map; 2154 } 2155 addStringAttribute(XmlPullParser parser, String att, ContentValues map, String key)2156 private void addStringAttribute(XmlPullParser parser, String att, 2157 ContentValues map, String key) { 2158 String val = parser.getAttributeValue(null, att); 2159 if (val != null) { 2160 map.put(key, val); 2161 } 2162 } 2163 addIntAttribute(XmlPullParser parser, String att, ContentValues map, String key)2164 private void addIntAttribute(XmlPullParser parser, String att, 2165 ContentValues map, String key) { 2166 String val = parser.getAttributeValue(null, att); 2167 if (val != null) { 2168 map.put(key, Integer.parseInt(val)); 2169 } 2170 } 2171 addBoolAttribute(XmlPullParser parser, String att, ContentValues map, String key)2172 private void addBoolAttribute(XmlPullParser parser, String att, 2173 ContentValues map, String key) { 2174 String val = parser.getAttributeValue(null, att); 2175 if (val != null) { 2176 map.put(key, Boolean.parseBoolean(val)); 2177 } 2178 } 2179 2180 /* 2181 * Loads apns from xml file into the database 2182 * 2183 * @param db the sqlite database to write to 2184 * @param parser the xml parser 2185 * 2186 */ loadApns(SQLiteDatabase db, XmlPullParser parser)2187 private void loadApns(SQLiteDatabase db, XmlPullParser parser) { 2188 if (parser != null) { 2189 try { 2190 db.beginTransaction(); 2191 XmlUtils.nextElement(parser); 2192 while (parser.getEventType() != XmlPullParser.END_DOCUMENT) { 2193 ContentValues row = getRow(parser); 2194 if (row == null) { 2195 throw new XmlPullParserException("Expected 'apn' tag", parser, null); 2196 } 2197 insertAddingDefaults(db, row); 2198 XmlUtils.nextElement(parser); 2199 } 2200 db.setTransactionSuccessful(); 2201 } catch (XmlPullParserException e) { 2202 loge("Got XmlPullParserException while loading apns." + e); 2203 } catch (IOException e) { 2204 loge("Got IOException while loading apns." + e); 2205 } catch (SQLException e) { 2206 loge("Got SQLException while loading apns." + e); 2207 } finally { 2208 db.endTransaction(); 2209 } 2210 } 2211 } 2212 insertAddingDefaults(SQLiteDatabase db, ContentValues row)2213 private void insertAddingDefaults(SQLiteDatabase db, ContentValues row) { 2214 row = setDefaultValue(row); 2215 try { 2216 db.insertWithOnConflict(CARRIERS_TABLE, null, row, SQLiteDatabase.CONFLICT_ABORT); 2217 if (VDBG) log("dbh.insertAddingDefaults: db.insert returned >= 0; insert " + 2218 "successful for cv " + row); 2219 } catch (SQLException e) { 2220 if (VDBG) log("dbh.insertAddingDefaults: exception " + e); 2221 // Insertion failed which could be due to a conflict. Check if that is the case and 2222 // update edited field accordingly. 2223 // Search for the exact same entry and update edited field. 2224 // If it is USER_EDITED/CARRIER_EDITED change it to UNEDITED, 2225 // and if USER/CARRIER_DELETED change it to USER/CARRIER_DELETED_BUT_PRESENT_IN_XML. 2226 Cursor oldRow = selectConflictingRow(db, CARRIERS_TABLE, row); 2227 if (oldRow != null) { 2228 // Update the row 2229 ContentValues mergedValues = new ContentValues(); 2230 int edited = oldRow.getInt(oldRow.getColumnIndex(EDITED_STATUS)); 2231 int old_edited = edited; 2232 if (edited != UNEDITED) { 2233 if (edited == USER_DELETED) { 2234 // USER_DELETED_BUT_PRESENT_IN_XML indicates entry has been deleted 2235 // by user but present in apn xml file. 2236 edited = USER_DELETED_BUT_PRESENT_IN_XML; 2237 } else if (edited == CARRIER_DELETED) { 2238 // CARRIER_DELETED_BUT_PRESENT_IN_XML indicates entry has been deleted 2239 // by user but present in apn xml file. 2240 edited = CARRIER_DELETED_BUT_PRESENT_IN_XML; 2241 } 2242 mergedValues.put(EDITED_STATUS, edited); 2243 } 2244 2245 mergeFieldsAndUpdateDb(db, CARRIERS_TABLE, oldRow, row, mergedValues, false, 2246 mContext); 2247 2248 if (VDBG) log("dbh.insertAddingDefaults: old edited = " + old_edited 2249 + " new edited = " + edited); 2250 2251 oldRow.close(); 2252 } 2253 } 2254 } 2255 } 2256 mergeFieldsAndUpdateDb(SQLiteDatabase db, String table, Cursor oldRow, ContentValues newRow, ContentValues mergedValues, boolean onUpgrade, Context context)2257 public static void mergeFieldsAndUpdateDb(SQLiteDatabase db, String table, Cursor oldRow, 2258 ContentValues newRow, ContentValues mergedValues, 2259 boolean onUpgrade, Context context) { 2260 if (newRow.containsKey(TYPE)) { 2261 // Merge the types 2262 String oldType = oldRow.getString(oldRow.getColumnIndex(TYPE)); 2263 String newType = newRow.getAsString(TYPE); 2264 2265 if (!oldType.equalsIgnoreCase(newType)) { 2266 if (oldType.equals("") || newType.equals("")) { 2267 newRow.put(TYPE, ""); 2268 } else { 2269 String[] oldTypes = oldType.toLowerCase().split(","); 2270 String[] newTypes = newType.toLowerCase().split(","); 2271 2272 if (VDBG) { 2273 log("mergeFieldsAndUpdateDb: Calling separateRowsNeeded() oldType=" + 2274 oldType + " old bearer=" + oldRow.getInt(oldRow.getColumnIndex( 2275 BEARER_BITMASK)) + " old networkType=" + 2276 oldRow.getInt(oldRow.getColumnIndex(NETWORK_TYPE_BITMASK)) + 2277 " old profile_id=" + oldRow.getInt(oldRow.getColumnIndex( 2278 PROFILE_ID)) + " newRow " + newRow); 2279 } 2280 2281 // If separate rows are needed, do not need to merge any further 2282 if (separateRowsNeeded(db, table, oldRow, newRow, context, oldTypes, 2283 newTypes)) { 2284 if (VDBG) log("mergeFieldsAndUpdateDb: separateRowsNeeded() returned " + 2285 "true"); 2286 return; 2287 } 2288 2289 // Merge the 2 types 2290 ArrayList<String> mergedTypes = new ArrayList<String>(); 2291 mergedTypes.addAll(Arrays.asList(oldTypes)); 2292 for (String s : newTypes) { 2293 if (!mergedTypes.contains(s.trim())) { 2294 mergedTypes.add(s); 2295 } 2296 } 2297 StringBuilder mergedType = new StringBuilder(); 2298 for (int i = 0; i < mergedTypes.size(); i++) { 2299 mergedType.append((i == 0 ? "" : ",") + mergedTypes.get(i)); 2300 } 2301 newRow.put(TYPE, mergedType.toString()); 2302 } 2303 } 2304 mergedValues.put(TYPE, newRow.getAsString(TYPE)); 2305 } 2306 2307 if (newRow.containsKey(BEARER_BITMASK)) { 2308 int oldBearer = oldRow.getInt(oldRow.getColumnIndex(BEARER_BITMASK)); 2309 int newBearer = newRow.getAsInteger(BEARER_BITMASK); 2310 if (oldBearer != newBearer) { 2311 if (oldBearer == 0 || newBearer == 0) { 2312 newRow.put(BEARER_BITMASK, 0); 2313 } else { 2314 newRow.put(BEARER_BITMASK, (oldBearer | newBearer)); 2315 } 2316 } 2317 mergedValues.put(BEARER_BITMASK, newRow.getAsInteger(BEARER_BITMASK)); 2318 } 2319 2320 if (newRow.containsKey(NETWORK_TYPE_BITMASK)) { 2321 int oldBitmask = oldRow.getInt(oldRow.getColumnIndex(NETWORK_TYPE_BITMASK)); 2322 int newBitmask = newRow.getAsInteger(NETWORK_TYPE_BITMASK); 2323 if (oldBitmask != newBitmask) { 2324 if (oldBitmask == 0 || newBitmask == 0) { 2325 newRow.put(NETWORK_TYPE_BITMASK, 0); 2326 } else { 2327 newRow.put(NETWORK_TYPE_BITMASK, (oldBitmask | newBitmask)); 2328 } 2329 } 2330 mergedValues.put(NETWORK_TYPE_BITMASK, newRow.getAsInteger(NETWORK_TYPE_BITMASK)); 2331 } 2332 2333 if (newRow.containsKey(BEARER_BITMASK) 2334 && newRow.containsKey(NETWORK_TYPE_BITMASK)) { 2335 syncBearerBitmaskAndNetworkTypeBitmask(mergedValues); 2336 } 2337 2338 if (!onUpgrade) { 2339 // Do not overwrite a carrier or user edit with EDITED=UNEDITED 2340 if (newRow.containsKey(EDITED_STATUS)) { 2341 int oldEdited = oldRow.getInt(oldRow.getColumnIndex(EDITED_STATUS)); 2342 int newEdited = newRow.getAsInteger(EDITED_STATUS); 2343 if (newEdited == UNEDITED && (oldEdited == CARRIER_EDITED 2344 || oldEdited == CARRIER_DELETED 2345 || oldEdited == CARRIER_DELETED_BUT_PRESENT_IN_XML 2346 || oldEdited == USER_EDITED 2347 || oldEdited == USER_DELETED 2348 || oldEdited == USER_DELETED_BUT_PRESENT_IN_XML)) { 2349 newRow.remove(EDITED_STATUS); 2350 } 2351 } 2352 mergedValues.putAll(newRow); 2353 } 2354 2355 if (mergedValues.size() > 0) { 2356 db.update(table, mergedValues, "_id=" + oldRow.getInt(oldRow.getColumnIndex("_id")), 2357 null); 2358 } 2359 } 2360 separateRowsNeeded(SQLiteDatabase db, String table, Cursor oldRow, ContentValues newRow, Context context, String[] oldTypes, String[] newTypes)2361 private static boolean separateRowsNeeded(SQLiteDatabase db, String table, Cursor oldRow, 2362 ContentValues newRow, Context context, 2363 String[] oldTypes, String[] newTypes) { 2364 // If this APN falls under persist_apns_for_plmn, and the 2365 // only difference between old type and new type is that one has dun, and 2366 // the APNs have profile_id 0 or not set, then set the profile_id to 1 for 2367 // the dun APN/remove dun from type. This will ensure both oldRow and newRow exist 2368 // separately in db. 2369 2370 boolean match = false; 2371 2372 // Check if APN falls under persist_apns_for_plmn 2373 if (context.getResources() != null) { 2374 String[] persistApnsForPlmns = context.getResources().getStringArray( 2375 R.array.persist_apns_for_plmn); 2376 for (String s : persistApnsForPlmns) { 2377 if (s.equalsIgnoreCase(newRow.getAsString(NUMERIC))) { 2378 match = true; 2379 break; 2380 } 2381 } 2382 } else { 2383 loge("separateRowsNeeded: resources=null"); 2384 } 2385 2386 if (!match) return false; 2387 2388 // APN falls under persist_apns_for_plmn 2389 // Check if only difference between old type and new type is that 2390 // one has dun 2391 ArrayList<String> oldTypesAl = new ArrayList<String>(Arrays.asList(oldTypes)); 2392 ArrayList<String> newTypesAl = new ArrayList<String>(Arrays.asList(newTypes)); 2393 ArrayList<String> listWithDun = null; 2394 ArrayList<String> listWithoutDun = null; 2395 boolean dunInOld = false; 2396 if (oldTypesAl.size() == newTypesAl.size() + 1) { 2397 listWithDun = oldTypesAl; 2398 listWithoutDun = newTypesAl; 2399 dunInOld = true; 2400 } else if (oldTypesAl.size() + 1 == newTypesAl.size()) { 2401 listWithDun = newTypesAl; 2402 listWithoutDun = oldTypesAl; 2403 } else { 2404 return false; 2405 } 2406 2407 if (listWithDun.contains("dun") && !listWithoutDun.contains("dun")) { 2408 listWithoutDun.add("dun"); 2409 if (!listWithDun.containsAll(listWithoutDun)) { 2410 return false; 2411 } 2412 2413 // Only difference between old type and new type is that 2414 // one has dun 2415 // Check if profile_id is 0/not set 2416 if (oldRow.getInt(oldRow.getColumnIndex(PROFILE_ID)) == 0) { 2417 if (dunInOld) { 2418 // Update oldRow to remove dun from its type field 2419 ContentValues updateOldRow = new ContentValues(); 2420 StringBuilder sb = new StringBuilder(); 2421 boolean first = true; 2422 for (String s : listWithDun) { 2423 if (!s.equalsIgnoreCase("dun")) { 2424 sb.append(first ? s : "," + s); 2425 first = false; 2426 } 2427 } 2428 String updatedType = sb.toString(); 2429 if (VDBG) { 2430 log("separateRowsNeeded: updating type in oldRow to " + updatedType); 2431 } 2432 updateOldRow.put(TYPE, updatedType); 2433 db.update(table, updateOldRow, 2434 "_id=" + oldRow.getInt(oldRow.getColumnIndex("_id")), null); 2435 return true; 2436 } else { 2437 if (VDBG) log("separateRowsNeeded: adding profile id 1 to newRow"); 2438 // Update newRow to set profile_id to 1 2439 newRow.put(PROFILE_ID, new Integer(1)); 2440 } 2441 } else { 2442 return false; 2443 } 2444 2445 // If match was found, both oldRow and newRow need to exist 2446 // separately in db. Add newRow to db. 2447 try { 2448 db.insertWithOnConflict(table, null, newRow, SQLiteDatabase.CONFLICT_REPLACE); 2449 if (VDBG) log("separateRowsNeeded: added newRow with profile id 1 to db"); 2450 return true; 2451 } catch (SQLException e) { 2452 loge("Exception on trying to add new row after updating profile_id"); 2453 } 2454 } 2455 2456 return false; 2457 } 2458 selectConflictingRow(SQLiteDatabase db, String table, ContentValues row)2459 public static Cursor selectConflictingRow(SQLiteDatabase db, String table, 2460 ContentValues row) { 2461 // Conflict is possible only when numeric, mcc, mnc (fields without any default value) 2462 // are set in the new row 2463 if (!row.containsKey(NUMERIC) || !row.containsKey(MCC) || !row.containsKey(MNC)) { 2464 loge("dbh.selectConflictingRow: called for non-conflicting row: " + row); 2465 return null; 2466 } 2467 2468 String[] columns = { "_id", 2469 TYPE, 2470 EDITED_STATUS, 2471 BEARER_BITMASK, 2472 NETWORK_TYPE_BITMASK, 2473 PROFILE_ID }; 2474 String selection = TextUtils.join("=? AND ", CARRIERS_UNIQUE_FIELDS) + "=?"; 2475 int i = 0; 2476 String[] selectionArgs = new String[CARRIERS_UNIQUE_FIELDS.size()]; 2477 for (String field : CARRIERS_UNIQUE_FIELDS) { 2478 if (!row.containsKey(field)) { 2479 selectionArgs[i++] = CARRIERS_UNIQUE_FIELDS_DEFAULTS.get(field); 2480 } else { 2481 if (CARRIERS_BOOLEAN_FIELDS.contains(field)) { 2482 // for boolean fields we overwrite the strings "true" and "false" with "1" 2483 // and "0" 2484 selectionArgs[i++] = convertStringToIntString(row.getAsString(field)); 2485 } else { 2486 selectionArgs[i++] = row.getAsString(field); 2487 } 2488 } 2489 } 2490 2491 Cursor c = db.query(table, columns, selection, selectionArgs, null, null, null); 2492 2493 if (c != null) { 2494 if (c.getCount() == 1) { 2495 if (VDBG) log("dbh.selectConflictingRow: " + c.getCount() + " conflicting " + 2496 "row found"); 2497 if (c.moveToFirst()) { 2498 return c; 2499 } else { 2500 loge("dbh.selectConflictingRow: moveToFirst() failed"); 2501 } 2502 } else { 2503 loge("dbh.selectConflictingRow: Expected 1 but found " + c.getCount() + 2504 " matching rows found for cv " + row); 2505 } 2506 c.close(); 2507 } else { 2508 loge("dbh.selectConflictingRow: Error - c is null; no matching row found for " + 2509 "cv " + row); 2510 } 2511 2512 return null; 2513 } 2514 2515 /** 2516 * Convert "true" and "false" to "1" and "0". 2517 * If the passed in string is already "1" or "0" returns the passed in string. 2518 */ convertStringToIntString(String boolString)2519 private static String convertStringToIntString(String boolString) { 2520 if ("0".equals(boolString) || "false".equalsIgnoreCase(boolString)) return "0"; 2521 return "1"; 2522 } 2523 2524 /** 2525 * Convert "1" and "0" to "true" and "false". 2526 * If the passed in string is already "true" or "false" returns the passed in string. 2527 */ convertStringToBoolString(String intString)2528 private static String convertStringToBoolString(String intString) { 2529 if ("0".equals(intString) || "false".equalsIgnoreCase(intString)) return "false"; 2530 return "true"; 2531 } 2532 2533 /** 2534 * These methods can be overridden in a subclass for testing TelephonyProvider using an 2535 * in-memory database. 2536 */ getReadableDatabase()2537 SQLiteDatabase getReadableDatabase() { 2538 return mOpenHelper.getReadableDatabase(); 2539 } getWritableDatabase()2540 SQLiteDatabase getWritableDatabase() { 2541 return mOpenHelper.getWritableDatabase(); 2542 } initDatabaseWithDatabaseHelper(SQLiteDatabase db)2543 void initDatabaseWithDatabaseHelper(SQLiteDatabase db) { 2544 mOpenHelper.initDatabase(db); 2545 } needApnDbUpdate()2546 boolean needApnDbUpdate() { 2547 return mOpenHelper.apnDbUpdateNeeded(); 2548 } 2549 apnSourceServiceExists(Context context)2550 private static boolean apnSourceServiceExists(Context context) { 2551 if (s_apnSourceServiceExists != null) { 2552 return s_apnSourceServiceExists; 2553 } 2554 try { 2555 String service = context.getResources().getString(R.string.apn_source_service); 2556 if (TextUtils.isEmpty(service)) { 2557 s_apnSourceServiceExists = false; 2558 } else { 2559 s_apnSourceServiceExists = context.getPackageManager().getServiceInfo( 2560 ComponentName.unflattenFromString(service), 0) 2561 != null; 2562 } 2563 } catch (PackageManager.NameNotFoundException e) { 2564 s_apnSourceServiceExists = false; 2565 } 2566 return s_apnSourceServiceExists; 2567 } 2568 restoreApnsWithService(int subId)2569 private void restoreApnsWithService(int subId) { 2570 Context context = getContext(); 2571 Resources r = context.getResources(); 2572 ServiceConnection connection = new ServiceConnection() { 2573 @Override 2574 public void onServiceConnected(ComponentName className, 2575 IBinder service) { 2576 log("restoreApnsWithService: onServiceConnected"); 2577 synchronized (mLock) { 2578 mIApnSourceService = IApnSourceService.Stub.asInterface(service); 2579 mLock.notifyAll(); 2580 } 2581 } 2582 2583 @Override 2584 public void onServiceDisconnected(ComponentName arg0) { 2585 loge("mIApnSourceService has disconnected unexpectedly"); 2586 synchronized (mLock) { 2587 mIApnSourceService = null; 2588 } 2589 } 2590 }; 2591 2592 Intent intent = new Intent(IApnSourceService.class.getName()); 2593 intent.setComponent(ComponentName.unflattenFromString( 2594 r.getString(R.string.apn_source_service))); 2595 log("binding to service to restore apns, intent=" + intent); 2596 try { 2597 if (context.bindService(intent, connection, Context.BIND_IMPORTANT | 2598 Context.BIND_AUTO_CREATE)) { 2599 synchronized (mLock) { 2600 while (mIApnSourceService == null) { 2601 try { 2602 mLock.wait(); 2603 } catch (InterruptedException e) { 2604 loge("Error while waiting for service connection: " + e); 2605 } 2606 } 2607 try { 2608 ContentValues[] values = mIApnSourceService.getApns(subId); 2609 if (values != null) { 2610 // we use the unsynchronized insert because this function is called 2611 // within the syncrhonized function delete() 2612 unsynchronizedBulkInsert(CONTENT_URI, values); 2613 log("restoreApnsWithService: restored"); 2614 } 2615 } catch (RemoteException e) { 2616 loge("Error applying apns from service: " + e); 2617 } 2618 } 2619 } else { 2620 loge("unable to bind to service from intent=" + intent); 2621 } 2622 } catch (SecurityException e) { 2623 loge("Error applying apns from service: " + e); 2624 } finally { 2625 if (connection != null) { 2626 context.unbindService(connection); 2627 } 2628 synchronized (mLock) { 2629 mIApnSourceService = null; 2630 } 2631 } 2632 } 2633 2634 2635 @Override onCreate()2636 public boolean onCreate() { 2637 mOpenHelper = new DatabaseHelper(getContext()); 2638 2639 try { 2640 PhoneFactory.addLocalLog(TAG, 100); 2641 } catch (IllegalArgumentException e) { 2642 // ignore 2643 } 2644 2645 boolean isNewBuild = false; 2646 String newBuildId = SystemProperties.get("ro.build.id", null); 2647 if (!TextUtils.isEmpty(newBuildId)) { 2648 // Check if build id has changed 2649 SharedPreferences sp = getContext().getSharedPreferences(BUILD_ID_FILE, 2650 Context.MODE_PRIVATE); 2651 String oldBuildId = sp.getString(RO_BUILD_ID, ""); 2652 if (!newBuildId.equals(oldBuildId)) { 2653 localLog("onCreate: build id changed from " + oldBuildId + " to " + newBuildId); 2654 isNewBuild = true; 2655 } else { 2656 if (VDBG) log("onCreate: build id did not change: " + oldBuildId); 2657 } 2658 sp.edit().putString(RO_BUILD_ID, newBuildId).apply(); 2659 } else { 2660 if (VDBG) log("onCreate: newBuildId is empty"); 2661 } 2662 2663 if (isNewBuild) { 2664 if (!apnSourceServiceExists(getContext())) { 2665 // Update APN DB 2666 updateApnDb(); 2667 } 2668 2669 // Add all APN related shared prefs to local log for dumpsys 2670 if (DBG) addAllApnSharedPrefToLocalLog(); 2671 } 2672 2673 SharedPreferences sp = getContext().getSharedPreferences(ENFORCED_FILE, 2674 Context.MODE_PRIVATE); 2675 mManagedApnEnforced = sp.getBoolean(ENFORCED_KEY, false); 2676 2677 if (VDBG) log("onCreate:- ret true"); 2678 2679 return true; 2680 } 2681 addAllApnSharedPrefToLocalLog()2682 private void addAllApnSharedPrefToLocalLog() { 2683 localLog("addAllApnSharedPrefToLocalLog"); 2684 SharedPreferences spApn = getContext().getSharedPreferences(PREF_FILE_APN, 2685 Context.MODE_PRIVATE); 2686 2687 Map<String, ?> allPrefApnId = spApn.getAll(); 2688 for (String key : allPrefApnId.keySet()) { 2689 try { 2690 localLog(key + ":" + allPrefApnId.get(key).toString()); 2691 } catch (Exception e) { 2692 localLog("Skipping over key " + key + " due to exception " + e); 2693 } 2694 } 2695 2696 SharedPreferences spFullApn = getContext().getSharedPreferences(PREF_FILE_FULL_APN, 2697 Context.MODE_PRIVATE); 2698 2699 Map<String, ?> allPrefFullApn = spFullApn.getAll(); 2700 for (String key : allPrefFullApn.keySet()) { 2701 try { 2702 localLog(key + ":" + allPrefFullApn.get(key).toString()); 2703 } catch (Exception e) { 2704 localLog("Skipping over key " + key + " due to exception " + e); 2705 } 2706 } 2707 } 2708 localLog(String logMsg)2709 private static void localLog(String logMsg) { 2710 Log.d(TAG, logMsg); 2711 PhoneFactory.localLog(TAG, logMsg); 2712 } 2713 isManagedApnEnforced()2714 private synchronized boolean isManagedApnEnforced() { 2715 return mManagedApnEnforced; 2716 } 2717 setManagedApnEnforced(boolean enforced)2718 private void setManagedApnEnforced(boolean enforced) { 2719 SharedPreferences sp = getContext().getSharedPreferences(ENFORCED_FILE, 2720 Context.MODE_PRIVATE); 2721 SharedPreferences.Editor editor = sp.edit(); 2722 editor.putBoolean(ENFORCED_KEY, enforced); 2723 editor.apply(); 2724 synchronized (this) { 2725 mManagedApnEnforced = enforced; 2726 } 2727 } 2728 setPreferredApnId(Long id, int subId, boolean saveApn)2729 private void setPreferredApnId(Long id, int subId, boolean saveApn) { 2730 SharedPreferences sp = getContext().getSharedPreferences(PREF_FILE_APN, 2731 Context.MODE_PRIVATE); 2732 SharedPreferences.Editor editor = sp.edit(); 2733 editor.putLong(COLUMN_APN_ID + subId, id != null ? id : INVALID_APN_ID); 2734 localLog("setPreferredApnId: " + COLUMN_APN_ID + subId + ":" 2735 + (id != null ? id : INVALID_APN_ID)); 2736 // This is for debug purposes. It indicates if this APN was set by DcTracker or user (true) 2737 // or if this was restored from APN saved in PREF_FILE_FULL_APN (false). 2738 editor.putBoolean(EXPLICIT_SET_CALLED + subId, saveApn); 2739 localLog("setPreferredApnId: " + EXPLICIT_SET_CALLED + subId + ":" + saveApn); 2740 editor.apply(); 2741 if (id == null || id.longValue() == INVALID_APN_ID) { 2742 deletePreferredApn(subId); 2743 } else { 2744 // If id is not invalid, and saveApn is true, save the actual APN in PREF_FILE_FULL_APN 2745 // too. 2746 if (saveApn) { 2747 setPreferredApn(id, subId); 2748 } 2749 } 2750 } 2751 getPreferredApnId(int subId, boolean checkApnSp)2752 private long getPreferredApnId(int subId, boolean checkApnSp) { 2753 SharedPreferences sp = getContext().getSharedPreferences(PREF_FILE_APN, 2754 Context.MODE_PRIVATE); 2755 long apnId = sp.getLong(COLUMN_APN_ID + subId, INVALID_APN_ID); 2756 if (apnId == INVALID_APN_ID && checkApnSp) { 2757 apnId = getPreferredApnIdFromApn(subId); 2758 if (apnId != INVALID_APN_ID) { 2759 setPreferredApnId(apnId, subId, false); 2760 } 2761 } 2762 return apnId; 2763 } 2764 getPreferredApnSetId(int subId)2765 private int getPreferredApnSetId(int subId) { 2766 SharedPreferences sp = getContext().getSharedPreferences(PREF_FILE_FULL_APN, 2767 Context.MODE_PRIVATE); 2768 try { 2769 return Integer.parseInt(sp.getString(APN_SET_ID + subId, null)); 2770 } catch (NumberFormatException e) { 2771 return NO_APN_SET_ID; 2772 } 2773 } 2774 deletePreferredApnId(Context context)2775 private void deletePreferredApnId(Context context) { 2776 SharedPreferences sp = context.getSharedPreferences(PREF_FILE_APN, 2777 Context.MODE_PRIVATE); 2778 SharedPreferences.Editor editor = sp.edit(); 2779 editor.clear(); 2780 editor.apply(); 2781 } 2782 setPreferredApn(Long id, int subId)2783 private void setPreferredApn(Long id, int subId) { 2784 localLog("setPreferredApn: _id " + id + " subId " + subId); 2785 SQLiteDatabase db = getWritableDatabase(); 2786 // query all unique fields from id 2787 String[] proj = CARRIERS_UNIQUE_FIELDS.toArray(new String[CARRIERS_UNIQUE_FIELDS.size()]); 2788 2789 Cursor c = db.query(CARRIERS_TABLE, proj, "_id=" + id, null, null, null, null); 2790 if (c != null) { 2791 if (c.getCount() == 1) { 2792 c.moveToFirst(); 2793 SharedPreferences sp = getContext().getSharedPreferences(PREF_FILE_FULL_APN, 2794 Context.MODE_PRIVATE); 2795 SharedPreferences.Editor editor = sp.edit(); 2796 // store values of all unique fields to SP 2797 for (String key : CARRIERS_UNIQUE_FIELDS) { 2798 editor.putString(key + subId, c.getString(c.getColumnIndex(key))); 2799 localLog("setPreferredApn: " + key + subId + ":" 2800 + c.getString(c.getColumnIndex(key))); 2801 } 2802 // also store the version number 2803 editor.putString(DB_VERSION_KEY + subId, "" + DATABASE_VERSION); 2804 localLog("setPreferredApn: " + DB_VERSION_KEY + subId + ":" + DATABASE_VERSION); 2805 editor.apply(); 2806 } else { 2807 log("setPreferredApn: # matching APNs found " + c.getCount()); 2808 } 2809 c.close(); 2810 } else { 2811 log("setPreferredApn: No matching APN found"); 2812 } 2813 } 2814 getPreferredApnIdFromApn(int subId)2815 private long getPreferredApnIdFromApn(int subId) { 2816 log("getPreferredApnIdFromApn: for subId " + subId); 2817 SQLiteDatabase db = getReadableDatabase(); 2818 2819 List<String> whereList = new ArrayList<>(); 2820 List<String> whereArgsList = new ArrayList<>(); 2821 SharedPreferences sp = getContext().getSharedPreferences(PREF_FILE_FULL_APN, 2822 Context.MODE_PRIVATE); 2823 for (String key : CARRIERS_UNIQUE_FIELDS) { 2824 String value = sp.getString(key + subId, null); 2825 if (value == null) { 2826 continue; 2827 } else { 2828 whereList.add(key); 2829 whereArgsList.add(value); 2830 } 2831 } 2832 if (whereList.size() == 0) return INVALID_APN_ID; 2833 2834 String where = TextUtils.join("=? and ", whereList) + "=?"; 2835 String[] whereArgs = new String[whereArgsList.size()]; 2836 whereArgs = whereArgsList.toArray(whereArgs); 2837 2838 long apnId = INVALID_APN_ID; 2839 Cursor c = db.query(CARRIERS_TABLE, new String[]{"_id"}, where, whereArgs, null, null, 2840 null); 2841 if (c != null) { 2842 if (c.getCount() == 1) { 2843 c.moveToFirst(); 2844 apnId = c.getInt(c.getColumnIndex("_id")); 2845 } else { 2846 log("getPreferredApnIdFromApn: returning INVALID. # matching APNs found " + 2847 c.getCount()); 2848 } 2849 c.close(); 2850 } else { 2851 log("getPreferredApnIdFromApn: returning INVALID. No matching APN found"); 2852 } 2853 return apnId; 2854 } 2855 deletePreferredApn(int subId)2856 private void deletePreferredApn(int subId) { 2857 log("deletePreferredApn: for subId " + subId); 2858 SharedPreferences sp = getContext().getSharedPreferences(PREF_FILE_FULL_APN, 2859 Context.MODE_PRIVATE); 2860 if (sp.contains(DB_VERSION_KEY + subId)) { 2861 log("deletePreferredApn: apn is stored. Deleting it now for subId " + subId); 2862 SharedPreferences.Editor editor = sp.edit(); 2863 editor.remove(DB_VERSION_KEY + subId); 2864 for (String key : CARRIERS_UNIQUE_FIELDS) { 2865 editor.remove(key + subId); 2866 } 2867 editor.apply(); 2868 } 2869 } 2870 isCallingFromSystemOrPhoneUid()2871 boolean isCallingFromSystemOrPhoneUid() { 2872 return mInjector.binderGetCallingUid() == Process.SYSTEM_UID || 2873 mInjector.binderGetCallingUid() == Process.PHONE_UID; 2874 } 2875 ensureCallingFromSystemOrPhoneUid(String message)2876 void ensureCallingFromSystemOrPhoneUid(String message) { 2877 if (!isCallingFromSystemOrPhoneUid()) { 2878 throw new SecurityException(message); 2879 } 2880 } 2881 2882 @Override query(Uri url, String[] projectionIn, String selection, String[] selectionArgs, String sort)2883 public synchronized Cursor query(Uri url, String[] projectionIn, String selection, 2884 String[] selectionArgs, String sort) { 2885 if (VDBG) log("query: url=" + url + ", projectionIn=" + projectionIn + ", selection=" 2886 + selection + "selectionArgs=" + selectionArgs + ", sort=" + sort); 2887 int subId = SubscriptionManager.getDefaultSubscriptionId(); 2888 String subIdString; 2889 SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 2890 qb.setStrict(true); // a little protection from injection attacks 2891 qb.setTables(CARRIERS_TABLE); 2892 2893 List<String> constraints = new ArrayList<String>(); 2894 2895 int match = s_urlMatcher.match(url); 2896 checkPermission(); 2897 switch (match) { 2898 case URL_TELEPHONY_USING_SUBID: { 2899 subIdString = url.getLastPathSegment(); 2900 try { 2901 subId = Integer.parseInt(subIdString); 2902 } catch (NumberFormatException e) { 2903 loge("NumberFormatException" + e); 2904 return null; 2905 } 2906 if (DBG) log("subIdString = " + subIdString + " subId = " + subId); 2907 TelephonyManager telephonyManager = getContext() 2908 .getSystemService(TelephonyManager.class).createForSubscriptionId(subId); 2909 constraints.add(NUMERIC + " = '" + telephonyManager.getSimOperator() + "'"); 2910 // TODO b/74213956 turn this back on once insertion includes correct sub id 2911 // constraints.add(SUBSCRIPTION_ID + "=" + subIdString); 2912 } 2913 // intentional fall through from above case 2914 case URL_TELEPHONY: { 2915 constraints.add(IS_NOT_OWNED_BY_DPC); 2916 break; 2917 } 2918 2919 case URL_CURRENT_USING_SUBID: { 2920 subIdString = url.getLastPathSegment(); 2921 try { 2922 subId = Integer.parseInt(subIdString); 2923 } catch (NumberFormatException e) { 2924 loge("NumberFormatException" + e); 2925 return null; 2926 } 2927 if (DBG) log("subIdString = " + subIdString + " subId = " + subId); 2928 // TODO b/74213956 turn this back on once insertion includes correct sub id 2929 // constraints.add(SUBSCRIPTION_ID + "=" + subIdString); 2930 } 2931 //intentional fall through from above case 2932 case URL_CURRENT: { 2933 constraints.add("current IS NOT NULL"); 2934 constraints.add(IS_NOT_OWNED_BY_DPC); 2935 // do not ignore the selection since MMS may use it. 2936 //selection = null; 2937 break; 2938 } 2939 2940 case URL_ID: { 2941 constraints.add("_id = " + url.getPathSegments().get(1)); 2942 constraints.add(IS_NOT_OWNED_BY_DPC); 2943 break; 2944 } 2945 2946 case URL_PREFERAPN_USING_SUBID: 2947 case URL_PREFERAPN_NO_UPDATE_USING_SUBID: { 2948 subIdString = url.getLastPathSegment(); 2949 try { 2950 subId = Integer.parseInt(subIdString); 2951 } catch (NumberFormatException e) { 2952 loge("NumberFormatException" + e); 2953 return null; 2954 } 2955 if (DBG) log("subIdString = " + subIdString + " subId = " + subId); 2956 // TODO b/74213956 turn this back on once insertion includes correct sub id 2957 // constraints.add(SUBSCRIPTION_ID + "=" + subIdString); 2958 } 2959 //intentional fall through from above case 2960 case URL_PREFERAPN: 2961 case URL_PREFERAPN_NO_UPDATE: { 2962 constraints.add("_id = " + getPreferredApnId(subId, true)); 2963 break; 2964 } 2965 2966 case URL_PREFERAPNSET_USING_SUBID: { 2967 subIdString = url.getLastPathSegment(); 2968 try { 2969 subId = Integer.parseInt(subIdString); 2970 } catch (NumberFormatException e) { 2971 loge("NumberFormatException" + e); 2972 return null; 2973 } 2974 if (DBG) log("subIdString = " + subIdString + " subId = " + subId); 2975 // TODO b/74213956 turn this back on once insertion includes correct sub id 2976 // constraints.add(SUBSCRIPTION_ID + "=" + subIdString); 2977 } 2978 // intentional fall through from above case 2979 case URL_PREFERAPNSET: { 2980 final int set = getPreferredApnSetId(subId); 2981 if (set == NO_APN_SET_ID) { 2982 return null; 2983 } 2984 constraints.add(APN_SET_ID + "=" + set); 2985 qb.appendWhere(TextUtils.join(" AND ", constraints)); 2986 return getSubscriptionMatchingAPNList(qb, projectionIn, selection, selectionArgs, 2987 sort, subId); 2988 } 2989 2990 case URL_DPC: { 2991 ensureCallingFromSystemOrPhoneUid("URL_DPC called from non SYSTEM_UID."); 2992 // DPC query only returns DPC records. 2993 constraints.add(IS_OWNED_BY_DPC); 2994 break; 2995 } 2996 2997 case URL_FILTERED_ID: 2998 case URL_FILTERED_USING_SUBID: { 2999 String idString = url.getLastPathSegment(); 3000 if (match == URL_FILTERED_ID) { 3001 constraints.add("_id = " + idString); 3002 } else { 3003 try { 3004 subId = Integer.parseInt(idString); 3005 // TODO b/74213956 turn this back on once insertion includes correct sub id 3006 // constraints.add(SUBSCRIPTION_ID + "=" + subIdString); 3007 } catch (NumberFormatException e) { 3008 loge("NumberFormatException" + e); 3009 return null; 3010 } 3011 } 3012 } 3013 //intentional fall through from above case 3014 case URL_FILTERED: { 3015 if (isManagedApnEnforced()) { 3016 // If enforced, return DPC records only. 3017 constraints.add(IS_OWNED_BY_DPC); 3018 } else { 3019 // Otherwise return non-DPC records only. 3020 constraints.add(IS_NOT_OWNED_BY_DPC); 3021 } 3022 break; 3023 } 3024 3025 case URL_ENFORCE_MANAGED: { 3026 ensureCallingFromSystemOrPhoneUid( 3027 "URL_ENFORCE_MANAGED called from non SYSTEM_UID."); 3028 MatrixCursor cursor = new MatrixCursor(new String[]{ENFORCED_KEY}); 3029 cursor.addRow(new Object[]{isManagedApnEnforced() ? 1 : 0}); 3030 return cursor; 3031 } 3032 3033 case URL_SIMINFO: { 3034 qb.setTables(SIMINFO_TABLE); 3035 break; 3036 } 3037 case URL_SIM_APN_LIST_ID: { 3038 subIdString = url.getLastPathSegment(); 3039 try { 3040 subId = Integer.parseInt(subIdString); 3041 } catch (NumberFormatException e) { 3042 loge("NumberFormatException" + e); 3043 return null; 3044 } 3045 } 3046 //intentional fall through from above case 3047 case URL_SIM_APN_LIST: { 3048 qb.appendWhere(IS_NOT_OWNED_BY_DPC); 3049 return getSubscriptionMatchingAPNList(qb, projectionIn, selection, selectionArgs, 3050 sort, subId); 3051 } 3052 3053 case URL_SIM_APN_LIST_FILTERED_ID: { 3054 subIdString = url.getLastPathSegment(); 3055 try { 3056 subId = Integer.parseInt(subIdString); 3057 } catch (NumberFormatException e) { 3058 loge("NumberFormatException" + e); 3059 return null; 3060 } 3061 } 3062 //intentional fall through from above case 3063 case URL_SIM_APN_LIST_FILTERED: { 3064 if (isManagedApnEnforced()) { 3065 // If enforced, return DPC records only. 3066 qb.appendWhereStandalone(IS_OWNED_BY_DPC); 3067 } else { 3068 // Otherwise return non-DPC records only. 3069 qb.appendWhereStandalone(IS_NOT_OWNED_BY_DPC); 3070 } 3071 return getSubscriptionMatchingAPNList(qb, projectionIn, selection, selectionArgs, 3072 sort, subId); 3073 } 3074 3075 default: { 3076 return null; 3077 } 3078 } 3079 3080 // appendWhere doesn't add ANDs so we do it ourselves 3081 if (constraints.size() > 0) { 3082 qb.appendWhere(TextUtils.join(" AND ", constraints)); 3083 } 3084 3085 SQLiteDatabase db = getReadableDatabase(); 3086 Cursor ret = null; 3087 try { 3088 // Exclude entries marked deleted 3089 if (CARRIERS_TABLE.equals(qb.getTables())) { 3090 if (TextUtils.isEmpty(selection)) { 3091 selection = ""; 3092 } else { 3093 selection += " and "; 3094 } 3095 selection += IS_NOT_USER_DELETED + " and " + 3096 IS_NOT_USER_DELETED_BUT_PRESENT_IN_XML + " and " + 3097 IS_NOT_CARRIER_DELETED + " and " + 3098 IS_NOT_CARRIER_DELETED_BUT_PRESENT_IN_XML; 3099 if (VDBG) log("query: selection modified to " + selection); 3100 } 3101 ret = qb.query(db, projectionIn, selection, selectionArgs, null, null, sort); 3102 } catch (SQLException e) { 3103 loge("got exception when querying: " + e); 3104 } 3105 if (ret != null) 3106 ret.setNotificationUri(getContext().getContentResolver(), url); 3107 return ret; 3108 } 3109 3110 /** 3111 * To find the current sim APN. Query APN based on {MCC, MNC, MVNO} and {Carrier_ID}. 3112 * 3113 * There has three steps: 3114 * 1. Query the APN based on { MCC, MNC, MVNO } and if has results jump to step 3, else jump to 3115 * step 2. 3116 * 2. Fallback to query the parent APN that query based on { MCC, MNC }. 3117 * 3. Append the result with the APN that query based on { Carrier_ID } 3118 */ getSubscriptionMatchingAPNList(SQLiteQueryBuilder qb, String[] projectionIn, String selection, String[] selectionArgs, String sort, int subId)3119 private Cursor getSubscriptionMatchingAPNList(SQLiteQueryBuilder qb, String[] projectionIn, 3120 String selection, String[] selectionArgs, String sort, int subId) { 3121 Cursor ret; 3122 Context context = getContext(); 3123 SubscriptionManager subscriptionManager = (SubscriptionManager) context 3124 .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); 3125 if (!subscriptionManager.isActiveSubscriptionId(subId)) { 3126 return null; 3127 } 3128 3129 final TelephonyManager tm = ((TelephonyManager) context 3130 .getSystemService(Context.TELEPHONY_SERVICE)) 3131 .createForSubscriptionId(subId); 3132 SQLiteDatabase db = getReadableDatabase(); 3133 String mccmnc = tm.getSimOperator(); 3134 int carrierId = tm.getSimCarrierId(); 3135 3136 qb.appendWhereStandalone(IS_NOT_USER_DELETED + " and " + 3137 IS_NOT_USER_DELETED_BUT_PRESENT_IN_XML + " and " + 3138 IS_NOT_CARRIER_DELETED + " and " + 3139 IS_NOT_CARRIER_DELETED_BUT_PRESENT_IN_XML); 3140 3141 // For query db one time, append all conditions in one selection and separate results after 3142 // the query is completed. IMSI has special match rule, so just query the MCC / MNC and 3143 // filter the MVNO by ourselves 3144 qb.appendWhereStandalone(NUMERIC + " = '" + mccmnc + "' OR " + 3145 CARRIER_ID + " = '" + carrierId + "'"); 3146 3147 ret = qb.query(db, null, selection, selectionArgs, null, null, sort); 3148 if (ret == null) { 3149 loge("query current APN but cursor is null."); 3150 return null; 3151 } 3152 3153 if (DBG) log("match current APN size: " + ret.getCount()); 3154 3155 String[] columnNames = projectionIn != null ? projectionIn : ret.getColumnNames(); 3156 MatrixCursor currentCursor = new MatrixCursor(columnNames); 3157 MatrixCursor parentCursor = new MatrixCursor(columnNames); 3158 MatrixCursor carrierIdCursor = new MatrixCursor(columnNames); 3159 3160 int numericIndex = ret.getColumnIndex(NUMERIC); 3161 int mvnoIndex = ret.getColumnIndex(MVNO_TYPE); 3162 int mvnoDataIndex = ret.getColumnIndex(MVNO_MATCH_DATA); 3163 int carrierIdIndex = ret.getColumnIndex(CARRIER_ID); 3164 3165 // Separate the result into MatrixCursor 3166 while (ret.moveToNext()) { 3167 List<String> data = new ArrayList<>(); 3168 for (String column : columnNames) { 3169 data.add(ret.getString(ret.getColumnIndex(column))); 3170 } 3171 3172 boolean isMVNOAPN = !TextUtils.isEmpty(ret.getString(numericIndex)) 3173 && tm.isCurrentSimOperator(ret.getString(numericIndex), 3174 getMvnoTypeIntFromString(ret.getString(mvnoIndex)), 3175 ret.getString(mvnoDataIndex)); 3176 boolean isMNOAPN = !TextUtils.isEmpty(ret.getString(numericIndex)) 3177 && ret.getString(numericIndex).equals(mccmnc) 3178 && TextUtils.isEmpty(ret.getString(mvnoIndex)); 3179 boolean isCarrierIdAPN = !TextUtils.isEmpty(ret.getString(carrierIdIndex)) 3180 && ret.getString(carrierIdIndex).equals(String.valueOf(carrierId)) 3181 && carrierId != TelephonyManager.UNKNOWN_CARRIER_ID; 3182 3183 if (isMVNOAPN) { 3184 // 1. The APN that query based on legacy SIM MCC/MCC and MVNO 3185 currentCursor.addRow(data); 3186 } else if (isMNOAPN) { 3187 // 2. The APN that query based on SIM MCC/MNC 3188 parentCursor.addRow(data); 3189 } else if (isCarrierIdAPN) { 3190 // The APN that query based on carrier Id (not include the MVNO or MNO APN) 3191 carrierIdCursor.addRow(data); 3192 } 3193 } 3194 ret.close(); 3195 3196 MatrixCursor result; 3197 if (currentCursor.getCount() > 0) { 3198 if (DBG) log("match MVNO APN: " + currentCursor.getCount()); 3199 result = currentCursor; 3200 } else if (parentCursor.getCount() > 0) { 3201 if (DBG) log("match MNO APN: " + parentCursor.getCount()); 3202 result = parentCursor; 3203 } else { 3204 if (DBG) log("can't find the MVNO and MNO APN"); 3205 result = new MatrixCursor(columnNames); 3206 } 3207 3208 if (DBG) log("match carrier id APN: " + carrierIdCursor.getCount()); 3209 appendCursorData(result, carrierIdCursor); 3210 return result; 3211 } 3212 appendCursorData(@onNull MatrixCursor from, @NonNull MatrixCursor to)3213 private static void appendCursorData(@NonNull MatrixCursor from, @NonNull MatrixCursor to) { 3214 while (to.moveToNext()) { 3215 List<Object> data = new ArrayList<>(); 3216 for (String column : to.getColumnNames()) { 3217 int index = to.getColumnIndex(column); 3218 switch (to.getType(index)) { 3219 case Cursor.FIELD_TYPE_INTEGER: 3220 data.add(to.getInt(index)); 3221 break; 3222 case Cursor.FIELD_TYPE_FLOAT: 3223 data.add(to.getFloat(index)); 3224 break; 3225 case Cursor.FIELD_TYPE_BLOB: 3226 data.add(to.getBlob(index)); 3227 break; 3228 case Cursor.FIELD_TYPE_STRING: 3229 case Cursor.FIELD_TYPE_NULL: 3230 data.add(to.getString(index)); 3231 break; 3232 } 3233 } 3234 from.addRow(data); 3235 } 3236 } 3237 3238 @Override getType(Uri url)3239 public String getType(Uri url) 3240 { 3241 switch (s_urlMatcher.match(url)) { 3242 case URL_TELEPHONY: 3243 case URL_TELEPHONY_USING_SUBID: 3244 return "vnd.android.cursor.dir/telephony-carrier"; 3245 3246 case URL_ID: 3247 case URL_FILTERED_ID: 3248 case URL_FILTERED_USING_SUBID: 3249 return "vnd.android.cursor.item/telephony-carrier"; 3250 3251 case URL_PREFERAPN_USING_SUBID: 3252 case URL_PREFERAPN_NO_UPDATE_USING_SUBID: 3253 case URL_PREFERAPN: 3254 case URL_PREFERAPN_NO_UPDATE: 3255 case URL_PREFERAPNSET: 3256 case URL_PREFERAPNSET_USING_SUBID: 3257 return "vnd.android.cursor.item/telephony-carrier"; 3258 3259 default: 3260 throw new IllegalArgumentException("Unknown URL " + url); 3261 } 3262 } 3263 3264 /** 3265 * Insert an array of ContentValues and call notifyChange at the end. 3266 */ 3267 @Override bulkInsert(Uri url, ContentValues[] values)3268 public synchronized int bulkInsert(Uri url, ContentValues[] values) { 3269 return unsynchronizedBulkInsert(url, values); 3270 } 3271 3272 /** 3273 * Do a bulk insert while inside a synchronized function. This is typically not safe and should 3274 * only be done when you are sure there will be no conflict. 3275 */ unsynchronizedBulkInsert(Uri url, ContentValues[] values)3276 private int unsynchronizedBulkInsert(Uri url, ContentValues[] values) { 3277 int count = 0; 3278 boolean notify = false; 3279 for (ContentValues value : values) { 3280 Pair<Uri, Boolean> rowAndNotify = insertSingleRow(url, value); 3281 if (rowAndNotify.first != null) { 3282 count++; 3283 } 3284 if (rowAndNotify.second == true) { 3285 notify = true; 3286 } 3287 } 3288 if (notify) { 3289 getContext().getContentResolver().notifyChange(CONTENT_URI, null, 3290 true, UserHandle.USER_ALL); 3291 } 3292 return count; 3293 } 3294 3295 @Override insert(Uri url, ContentValues initialValues)3296 public synchronized Uri insert(Uri url, ContentValues initialValues) { 3297 Pair<Uri, Boolean> rowAndNotify = insertSingleRow(url, initialValues); 3298 if (rowAndNotify.second) { 3299 getContext().getContentResolver().notifyChange(CONTENT_URI, null, 3300 true, UserHandle.USER_ALL); 3301 } 3302 return rowAndNotify.first; 3303 } 3304 3305 /** 3306 * Internal insert function to prevent code duplication for URL_TELEPHONY and URL_DPC. 3307 * 3308 * @param values the value that caller wants to insert 3309 * @return a pair in which the first element refers to the Uri for the row inserted, the second 3310 * element refers to whether sends out nofitication. 3311 */ insertRowWithValue(ContentValues values)3312 private Pair<Uri, Boolean> insertRowWithValue(ContentValues values) { 3313 Uri result = null; 3314 boolean notify = false; 3315 SQLiteDatabase db = getWritableDatabase(); 3316 3317 try { 3318 // Abort on conflict of unique fields and attempt merge 3319 long rowID = db.insertWithOnConflict(CARRIERS_TABLE, null, values, 3320 SQLiteDatabase.CONFLICT_ABORT); 3321 if (rowID >= 0) { 3322 result = ContentUris.withAppendedId(CONTENT_URI, rowID); 3323 notify = true; 3324 } 3325 if (VDBG) log("insert: inserted " + values.toString() + " rowID = " + rowID); 3326 } catch (SQLException e) { 3327 log("insert: exception " + e); 3328 // Insertion failed which could be due to a conflict. Check if that is the case 3329 // and merge the entries 3330 Cursor oldRow = selectConflictingRow(db, CARRIERS_TABLE, values); 3331 if (oldRow != null) { 3332 ContentValues mergedValues = new ContentValues(); 3333 mergeFieldsAndUpdateDb(db, CARRIERS_TABLE, oldRow, values, 3334 mergedValues, false, getContext()); 3335 oldRow.close(); 3336 notify = true; 3337 } 3338 } 3339 return Pair.create(result, notify); 3340 } 3341 insertSingleRow(Uri url, ContentValues initialValues)3342 private Pair<Uri, Boolean> insertSingleRow(Uri url, ContentValues initialValues) { 3343 Uri result = null; 3344 int subId = SubscriptionManager.getDefaultSubscriptionId(); 3345 3346 checkPermission(); 3347 syncBearerBitmaskAndNetworkTypeBitmask(initialValues); 3348 3349 boolean notify = false; 3350 SQLiteDatabase db = getWritableDatabase(); 3351 int match = s_urlMatcher.match(url); 3352 switch (match) 3353 { 3354 case URL_TELEPHONY_USING_SUBID: 3355 { 3356 String subIdString = url.getLastPathSegment(); 3357 try { 3358 subId = Integer.parseInt(subIdString); 3359 } catch (NumberFormatException e) { 3360 loge("NumberFormatException" + e); 3361 return Pair.create(result, notify); 3362 } 3363 if (DBG) log("subIdString = " + subIdString + " subId = " + subId); 3364 } 3365 //intentional fall through from above case 3366 3367 case URL_TELEPHONY: 3368 { 3369 ContentValues values; 3370 if (initialValues != null) { 3371 values = new ContentValues(initialValues); 3372 } else { 3373 values = new ContentValues(); 3374 } 3375 3376 values = setDefaultValue(values); 3377 if (!values.containsKey(EDITED_STATUS)) { 3378 values.put(EDITED_STATUS, CARRIER_EDITED); 3379 } 3380 // Owned_by should be others if inserted via general uri. 3381 values.put(OWNED_BY, OWNED_BY_OTHERS); 3382 3383 Pair<Uri, Boolean> ret = insertRowWithValue(values); 3384 result = ret.first; 3385 notify = ret.second; 3386 break; 3387 } 3388 3389 case URL_CURRENT_USING_SUBID: 3390 { 3391 String subIdString = url.getLastPathSegment(); 3392 try { 3393 subId = Integer.parseInt(subIdString); 3394 } catch (NumberFormatException e) { 3395 loge("NumberFormatException" + e); 3396 return Pair.create(result, notify); 3397 } 3398 if (DBG) log("subIdString = " + subIdString + " subId = " + subId); 3399 // FIXME use subId in the query 3400 } 3401 //intentional fall through from above case 3402 3403 case URL_CURRENT: 3404 { 3405 // zero out the previous operator 3406 db.update(CARRIERS_TABLE, s_currentNullMap, CURRENT + "!=0", null); 3407 3408 String numeric = initialValues.getAsString(NUMERIC); 3409 int updated = db.update(CARRIERS_TABLE, s_currentSetMap, 3410 NUMERIC + " = '" + numeric + "'", null); 3411 3412 if (updated > 0) 3413 { 3414 if (VDBG) log("Setting numeric '" + numeric + "' to be the current operator"); 3415 } 3416 else 3417 { 3418 loge("Failed setting numeric '" + numeric + "' to the current operator"); 3419 } 3420 break; 3421 } 3422 3423 case URL_PREFERAPN_USING_SUBID: 3424 case URL_PREFERAPN_NO_UPDATE_USING_SUBID: 3425 { 3426 String subIdString = url.getLastPathSegment(); 3427 try { 3428 subId = Integer.parseInt(subIdString); 3429 } catch (NumberFormatException e) { 3430 loge("NumberFormatException" + e); 3431 return Pair.create(result, notify); 3432 } 3433 if (DBG) log("subIdString = " + subIdString + " subId = " + subId); 3434 } 3435 //intentional fall through from above case 3436 3437 case URL_PREFERAPN: 3438 case URL_PREFERAPN_NO_UPDATE: 3439 { 3440 if (initialValues != null) { 3441 if(initialValues.containsKey(COLUMN_APN_ID)) { 3442 setPreferredApnId(initialValues.getAsLong(COLUMN_APN_ID), subId, true); 3443 } 3444 } 3445 break; 3446 } 3447 3448 case URL_DPC: { 3449 ensureCallingFromSystemOrPhoneUid("URL_DPC called from non SYSTEM_UID."); 3450 3451 ContentValues values; 3452 if (initialValues != null) { 3453 values = new ContentValues(initialValues); 3454 } else { 3455 values = new ContentValues(); 3456 } 3457 3458 // Owned_by should be DPC if inserted via URL_DPC. 3459 values.put(OWNED_BY, OWNED_BY_DPC); 3460 // DPC records should not be user editable. 3461 values.put(USER_EDITABLE, false); 3462 3463 final long rowID = db.insertWithOnConflict(CARRIERS_TABLE, null, values, 3464 SQLiteDatabase.CONFLICT_IGNORE); 3465 if (rowID >= 0) { 3466 result = ContentUris.withAppendedId(CONTENT_URI, rowID); 3467 notify = true; 3468 } 3469 if (VDBG) log("insert: inserted " + values.toString() + " rowID = " + rowID); 3470 3471 break; 3472 } 3473 3474 case URL_SIMINFO: { 3475 long id = db.insert(SIMINFO_TABLE, null, initialValues); 3476 result = ContentUris.withAppendedId(Telephony.SimInfo.CONTENT_URI, id); 3477 break; 3478 } 3479 } 3480 3481 return Pair.create(result, notify); 3482 } 3483 3484 @Override delete(Uri url, String where, String[] whereArgs)3485 public synchronized int delete(Uri url, String where, String[] whereArgs) { 3486 int count = 0; 3487 int subId = SubscriptionManager.getDefaultSubscriptionId(); 3488 String userOrCarrierEdited = ") and (" + 3489 IS_USER_EDITED + " or " + 3490 IS_CARRIER_EDITED + ")"; 3491 String notUserOrCarrierEdited = ") and (" + 3492 IS_NOT_USER_EDITED + " and " + 3493 IS_NOT_CARRIER_EDITED + ")"; 3494 String unedited = ") and " + IS_UNEDITED; 3495 ContentValues cv = new ContentValues(); 3496 cv.put(EDITED_STATUS, USER_DELETED); 3497 3498 checkPermission(); 3499 3500 SQLiteDatabase db = getWritableDatabase(); 3501 int match = s_urlMatcher.match(url); 3502 switch (match) 3503 { 3504 case URL_DELETE: 3505 { 3506 // Delete preferred APN for all subIds 3507 deletePreferredApnId(getContext()); 3508 // Delete unedited entries 3509 count = db.delete(CARRIERS_TABLE, "(" + where + unedited + " and " + 3510 IS_NOT_OWNED_BY_DPC, whereArgs); 3511 break; 3512 } 3513 3514 case URL_TELEPHONY_USING_SUBID: 3515 { 3516 String subIdString = url.getLastPathSegment(); 3517 try { 3518 subId = Integer.parseInt(subIdString); 3519 } catch (NumberFormatException e) { 3520 loge("NumberFormatException" + e); 3521 throw new IllegalArgumentException("Invalid subId " + url); 3522 } 3523 if (DBG) log("subIdString = " + subIdString + " subId = " + subId); 3524 // FIXME use subId in query 3525 } 3526 //intentional fall through from above case 3527 3528 case URL_TELEPHONY: 3529 { 3530 // Delete user/carrier edited entries 3531 count = db.delete(CARRIERS_TABLE, "(" + where + userOrCarrierEdited 3532 + " and " + IS_NOT_OWNED_BY_DPC, whereArgs); 3533 // Otherwise mark as user deleted instead of deleting 3534 count += db.update(CARRIERS_TABLE, cv, "(" + where + 3535 notUserOrCarrierEdited + " and " + IS_NOT_OWNED_BY_DPC, whereArgs); 3536 break; 3537 } 3538 3539 case URL_CURRENT_USING_SUBID: { 3540 String subIdString = url.getLastPathSegment(); 3541 try { 3542 subId = Integer.parseInt(subIdString); 3543 } catch (NumberFormatException e) { 3544 loge("NumberFormatException" + e); 3545 throw new IllegalArgumentException("Invalid subId " + url); 3546 } 3547 if (DBG) log("subIdString = " + subIdString + " subId = " + subId); 3548 // FIXME use subId in query 3549 } 3550 //intentional fall through from above case 3551 3552 case URL_CURRENT: 3553 { 3554 // Delete user/carrier edited entries 3555 count = db.delete(CARRIERS_TABLE, "(" + where + userOrCarrierEdited 3556 + " and " + IS_NOT_OWNED_BY_DPC, whereArgs); 3557 // Otherwise mark as user deleted instead of deleting 3558 count += db.update(CARRIERS_TABLE, cv, "(" + where + 3559 notUserOrCarrierEdited + " and " + IS_NOT_OWNED_BY_DPC, whereArgs); 3560 break; 3561 } 3562 3563 case URL_ID: 3564 { 3565 // Delete user/carrier edited entries 3566 count = db.delete(CARRIERS_TABLE, 3567 "(" + _ID + "=?" + userOrCarrierEdited + 3568 " and " + IS_NOT_OWNED_BY_DPC, 3569 new String[] { url.getLastPathSegment() }); 3570 // Otherwise mark as user deleted instead of deleting 3571 count += db.update(CARRIERS_TABLE, cv, 3572 "(" + _ID + "=?" + notUserOrCarrierEdited + 3573 " and " + IS_NOT_OWNED_BY_DPC, 3574 new String[]{url.getLastPathSegment() }); 3575 break; 3576 } 3577 3578 case URL_RESTOREAPN_USING_SUBID: { 3579 String subIdString = url.getLastPathSegment(); 3580 try { 3581 subId = Integer.parseInt(subIdString); 3582 } catch (NumberFormatException e) { 3583 loge("NumberFormatException" + e); 3584 throw new IllegalArgumentException("Invalid subId " + url); 3585 } 3586 if (DBG) log("subIdString = " + subIdString + " subId = " + subId); 3587 } 3588 // intentional fall through from above case 3589 3590 case URL_RESTOREAPN: { 3591 count = 1; 3592 restoreDefaultAPN(subId); 3593 getContext().getContentResolver().notifyChange( 3594 Uri.withAppendedPath(CONTENT_URI, "restore/subId/" + subId), null, 3595 true, UserHandle.USER_ALL); 3596 break; 3597 } 3598 3599 case URL_PREFERAPN_USING_SUBID: 3600 case URL_PREFERAPN_NO_UPDATE_USING_SUBID: { 3601 String subIdString = url.getLastPathSegment(); 3602 try { 3603 subId = Integer.parseInt(subIdString); 3604 } catch (NumberFormatException e) { 3605 loge("NumberFormatException" + e); 3606 throw new IllegalArgumentException("Invalid subId " + url); 3607 } 3608 if (DBG) log("subIdString = " + subIdString + " subId = " + subId); 3609 } 3610 //intentional fall through from above case 3611 3612 case URL_PREFERAPN: 3613 case URL_PREFERAPN_NO_UPDATE: 3614 { 3615 setPreferredApnId((long)INVALID_APN_ID, subId, true); 3616 if ((match == URL_PREFERAPN) || (match == URL_PREFERAPN_USING_SUBID)) count = 1; 3617 break; 3618 } 3619 3620 case URL_DPC_ID: { 3621 ensureCallingFromSystemOrPhoneUid("URL_DPC_ID called from non SYSTEM_UID."); 3622 3623 // Only delete if owned by DPC. 3624 count = db.delete(CARRIERS_TABLE, "(" + _ID + "=?)" + " and " + IS_OWNED_BY_DPC, 3625 new String[] { url.getLastPathSegment() }); 3626 break; 3627 } 3628 3629 case URL_SIMINFO: { 3630 count = db.delete(SIMINFO_TABLE, where, whereArgs); 3631 break; 3632 } 3633 3634 case URL_UPDATE_DB: { 3635 updateApnDb(); 3636 count = 1; 3637 break; 3638 } 3639 3640 default: { 3641 throw new UnsupportedOperationException("Cannot delete that URL: " + url); 3642 } 3643 } 3644 3645 if (count > 0) { 3646 getContext().getContentResolver().notifyChange(CONTENT_URI, null, 3647 true, UserHandle.USER_ALL); 3648 } 3649 3650 return count; 3651 } 3652 3653 @Override update(Uri url, ContentValues values, String where, String[] whereArgs)3654 public synchronized int update(Uri url, ContentValues values, String where, String[] whereArgs) 3655 { 3656 int count = 0; 3657 int uriType = URL_UNKNOWN; 3658 int subId = SubscriptionManager.getDefaultSubscriptionId(); 3659 3660 checkPermission(); 3661 syncBearerBitmaskAndNetworkTypeBitmask(values); 3662 3663 SQLiteDatabase db = getWritableDatabase(); 3664 int match = s_urlMatcher.match(url); 3665 switch (match) 3666 { 3667 case URL_TELEPHONY_USING_SUBID: 3668 { 3669 String subIdString = url.getLastPathSegment(); 3670 try { 3671 subId = Integer.parseInt(subIdString); 3672 } catch (NumberFormatException e) { 3673 loge("NumberFormatException" + e); 3674 throw new IllegalArgumentException("Invalid subId " + url); 3675 } 3676 if (DBG) log("subIdString = " + subIdString + " subId = " + subId); 3677 //FIXME use subId in the query 3678 } 3679 //intentional fall through from above case 3680 3681 case URL_TELEPHONY: 3682 { 3683 if (!values.containsKey(EDITED_STATUS)) { 3684 values.put(EDITED_STATUS, CARRIER_EDITED); 3685 } 3686 3687 // Replace on conflict so that if same APN is present in db with edited 3688 // as UNEDITED or USER/CARRIER_DELETED, it is replaced with 3689 // edited USER/CARRIER_EDITED 3690 count = db.updateWithOnConflict(CARRIERS_TABLE, values, where + 3691 " and " + IS_NOT_OWNED_BY_DPC, whereArgs, 3692 SQLiteDatabase.CONFLICT_REPLACE); 3693 break; 3694 } 3695 3696 case URL_CURRENT_USING_SUBID: 3697 { 3698 String subIdString = url.getLastPathSegment(); 3699 try { 3700 subId = Integer.parseInt(subIdString); 3701 } catch (NumberFormatException e) { 3702 loge("NumberFormatException" + e); 3703 throw new IllegalArgumentException("Invalid subId " + url); 3704 } 3705 if (DBG) log("subIdString = " + subIdString + " subId = " + subId); 3706 //FIXME use subId in the query 3707 } 3708 //intentional fall through from above case 3709 3710 case URL_CURRENT: 3711 { 3712 if (!values.containsKey(EDITED_STATUS)) { 3713 values.put(EDITED_STATUS, CARRIER_EDITED); 3714 } 3715 // Replace on conflict so that if same APN is present in db with edited 3716 // as UNEDITED or USER/CARRIER_DELETED, it is replaced with 3717 // edited USER/CARRIER_EDITED 3718 count = db.updateWithOnConflict(CARRIERS_TABLE, values, where + 3719 " and " + IS_NOT_OWNED_BY_DPC, 3720 whereArgs, SQLiteDatabase.CONFLICT_REPLACE); 3721 break; 3722 } 3723 3724 case URL_ID: 3725 { 3726 String rowID = url.getLastPathSegment(); 3727 if (where != null || whereArgs != null) { 3728 throw new UnsupportedOperationException( 3729 "Cannot update URL " + url + " with a where clause"); 3730 } 3731 if (!values.containsKey(EDITED_STATUS)) { 3732 values.put(EDITED_STATUS, CARRIER_EDITED); 3733 } 3734 3735 try { 3736 count = db.updateWithOnConflict(CARRIERS_TABLE, values, _ID + "=?" + " and " + 3737 IS_NOT_OWNED_BY_DPC, new String[] { rowID }, 3738 SQLiteDatabase.CONFLICT_ABORT); 3739 } catch (SQLException e) { 3740 // Update failed which could be due to a conflict. Check if that is 3741 // the case and merge the entries 3742 log("update: exception " + e); 3743 Cursor oldRow = selectConflictingRow(db, CARRIERS_TABLE, values); 3744 if (oldRow != null) { 3745 ContentValues mergedValues = new ContentValues(); 3746 mergeFieldsAndUpdateDb(db, CARRIERS_TABLE, oldRow, values, 3747 mergedValues, false, getContext()); 3748 oldRow.close(); 3749 db.delete(CARRIERS_TABLE, _ID + "=?" + " and " + IS_NOT_OWNED_BY_DPC, 3750 new String[] { rowID }); 3751 } 3752 } 3753 break; 3754 } 3755 3756 case URL_PREFERAPN_USING_SUBID: 3757 case URL_PREFERAPN_NO_UPDATE_USING_SUBID: 3758 { 3759 String subIdString = url.getLastPathSegment(); 3760 try { 3761 subId = Integer.parseInt(subIdString); 3762 } catch (NumberFormatException e) { 3763 loge("NumberFormatException" + e); 3764 throw new IllegalArgumentException("Invalid subId " + url); 3765 } 3766 if (DBG) log("subIdString = " + subIdString + " subId = " + subId); 3767 } 3768 3769 case URL_PREFERAPN: 3770 case URL_PREFERAPN_NO_UPDATE: 3771 { 3772 if (values != null) { 3773 if (values.containsKey(COLUMN_APN_ID)) { 3774 setPreferredApnId(values.getAsLong(COLUMN_APN_ID), subId, true); 3775 if ((match == URL_PREFERAPN) || 3776 (match == URL_PREFERAPN_USING_SUBID)) { 3777 count = 1; 3778 } 3779 } 3780 } 3781 break; 3782 } 3783 3784 case URL_DPC_ID: 3785 { 3786 ensureCallingFromSystemOrPhoneUid("URL_DPC_ID called from non SYSTEM_UID."); 3787 3788 if (where != null || whereArgs != null) { 3789 throw new UnsupportedOperationException( 3790 "Cannot update URL " + url + " with a where clause"); 3791 } 3792 count = db.updateWithOnConflict(CARRIERS_TABLE, values, 3793 _ID + "=?" + " and " + IS_OWNED_BY_DPC, 3794 new String[] { url.getLastPathSegment() }, SQLiteDatabase.CONFLICT_IGNORE); 3795 break; 3796 } 3797 3798 case URL_ENFORCE_MANAGED: { 3799 ensureCallingFromSystemOrPhoneUid( 3800 "URL_ENFORCE_MANAGED called from non SYSTEM_UID."); 3801 if (values != null) { 3802 if (values.containsKey(ENFORCED_KEY)) { 3803 setManagedApnEnforced(values.getAsBoolean(ENFORCED_KEY)); 3804 count = 1; 3805 } 3806 } 3807 break; 3808 } 3809 3810 case URL_SIMINFO_USING_SUBID: 3811 String subIdString = url.getLastPathSegment(); 3812 try { 3813 subId = Integer.parseInt(subIdString); 3814 } catch (NumberFormatException e) { 3815 loge("NumberFormatException" + e); 3816 throw new IllegalArgumentException("Invalid subId " + url); 3817 } 3818 if (DBG) log("subIdString = " + subIdString + " subId = " + subId); 3819 if (where != null || whereArgs != null) { 3820 throw new UnsupportedOperationException( 3821 "Cannot update URL " + url + " with a where clause"); 3822 } 3823 count = db.update(SIMINFO_TABLE, values, _ID + "=?", 3824 new String[] { subIdString}); 3825 uriType = URL_SIMINFO_USING_SUBID; 3826 break; 3827 3828 case URL_SIMINFO: { 3829 count = db.update(SIMINFO_TABLE, values, where, whereArgs); 3830 uriType = URL_SIMINFO; 3831 break; 3832 } 3833 3834 default: { 3835 throw new UnsupportedOperationException("Cannot update that URL: " + url); 3836 } 3837 } 3838 3839 if (count > 0) { 3840 boolean usingSubId = false; 3841 switch (uriType) { 3842 case URL_SIMINFO_USING_SUBID: 3843 usingSubId = true; 3844 // intentional fall through from above case 3845 case URL_SIMINFO: 3846 // skip notifying descendant URLs to avoid unneccessary wake up. 3847 // If not set, any change to SIMINFO will notify observers which listens to 3848 // specific field of SIMINFO. 3849 getContext().getContentResolver().notifyChange( 3850 Telephony.SimInfo.CONTENT_URI, null, 3851 ContentResolver.NOTIFY_SYNC_TO_NETWORK 3852 | ContentResolver.NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS, 3853 UserHandle.USER_ALL); 3854 // notify observers on specific user settings changes. 3855 if (values.containsKey(Telephony.SimInfo.COLUMN_WFC_IMS_ENABLED)) { 3856 getContext().getContentResolver().notifyChange( 3857 getNotifyContentUri(SubscriptionManager.WFC_ENABLED_CONTENT_URI, 3858 usingSubId, subId), null, true, UserHandle.USER_ALL); 3859 } 3860 if (values.containsKey(Telephony.SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED)) { 3861 getContext().getContentResolver().notifyChange( 3862 getNotifyContentUri(SubscriptionManager 3863 .ADVANCED_CALLING_ENABLED_CONTENT_URI, 3864 usingSubId, subId), null, true, UserHandle.USER_ALL); 3865 } 3866 if (values.containsKey(Telephony.SimInfo.COLUMN_VT_IMS_ENABLED)) { 3867 getContext().getContentResolver().notifyChange( 3868 getNotifyContentUri(SubscriptionManager.VT_ENABLED_CONTENT_URI, 3869 usingSubId, subId), null, true, UserHandle.USER_ALL); 3870 } 3871 if (values.containsKey(Telephony.SimInfo.COLUMN_WFC_IMS_MODE)) { 3872 getContext().getContentResolver().notifyChange( 3873 getNotifyContentUri(SubscriptionManager.WFC_MODE_CONTENT_URI, 3874 usingSubId, subId), null, true, UserHandle.USER_ALL); 3875 } 3876 if (values.containsKey(Telephony.SimInfo.COLUMN_WFC_IMS_ROAMING_MODE)) { 3877 getContext().getContentResolver().notifyChange(getNotifyContentUri( 3878 SubscriptionManager.WFC_ROAMING_MODE_CONTENT_URI, 3879 usingSubId, subId), null, true, UserHandle.USER_ALL); 3880 } 3881 if (values.containsKey(Telephony.SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED)) { 3882 getContext().getContentResolver().notifyChange(getNotifyContentUri( 3883 SubscriptionManager.WFC_ROAMING_ENABLED_CONTENT_URI, 3884 usingSubId, subId), null, true, UserHandle.USER_ALL); 3885 } 3886 if (values.containsKey(Telephony.SimInfo.COLUMN_IMS_RCS_UCE_ENABLED)) { 3887 getContext().getContentResolver().notifyChange(getNotifyContentUri( 3888 Uri.withAppendedPath(Telephony.SimInfo.CONTENT_URI, 3889 Telephony.SimInfo.COLUMN_IMS_RCS_UCE_ENABLED), usingSubId, subId), 3890 null, true, UserHandle.USER_ALL); 3891 } 3892 break; 3893 default: 3894 getContext().getContentResolver().notifyChange( 3895 CONTENT_URI, null, true, UserHandle.USER_ALL); 3896 } 3897 } 3898 3899 return count; 3900 } 3901 getNotifyContentUri(Uri uri, boolean usingSubId, int subId)3902 private static Uri getNotifyContentUri(Uri uri, boolean usingSubId, int subId) { 3903 return (usingSubId) ? Uri.withAppendedPath(uri, "" + subId) : uri; 3904 } 3905 checkPermission()3906 private void checkPermission() { 3907 int status = getContext().checkCallingOrSelfPermission( 3908 "android.permission.WRITE_APN_SETTINGS"); 3909 if (status == PackageManager.PERMISSION_GRANTED) { 3910 return; 3911 } 3912 3913 PackageManager packageManager = getContext().getPackageManager(); 3914 String[] packages = packageManager.getPackagesForUid(Binder.getCallingUid()); 3915 3916 TelephonyManager telephonyManager = 3917 (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE); 3918 for (String pkg : packages) { 3919 if (telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(pkg) == 3920 TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { 3921 return; 3922 } 3923 } 3924 throw new SecurityException("No permission to write APN settings"); 3925 } 3926 checkPhonePrivilegePermission()3927 private void checkPhonePrivilegePermission() { 3928 int status = getContext().checkCallingOrSelfPermission( 3929 "android.permission.READ_PRIVILEGED_PHONE_STATE"); 3930 if (status == PackageManager.PERMISSION_GRANTED) { 3931 return; 3932 } 3933 throw new SecurityException("No phone privilege permission"); 3934 } 3935 3936 private DatabaseHelper mOpenHelper; 3937 restoreDefaultAPN(int subId)3938 private void restoreDefaultAPN(int subId) { 3939 SQLiteDatabase db = getWritableDatabase(); 3940 TelephonyManager telephonyManager = 3941 (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE); 3942 String where = null; 3943 if (telephonyManager.getPhoneCount() > 1) { 3944 where = getWhereClauseForRestoreDefaultApn(db, subId); 3945 } 3946 if (TextUtils.isEmpty(where)) { 3947 where = IS_NOT_OWNED_BY_DPC; 3948 } 3949 log("restoreDefaultAPN: where: " + where); 3950 3951 try { 3952 db.delete(CARRIERS_TABLE, where, null); 3953 } catch (SQLException e) { 3954 loge("got exception when deleting to restore: " + e); 3955 } 3956 3957 // delete preferred apn ids and preferred apns (both stored in diff SharedPref) for all 3958 // subIds 3959 SharedPreferences spApnId = getContext().getSharedPreferences(PREF_FILE_APN, 3960 Context.MODE_PRIVATE); 3961 SharedPreferences.Editor editorApnId = spApnId.edit(); 3962 editorApnId.clear(); 3963 editorApnId.apply(); 3964 3965 SharedPreferences spApn = getContext().getSharedPreferences(PREF_FILE_FULL_APN, 3966 Context.MODE_PRIVATE); 3967 SharedPreferences.Editor editorApn = spApn.edit(); 3968 editorApn.clear(); 3969 editorApn.apply(); 3970 3971 if (apnSourceServiceExists(getContext())) { 3972 restoreApnsWithService(subId); 3973 } else { 3974 initDatabaseWithDatabaseHelper(db); 3975 } 3976 } 3977 getWhereClauseForRestoreDefaultApn(SQLiteDatabase db, int subId)3978 private String getWhereClauseForRestoreDefaultApn(SQLiteDatabase db, int subId) { 3979 TelephonyManager telephonyManager = 3980 getContext().getSystemService(TelephonyManager.class).createForSubscriptionId(subId); 3981 String simOperator = telephonyManager.getSimOperator(); 3982 Cursor cursor = db.query(CARRIERS_TABLE, new String[] {MVNO_TYPE, MVNO_MATCH_DATA}, 3983 NUMERIC + "='" + simOperator + "'", null, null, null, DEFAULT_SORT_ORDER); 3984 String where = null; 3985 3986 if (cursor != null) { 3987 cursor.moveToFirst(); 3988 while (!cursor.isAfterLast()) { 3989 String mvnoType = cursor.getString(0 /* MVNO_TYPE index */); 3990 String mvnoMatchData = cursor.getString(1 /* MVNO_MATCH_DATA index */); 3991 if (!TextUtils.isEmpty(mvnoType) && !TextUtils.isEmpty(mvnoMatchData) 3992 && telephonyManager.isCurrentSimOperator(simOperator, 3993 getMvnoTypeIntFromString(mvnoType), mvnoMatchData)) { 3994 where = NUMERIC + "='" + simOperator + "'" 3995 + " AND " + MVNO_TYPE + "='" + mvnoType + "'" 3996 + " AND " + MVNO_MATCH_DATA + "='" + mvnoMatchData + "'" 3997 + " AND " + IS_NOT_OWNED_BY_DPC; 3998 break; 3999 } 4000 cursor.moveToNext(); 4001 } 4002 cursor.close(); 4003 4004 if (TextUtils.isEmpty(where)) { 4005 where = NUMERIC + "='" + simOperator + "'" 4006 + " AND (" + MVNO_TYPE + "='' OR " + MVNO_MATCH_DATA + "='')" 4007 + " AND " + IS_NOT_OWNED_BY_DPC; 4008 } 4009 } 4010 return where; 4011 } 4012 updateApnDb()4013 private synchronized void updateApnDb() { 4014 if (apnSourceServiceExists(getContext())) { 4015 loge("called updateApnDb when apn source service exists"); 4016 return; 4017 } 4018 4019 if (!needApnDbUpdate()) { 4020 log("Skipping apn db update since apn-conf has not changed."); 4021 return; 4022 } 4023 4024 SQLiteDatabase db = getWritableDatabase(); 4025 4026 // Delete preferred APN for all subIds 4027 deletePreferredApnId(getContext()); 4028 4029 // Delete entries in db 4030 try { 4031 if (VDBG) log("updateApnDb: deleting edited=UNEDITED entries"); 4032 db.delete(CARRIERS_TABLE, IS_UNEDITED + " and " + IS_NOT_OWNED_BY_DPC, null); 4033 } catch (SQLException e) { 4034 loge("got exception when deleting to update: " + e); 4035 } 4036 4037 initDatabaseWithDatabaseHelper(db); 4038 4039 // Notify listeners of DB change since DB has been updated 4040 getContext().getContentResolver().notifyChange( 4041 CONTENT_URI, null, true, UserHandle.USER_ALL); 4042 4043 } 4044 fillInMccMncStringAtCursor(Context context, SQLiteDatabase db, Cursor c)4045 public static void fillInMccMncStringAtCursor(Context context, SQLiteDatabase db, Cursor c) { 4046 int mcc, mnc; 4047 String subId; 4048 try { 4049 mcc = c.getInt(c.getColumnIndexOrThrow(Telephony.SimInfo.COLUMN_MCC)); 4050 mnc = c.getInt(c.getColumnIndexOrThrow(Telephony.SimInfo.COLUMN_MNC)); 4051 subId = c.getString(c.getColumnIndexOrThrow( 4052 Telephony.SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID)); 4053 } catch (IllegalArgumentException e) { 4054 Log.e(TAG, "Possible database corruption -- some columns not found."); 4055 return; 4056 } 4057 4058 String mccString = String.format(Locale.getDefault(), "%03d", mcc); 4059 String mncString = getBestStringMnc(context, mccString, mnc); 4060 ContentValues cv = new ContentValues(2); 4061 cv.put(Telephony.SimInfo.COLUMN_MCC_STRING, mccString); 4062 cv.put(Telephony.SimInfo.COLUMN_MNC_STRING, mncString); 4063 db.update(SIMINFO_TABLE, cv, 4064 Telephony.SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID + "=?", 4065 new String[]{subId}); 4066 } 4067 4068 /* 4069 * Find the best string-form mnc by looking up possibilities in the carrier id db. 4070 * Default to the three-digit version if neither/both are valid. 4071 */ getBestStringMnc(Context context, String mcc, int mnc)4072 private static String getBestStringMnc(Context context, String mcc, int mnc) { 4073 if (mnc >= 100 && mnc <= 999) { 4074 return String.valueOf(mnc); 4075 } 4076 String twoDigitMnc = String.format(Locale.getDefault(), "%02d", mnc); 4077 String threeDigitMnc = "0" + twoDigitMnc; 4078 4079 try ( 4080 Cursor twoDigitMncCursor = context.getContentResolver().query( 4081 Telephony.CarrierId.All.CONTENT_URI, 4082 /* projection */ null, 4083 /* selection */ Telephony.CarrierId.All.MCCMNC + "=?", 4084 /* selectionArgs */ new String[]{mcc + twoDigitMnc}, null) 4085 ) { 4086 if (twoDigitMncCursor.getCount() > 0) { 4087 return twoDigitMnc; 4088 } 4089 return threeDigitMnc; 4090 } 4091 } 4092 4093 /** 4094 * Sync the bearer bitmask and network type bitmask when inserting and updating. 4095 * Since bearerBitmask is deprecating, map the networkTypeBitmask to bearerBitmask if 4096 * networkTypeBitmask was provided. But if networkTypeBitmask was not provided, map the 4097 * bearerBitmask to networkTypeBitmask. 4098 */ syncBearerBitmaskAndNetworkTypeBitmask(ContentValues values)4099 private static void syncBearerBitmaskAndNetworkTypeBitmask(ContentValues values) { 4100 if (values.containsKey(NETWORK_TYPE_BITMASK)) { 4101 int convertedBitmask = convertNetworkTypeBitmaskToBearerBitmask( 4102 values.getAsInteger(NETWORK_TYPE_BITMASK)); 4103 if (values.containsKey(BEARER_BITMASK) 4104 && convertedBitmask != values.getAsInteger(BEARER_BITMASK)) { 4105 loge("Network type bitmask and bearer bitmask are not compatible."); 4106 } 4107 values.put(BEARER_BITMASK, convertNetworkTypeBitmaskToBearerBitmask( 4108 values.getAsInteger(NETWORK_TYPE_BITMASK))); 4109 } else { 4110 if (values.containsKey(BEARER_BITMASK)) { 4111 int convertedBitmask = convertBearerBitmaskToNetworkTypeBitmask( 4112 values.getAsInteger(BEARER_BITMASK)); 4113 values.put(NETWORK_TYPE_BITMASK, convertedBitmask); 4114 } 4115 } 4116 } 4117 4118 /** 4119 * Log with debug 4120 * 4121 * @param s is string log 4122 */ log(String s)4123 private static void log(String s) { 4124 Log.d(TAG, s); 4125 } 4126 loge(String s)4127 private static void loge(String s) { 4128 Log.e(TAG, s); 4129 } 4130 getMvnoTypeIntFromString(String mvnoType)4131 private static int getMvnoTypeIntFromString(String mvnoType) { 4132 String mvnoTypeString = TextUtils.isEmpty(mvnoType) ? mvnoType : mvnoType.toLowerCase(); 4133 Integer mvnoTypeInt = MVNO_TYPE_STRING_MAP.get(mvnoTypeString); 4134 return mvnoTypeInt == null ? UNSPECIFIED_INT : mvnoTypeInt; 4135 } 4136 getBitmaskFromString(String bearerList)4137 private static int getBitmaskFromString(String bearerList) { 4138 String[] bearers = bearerList.split("\\|"); 4139 int bearerBitmask = 0; 4140 for (String bearer : bearers) { 4141 int bearerInt = 0; 4142 try { 4143 bearerInt = Integer.parseInt(bearer.trim()); 4144 } catch (NumberFormatException nfe) { 4145 return 0; 4146 } 4147 4148 if (bearerInt == 0) { 4149 return 0; 4150 } 4151 bearerBitmask |= getBitmaskForTech(bearerInt); 4152 } 4153 return bearerBitmask; 4154 } 4155 4156 /** 4157 * Transform RIL radio technology value to Network 4158 * type bitmask{@link android.telephony.TelephonyManager.NetworkTypeBitMask}. 4159 * 4160 * @param rat The RIL radio technology. 4161 * @return The network type 4162 * bitmask{@link android.telephony.TelephonyManager.NetworkTypeBitMask}. 4163 */ rilRadioTechnologyToNetworkTypeBitmask(int rat)4164 private static int rilRadioTechnologyToNetworkTypeBitmask(int rat) { 4165 switch (rat) { 4166 case RIL_RADIO_TECHNOLOGY_GPRS: 4167 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_GPRS; 4168 case RIL_RADIO_TECHNOLOGY_EDGE: 4169 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_EDGE; 4170 case RIL_RADIO_TECHNOLOGY_UMTS: 4171 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_UMTS; 4172 case RIL_RADIO_TECHNOLOGY_HSDPA: 4173 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_HSDPA; 4174 case RIL_RADIO_TECHNOLOGY_HSUPA: 4175 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_HSUPA; 4176 case RIL_RADIO_TECHNOLOGY_HSPA: 4177 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_HSPA; 4178 case RIL_RADIO_TECHNOLOGY_IS95A: 4179 case RIL_RADIO_TECHNOLOGY_IS95B: 4180 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_CDMA; 4181 case RIL_RADIO_TECHNOLOGY_1xRTT: 4182 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_1xRTT; 4183 case RIL_RADIO_TECHNOLOGY_EVDO_0: 4184 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_EVDO_0; 4185 case RIL_RADIO_TECHNOLOGY_EVDO_A: 4186 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_EVDO_A; 4187 case RIL_RADIO_TECHNOLOGY_EVDO_B: 4188 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_EVDO_B; 4189 case RIL_RADIO_TECHNOLOGY_EHRPD: 4190 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_EHRPD; 4191 case RIL_RADIO_TECHNOLOGY_LTE: 4192 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_LTE; 4193 case RIL_RADIO_TECHNOLOGY_HSPAP: 4194 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_HSPAP; 4195 case RIL_RADIO_TECHNOLOGY_GSM: 4196 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_GSM; 4197 case RIL_RADIO_TECHNOLOGY_TD_SCDMA: 4198 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_TD_SCDMA; 4199 case RIL_RADIO_TECHNOLOGY_IWLAN: 4200 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_IWLAN; 4201 case RIL_RADIO_TECHNOLOGY_LTE_CA: 4202 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_LTE_CA; 4203 case RIL_RADIO_TECHNOLOGY_NR: 4204 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_NR; 4205 default: 4206 return (int) TelephonyManager.NETWORK_TYPE_BITMASK_UNKNOWN; 4207 } 4208 } 4209 4210 /** 4211 * Convert network type bitmask to bearer bitmask. 4212 * 4213 * @param networkTypeBitmask The network type bitmask value 4214 * @return The bearer bitmask value. 4215 */ convertNetworkTypeBitmaskToBearerBitmask(int networkTypeBitmask)4216 private static int convertNetworkTypeBitmaskToBearerBitmask(int networkTypeBitmask) { 4217 if (networkTypeBitmask == 0) { 4218 return 0; 4219 } 4220 4221 int bearerBitmask = 0; 4222 for (int bearerInt = 0; bearerInt < NEXT_RIL_RADIO_TECHNOLOGY; bearerInt++) { 4223 if (bitmaskHasTarget(networkTypeBitmask, 4224 rilRadioTechnologyToNetworkTypeBitmask(bearerInt))) { 4225 bearerBitmask |= getBitmaskForTech(bearerInt); 4226 } 4227 } 4228 return bearerBitmask; 4229 } 4230 4231 /** 4232 * Convert bearer bitmask to network type bitmask. 4233 * 4234 * @param bearerBitmask The bearer bitmask value. 4235 * @return The network type bitmask value. 4236 */ convertBearerBitmaskToNetworkTypeBitmask(int bearerBitmask)4237 private static int convertBearerBitmaskToNetworkTypeBitmask(int bearerBitmask) { 4238 if (bearerBitmask == 0) { 4239 return 0; 4240 } 4241 4242 int networkTypeBitmask = 0; 4243 for (int bearerUnitInt = 0; bearerUnitInt < NEXT_RIL_RADIO_TECHNOLOGY; bearerUnitInt++) { 4244 int bearerUnitBitmask = getBitmaskForTech(bearerUnitInt); 4245 if (bitmaskHasTarget(bearerBitmask, bearerUnitBitmask)) { 4246 networkTypeBitmask |= rilRadioTechnologyToNetworkTypeBitmask(bearerUnitInt); 4247 } 4248 } 4249 return networkTypeBitmask; 4250 } 4251 bitmaskHasTarget(int bearerBitmask, int targetBitmask)4252 private static boolean bitmaskHasTarget(int bearerBitmask, int targetBitmask) { 4253 if (bearerBitmask == 0) { 4254 return true; 4255 } else if (targetBitmask != 0) { 4256 return ((bearerBitmask & targetBitmask) != 0); 4257 } 4258 return false; 4259 } 4260 getBitmaskForTech(int radioTech)4261 private static int getBitmaskForTech(int radioTech) { 4262 if (radioTech >= 1) { 4263 return (1 << (radioTech - 1)); 4264 } 4265 return 0; 4266 } 4267 } 4268