Snap for 6439596 from ddb62c707a0be7353e5d5c14d40cd2b83e10638a to qt-aml-tzdata-release

Change-Id: I904979de6266fc7608c8c40373928a8f3a816157
diff --git a/OWNERS b/OWNERS
index bce6270..92458db 100644
--- a/OWNERS
+++ b/OWNERS
@@ -10,4 +10,3 @@
 tgunn@google.com
 breadley@google.com
 nazaninb@google.com
-sarahchin@google.com
diff --git a/TEST_MAPPING b/TEST_MAPPING
deleted file mode 100644
index ee02cd3..0000000
--- a/TEST_MAPPING
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  "presubmit": [
-    {
-      "name": "CtsTelephonyProviderTestCases"
-    }
-  ]
-}
diff --git a/assets/carrier_list.pb b/assets/carrier_list.pb
index 0c5e5b9..3519d2c 100644
--- a/assets/carrier_list.pb
+++ b/assets/carrier_list.pb
Binary files differ
diff --git a/assets/carrier_list.textpb b/assets/carrier_list.textpb
index ab01907..b1c6825 100644
--- a/assets/carrier_list.textpb
+++ b/assets/carrier_list.textpb
Binary files differ
diff --git a/assets/sdk29_carrier_id/carrier_list.pb b/assets/sdk29_carrier_id/carrier_list.pb
deleted file mode 100644
index 125de1a..0000000
--- a/assets/sdk29_carrier_id/carrier_list.pb
+++ /dev/null
Binary files differ
diff --git a/assets/sdk29_carrier_id/carrier_list.textpb b/assets/sdk29_carrier_id/carrier_list.textpb
deleted file mode 100644
index 648571e..0000000
--- a/assets/sdk29_carrier_id/carrier_list.textpb
+++ /dev/null
Binary files differ
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 6cfcdfb..f3baf24 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -17,5 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" product="tablet" msgid="9194799012395299737">"Configuration du réseau mobile"</string>
-    <string name="app_label" product="default" msgid="8338087656149558019">"Stockage tél. et SMS/MMS"</string>
+    <string name="app_label" product="default" msgid="8338087656149558019">"Téléphone et stockage des messages"</string>
 </resources>
diff --git a/src/com/android/providers/telephony/CellBroadcastProvider.java b/src/com/android/providers/telephony/CellBroadcastProvider.java
index ccb3f4a..4c8a7e2 100644
--- a/src/com/android/providers/telephony/CellBroadcastProvider.java
+++ b/src/com/android/providers/telephony/CellBroadcastProvider.java
@@ -61,7 +61,7 @@
     private static final String DATABASE_NAME = "cellbroadcasts.db";
 
     /** Database version. */
-    private static final int DATABASE_VERSION = 2;
+    private static final int DATABASE_VERSION = 1;
 
     /** URI matcher for ContentProvider queries. */
     private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
@@ -243,7 +243,6 @@
         return "CREATE TABLE " + tableName + " ("
                 + CellBroadcasts._ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
                 + CellBroadcasts.SUB_ID + " INTEGER,"
-                + CellBroadcasts.SLOT_INDEX + " INTEGER DEFAULT 0,"
                 + CellBroadcasts.GEOGRAPHICAL_SCOPE + " INTEGER,"
                 + CellBroadcasts.PLMN + " TEXT,"
                 + CellBroadcasts.LAC + " INTEGER,"
@@ -300,16 +299,7 @@
         }
 
         @Override
-        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
-            if (DBG) {
-                Log.d(TAG, "onUpgrade: oldV=" + oldVersion + " newV=" + newVersion);
-            }
-            if (newVersion == 2) {
-                db.execSQL("ALTER TABLE " + CELL_BROADCASTS_TABLE_NAME + " ADD COLUMN "
-                        + CellBroadcasts.SLOT_INDEX + " INTEGER DEFAULT 0;");
-                Log.d(TAG, "add slotIndex column");
-            }
-        }
+        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}
     }
 
     private class CellBroadcastPermissionChecker implements PermissionChecker {
diff --git a/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java b/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
index 4add85d..7ecfc46 100644
--- a/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
+++ b/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
@@ -17,7 +17,6 @@
 package com.android.providers.telephony;
 
 import static android.provider.Telephony.RcsColumns.IS_RCS_TABLE_SCHEMA_CODE_COMPLETE;
-import static com.android.internal.telephony.SmsResponse.NO_ERROR_CODE;
 
 import android.content.BroadcastReceiver;
 import android.content.ContentValues;
@@ -546,7 +545,7 @@
                 intent.putExtra(Intents.EXTRA_IS_INITIAL_CREATE, true);
             }
 
-            mContext.sendBroadcast(intent, android.Manifest.permission.READ_SMS);
+            mContext.sendBroadcast(intent);
         }
         createMmsTables(db);
         createSmsTables(db);
@@ -1013,7 +1012,7 @@
             "service_center TEXT," +
             "locked INTEGER DEFAULT 0," +
             "sub_id INTEGER DEFAULT " + SubscriptionManager.INVALID_SUBSCRIPTION_ID + ", " +
-            "error_code INTEGER DEFAULT " + NO_ERROR_CODE + ", " +
+            "error_code INTEGER DEFAULT 0," +
             "creator TEXT," +
             "seen INTEGER DEFAULT 0" +
             ");";
@@ -1817,7 +1816,7 @@
 
     private void upgradeDatabaseToVersion48(SQLiteDatabase db) {
         // Add 'error_code' column to sms table.
-        db.execSQL("ALTER TABLE sms ADD COLUMN error_code INTEGER DEFAULT " + NO_ERROR_CODE);
+        db.execSQL("ALTER TABLE sms ADD COLUMN error_code INTEGER DEFAULT 0");
     }
 
     private void upgradeDatabaseToVersion51(SQLiteDatabase db) {
diff --git a/src/com/android/providers/telephony/MmsSmsProvider.java b/src/com/android/providers/telephony/MmsSmsProvider.java
index 1170aad..dbf85ae 100644
--- a/src/com/android/providers/telephony/MmsSmsProvider.java
+++ b/src/com/android/providers/telephony/MmsSmsProvider.java
@@ -305,7 +305,6 @@
     private SQLiteOpenHelper mOpenHelper;
 
     private boolean mUseStrictPhoneNumberComparation;
-    private int mMinMatch;
 
     private static final String METHOD_IS_RESTORING = "is_restoring";
     private static final String IS_RESTORING_KEY = "restoring";
@@ -317,9 +316,6 @@
         mUseStrictPhoneNumberComparation =
             getContext().getResources().getBoolean(
                     com.android.internal.R.bool.config_use_strict_phone_number_comparation);
-        mMinMatch =
-            getContext().getResources().getInteger(
-                    com.android.internal.R.integer.config_phonenumber_compare_min_match);
         TelephonyBackupAgent.DeferredSmsMmsRestoreService.startIfFilesExist(getContext());
         return true;
     }
@@ -336,6 +332,16 @@
         final String pduTable = MmsProvider.getPduTable(accessRestricted);
         final String smsTable = SmsProvider.getSmsTable(accessRestricted);
 
+        // If access is restricted, we don't allow subqueries in the query.
+        if (accessRestricted) {
+            try {
+                SqlQueryChecker.checkQueryParametersForSubqueries(projection, selection, sortOrder);
+            } catch (IllegalArgumentException e) {
+                Log.w(LOG_TAG, "Query rejected: " + e.getMessage());
+                return null;
+            }
+        }
+
         SQLiteDatabase db = mOpenHelper.getReadableDatabase();
         Cursor cursor = null;
         final int match = URI_MATCHER.match(uri);
@@ -546,7 +552,7 @@
             selectionArgs = new String[] { refinedAddress };
         } else {
             selection += " OR PHONE_NUMBERS_EQUAL(address, ?, " +
-                        (mUseStrictPhoneNumberComparation ? "1)" : "0, " + mMinMatch + ")");
+                        (mUseStrictPhoneNumberComparation ? 1 : 0) + ")";
             selectionArgs = new String[] { refinedAddress, refinedAddress };
         }
 
@@ -1001,14 +1007,13 @@
      *   FROM pdu, (SELECT msg_id AS address_msg_id
      *              FROM addr
      *              WHERE (address='<phoneNumber>' OR
-     *              PHONE_NUMBERS_EQUAL(addr.address, '<phoneNumber>', 1/0, none/mMinMatch)))
+     *              PHONE_NUMBERS_EQUAL(addr.address, '<phoneNumber>', 1/0)))
      *             AS matching_addresses
      *   WHERE pdu._id = matching_addresses.address_msg_id
      * UNION
      * SELECT ...
      *   FROM sms
-     *   WHERE (address='<phoneNumber>' OR
-     *          PHONE_NUMBERS_EQUAL(sms.address, '<phoneNumber>', 1/0, none/mMinMatch));
+     *   WHERE (address='<phoneNumber>' OR PHONE_NUMBERS_EQUAL(sms.address, '<phoneNumber>', 1/0));
      */
     private Cursor getMessagesByPhoneNumber(
             String phoneNumber, String[] projection, String selection,
@@ -1023,7 +1028,7 @@
                         selection,
                         "(address=" + escapedPhoneNumber + " OR PHONE_NUMBERS_EQUAL(address, " +
                         escapedPhoneNumber +
-                        (mUseStrictPhoneNumberComparation ? ", 1))" : ", 0, " + mMinMatch + "))"));
+                        (mUseStrictPhoneNumberComparation ? ", 1))" : ", 0))"));
         SQLiteQueryBuilder mmsQueryBuilder = new SQLiteQueryBuilder();
         SQLiteQueryBuilder smsQueryBuilder = new SQLiteQueryBuilder();
 
