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