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