@@ -1035,7 +1040,7 @@
                 "FROM addr WHERE (address=" + escapedPhoneNumber +
                 " OR PHONE_NUMBERS_EQUAL(addr.address, " +
                 escapedPhoneNumber +
-                (mUseStrictPhoneNumberComparation ? ", 1))) " : ", 0, " + mMinMatch + "))) ") +
+                (mUseStrictPhoneNumberComparation ? ", 1))) " : ", 0))) ") +
                 "AS matching_addresses");
         smsQueryBuilder.setTables(smsTable);
 
diff --git a/src/com/android/providers/telephony/SQLiteTokenizer.java b/src/com/android/providers/telephony/SQLiteTokenizer.java
new file mode 100644
index 0000000..39749fb
--- /dev/null
+++ b/src/com/android/providers/telephony/SQLiteTokenizer.java
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.providers.telephony;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.function.Consumer;
+
+/**
+ * Copied from frameworks/base/core/java/android/database/sqlite/SQLiteTokenizer.java
+ *
+ * SQL Tokenizer specialized to extract tokens from SQL (snippets).
+ * <p>
+ * Based on sqlite3GetToken() in tokenzie.c in SQLite.
+ * <p>
+ * Source for v3.8.6 (which android uses): http://www.sqlite.org/src/artifact/ae45399d6252b4d7
+ * (Latest source as of now: http://www.sqlite.org/src/artifact/78c8085bc7af1922)
+ * <p>
+ * Also draft spec: http://www.sqlite.org/draft/tokenreq.html
+ */
+public class SQLiteTokenizer {
+    private static boolean isAlpha(char ch) {
+        return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || (ch == '_');
+    }
+
+    private static boolean isNum(char ch) {
+        return ('0' <= ch && ch <= '9');
+    }
+
+    private static boolean isAlNum(char ch) {
+        return isAlpha(ch) || isNum(ch);
+    }
+
+    private static boolean isAnyOf(char ch, String set) {
+        return set.indexOf(ch) >= 0;
+    }
+
+    private static IllegalArgumentException genException(String message, String sql) {
+        throw new IllegalArgumentException(message + " in '" + sql + "'");
+    }
+
+    private static char peek(String s, int index) {
+        return index < s.length() ? s.charAt(index) : '\0';
+    }
+
+    public static final int OPTION_NONE = 0;
+
+    /**
+     * Require that SQL contains only tokens; any comments or values will result
+     * in an exception.
+     */
+    public static final int OPTION_TOKEN_ONLY = 1 << 0;
+
+    /**
+     * Tokenize the given SQL, returning the list of each encountered token.
+     *
+     * @throws IllegalArgumentException if invalid SQL is encountered.
+     */
+    public static List<String> tokenize(@Nullable String sql, int options) {
+        final ArrayList<String> res = new ArrayList<>();
+        tokenize(sql, options, res::add);
+        return res;
+    }
+
+    /**
+     * Tokenize the given SQL, sending each encountered token to the given
+     * {@link Consumer}.
+     *
+     * @throws IllegalArgumentException if invalid SQL is encountered.
+     */
+    public static void tokenize(@Nullable String sql, int options, Consumer<String> checker) {
+        if (sql == null) {
+            return;
+        }
+        int pos = 0;
+        final int len = sql.length();
+        while (pos < len) {
+            final char ch = peek(sql, pos);
+
+            // Regular token.
+            if (isAlpha(ch)) {
+                final int start = pos;
+                pos++;
+                while (isAlNum(peek(sql, pos))) {
+                    pos++;
+                }
+                final int end = pos;
+
+                final String token = sql.substring(start, end);
+                checker.accept(token);
+
+                continue;
+            }
+
+            // Handle quoted tokens
+            if (isAnyOf(ch, "'\"`")) {
+                final int quoteStart = pos;
+                pos++;
+
+                for (;;) {
+                    pos = sql.indexOf(ch, pos);
+                    if (pos < 0) {
+                        throw genException("Unterminated quote", sql);
+                    }
+                    if (peek(sql, pos + 1) != ch) {
+                        break;
+                    }
+                    // Quoted quote char -- e.g. "abc""def" is a single string.
+                    pos += 2;
+                }
+                final int quoteEnd = pos;
+                pos++;
+
+                if (ch != '\'') {
+                    // Extract the token
+                    final String tokenUnquoted = sql.substring(quoteStart + 1, quoteEnd);
+
+                    final String token;
+
+                    // Unquote if needed. i.e. "aa""bb" -> aa"bb
+                    if (tokenUnquoted.indexOf(ch) >= 0) {
+                        token = tokenUnquoted.replaceAll(
+                                String.valueOf(ch) + ch, String.valueOf(ch));
+                    } else {
+                        token = tokenUnquoted;
+                    }
+                    checker.accept(token);
+                } else {
+                    if ((options &= OPTION_TOKEN_ONLY) != 0) {
+                        throw genException("Non-token detected", sql);
+                    }
+                }
+                continue;
+            }
+            // Handle tokens enclosed in [...]
+            if (ch == '[') {
+                final int quoteStart = pos;
+                pos++;
+
+                pos = sql.indexOf(']', pos);
+                if (pos < 0) {
+                    throw genException("Unterminated quote", sql);
+                }
+                final int quoteEnd = pos;
+                pos++;
+
+                final String token = sql.substring(quoteStart + 1, quoteEnd);
+
+                checker.accept(token);
+                continue;
+            }
+            if ((options &= OPTION_TOKEN_ONLY) != 0) {
+                throw genException("Non-token detected", sql);
+            }
+
+            // Detect comments.
+            if (ch == '-' && peek(sql, pos + 1) == '-') {
+                pos += 2;
+                pos = sql.indexOf('\n', pos);
+                if (pos < 0) {
+                    // We disallow strings ending in an inline comment.
+                    throw genException("Unterminated comment", sql);
+                }
+                pos++;
+
+                continue;
+            }
+            if (ch == '/' && peek(sql, pos + 1) == '*') {
+                pos += 2;
+                pos = sql.indexOf("*/", pos);
+                if (pos < 0) {
+                    throw genException("Unterminated comment", sql);
+                }
+                pos += 2;
+
+                continue;
+            }
+
+            // Semicolon is never allowed.
+            if (ch == ';') {
+                throw genException("Semicolon is not allowed", sql);
+            }
+
+            // For this purpose, we can simply ignore other characters.
+            // (Note it doesn't handle the X'' literal properly and reports this X as a token,
+            // but that should be fine...)
+            pos++;
+        }
+    }
+
+    /**
+     * Test if given token is a
+     * <a href="https://www.sqlite.org/lang_keywords.html">SQLite reserved
+     * keyword</a>.
+     */
+    public static boolean isKeyword(@NonNull String token) {
+        switch (token.toUpperCase(Locale.US)) {
+            case "ABORT": case "ACTION": case "ADD": case "AFTER":
+            case "ALL": case "ALTER": case "ANALYZE": case "AND":
+            case "AS": case "ASC": case "ATTACH": case "AUTOINCREMENT":
+            case "BEFORE": case "BEGIN": case "BETWEEN": case "BINARY":
+            case "BY": case "CASCADE": case "CASE": case "CAST":
+            case "CHECK": case "COLLATE": case "COLUMN": case "COMMIT":
+            case "CONFLICT": case "CONSTRAINT": case "CREATE": case "CROSS":
+            case "CURRENT": case "CURRENT_DATE": case "CURRENT_TIME": case "CURRENT_TIMESTAMP":
+            case "DATABASE": case "DEFAULT": case "DEFERRABLE": case "DEFERRED":
+            case "DELETE": case "DESC": case "DETACH": case "DISTINCT":
+            case "DO": case "DROP": case "EACH": case "ELSE":
+            case "END": case "ESCAPE": case "EXCEPT": case "EXCLUDE":
+            case "EXCLUSIVE": case "EXISTS": case "EXPLAIN": case "FAIL":
+            case "FILTER": case "FOLLOWING": case "FOR": case "FOREIGN":
+            case "FROM": case "FULL": case "GLOB": case "GROUP":
+            case "GROUPS": case "HAVING": case "IF": case "IGNORE":
+            case "IMMEDIATE": case "IN": case "INDEX": case "INDEXED":
+            case "INITIALLY": case "INNER": case "INSERT": case "INSTEAD":
+            case "INTERSECT": case "INTO": case "IS": case "ISNULL":
+            case "JOIN": case "KEY": case "LEFT": case "LIKE":
+            case "LIMIT": case "MATCH": case "NATURAL": case "NO":
+            case "NOCASE": case "NOT": case "NOTHING": case "NOTNULL":
+            case "NULL": case "OF": case "OFFSET": case "ON":
+            case "OR": case "ORDER": case "OTHERS": case "OUTER":
+            case "OVER": case "PARTITION": case "PLAN": case "PRAGMA":
+            case "PRECEDING": case "PRIMARY": case "QUERY": case "RAISE":
+            case "RANGE": case "RECURSIVE": case "REFERENCES": case "REGEXP":
+            case "REINDEX": case "RELEASE": case "RENAME": case "REPLACE":
+            case "RESTRICT": case "RIGHT": case "ROLLBACK": case "ROW":
+            case "ROWS": case "RTRIM": case "SAVEPOINT": case "SELECT":
+            case "SET": case "TABLE": case "TEMP": case "TEMPORARY":
+            case "THEN": case "TIES": case "TO": case "TRANSACTION":
+            case "TRIGGER": case "UNBOUNDED": case "UNION": case "UNIQUE":
+            case "UPDATE": case "USING": case "VACUUM": case "VALUES":
+            case "VIEW": case "VIRTUAL": case "WHEN": case "WHERE":
+            case "WINDOW": case "WITH": case "WITHOUT":
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * Test if given token is a
+     * <a href="https://www.sqlite.org/lang_corefunc.html">SQLite reserved
+     * function</a>.
+     */
+    public static boolean isFunction(@NonNull String token) {
+        switch (token.toLowerCase(Locale.US)) {
+            case "abs": case "avg": case "char": case "coalesce":
+            case "count": case "glob": case "group_concat": case "hex":
+            case "ifnull": case "instr": case "length": case "like":
+            case "likelihood": case "likely": case "lower": case "ltrim":
+            case "max": case "min": case "nullif": case "random":
+            case "randomblob": case "replace": case "round": case "rtrim":
+            case "substr": case "sum": case "total": case "trim":
+            case "typeof": case "unicode": case "unlikely": case "upper":
+            case "zeroblob":
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * Test if given token is a
+     * <a href="https://www.sqlite.org/datatype3.html">SQLite reserved type</a>.
+     */
+    public static boolean isType(@NonNull String token) {
+        switch (token.toUpperCase(Locale.US)) {
+            case "INT": case "INTEGER": case "TINYINT": case "SMALLINT":
+            case "MEDIUMINT": case "BIGINT": case "INT2": case "INT8":
+            case "CHARACTER": case "VARCHAR": case "NCHAR": case "NVARCHAR":
+            case "TEXT": case "CLOB": case "BLOB": case "REAL":
+            case "DOUBLE": case "FLOAT": case "NUMERIC": case "DECIMAL":
+            case "BOOLEAN": case "DATE": case "DATETIME":
+                return true;
+            default:
+                return false;
+        }
+    }
+}
diff --git a/src/com/android/providers/telephony/SmsProvider.java b/src/com/android/providers/telephony/SmsProvider.java
index ddfa14c..1213c37 100644
--- a/src/com/android/providers/telephony/SmsProvider.java
+++ b/src/com/android/providers/telephony/SmsProvider.java
@@ -16,8 +16,6 @@
 
 package com.android.providers.telephony;
 
-import static com.android.internal.telephony.SmsResponse.NO_ERROR_CODE;
-
 import android.annotation.NonNull;
 import android.app.AppOpsManager;
 import android.content.ContentProvider;
@@ -77,7 +75,7 @@
         // N.B.: These columns must appear in the same order as the
         // calls to add appear in convertIccToSms.
         "service_center_address",       // getServiceCenterAddress
-        "address",                      // getDisplayOriginatingAddress or getRecipientAddress
+        "address",                      // getDisplayOriginatingAddress
         "message_class",                // getMessageClass
         "body",                         // getDisplayMessageBody
         "date",                         // getTimestampMillis
@@ -85,9 +83,9 @@
         "index_on_icc",                 // getIndexOnIcc
         "is_status_report",             // isStatusReportMessage
         "transport_type",               // Always "sms".
-        "type",                         // depend on getStatusOnIcc
+        "type",                         // Always MESSAGE_TYPE_ALL.
         "locked",                       // Always 0 (false).
-        "error_code",                   // Always -1 (NO_ERROR_CODE), previously it was 0 always.
+        "error_code",                   // Always 0
         "_id"
     };
 
@@ -124,6 +122,16 @@
         final String smsTable = getSmsTable(accessRestricted);
         SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
 
+        // If access is restricted, we don't allow subqueries in the query.
+        if (accessRestricted) {
+            try {
+                SqlQueryChecker.checkQueryParametersForSubqueries(projectionIn, selection, sort);
+            } catch (IllegalArgumentException e) {
+                Log.w(TAG, "Query rejected: " + e.getMessage());
+                return null;
+            }
+        }
+
         // Generate the body of the query.
         int match = sURLMatcher.match(url);
         SQLiteDatabase db = getReadableDatabase(match);
@@ -294,39 +302,21 @@
     }
 
     private Object[] convertIccToSms(SmsMessage message, int id) {
-        int statusOnIcc = message.getStatusOnIcc();
-        int type = Sms.MESSAGE_TYPE_ALL;
-        switch (statusOnIcc) {
-            case SmsManager.STATUS_ON_ICC_READ:
-            case SmsManager.STATUS_ON_ICC_UNREAD:
-                type = Sms.MESSAGE_TYPE_INBOX;
-                break;
-            case SmsManager.STATUS_ON_ICC_SENT:
-                type = Sms.MESSAGE_TYPE_SENT;
-                break;
-            case SmsManager.STATUS_ON_ICC_UNSENT:
-                type = Sms.MESSAGE_TYPE_OUTBOX;
-                break;
-        }
         // N.B.: These calls must appear in the same order as the
         // columns appear in ICC_COLUMNS.
         Object[] row = new Object[13];
         row[0] = message.getServiceCenterAddress();
-        row[1] =
-                (type == Sms.MESSAGE_TYPE_INBOX)
-                        ? message.getDisplayOriginatingAddress()
-                        : message.getRecipientAddress();
-
+        row[1] = message.getDisplayOriginatingAddress();
         row[2] = String.valueOf(message.getMessageClass());
         row[3] = message.getDisplayMessageBody();
         row[4] = message.getTimestampMillis();
-        row[5] = statusOnIcc;
+        row[5] = Sms.STATUS_NONE;
         row[6] = message.getIndexOnIcc();
         row[7] = message.isStatusReportMessage();
         row[8] = "sms";
-        row[9] = type;
+        row[9] = TextBasedSmsColumns.MESSAGE_TYPE_ALL;
         row[10] = 0;      // locked
-        row[11] = NO_ERROR_CODE;
+        row[11] = 0;      // error_code
         row[12] = id;
         return row;
     }
@@ -652,12 +642,7 @@
             db.insert(TABLE_WORDS, Telephony.MmsSms.WordsTable.INDEXED_TEXT, cv);
         }
         if (rowID > 0) {
-            Uri uri = null;
-            if (table == TABLE_SMS) {
-                uri = Uri.withAppendedPath(Sms.CONTENT_URI, String.valueOf(rowID));
-            } else {
-                uri = Uri.withAppendedPath(url, String.valueOf(rowID));
-            }
+            Uri uri = Uri.withAppendedPath(url, String.valueOf(rowID));
             if (Log.isLoggable(TAG, Log.VERBOSE)) {
                 Log.d(TAG, "insert " + uri + " succeeded");
             }
diff --git a/src/com/android/providers/telephony/SqlQueryChecker.java b/src/com/android/providers/telephony/SqlQueryChecker.java
new file mode 100644
index 0000000..a98dd25
--- /dev/null
+++ b/src/com/android/providers/telephony/SqlQueryChecker.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.providers.telephony;
+
+public class SqlQueryChecker {
+    private static final String SELECT_TOKEN = "select";
+
+    static void checkToken(String token) {
+        if (SELECT_TOKEN.equals(token.toLowerCase())) {
+            throw new IllegalArgumentException("SELECT token not allowed in query");
+        }
+    }
+
+    /**
+     * Check the query parameters to see if they contain subqueries. Throws an
+     * {@link IllegalArgumentException} if they do. See
+     * {@link android.content.ContentProvider#query} for the definitions of the arguments.
+     */
+    static void checkQueryParametersForSubqueries(String[] projection,
+            String selection, String sortOrder) {
+        if (projection != null) {
+            for (String proj : projection) {
+                SQLiteTokenizer.tokenize(proj, SQLiteTokenizer.OPTION_NONE,
+                        SqlQueryChecker::checkToken);
+            }
+        }
+        SQLiteTokenizer.tokenize(selection, SQLiteTokenizer.OPTION_NONE,
+                SqlQueryChecker::checkToken);
+        SQLiteTokenizer.tokenize(sortOrder, SQLiteTokenizer.OPTION_NONE,
+                SqlQueryChecker::checkToken);
+    }
+}
diff --git a/src/com/android/providers/telephony/SqlTokenFinder.java b/src/com/android/providers/telephony/SqlTokenFinder.java
new file mode 100644
index 0000000..9be49fe
--- /dev/null
+++ b/src/com/android/providers/telephony/SqlTokenFinder.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.providers.telephony;
+
+import android.annotation.Nullable;
+
+import java.util.function.Consumer;
+
+/**
+ * Simple SQL parser to check statements for usage of prohibited/sensitive fields. Mostly copied
+ * from
+ * packages/providers/ContactsProvider/src/com/android/providers/contacts/sqlite/SqlChecker.java
+ */
+public class SqlTokenFinder{
+    private static boolean isAlpha(char ch) {
+        return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || (ch == '_');
+    }
+
+    private static boolean isNum(char ch) {
+        return ('0' <= ch && ch <= '9');
+    }
+
+    private static boolean isAlNum(char ch) {
+        return isAlpha(ch) || isNum(ch);
+    }
+
+    private static boolean isAnyOf(char ch, String set) {
+        return set.indexOf(ch) >= 0;
+    }
+
+    private static char peek(String s, int index) {
+        return index < s.length() ? s.charAt(index) : '\0';
+    }
+
+    /**
+     * SQL Tokenizer specialized to extract tokens from SQL (snippets).
+     *
+     * Based on sqlite3GetToken() in tokenzie.c in SQLite.
+     *
+     * Source for v3.8.6 (which android uses): http://www.sqlite.org/src/artifact/ae45399d6252b4d7
+     * (Latest source as of now: http://www.sqlite.org/src/artifact/78c8085bc7af1922)
+     *
+     * Also draft spec: http://www.sqlite.org/draft/tokenreq.html
+     */
+    public static void findTokens(@Nullable String sql, Consumer<String> checker) {
+        if (sql == null) {
+            return;
+        }
+        int pos = 0;
+        final int len = sql.length();
+        while (pos < len) {
+            final char ch = peek(sql, pos);
+
+            // Regular token.
+            if (isAlpha(ch)) {
+                final int start = pos;
+                pos++;
+                while (isAlNum(peek(sql, pos))) {
+                    pos++;
+                }
+                final int end = pos;
+
+                final String token = sql.substring(start, end);
+                checker.accept(token);
+
+                continue;
+            }
+
+            // Handle quoted tokens
+            if (isAnyOf(ch, "'\"`")) {
+                final int quoteStart = pos;
+                pos++;
+
+                for (;;) {
+                    pos = sql.indexOf(ch, pos);
+                    if (pos < 0) {
+                        throw new IllegalArgumentException("Unterminated quote in" + sql);
+                    }
+                    if (peek(sql, pos + 1) != ch) {
+                        break;
+                    }
+                    // Quoted quote char -- e.g. "abc""def" is a single string.
+                    pos += 2;
+                }
+                final int quoteEnd = pos;
+                pos++;
+
+                if (ch != '\'') {
+                    // Extract the token
+                    final String tokenUnquoted = sql.substring(quoteStart + 1, quoteEnd);
+
+                    final String token;
+
+                    // Unquote if needed. i.e. "aa""bb" -> aa"bb
+                    if (tokenUnquoted.indexOf(ch) >= 0) {
+                        token = tokenUnquoted.replaceAll(
+                                String.valueOf(ch) + ch, String.valueOf(ch));
+                    } else {
+                        token = tokenUnquoted;
+                    }
+                    checker.accept(token);
+                }
+                continue;
+            }
+            // Handle tokens enclosed in [...]
+            if (ch == '[') {
+                final int quoteStart = pos;
+                pos++;
+
+                pos = sql.indexOf(']', pos);
+                if (pos < 0) {
+                    throw new IllegalArgumentException("Unterminated quote in" + sql);
+                }
+                final int quoteEnd = pos;
+                pos++;
+
+                final String token = sql.substring(quoteStart + 1, quoteEnd);
+
+                checker.accept(token);
+                continue;
+            }
+
+            // Detect comments.
+            if (ch == '-' && peek(sql, pos + 1) == '-') {
+                pos += 2;
+                pos = sql.indexOf('\n', pos);
+                if (pos < 0) {
+                    // We disallow strings ending in an inline comment.
+                    throw new IllegalArgumentException("Unterminated comment in" + sql);
+                }
+                pos++;
+
+                continue;
+            }
+            if (ch == '/' && peek(sql, pos + 1) == '*') {
+                pos += 2;
+                pos = sql.indexOf("*/", pos);
+                if (pos < 0) {
+                    throw new IllegalArgumentException("Unterminated comment in" + sql);
+                }
+                pos += 2;
+
+                continue;
+            }
+
+            // Semicolon is never allowed.
+            if (ch == ';') {
+                throw new IllegalArgumentException("Semicolon is not allowed in " + sql);
+            }
+
+            // For this purpose, we can simply ignore other characters.
+            // (Note it doesn't handle the X'' literal properly and reports this X as a token,
+            // but that should be fine...)
+            pos++;
+        }
+    }
+}
diff --git a/src/com/android/providers/telephony/TelephonyProvider.java b/src/com/android/providers/telephony/TelephonyProvider.java
index 0edbffc..c564a07 100644
--- a/src/com/android/providers/telephony/TelephonyProvider.java
+++ b/src/com/android/providers/telephony/TelephonyProvider.java
@@ -106,6 +106,7 @@
 import android.telephony.TelephonyManager;
 import android.telephony.data.ApnSetting;
 import android.text.TextUtils;
+import android.util.EventLog;
 import android.util.Log;
 import android.util.Pair;
 import android.util.Xml;
@@ -206,6 +207,10 @@
     private static final String DEFAULT_PROTOCOL = "IP";
     private static final String DEFAULT_ROAMING_PROTOCOL = "IP";
 
+    // Used to check if certain queries contain subqueries that may attempt to access sensitive
+    // fields in the carriers db.
+    private static final String SQL_SELECT_TOKEN = "select";
+
     private static final UriMatcher s_urlMatcher = new UriMatcher(UriMatcher.NO_MATCH);
 
     private static final ContentValues s_currentNullMap;
@@ -479,41 +484,7 @@
     }
 
     @VisibleForTesting
-    public static int getVersion(Context context) {
-        if (VDBG) log("getVersion:+");
-        // Get the database version, combining a static schema version and the XML version
-        Resources r = context.getResources();
-        if (r == null) {
-            loge("resources=null, return version=" + Integer.toHexString(DATABASE_VERSION));
-            return DATABASE_VERSION;
-        }
-        XmlResourceParser parser = r.getXml(com.android.internal.R.xml.apns);
-        try {
-            XmlUtils.beginDocument(parser, "apns");
-            int publicversion = Integer.parseInt(parser.getAttributeValue(null, "version"));
-            int version = DATABASE_VERSION | publicversion;
-            if (VDBG) log("getVersion:- version=0x" + Integer.toHexString(version));
-            return version;
-        } catch (Exception e) {
-            loge("Can't get version of APN database" + e + " return version=" +
-                    Integer.toHexString(DATABASE_VERSION));
-            return DATABASE_VERSION;
-        } finally {
-            parser.close();
-        }
-    }
-
-    static public ContentValues setDefaultValue(ContentValues values) {
-        if (!values.containsKey(SUBSCRIPTION_ID)) {
-            int subId = SubscriptionManager.getDefaultSubscriptionId();
-            values.put(SUBSCRIPTION_ID, subId);
-        }
-
-        return values;
-    }
-
-    @VisibleForTesting
-    public class DatabaseHelper extends SQLiteOpenHelper {
+    public static class DatabaseHelper extends SQLiteOpenHelper {
         // Context to access resources with
         private Context mContext;
 
@@ -530,6 +501,31 @@
             setWriteAheadLoggingEnabled(false);
         }
 
+        @VisibleForTesting
+        public static int getVersion(Context context) {
+            if (VDBG) log("getVersion:+");
+            // Get the database version, combining a static schema version and the XML version
+            Resources r = context.getResources();
+            if (r == null) {
+                loge("resources=null, return version=" + Integer.toHexString(DATABASE_VERSION));
+                return DATABASE_VERSION;
+            }
+            XmlResourceParser parser = r.getXml(com.android.internal.R.xml.apns);
+            try {
+                XmlUtils.beginDocument(parser, "apns");
+                int publicversion = Integer.parseInt(parser.getAttributeValue(null, "version"));
+                int version = DATABASE_VERSION | publicversion;
+                if (VDBG) log("getVersion:- version=0x" + Integer.toHexString(version));
+                return version;
+            } catch (Exception e) {
+                loge("Can't get version of APN database" + e + " return version=" +
+                        Integer.toHexString(DATABASE_VERSION));
+                return DATABASE_VERSION;
+            } finally {
+                parser.close();
+            }
+        }
+
         @Override
         public void onCreate(SQLiteDatabase db) {
             if (DBG) log("dbh.onCreate:+ db=" + db);
@@ -609,7 +605,7 @@
             return checksum;
         }
 
-        private byte[] toByteArray(InputStream input) throws IOException {
+        private static byte[] toByteArray(InputStream input) throws IOException {
             byte[] buffer = new byte[128];
             int bytesRead;
             ByteArrayOutputStream output = new ByteArrayOutputStream();
@@ -767,8 +763,6 @@
                 log("dbh.onUpgrade:+ db=" + db + " oldV=" + oldVersion + " newV=" + newVersion);
             }
 
-            deletePreferredApnId(mContext);
-
             if (oldVersion < (5 << 16 | 6)) {
                 // 5 << 16 is the Database version and 6 in the xml version.
 
@@ -1884,7 +1878,7 @@
                                         e + " for cv " + cv);
                             // Insertion failed which could be due to a conflict. Check if that is
                             // the case and merge the entries
-                            Cursor oldRow = selectConflictingRow(db,
+                            Cursor oldRow = DatabaseHelper.selectConflictingRow(db,
                                     CARRIERS_TABLE_TMP, cv);
                             if (oldRow != null) {
                                 ContentValues mergedValues = new ContentValues();
@@ -2117,6 +2111,15 @@
             }
         }
 
+        static public ContentValues setDefaultValue(ContentValues values) {
+            if (!values.containsKey(SUBSCRIPTION_ID)) {
+                int subId = SubscriptionManager.getDefaultSubscriptionId();
+                values.put(SUBSCRIPTION_ID, subId);
+            }
+
+            return values;
+        }
+
         private void insertAddingDefaults(SQLiteDatabase db, ContentValues row) {
             row = setDefaultValue(row);
             try {
@@ -2159,264 +2162,264 @@
                 }
             }
         }
-    }
 
-    public static void mergeFieldsAndUpdateDb(SQLiteDatabase db, String table, Cursor oldRow,
-            ContentValues newRow, ContentValues mergedValues,
-            boolean onUpgrade, Context context) {
-        if (newRow.containsKey(TYPE)) {
-            // Merge the types
-            String oldType = oldRow.getString(oldRow.getColumnIndex(TYPE));
-            String newType = newRow.getAsString(TYPE);
+        public static void mergeFieldsAndUpdateDb(SQLiteDatabase db, String table, Cursor oldRow,
+                                                  ContentValues newRow, ContentValues mergedValues,
+                                                  boolean onUpgrade, Context context) {
+            if (newRow.containsKey(TYPE)) {
+                // Merge the types
+                String oldType = oldRow.getString(oldRow.getColumnIndex(TYPE));
+                String newType = newRow.getAsString(TYPE);
 
-            if (!oldType.equalsIgnoreCase(newType)) {
-                if (oldType.equals("") || newType.equals("")) {
-                    newRow.put(TYPE, "");
-                } else {
-                    String[] oldTypes = oldType.toLowerCase().split(",");
-                    String[] newTypes = newType.toLowerCase().split(",");
+                if (!oldType.equalsIgnoreCase(newType)) {
+                    if (oldType.equals("") || newType.equals("")) {
+                        newRow.put(TYPE, "");
+                    } else {
+                        String[] oldTypes = oldType.toLowerCase().split(",");
+                        String[] newTypes = newType.toLowerCase().split(",");
 
-                    if (VDBG) {
-                        log("mergeFieldsAndUpdateDb: Calling separateRowsNeeded() oldType=" +
-                                oldType + " old bearer=" + oldRow.getInt(oldRow.getColumnIndex(
-                                BEARER_BITMASK)) +  " old networkType=" +
-                                oldRow.getInt(oldRow.getColumnIndex(NETWORK_TYPE_BITMASK)) +
-                                " old profile_id=" + oldRow.getInt(oldRow.getColumnIndex(
-                                PROFILE_ID)) + " newRow " + newRow);
-                    }
-
-                    // If separate rows are needed, do not need to merge any further
-                    if (separateRowsNeeded(db, table, oldRow, newRow, context, oldTypes,
-                            newTypes)) {
-                        if (VDBG) log("mergeFieldsAndUpdateDb: separateRowsNeeded() returned " +
-                                "true");
-                        return;
-                    }
-
-                    // Merge the 2 types
-                    ArrayList<String> mergedTypes = new ArrayList<String>();
-                    mergedTypes.addAll(Arrays.asList(oldTypes));
-                    for (String s : newTypes) {
-                        if (!mergedTypes.contains(s.trim())) {
-                            mergedTypes.add(s);
+                        if (VDBG) {
+                            log("mergeFieldsAndUpdateDb: Calling separateRowsNeeded() oldType=" +
+                                    oldType + " old bearer=" + oldRow.getInt(oldRow.getColumnIndex(
+                                    BEARER_BITMASK)) +  " old networkType=" +
+                                    oldRow.getInt(oldRow.getColumnIndex(NETWORK_TYPE_BITMASK)) +
+                                    " old profile_id=" + oldRow.getInt(oldRow.getColumnIndex(
+                                    PROFILE_ID)) + " newRow " + newRow);
                         }
+
+                        // If separate rows are needed, do not need to merge any further
+                        if (separateRowsNeeded(db, table, oldRow, newRow, context, oldTypes,
+                                newTypes)) {
+                            if (VDBG) log("mergeFieldsAndUpdateDb: separateRowsNeeded() returned " +
+                                    "true");
+                            return;
+                        }
+
+                        // Merge the 2 types
+                        ArrayList<String> mergedTypes = new ArrayList<String>();
+                        mergedTypes.addAll(Arrays.asList(oldTypes));
+                        for (String s : newTypes) {
+                            if (!mergedTypes.contains(s.trim())) {
+                                mergedTypes.add(s);
+                            }
+                        }
+                        StringBuilder mergedType = new StringBuilder();
+                        for (int i = 0; i < mergedTypes.size(); i++) {
+                            mergedType.append((i == 0 ? "" : ",") + mergedTypes.get(i));
+                        }
+                        newRow.put(TYPE, mergedType.toString());
                     }
-                    StringBuilder mergedType = new StringBuilder();
-                    for (int i = 0; i < mergedTypes.size(); i++) {
-                        mergedType.append((i == 0 ? "" : ",") + mergedTypes.get(i));
+                }
+                mergedValues.put(TYPE, newRow.getAsString(TYPE));
+            }
+
+            if (newRow.containsKey(BEARER_BITMASK)) {
+                int oldBearer = oldRow.getInt(oldRow.getColumnIndex(BEARER_BITMASK));
+                int newBearer = newRow.getAsInteger(BEARER_BITMASK);
+                if (oldBearer != newBearer) {
+                    if (oldBearer == 0 || newBearer == 0) {
+                        newRow.put(BEARER_BITMASK, 0);
+                    } else {
+                        newRow.put(BEARER_BITMASK, (oldBearer | newBearer));
                     }
-                    newRow.put(TYPE, mergedType.toString());
                 }
+                mergedValues.put(BEARER_BITMASK, newRow.getAsInteger(BEARER_BITMASK));
             }
-            mergedValues.put(TYPE, newRow.getAsString(TYPE));
+
+            if (newRow.containsKey(NETWORK_TYPE_BITMASK)) {
+                int oldBitmask = oldRow.getInt(oldRow.getColumnIndex(NETWORK_TYPE_BITMASK));
+                int newBitmask = newRow.getAsInteger(NETWORK_TYPE_BITMASK);
+                if (oldBitmask != newBitmask) {
+                    if (oldBitmask == 0 || newBitmask == 0) {
+                        newRow.put(NETWORK_TYPE_BITMASK, 0);
+                    } else {
+                        newRow.put(NETWORK_TYPE_BITMASK, (oldBitmask | newBitmask));
+                    }
+                }
+                mergedValues.put(NETWORK_TYPE_BITMASK, newRow.getAsInteger(NETWORK_TYPE_BITMASK));
+            }
+
+            if (newRow.containsKey(BEARER_BITMASK)
+                    && newRow.containsKey(NETWORK_TYPE_BITMASK)) {
+                syncBearerBitmaskAndNetworkTypeBitmask(mergedValues);
+            }
+
+            if (!onUpgrade) {
+                // Do not overwrite a carrier or user edit with EDITED=UNEDITED
+                if (newRow.containsKey(EDITED_STATUS)) {
+                    int oldEdited = oldRow.getInt(oldRow.getColumnIndex(EDITED_STATUS));
+                    int newEdited = newRow.getAsInteger(EDITED_STATUS);
+                    if (newEdited == UNEDITED && (oldEdited == CARRIER_EDITED
+                                || oldEdited == CARRIER_DELETED
+                                || oldEdited == CARRIER_DELETED_BUT_PRESENT_IN_XML
+                                || oldEdited == USER_EDITED
+                                || oldEdited == USER_DELETED
+                                || oldEdited == USER_DELETED_BUT_PRESENT_IN_XML)) {
+                        newRow.remove(EDITED_STATUS);
+                    }
+                }
+                mergedValues.putAll(newRow);
+            }
+
+            if (mergedValues.size() > 0) {
+                db.update(table, mergedValues, "_id=" + oldRow.getInt(oldRow.getColumnIndex("_id")),
+                        null);
+            }
         }
 
-        if (newRow.containsKey(BEARER_BITMASK)) {
-            int oldBearer = oldRow.getInt(oldRow.getColumnIndex(BEARER_BITMASK));
-            int newBearer = newRow.getAsInteger(BEARER_BITMASK);
-            if (oldBearer != newBearer) {
-                if (oldBearer == 0 || newBearer == 0) {
-                    newRow.put(BEARER_BITMASK, 0);
+        private static boolean separateRowsNeeded(SQLiteDatabase db, String table, Cursor oldRow,
+                                                  ContentValues newRow, Context context,
+                                                  String[] oldTypes, String[] newTypes) {
+            // If this APN falls under persist_apns_for_plmn, and the
+            // only difference between old type and new type is that one has dun, and
+            // the APNs have profile_id 0 or not set, then set the profile_id to 1 for
+            // the dun APN/remove dun from type. This will ensure both oldRow and newRow exist
+            // separately in db.
+
+            boolean match = false;
+
+            // Check if APN falls under persist_apns_for_plmn
+            if (context.getResources() != null) {
+                String[] persistApnsForPlmns = context.getResources().getStringArray(
+                        R.array.persist_apns_for_plmn);
+                for (String s : persistApnsForPlmns) {
+                    if (s.equalsIgnoreCase(newRow.getAsString(NUMERIC))) {
+                        match = true;
+                        break;
+                    }
+                }
+            } else {
+                loge("separateRowsNeeded: resources=null");
+            }
+
+            if (!match) return false;
+
+            // APN falls under persist_apns_for_plmn
+            // Check if only difference between old type and new type is that
+            // one has dun
+            ArrayList<String> oldTypesAl = new ArrayList<String>(Arrays.asList(oldTypes));
+            ArrayList<String> newTypesAl = new ArrayList<String>(Arrays.asList(newTypes));
+            ArrayList<String> listWithDun = null;
+            ArrayList<String> listWithoutDun = null;
+            boolean dunInOld = false;
+            if (oldTypesAl.size() == newTypesAl.size() + 1) {
+                listWithDun = oldTypesAl;
+                listWithoutDun = newTypesAl;
+                dunInOld = true;
+            } else if (oldTypesAl.size() + 1 == newTypesAl.size()) {
+                listWithDun = newTypesAl;
+                listWithoutDun = oldTypesAl;
+            } else {
+                return false;
+            }
+
+            if (listWithDun.contains("dun") && !listWithoutDun.contains("dun")) {
+                listWithoutDun.add("dun");
+                if (!listWithDun.containsAll(listWithoutDun)) {
+                    return false;
+                }
+
+                // Only difference between old type and new type is that
+                // one has dun
+                // Check if profile_id is 0/not set
+                if (oldRow.getInt(oldRow.getColumnIndex(PROFILE_ID)) == 0) {
+                    if (dunInOld) {
+                        // Update oldRow to remove dun from its type field
+                        ContentValues updateOldRow = new ContentValues();
+                        StringBuilder sb = new StringBuilder();
+                        boolean first = true;
+                        for (String s : listWithDun) {
+                            if (!s.equalsIgnoreCase("dun")) {
+                                sb.append(first ? s : "," + s);
+                                first = false;
+                            }
+                        }
+                        String updatedType = sb.toString();
+                        if (VDBG) {
+                            log("separateRowsNeeded: updating type in oldRow to " + updatedType);
+                        }
+                        updateOldRow.put(TYPE, updatedType);
+                        db.update(table, updateOldRow,
+                                "_id=" + oldRow.getInt(oldRow.getColumnIndex("_id")), null);
+                        return true;
+                    } else {
+                        if (VDBG) log("separateRowsNeeded: adding profile id 1 to newRow");
+                        // Update newRow to set profile_id to 1
+                        newRow.put(PROFILE_ID, new Integer(1));
+                    }
                 } else {
-                    newRow.put(BEARER_BITMASK, (oldBearer | newBearer));
+                    return false;
+                }
+
+                // If match was found, both oldRow and newRow need to exist
+                // separately in db. Add newRow to db.
+                try {
+                    db.insertWithOnConflict(table, null, newRow, SQLiteDatabase.CONFLICT_REPLACE);
+                    if (VDBG) log("separateRowsNeeded: added newRow with profile id 1 to db");
+                    return true;
+                } catch (SQLException e) {
+                    loge("Exception on trying to add new row after updating profile_id");
                 }
             }
-            mergedValues.put(BEARER_BITMASK, newRow.getAsInteger(BEARER_BITMASK));
-        }
 
-        if (newRow.containsKey(NETWORK_TYPE_BITMASK)) {
-            int oldBitmask = oldRow.getInt(oldRow.getColumnIndex(NETWORK_TYPE_BITMASK));
-            int newBitmask = newRow.getAsInteger(NETWORK_TYPE_BITMASK);
-            if (oldBitmask != newBitmask) {
-                if (oldBitmask == 0 || newBitmask == 0) {
-                    newRow.put(NETWORK_TYPE_BITMASK, 0);
-                } else {
-                    newRow.put(NETWORK_TYPE_BITMASK, (oldBitmask | newBitmask));
-                }
-            }
-            mergedValues.put(NETWORK_TYPE_BITMASK, newRow.getAsInteger(NETWORK_TYPE_BITMASK));
-        }
-
-        if (newRow.containsKey(BEARER_BITMASK)
-                && newRow.containsKey(NETWORK_TYPE_BITMASK)) {
-            syncBearerBitmaskAndNetworkTypeBitmask(mergedValues);
-        }
-
-        if (!onUpgrade) {
-            // Do not overwrite a carrier or user edit with EDITED=UNEDITED
-            if (newRow.containsKey(EDITED_STATUS)) {
-                int oldEdited = oldRow.getInt(oldRow.getColumnIndex(EDITED_STATUS));
-                int newEdited = newRow.getAsInteger(EDITED_STATUS);
-                if (newEdited == UNEDITED && (oldEdited == CARRIER_EDITED
-                        || oldEdited == CARRIER_DELETED
-                        || oldEdited == CARRIER_DELETED_BUT_PRESENT_IN_XML
-                        || oldEdited == USER_EDITED
-                        || oldEdited == USER_DELETED
-                        || oldEdited == USER_DELETED_BUT_PRESENT_IN_XML)) {
-                    newRow.remove(EDITED_STATUS);
-                }
-            }
-            mergedValues.putAll(newRow);
-        }
-
-        if (mergedValues.size() > 0) {
-            db.update(table, mergedValues, "_id=" + oldRow.getInt(oldRow.getColumnIndex("_id")),
-                    null);
-        }
-    }
-
-    private static boolean separateRowsNeeded(SQLiteDatabase db, String table, Cursor oldRow,
-            ContentValues newRow, Context context,
-            String[] oldTypes, String[] newTypes) {
-        // If this APN falls under persist_apns_for_plmn, and the
-        // only difference between old type and new type is that one has dun, and
-        // the APNs have profile_id 0 or not set, then set the profile_id to 1 for
-        // the dun APN/remove dun from type. This will ensure both oldRow and newRow exist
-        // separately in db.
-
-        boolean match = false;
-
-        // Check if APN falls under persist_apns_for_plmn
-        if (context.getResources() != null) {
-            String[] persistApnsForPlmns = context.getResources().getStringArray(
-                    R.array.persist_apns_for_plmn);
-            for (String s : persistApnsForPlmns) {
-                if (s.equalsIgnoreCase(newRow.getAsString(NUMERIC))) {
-                    match = true;
-                    break;
-                }
-            }
-        } else {
-            loge("separateRowsNeeded: resources=null");
-        }
-
-        if (!match) return false;
-
-        // APN falls under persist_apns_for_plmn
-        // Check if only difference between old type and new type is that
-        // one has dun
-        ArrayList<String> oldTypesAl = new ArrayList<String>(Arrays.asList(oldTypes));
-        ArrayList<String> newTypesAl = new ArrayList<String>(Arrays.asList(newTypes));
-        ArrayList<String> listWithDun = null;
-        ArrayList<String> listWithoutDun = null;
-        boolean dunInOld = false;
-        if (oldTypesAl.size() == newTypesAl.size() + 1) {
-            listWithDun = oldTypesAl;
-            listWithoutDun = newTypesAl;
-            dunInOld = true;
-        } else if (oldTypesAl.size() + 1 == newTypesAl.size()) {
-            listWithDun = newTypesAl;
-            listWithoutDun = oldTypesAl;
-        } else {
             return false;
         }
 
-        if (listWithDun.contains("dun") && !listWithoutDun.contains("dun")) {
-            listWithoutDun.add("dun");
-            if (!listWithDun.containsAll(listWithoutDun)) {
-                return false;
+        public static Cursor selectConflictingRow(SQLiteDatabase db, String table,
+                                                  ContentValues row) {
+            // Conflict is possible only when numeric, mcc, mnc (fields without any default value)
+            // are set in the new row
+            if (!row.containsKey(NUMERIC) || !row.containsKey(MCC) || !row.containsKey(MNC)) {
+                loge("dbh.selectConflictingRow: called for non-conflicting row: " + row);
+                return null;
             }
 
-            // Only difference between old type and new type is that
-            // one has dun
-            // Check if profile_id is 0/not set
-            if (oldRow.getInt(oldRow.getColumnIndex(PROFILE_ID)) == 0) {
-                if (dunInOld) {
-                    // Update oldRow to remove dun from its type field
-                    ContentValues updateOldRow = new ContentValues();
-                    StringBuilder sb = new StringBuilder();
-                    boolean first = true;
-                    for (String s : listWithDun) {
-                        if (!s.equalsIgnoreCase("dun")) {
-                            sb.append(first ? s : "," + s);
-                            first = false;
-                        }
-                    }
-                    String updatedType = sb.toString();
-                    if (VDBG) {
-                        log("separateRowsNeeded: updating type in oldRow to " + updatedType);
-                    }
-                    updateOldRow.put(TYPE, updatedType);
-                    db.update(table, updateOldRow,
-                            "_id=" + oldRow.getInt(oldRow.getColumnIndex("_id")), null);
-                    return true;
+            String[] columns = { "_id",
+                    TYPE,
+                    EDITED_STATUS,
+                    BEARER_BITMASK,
+                    NETWORK_TYPE_BITMASK,
+                    PROFILE_ID };
+            String selection = TextUtils.join("=? AND ", CARRIERS_UNIQUE_FIELDS) + "=?";
+            int i = 0;
+            String[] selectionArgs = new String[CARRIERS_UNIQUE_FIELDS.size()];
+            for (String field : CARRIERS_UNIQUE_FIELDS) {
+                if (!row.containsKey(field)) {
+                    selectionArgs[i++] = CARRIERS_UNIQUE_FIELDS_DEFAULTS.get(field);
                 } else {
-                    if (VDBG) log("separateRowsNeeded: adding profile id 1 to newRow");
-                    // Update newRow to set profile_id to 1
-                    newRow.put(PROFILE_ID, new Integer(1));
+                    if (CARRIERS_BOOLEAN_FIELDS.contains(field)) {
+                        // for boolean fields we overwrite the strings "true" and "false" with "1"
+                        // and "0"
+                        selectionArgs[i++] = convertStringToIntString(row.getAsString(field));
+                    } else {
+                        selectionArgs[i++] = row.getAsString(field);
+                    }
                 }
+            }
+
+            Cursor c = db.query(table, columns, selection, selectionArgs, null, null, null);
+
+            if (c != null) {
+                if (c.getCount() == 1) {
+                    if (VDBG) log("dbh.selectConflictingRow: " + c.getCount() + " conflicting " +
+                            "row found");
+                    if (c.moveToFirst()) {
+                        return c;
+                    } else {
+                        loge("dbh.selectConflictingRow: moveToFirst() failed");
+                    }
+                } else {
+                    loge("dbh.selectConflictingRow: Expected 1 but found " + c.getCount() +
+                            " matching rows found for cv " + row);
+                }
+                c.close();
             } else {
-                return false;
+                loge("dbh.selectConflictingRow: Error - c is null; no matching row found for " +
+                        "cv " + row);
             }
 
-            // If match was found, both oldRow and newRow need to exist
-            // separately in db. Add newRow to db.
-            try {
-                db.insertWithOnConflict(table, null, newRow, SQLiteDatabase.CONFLICT_REPLACE);
-                if (VDBG) log("separateRowsNeeded: added newRow with profile id 1 to db");
-                return true;
-            } catch (SQLException e) {
-                loge("Exception on trying to add new row after updating profile_id");
-            }
-        }
-
-        return false;
-    }
-
-    public static Cursor selectConflictingRow(SQLiteDatabase db, String table,
-            ContentValues row) {
-        // Conflict is possible only when numeric, mcc, mnc (fields without any default value)
-        // are set in the new row
-        if (!row.containsKey(NUMERIC) || !row.containsKey(MCC) || !row.containsKey(MNC)) {
-            loge("dbh.selectConflictingRow: called for non-conflicting row: " + row);
             return null;
         }
-
-        String[] columns = { "_id",
-                TYPE,
-                EDITED_STATUS,
-                BEARER_BITMASK,
-                NETWORK_TYPE_BITMASK,
-                PROFILE_ID };
-        String selection = TextUtils.join("=? AND ", CARRIERS_UNIQUE_FIELDS) + "=?";
-        int i = 0;
-        String[] selectionArgs = new String[CARRIERS_UNIQUE_FIELDS.size()];
-        for (String field : CARRIERS_UNIQUE_FIELDS) {
-            if (!row.containsKey(field)) {
-                selectionArgs[i++] = CARRIERS_UNIQUE_FIELDS_DEFAULTS.get(field);
-            } else {
-                if (CARRIERS_BOOLEAN_FIELDS.contains(field)) {
-                    // for boolean fields we overwrite the strings "true" and "false" with "1"
-                    // and "0"
-                    selectionArgs[i++] = convertStringToIntString(row.getAsString(field));
-                } else {
-                    selectionArgs[i++] = row.getAsString(field);
-                }
-            }
-        }
-
-        Cursor c = db.query(table, columns, selection, selectionArgs, null, null, null);
-
-        if (c != null) {
-            if (c.getCount() == 1) {
-                if (VDBG) log("dbh.selectConflictingRow: " + c.getCount() + " conflicting " +
-                        "row found");
-                if (c.moveToFirst()) {
-                    return c;
-                } else {
-                    loge("dbh.selectConflictingRow: moveToFirst() failed");
-                }
-            } else {
-                loge("dbh.selectConflictingRow: Expected 1 but found " + c.getCount() +
-                        " matching rows found for cv " + row);
-            }
-            c.close();
-        } else {
-            loge("dbh.selectConflictingRow: Error - c is null; no matching row found for " +
-                    "cv " + row);
-        }
-
-        return null;
     }
 
     /**
@@ -2569,6 +2572,25 @@
 
         if (isNewBuild) {
             if (!apnSourceServiceExists(getContext())) {
+                // Call getReadableDatabase() to make sure onUpgrade is called
+                if (VDBG) log("onCreate: calling getReadableDatabase to trigger onUpgrade");
+                SQLiteDatabase db = getReadableDatabase();
+
+                // Get rid of old preferred apn shared preferences
+                SubscriptionManager sm = SubscriptionManager.from(getContext());
+                if (sm != null) {
+                    List<SubscriptionInfo> subInfoList = sm.getAllSubscriptionInfoList();
+                    for (SubscriptionInfo subInfo : subInfoList) {
+                        SharedPreferences spPrefFile = getContext().getSharedPreferences(
+                                PREF_FILE_APN + subInfo.getSubscriptionId(), Context.MODE_PRIVATE);
+                        if (spPrefFile != null) {
+                            SharedPreferences.Editor editor = spPrefFile.edit();
+                            editor.clear();
+                            editor.apply();
+                        }
+                    }
+                }
+
                 // Update APN DB
                 updateApnDb();
             }
@@ -2679,9 +2701,29 @@
         }
     }
 
-    private void deletePreferredApnId(Context context) {
-        SharedPreferences sp = context.getSharedPreferences(PREF_FILE_APN,
+    private void deletePreferredApnId() {
+        SharedPreferences sp = getContext().getSharedPreferences(PREF_FILE_APN,
                 Context.MODE_PRIVATE);
+
+        // Before deleting, save actual preferred apns (not the ids) in a separate SP.
+        // NOTE: This code to call setPreferredApn() can be removed since the function is now called
+        // from setPreferredApnId(). However older builds (pre oc-mr1) do not have that change, so
+        // when devices upgrade from those builds and this function is called, this code is needed
+        // otherwise the preferred APN will be lost.
+        Map<String, ?> allPrefApnId = sp.getAll();
+        for (String key : allPrefApnId.keySet()) {
+            // extract subId from key by removing COLUMN_APN_ID
+            try {
+                int subId = Integer.parseInt(key.replace(COLUMN_APN_ID, ""));
+                long apnId = getPreferredApnId(subId, false);
+                if (apnId != INVALID_APN_ID) {
+                    setPreferredApn(apnId, subId);
+                }
+            } catch (Exception e) {
+                loge("Skipping over key " + key + " due to exception " + e);
+            }
+        }
+
         SharedPreferences.Editor editor = sp.edit();
         editor.clear();
         editor.apply();
@@ -2722,27 +2764,19 @@
     private long getPreferredApnIdFromApn(int subId) {
         log("getPreferredApnIdFromApn: for subId " + subId);
         SQLiteDatabase db = getReadableDatabase();
-
-        List<String> whereList = new ArrayList<>();
-        List<String> whereArgsList = new ArrayList<>();
+        String where = TextUtils.join("=? and ", CARRIERS_UNIQUE_FIELDS) + "=?";
+        String[] whereArgs = new String[CARRIERS_UNIQUE_FIELDS.size()];
         SharedPreferences sp = getContext().getSharedPreferences(PREF_FILE_FULL_APN,
                 Context.MODE_PRIVATE);
-        for (String key : CARRIERS_UNIQUE_FIELDS) {
-            String value = sp.getString(key + subId, null);
-            if (value == null) {
-                continue;
-            } else {
-                whereList.add(key);
-                whereArgsList.add(value);
-            }
-        }
-        if (whereList.size() == 0) return INVALID_APN_ID;
-
-        String where = TextUtils.join("=? and ", whereList) + "=?";
-        String[] whereArgs = new String[whereArgsList.size()];
-        whereArgs = whereArgsList.toArray(whereArgs);
-
         long apnId = INVALID_APN_ID;
+        int i = 0;
+        for (String key : CARRIERS_UNIQUE_FIELDS) {
+            whereArgs[i] = sp.getString(key + subId, null);
+            if (whereArgs[i] == null) {
+                return INVALID_APN_ID;
+            }
+            i++;
+        }
         Cursor c = db.query(CARRIERS_TABLE, new String[]{"_id"}, where, whereArgs, null, null,
                 null);
         if (c != null) {
@@ -2802,7 +2836,7 @@
         List<String> constraints = new ArrayList<String>();
 
         int match = s_urlMatcher.match(url);
-        checkPermission();
+        checkQueryPermission(match, projectionIn, selection, sort);
         switch (match) {
             case URL_TELEPHONY_USING_SUBID: {
                 subIdString = url.getLastPathSegment();
@@ -3011,6 +3045,69 @@
         return ret;
     }
 
+    private void checkQueryPermission(int match, String[] projectionIn, String selection,
+            String sort) {
+        // Determine if we need to do a check for fields in the selection
+        boolean selectionOrSortContainsSensitiveFields;
+        try {
+            selectionOrSortContainsSensitiveFields = containsSensitiveFields(selection);
+            selectionOrSortContainsSensitiveFields |= containsSensitiveFields(sort);
+        } catch (IllegalArgumentException e) {
+            // Malformed sql, check permission anyway and return.
+            checkPermission();
+            return;
+        }
+
+        if (selectionOrSortContainsSensitiveFields) {
+            try {
+                checkPermission();
+            } catch (SecurityException e) {
+                EventLog.writeEvent(0x534e4554, "124107808", Binder.getCallingUid());
+                throw e;
+            }
+        }
+
+        if (match != URL_SIMINFO && match != URL_SIMINFO_USING_SUBID) {
+            if (projectionIn != null) {
+                for (String column : projectionIn) {
+                    if (TYPE.equals(column) ||
+                            MMSC.equals(column) ||
+                            MMSPROXY.equals(column) ||
+                            MMSPORT.equals(column) ||
+                            MVNO_TYPE.equals(column) ||
+                            MVNO_MATCH_DATA.equals(column) ||
+                            APN.equals(column)) {
+                    } else {
+                        checkPermission();
+                        break;
+                    }
+                }
+            } else {
+                // null returns all columns, so need permission check
+                checkPermission();
+            }
+        } else {
+            // if querying siminfo, caller should have read privilege permissions
+            checkPhonePrivilegePermission();
+        }
+    }
+
+    private boolean containsSensitiveFields(String sqlStatement) {
+        try {
+            SqlTokenFinder.findTokens(sqlStatement, s -> {
+                switch (s.toLowerCase()) {
+                    case USER:
+                    case PASSWORD:
+                    case SQL_SELECT_TOKEN:
+                        throw new SecurityException();
+                }
+            });
+        } catch (SecurityException e) {
+            return true;
+        }
+        return false;
+    }
+
     /**
      * To find the current sim APN. Query APN based on {MCC, MNC, MVNO} to support backward
      * compatibility but will move to carrier id in the future.
@@ -3188,10 +3285,10 @@
             log("insert: exception " + e);
             // Insertion failed which could be due to a conflict. Check if that is the case
             // and merge the entries
-            Cursor oldRow = selectConflictingRow(db, CARRIERS_TABLE, values);
+            Cursor oldRow = DatabaseHelper.selectConflictingRow(db, CARRIERS_TABLE, values);
             if (oldRow != null) {
                 ContentValues mergedValues = new ContentValues();
-                mergeFieldsAndUpdateDb(db, CARRIERS_TABLE, oldRow, values,
+                DatabaseHelper.mergeFieldsAndUpdateDb(db, CARRIERS_TABLE, oldRow, values,
                         mergedValues, false, getContext());
                 oldRow.close();
                 notify = true;
@@ -3234,7 +3331,7 @@
                     values = new ContentValues();
                 }
 
-                values = setDefaultValue(values);
+                values = DatabaseHelper.setDefaultValue(values);
                 if (!values.containsKey(EDITED_STATUS)) {
                     values.put(EDITED_STATUS, CARRIER_EDITED);
                 }
@@ -3365,7 +3462,7 @@
             case URL_DELETE:
             {
                 // Delete preferred APN for all subIds
-                deletePreferredApnId(getContext());
+                deletePreferredApnId();
                 // Delete unedited entries
                 count = db.delete(CARRIERS_TABLE, "(" + where + unedited + " and " +
                         IS_NOT_OWNED_BY_DPC, whereArgs);
@@ -3601,10 +3698,10 @@
                     // Update failed which could be due to a conflict. Check if that is
                     // the case and merge the entries
                     log("update: exception " + e);
-                    Cursor oldRow = selectConflictingRow(db, CARRIERS_TABLE, values);
+                    Cursor oldRow = DatabaseHelper.selectConflictingRow(db, CARRIERS_TABLE, values);
                     if (oldRow != null) {
                         ContentValues mergedValues = new ContentValues();
-                        mergeFieldsAndUpdateDb(db, CARRIERS_TABLE, oldRow, values,
+                        DatabaseHelper.mergeFieldsAndUpdateDb(db, CARRIERS_TABLE, oldRow, values,
                                 mergedValues, false, getContext());
                         oldRow.close();
                         db.delete(CARRIERS_TABLE, _ID + "=?" + " and " + IS_NOT_OWNED_BY_DPC,
@@ -3893,7 +3990,7 @@
         SQLiteDatabase db = getWritableDatabase();
 
         // Delete preferred APN for all subIds
-        deletePreferredApnId(getContext());
+        deletePreferredApnId();
 
         // Delete entries in db
         try {
diff --git a/tests/src/com/android/providers/telephony/TelephonyDatabaseHelperTest.java b/tests/src/com/android/providers/telephony/TelephonyDatabaseHelperTest.java
index 26df3c0..8287352 100644
--- a/tests/src/com/android/providers/telephony/TelephonyDatabaseHelperTest.java
+++ b/tests/src/com/android/providers/telephony/TelephonyDatabaseHelperTest.java
@@ -59,7 +59,7 @@
     public void setUp() {
         Log.d(TAG, "setUp() +");
         mContext = InstrumentationRegistry.getContext();
-        mHelper = new TelephonyProviderTestable().new DatabaseHelper(mContext);
+        mHelper = new TelephonyProvider.DatabaseHelper(mContext);
         mInMemoryDbHelper = new InMemoryTelephonyProviderV5DbHelper();
         Log.d(TAG, "setUp() -");
     }
@@ -69,7 +69,7 @@
         Log.d(TAG, "databaseHelperOnUpgrade_hasApnSetIdField");
         // (5 << 16 | 6) is the first upgrade trigger in onUpgrade
         SQLiteDatabase db = mInMemoryDbHelper.getWritableDatabase();
-        mHelper.onUpgrade(db, (4 << 16), TelephonyProvider.getVersion(mContext));
+        mHelper.onUpgrade(db, (4 << 16), TelephonyProvider.DatabaseHelper.getVersion(mContext));
 
         // the upgraded db must have the APN_SET_ID field
         Cursor cursor = db.query("carriers", null, null, null, null, null, null);
@@ -84,7 +84,7 @@
         Log.d(TAG, "databaseHelperOnUpgrade_hasSubscriptionTypeField");
         // (5 << 16 | 6) is the first upgrade trigger in onUpgrade
         SQLiteDatabase db = mInMemoryDbHelper.getWritableDatabase();
-        mHelper.onUpgrade(db, (4 << 16), TelephonyProvider.getVersion(mContext));
+        mHelper.onUpgrade(db, (4 << 16), TelephonyProvider.DatabaseHelper.getVersion(mContext));
 
         // the upgraded db must have the Telephony.Carriers.CARRIER_ID field
         Cursor cursor = db.query("carriers", null, null, null, null, null, null);
@@ -97,7 +97,7 @@
     public void databaseHelperOnUpgrade_hasCountryIsoField() {
         Log.d(TAG, "databaseHelperOnUpgrade_hasCountryIsoField");
         SQLiteDatabase db = mInMemoryDbHelper.getWritableDatabase();
-        mHelper.onUpgrade(db, (4 << 16), TelephonyProvider.getVersion(mContext));
+        mHelper.onUpgrade(db, (4 << 16), TelephonyProvider.DatabaseHelper.getVersion(mContext));
 
         // the upgraded db must have the Telephony.Carriers.CARRIER_ID field
         Cursor cursor = db.query("simInfo", null, null, null, null, null, null);
@@ -110,7 +110,7 @@
     public void databaseHelperOnUpgrade_hasProfileClassField() {
         Log.d(TAG, "databaseHelperOnUpgrade_hasProfileClassField");
         SQLiteDatabase db = mInMemoryDbHelper.getWritableDatabase();
-        mHelper.onUpgrade(db, (4 << 16), TelephonyProvider.getVersion(mContext));
+        mHelper.onUpgrade(db, (4 << 16), TelephonyProvider.DatabaseHelper.getVersion(mContext));
 
         // the upgraded db must have the PROFILE_CLASS field
         Cursor cursor = db.query("siminfo", null, null, null, null, null, null);
@@ -124,7 +124,7 @@
         Log.d(TAG, "databaseHelperOnUpgrade_hasSkip464XlatField");
         // (5 << 16 | 6) is the first upgrade trigger in onUpgrade
         SQLiteDatabase db = mInMemoryDbHelper.getWritableDatabase();
-        mHelper.onUpgrade(db, (4 << 16), TelephonyProvider.getVersion(mContext));
+        mHelper.onUpgrade(db, (4 << 16), TelephonyProvider.DatabaseHelper.getVersion(mContext));
 
         // the upgraded db must have the Telephony.Carriers.CARRIER_ID field
         Cursor cursor = db.query("carriers", null, null, null, null, null, null);
@@ -138,7 +138,7 @@
         Log.d(TAG, "databaseHelperOnUpgrade_columnsMatchNewlyCreatedDb");
         // (5 << 16 | 6) is the first upgrade trigger in onUpgrade
         SQLiteDatabase db = mInMemoryDbHelper.getWritableDatabase();
-        mHelper.onUpgrade(db, (4 << 16), TelephonyProvider.getVersion(mContext));
+        mHelper.onUpgrade(db, (4 << 16), TelephonyProvider.DatabaseHelper.getVersion(mContext));
 
         // compare upgraded carriers table to a carriers table created from scratch
         db.execSQL(TelephonyProvider.getStringForCarrierTableCreation("carriers_full"));
@@ -174,7 +174,7 @@
         Log.d(TAG, "databaseHelperOnUpgrade_hasSubscriptionTypeField");
         // (5 << 16 | 6) is the first upgrade trigger in onUpgrade
         SQLiteDatabase db = mInMemoryDbHelper.getWritableDatabase();
-        mHelper.onUpgrade(db, (4 << 16), TelephonyProvider.getVersion(mContext));
+        mHelper.onUpgrade(db, (4 << 16), TelephonyProvider.DatabaseHelper.getVersion(mContext));
 
         // the upgraded db must have the SubscriptionManager.SUBSCRIPTION_TYPE field
         Cursor cursor = db.query("siminfo", null, null, null, null, null, null);