[automerger skipped] Merge "Use XmlUtils from internal.util instead of the telephony copy" am: 7ed1a8a9c1 am: f644fd877d am: 51690cc6c7 -s ours
am skip reason: Change-Id I831f5211388c6a7627551c71d966d2b9c50cc131 with SHA-1 9f47c3fe9d is in history
Change-Id: I22f393a60c7f04ee975d997adc7cf2889fdcdd6a
diff --git a/Android.bp b/Android.bp
index eabd567..c7ecd27 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,9 +1,9 @@
android_app {
name: "TelephonyProvider",
privileged: true,
- srcs: ["src/**/*.java"],
+ srcs: ["src/**/*.java", "proto/**/*.proto"],
platform_apis: true,
certificate: "platform",
libs: ["telephony-common"],
- static_libs: ["android-common"],
+ static_libs: ["android-common", "telephonyprovider-protos"],
}
diff --git a/proto/Android.bp b/proto/Android.bp
new file mode 100644
index 0000000..4420263
--- /dev/null
+++ b/proto/Android.bp
@@ -0,0 +1,29 @@
+// 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.
+
+java_library_static {
+ name: "telephonyprovider-protos",
+ proto: {
+ type: "nano",
+ output_params: [
+ "store_unknown_fields=true",
+ "enum_style=java",
+ ],
+ },
+ srcs: ["src/**/*.proto"],
+ sdk_version: "core_platform",
+ jarjar_rules: "jarjar-rules.txt",
+ // Pin java_version until jarjar is certified to support later versions. http://b/72703434
+ java_version: "1.8",
+}
diff --git a/proto/jarjar-rules.txt b/proto/jarjar-rules.txt
new file mode 100644
index 0000000..4cad1ee
--- /dev/null
+++ b/proto/jarjar-rules.txt
@@ -0,0 +1 @@
+rule com.google.protobuf.nano.** com.android.providers.telephony.protobuf.nano.@1
\ No newline at end of file
diff --git a/proto/src/carrierId.proto b/proto/src/carrierId.proto
new file mode 100644
index 0000000..9d2f29e
--- /dev/null
+++ b/proto/src/carrierId.proto
@@ -0,0 +1,92 @@
+//
+// 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.
+//
+
+syntax = "proto2";
+
+package carrierIdentification;
+
+option java_package = "com.android.providers.telephony";
+option java_outer_classname = "CarrierIdProto";
+
+// A complete list of carriers
+message CarrierList {
+ // A collection of carriers. one entry for one carrier.
+ repeated CarrierId carrier_id = 1;
+ // Version number of current carrier list
+ optional int32 version = 2;
+};
+
+// CarrierId is the unique representation of a carrier in CID table.
+message CarrierId {
+ // [Optional] A unique canonical number designated to a carrier.
+ optional int32 canonical_id = 1;
+
+ // [Optional] A user-friendly carrier name (not localized).
+ optional string carrier_name = 2;
+
+ // [Optional] Carrier attributes to match a carrier. At least one value is required.
+ repeated CarrierAttribute carrier_attribute = 3;
+
+ // [Optional] A unique canonical number to represent its parent carrier. The parent-child
+ // relationship can be used to differentiate a single carrier by different networks,
+ // by prepaid v.s. postpaid or even by 4G v.s. 3G plan.
+ optional int32 parent_canonical_id = 4;
+};
+
+// Attributes used to match a carrier.
+// For each field within this message:
+// - if not set, the attribute is ignored;
+// - if set, the device must have one of the specified values to match.
+// Match is based on AND between any field that is set and OR for values within a repeated field.
+message CarrierAttribute {
+ // [Optional] The MCC and MNC that map to this carrier. At least one value is required.
+ repeated string mccmnc_tuple = 1;
+
+ // [Optional] Prefix of IMSI (International Mobile Subscriber Identity) in
+ // decimal format. Some digits can be replaced with "x" symbols matching any digit.
+ // Sample values: 20404794, 21670xx2xxx.
+ repeated string imsi_prefix_xpattern = 2;
+
+ // [Optional] The Service Provider Name. Read from subscription EF_SPN.
+ // Sample values: C Spire, LeclercMobile
+ repeated string spn = 3;
+
+ // [Optional] PLMN network name. Read from subscription EF_PNN.
+ // Sample values:
+ repeated string plmn = 4;
+
+ // [Optional] Group Identifier Level1 for a GSM phone. Read from subscription EF_GID1.
+ // Sample values: 6D, BAE0000000000000
+ repeated string gid1 = 5;
+
+ // [Optional] Group Identifier Level2 for a GSM phone. Read from subscription EF_GID2.
+ // Sample values: 6D, BAE0000000000000
+ repeated string gid2 = 6;
+
+ // [Optional] The Access Point Name, corresponding to "apn" field returned by
+ // "content://telephony/carriers/preferapn" on device.
+ // Sample values: fast.t-mobile.com, internet
+ repeated string preferred_apn = 7;
+
+ // [Optional] Prefix of Integrated Circuit Card Identifier. Read from subscription EF_ICCID.
+ // Sample values: 894430, 894410
+ repeated string iccid_prefix = 8;
+
+ // [Optional] Carrier Privilege Access Rule in hex string.
+ // Sample values: 61ed377e85d386a8dfee6b864bd85b0bfaa5af88
+ repeated string privilege_access_rule = 9;
+};
+
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/CarrierIdProvider.java b/src/com/android/providers/telephony/CarrierIdProvider.java
index 44f053d..122c304 100644
--- a/src/com/android/providers/telephony/CarrierIdProvider.java
+++ b/src/com/android/providers/telephony/CarrierIdProvider.java
@@ -25,23 +25,23 @@
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.MatrixCursor;
-import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
+import android.os.FileUtils;
import android.os.SystemProperties;
import android.provider.Telephony.CarrierId;
+import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.text.TextUtils;
import android.util.Log;
-import android.util.Pair;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.SubscriptionController;
-import com.android.internal.telephony.nano.CarrierIdProto;
+import com.android.internal.telephony.util.TelephonyUtils;
+import com.android.providers.telephony.nano.CarrierIdProto;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -54,8 +54,6 @@
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
-import libcore.io.IoUtils;
-
/**
* This class provides the ability to query the Carrier Identification databases
* (A.K.A. cid) which is stored in a SQLite database.
@@ -536,7 +534,7 @@
} catch (IOException ex) {
Log.e(TAG, "read carrier list from assets pb failure: " + ex);
} finally {
- IoUtils.closeQuietly(is);
+ FileUtils.closeQuietly(is);
}
try {
is = new FileInputStream(new File(Environment.getDataDirectory(), OTA_UPDATED_PB_PATH));
@@ -544,7 +542,7 @@
} catch (IOException ex) {
Log.e(TAG, "read carrier list from ota pb failure: " + ex);
} finally {
- IoUtils.closeQuietly(is);
+ FileUtils.closeQuietly(is);
}
// compare version
@@ -553,7 +551,7 @@
version = assets.version;
}
// bypass version check for ota carrier id test
- if (ota != null && ((Build.IS_DEBUGGABLE && SystemProperties.getBoolean(
+ if (ota != null && ((TelephonyUtils.IS_DEBUGGABLE && SystemProperties.getBoolean(
"persist.telephony.test.carrierid.ota", false))
|| (ota.version > version))) {
carrierList = ota;
@@ -607,13 +605,21 @@
// Handle DEFAULT_SUBSCRIPTION_ID
if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
- subId = SubscriptionController.getInstance().getDefaultSubId();
+ subId = SubscriptionManager.getDefaultSubscriptionId();
}
- if (!SubscriptionController.getInstance().isActiveSubId(subId)) {
+ SubscriptionManager sm = (SubscriptionManager) getContext().getSystemService(
+ Context.TELEPHONY_SUBSCRIPTION_SERVICE);
+ if (!sm.isActiveSubscriptionId(subId)) {
// Remove absent subId from the currentSubscriptionMap.
- final List activeSubscriptions = Arrays.asList(SubscriptionController.getInstance()
- .getActiveSubIdList(false));
+ List activeSubscriptions = new ArrayList<>();
+ final List<SubscriptionInfo> subscriptionInfoList =
+ sm.getActiveAndHiddenSubscriptionInfoList();
+ if (subscriptionInfoList != null) {
+ for (SubscriptionInfo subInfo : subscriptionInfoList) {
+ activeSubscriptions.add(subInfo.getSubscriptionId());
+ }
+ }
int count = 0;
for (int subscription : mCurrentSubscriptionMap.keySet()) {
if (!activeSubscriptions.contains(subscription)) {
@@ -633,7 +639,7 @@
private Cursor queryCarrierIdForCurrentSubscription(Uri uri, String[] projectionIn) {
// Parse the subId, using the default subId if subId is not provided
- int subId = SubscriptionController.getInstance().getDefaultSubId();
+ int subId = SubscriptionManager.getDefaultSubscriptionId();
if (!TextUtils.isEmpty(uri.getLastPathSegment())) {
try {
subId = Integer.parseInt(uri.getLastPathSegment());
@@ -645,7 +651,7 @@
// Handle DEFAULT_SUBSCRIPTION_ID
if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
- subId = SubscriptionController.getInstance().getDefaultSubId();
+ subId = SubscriptionManager.getDefaultSubscriptionId();
}
if (!mCurrentSubscriptionMap.containsKey(subId)) {
diff --git a/src/com/android/providers/telephony/MmsProvider.java b/src/com/android/providers/telephony/MmsProvider.java
index 30158c3..96059d7 100644
--- a/src/com/android/providers/telephony/MmsProvider.java
+++ b/src/com/android/providers/telephony/MmsProvider.java
@@ -31,7 +31,6 @@
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.os.Binder;
-import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
import android.os.UserHandle;
import android.provider.BaseColumns;
@@ -44,6 +43,8 @@
import android.provider.Telephony.Mms.Rate;
import android.provider.Telephony.MmsSms;
import android.provider.Telephony.Threads;
+import android.system.ErrnoException;
+import android.system.Os;
import android.text.TextUtils;
import android.util.Log;
@@ -518,9 +519,13 @@
// Give everyone rw permission until we encrypt the file
// (in PduPersister.persistData). Once the file is encrypted, the
// permissions will be set to 0644.
- int result = FileUtils.setPermissions(path, 0666, -1, -1);
- if (LOCAL_LOGV) {
- Log.d(TAG, "MmsProvider.insert setPermissions result: " + result);
+ try {
+ Os.chmod(path, 0666);
+ if (LOCAL_LOGV) {
+ Log.d(TAG, "MmsProvider.insert chmod is successful");
+ }
+ } catch (ErrnoException e) {
+ Log.e(TAG, "Exception in chmod: " + e);
}
} catch (IOException e) {
Log.e(TAG, "createNewFile", e);
@@ -816,10 +821,13 @@
String path = getContext().getDir(PARTS_DIR_NAME, 0).getPath() + '/' +
uri.getPathSegments().get(1);
// Reset the file permission back to read for everyone but me.
- int result = FileUtils.setPermissions(path, 0644, -1, -1);
- if (LOCAL_LOGV) {
- Log.d(TAG, "MmsProvider.update setPermissions result: " + result +
- " for path: " + path);
+ try {
+ Os.chmod(path, 0644);
+ if (LOCAL_LOGV) {
+ Log.d(TAG, "MmsProvider.update chmod is successful for path: " + path);
+ }
+ } catch (ErrnoException e) {
+ Log.e(TAG, "Exception in chmod: " + e);
}
return 0;
diff --git a/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java b/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
index 887d94c..7adc7de 100644
--- a/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
+++ b/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
@@ -47,7 +47,6 @@
import android.provider.Telephony.Threads;
import android.telephony.SubscriptionManager;
import android.util.Log;
-import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.google.android.mms.pdu.EncodedStringValue;
@@ -266,7 +265,7 @@
/**
* The primary purpose of this DatabaseErrorHandler is to broadcast an intent on corruption and
- * print a Slog.wtf so database corruption can be caught earlier.
+ * print a Log.wtf so database corruption can be caught earlier.
*/
private static class MmsSmsDatabaseErrorHandler implements DatabaseErrorHandler {
private DefaultDatabaseErrorHandler mDefaultDatabaseErrorHandler
@@ -556,7 +555,7 @@
}
private static void localLogWtf(String logMsg) {
- Slog.wtf(TAG, logMsg);
+ Log.wtf(TAG, logMsg);
}
private boolean isInitialCreateDone() {
diff --git a/src/com/android/providers/telephony/MmsSmsProvider.java b/src/com/android/providers/telephony/MmsSmsProvider.java
index 1170aad..f5aeadc 100644
--- a/src/com/android/providers/telephony/MmsSmsProvider.java
+++ b/src/com/android/providers/telephony/MmsSmsProvider.java
@@ -336,6 +336,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);
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/ServiceStateProvider.java b/src/com/android/providers/telephony/ServiceStateProvider.java
index f707200..2b4fae3 100644
--- a/src/com/android/providers/telephony/ServiceStateProvider.java
+++ b/src/com/android/providers/telephony/ServiceStateProvider.java
@@ -60,7 +60,6 @@
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.SubscriptionController;
import java.util.HashMap;
@@ -111,7 +110,7 @@
@VisibleForTesting
public int getDefaultSubId() {
- return SubscriptionController.getInstance().getDefaultSubId();
+ return SubscriptionManager.getDefaultSubscriptionId();
}
@Override
diff --git a/src/com/android/providers/telephony/SmsProvider.java b/src/com/android/providers/telephony/SmsProvider.java
index ddfa14c..24c610e 100644
--- a/src/com/android/providers/telephony/SmsProvider.java
+++ b/src/com/android/providers/telephony/SmsProvider.java
@@ -124,6 +124,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);
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/TelephonyBackupAgent.java b/src/com/android/providers/telephony/TelephonyBackupAgent.java
index b3c0d99..b88cd6b 100644
--- a/src/com/android/providers/telephony/TelephonyBackupAgent.java
+++ b/src/com/android/providers/telephony/TelephonyBackupAgent.java
@@ -531,9 +531,7 @@
for (File file : files) {
final String fileName = file.getName();
- if (DEBUG) {
- Log.d(TAG, "onHandleIntent restoring file " + fileName);
- }
+ Log.d(TAG, "onHandleIntent restoring file " + fileName);
try (FileInputStream fileInputStream = new FileInputStream(file)) {
mTelephonyBackupAgent.doRestoreFile(fileName, fileInputStream.getFD());
didRestore = true;
@@ -547,9 +545,7 @@
if (didRestore) {
// Tell the default sms app to do a full sync now that the messages have been
// restored.
- if (DEBUG) {
- Log.d(TAG, "onHandleIntent done - notifying default sms app");
- }
+ Log.d(TAG, "onHandleIntent done - notifying default sms app");
ProviderUtil.notifyIfNotDefaultSmsApp(null /*uri*/, null /*calling package*/,
this);
}
@@ -605,25 +601,17 @@
}
private void doRestoreFile(String fileName, FileDescriptor fd) throws IOException {
- if (DEBUG) {
- Log.d(TAG, "Restoring file " + fileName);
- }
+ Log.d(TAG, "Restoring file " + fileName);
try (JsonReader jsonReader = getJsonReader(fd)) {
if (fileName.endsWith(SMS_BACKUP_FILE_SUFFIX)) {
- if (DEBUG) {
- Log.d(TAG, "Restoring SMS");
- }
+ Log.d(TAG, "Restoring SMS");
putSmsMessagesToProvider(jsonReader);
} else if (fileName.endsWith(MMS_BACKUP_FILE_SUFFIX)) {
- if (DEBUG) {
- Log.d(TAG, "Restoring text MMS");
- }
+ Log.d(TAG, "Restoring text MMS");
putMmsMessagesToProvider(jsonReader);
} else {
- if (DEBUG) {
- Log.e(TAG, "Unknown file to restore:" + fileName);
- }
+ Log.e(TAG, "Unknown file to restore:" + fileName);
}
}
}
@@ -654,6 +642,7 @@
@VisibleForTesting
void putMmsMessagesToProvider(JsonReader jsonReader) throws IOException {
jsonReader.beginArray();
+ int total = 0;
while (jsonReader.hasNext()) {
final Mms mms = readMmsFromReader(jsonReader);
if (DEBUG) {
@@ -662,11 +651,15 @@
if (doesMmsExist(mms)) {
if (DEBUG) {
Log.e(TAG, String.format("Mms: %s already exists", mms.toString()));
+ } else {
+ Log.w(TAG, "Mms: Found duplicate MMS");
}
continue;
}
+ total++;
addMmsMessage(mms);
}
+ Log.d(TAG, "putMmsMessagesToProvider handled " + total + " new messages.");
}
@VisibleForTesting
@@ -823,6 +816,8 @@
default:
if (DEBUG) {
Log.w(TAG, "readSmsValuesFromReader Unknown name:" + name);
+ } else {
+ Log.w(TAG, "readSmsValuesFromReader encountered unknown name.");
}
jsonReader.skipValue();
break;
@@ -955,9 +950,7 @@
mms.values.put(name, jsonReader.nextString());
break;
default:
- if (DEBUG) {
- Log.d(TAG, "Unknown name:" + name);
- }
+ Log.d(TAG, "Unknown JSON element name:" + name);
jsonReader.skipValue();
break;
}
@@ -995,9 +988,7 @@
values,
ARCHIVE_THREAD_SELECTION,
new String[] { Long.toString(threadId)}) != 1) {
- if (DEBUG) {
- Log.e(TAG, "archiveThread: failed to update database");
- }
+ Log.e(TAG, "archiveThread: failed to update database");
}
}
@@ -1066,9 +1057,7 @@
addrValues.put(name, jsonReader.nextString());
break;
default:
- if (DEBUG) {
- Log.d(TAG, "Unknown name:" + name);
- }
+ Log.d(TAG, "Unknown JSON Element name:" + name);
jsonReader.skipValue();
break;
}
@@ -1099,9 +1088,7 @@
attachmentValues.put(name, jsonReader.nextString());
break;
default:
- if (DEBUG) {
- Log.d(TAG, "getMmsAttachmentsFromReader Unknown name:" + name);
- }
+ Log.d(TAG, "getMmsAttachmentsFromReader Unknown name:" + name);
jsonReader.skipValue();
break;
}
@@ -1110,9 +1097,7 @@
if (attachmentValues.containsKey(MMS_ATTACHMENT_FILENAME)) {
mms.attachments.add(attachmentValues);
} else {
- if (DEBUG) {
- Log.d(TAG, "Attachment json with no filenames");
- }
+ Log.d(TAG, "Attachment json with no filenames");
}
}
jsonReader.endArray();
@@ -1140,9 +1125,7 @@
values.put(Telephony.Mms.Part.CONTENT_LOCATION, "smil.xml");
values.put(Telephony.Mms.Part.TEXT, smil);
if (mContentResolver.insert(partUri, values) == null) {
- if (DEBUG) {
- Log.e(TAG, "Could not insert SMIL part");
- }
+ Log.e(TAG, "Could not insert SMIL part");
return;
}
}
@@ -1162,9 +1145,7 @@
values.put(Telephony.Mms.Part.TEXT, mms.body == null ? "" : mms.body.text);
if (mContentResolver.insert(partUri, values) == null) {
- if (DEBUG) {
- Log.e(TAG, "Could not insert body part");
- }
+ Log.e(TAG, "Could not insert body part");
return;
}
}
@@ -1184,9 +1165,7 @@
getDataDir() + ATTACHMENT_DATA_PATH + filename);
Uri newPartUri = mContentResolver.insert(partUri, values);
if (newPartUri == null) {
- if (DEBUG) {
- Log.e(TAG, "Could not insert attachment part");
- }
+ Log.e(TAG, "Could not insert attachment part");
return;
}
}
@@ -1195,9 +1174,7 @@
// Insert mms.
final Uri mmsUri = mContentResolver.insert(Telephony.Mms.CONTENT_URI, mms.values);
if (mmsUri == null) {
- if (DEBUG) {
- Log.e(TAG, "Could not insert mms");
- }
+ Log.e(TAG, "Could not insert mms");
return;
}
@@ -1301,9 +1278,7 @@
try {
threadId = Telephony.Threads.getOrCreateThreadId(this, recipients);
} catch (RuntimeException e) {
- if (DEBUG) {
- Log.e(TAG, e.toString());
- }
+ Log.e(TAG, "Problem obtaining thread.", e);
}
mCacheGetOrCreateThreadId.put(recipients, threadId);
return threadId;
@@ -1377,15 +1352,11 @@
try {
longId = Long.parseLong(id);
if (longId < 0) {
- if (DEBUG) {
- Log.e(TAG, "getAddresses: invalid id " + longId);
- }
+ Log.e(TAG, "getAddresses: invalid id " + longId);
continue;
}
} catch (final NumberFormatException ex) {
- if (DEBUG) {
- Log.e(TAG, "getAddresses: invalid id. " + ex, ex);
- }
+ Log.e(TAG, "getAddresses: invalid id " + ex, ex);
// skip this id
continue;
}
@@ -1397,10 +1368,9 @@
ContentUris.withAppendedId(SINGLE_CANONICAL_ADDRESS_URI, longId),
null, null, null, null);
} catch (final Exception e) {
- if (DEBUG) {
- Log.e(TAG, "getAddresses: query failed for id " + longId, e);
- }
+ Log.e(TAG, "getAddresses: query failed for id " + longId, e);
}
+
if (c != null) {
try {
if (c.moveToFirst()) {
@@ -1408,9 +1378,7 @@
if (!TextUtils.isEmpty(number)) {
numbers.add(number);
} else {
- if (DEBUG) {
- Log.d(TAG, "Canonical MMS/SMS address is empty for id: " + longId);
- }
+ Log.d(TAG, "Canonical MMS/SMS address is empty for id: " + longId);
}
}
} finally {
@@ -1419,9 +1387,7 @@
}
}
if (numbers.isEmpty()) {
- if (DEBUG) {
- Log.d(TAG, "No MMS addresses found from ids string [" + spaceSepIds + "]");
- }
+ Log.d(TAG, "No MMS addresses found from ids string [" + spaceSepIds + "]");
}
return numbers;
}
diff --git a/src/com/android/providers/telephony/TelephonyProvider.java b/src/com/android/providers/telephony/TelephonyProvider.java
index 872acd9..5ec850d 100644
--- a/src/com/android/providers/telephony/TelephonyProvider.java
+++ b/src/com/android/providers/telephony/TelephonyProvider.java
@@ -94,15 +94,14 @@
import android.net.Uri;
import android.os.Binder;
import android.os.Environment;
-import android.os.FileUtils;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Telephony;
import android.telephony.ServiceState;
-import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
@@ -114,18 +113,20 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.IApnSourceService;
+import com.android.internal.compat.IPlatformCompat;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.dataconnection.ApnSettingUtils;
import com.android.internal.telephony.uicc.IccRecords;
import com.android.internal.telephony.uicc.UiccController;
import com.android.internal.util.XmlUtils;
+import android.service.carrier.IApnSourceService;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.ByteArrayOutputStream;
import java.io.File;
+import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
@@ -138,6 +139,7 @@
import java.util.Locale;
import java.util.Map;
import java.util.Set;
+import java.util.zip.CheckedInputStream;
import java.util.zip.CRC32;
public class TelephonyProvider extends ContentProvider
@@ -147,7 +149,7 @@
private static final boolean DBG = true;
private static final boolean VDBG = false; // STOPSHIP if true
- private static final int DATABASE_VERSION = 42 << 16;
+ private static final int DATABASE_VERSION = 43 << 16;
private static final int URL_UNKNOWN = 0;
private static final int URL_TELEPHONY = 1;
private static final int URL_CURRENT = 2;
@@ -416,7 +418,8 @@
+ SubscriptionManager.WHITE_LISTED_APN_DATA + " INTEGER DEFAULT 0,"
+ SubscriptionManager.GROUP_OWNER + " TEXT,"
+ SubscriptionManager.DATA_ENABLED_OVERRIDE_RULES + " TEXT,"
- + SubscriptionManager.IMSI + " TEXT"
+ + SubscriptionManager.IMSI + " TEXT,"
+ + SubscriptionManager.UICC_APPLICATIONS_ENABLED + " INTEGER DEFAULT 1"
+ ");";
}
@@ -598,10 +601,18 @@
}
private long getChecksum(File file) {
- long checksum = -1;
- try {
- checksum = FileUtils.checksumCrc32(file);
- if (DBG) log("Checksum for " + file.getAbsolutePath() + " is " + checksum);
+ CRC32 checkSummer = new CRC32();
+ long checkSum = -1;
+ try (CheckedInputStream cis =
+ new CheckedInputStream(new FileInputStream(file), checkSummer)){
+ byte[] buf = new byte[128];
+ if(cis != null) {
+ while(cis.read(buf) >= 0) {
+ // Just read for checksum to get calculated.
+ }
+ }
+ checkSum = checkSummer.getValue();
+ if (DBG) log("Checksum for " + file.getAbsolutePath() + " is " + checkSum);
} catch (FileNotFoundException e) {
loge("FileNotFoundException for " + file.getAbsolutePath() + ":" + e);
} catch (IOException e) {
@@ -613,14 +624,14 @@
try (InputStream inputStream = mContext.getResources().
openRawResource(com.android.internal.R.xml.apns)) {
byte[] array = toByteArray(inputStream);
- CRC32 c = new CRC32();
- c.update(array);
- checksum += c.getValue();
- if (DBG) log("Checksum after adding resource is " + checksum);
+ checkSummer.reset();
+ checkSummer.update(array);
+ checkSum += checkSummer.getValue();
+ if (DBG) log("Checksum after adding resource is " + checkSummer.getValue());
} catch (IOException | Resources.NotFoundException e) {
loge("Exception when calculating checksum for internal apn resources: " + e);
}
- return checksum;
+ return checkSum;
}
private byte[] toByteArray(InputStream input) throws IOException {
@@ -1387,6 +1398,21 @@
}
}
+ if (oldVersion < (43 << 16 | 6)) {
+ try {
+ // Try to update the siminfo table. It might not be there.
+ db.execSQL("ALTER TABLE " + SIMINFO_TABLE + " ADD COLUMN "
+ + SubscriptionManager.UICC_APPLICATIONS_ENABLED
+ + " INTEGER DEFAULT 1;");
+ } catch (SQLiteException e) {
+ if (DBG) {
+ log("onUpgrade skipping " + SIMINFO_TABLE + " upgrade. " +
+ "The table will get created in onOpen.");
+ }
+ }
+ oldVersion = 43 << 16 | 6;
+ }
+
if (DBG) {
log("dbh.onUpgrade:- db=" + db + " oldV=" + oldVersion + " newV=" + newVersion);
@@ -3379,7 +3405,7 @@
case URL_SIMINFO: {
long id = db.insert(SIMINFO_TABLE, null, initialValues);
- result = ContentUris.withAppendedId(SubscriptionManager.CONTENT_URI, id);
+ result = ContentUris.withAppendedId(Telephony.SimInfo.CONTENT_URI, id);
break;
}
}
@@ -3753,7 +3779,7 @@
// If not set, any change to SIMINFO will notify observers which listens to
// specific field of SIMINFO.
getContext().getContentResolver().notifyChange(
- SubscriptionManager.CONTENT_URI, null,
+ Telephony.SimInfo.CONTENT_URI, null,
ContentResolver.NOTIFY_SYNC_TO_NETWORK
| ContentResolver.NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS,
UserHandle.USER_ALL);
@@ -3821,16 +3847,20 @@
return;
}
}
- throw new SecurityException("No permission to write APN settings");
- }
- private void checkPhonePrivilegePermission() {
- int status = getContext().checkCallingOrSelfPermission(
- "android.permission.READ_PRIVILEGED_PHONE_STATE");
- if (status == PackageManager.PERMISSION_GRANTED) {
- return;
+ IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface(
+ ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
+ if (platformCompat != null) {
+ try {
+ platformCompat.reportChangeByUid(
+ Telephony.Carriers.APN_READING_PERMISSION_CHANGE_ID,
+ Binder.getCallingUid());
+ } catch (RemoteException e) {
+ //ignore
+ }
}
- throw new SecurityException("No phone privilege permission");
+
+ throw new SecurityException("No permission to access APN settings");
}
private DatabaseHelper mOpenHelper;
diff --git a/tests/src/com/android/providers/telephony/CarrierIdProviderTest.java b/tests/src/com/android/providers/telephony/CarrierIdProviderTest.java
index bc39260..ee0e016 100644
--- a/tests/src/com/android/providers/telephony/CarrierIdProviderTest.java
+++ b/tests/src/com/android/providers/telephony/CarrierIdProviderTest.java
@@ -17,6 +17,7 @@
package com.android.providers.telephony;
import android.content.ContentValues;
+import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
@@ -26,23 +27,21 @@
import android.net.Uri;
import android.os.Handler;
import android.provider.Telephony.CarrierId;
+import android.telephony.SubscriptionManager;
import android.test.mock.MockContentResolver;
import android.test.mock.MockContext;
import android.util.Log;
-import com.android.internal.telephony.SubscriptionController;
-
import junit.framework.TestCase;
import org.junit.Assert;
import org.junit.Test;
-import java.lang.reflect.Field;
-
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
/**
* Tests for testing CRUD operations of CarrierIdProvider.
@@ -77,12 +76,12 @@
private CarrierIdProviderTestable mCarrierIdProviderTestable;
private FakeContentObserver mContentObserver;
private SharedPreferences mSharedPreferences = mock(SharedPreferences.class);
- private SubscriptionController mSubController = mock(SubscriptionController.class);
+ private SubscriptionManager subscriptionManager = mock(SubscriptionManager.class);
private class FakeContentResolver extends MockContentResolver {
@Override
- public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
- super.notifyChange(uri, observer, syncToNetwork);
+ public void notifyChange(Uri uri, ContentObserver observer) {
+ super.notifyChange(uri, observer);
Log.d(TAG, "onChanged(uri=" + uri + ")" + observer);
mContentObserver.dispatchChange(false, uri);
}
@@ -121,8 +120,13 @@
@Override
public Object getSystemService(String name) {
- Log.d(TAG, "getSystemService: returning null");
- return null;
+ switch (name) {
+ case Context.TELEPHONY_SUBSCRIPTION_SERVICE:
+ return subscriptionManager;
+ default:
+ Log.d(TAG, "getSystemService: returning null");
+ return null;
+ }
}
@Override
@@ -148,12 +152,6 @@
mContext = new MockContextWithProvider(mCarrierIdProviderTestable);
mContentResolver = mContext.getContentResolver();
mContentObserver = new FakeContentObserver(null);
-
- doReturn("").when(mSubController).getDataEnabledOverrideRules(anyInt());
-
- Field field = SubscriptionController.class.getDeclaredField("sInstance");
- field.setAccessible(true);
- field.set(null, mSubController);
}
@Override
@@ -341,8 +339,7 @@
ContentValues cv = new ContentValues();
cv.put(CarrierId.CARRIER_ID, dummy_cid);
cv.put(CarrierId.CARRIER_NAME, dummy_name);
- doReturn(1).when(mSubController).getDefaultSubId();
- doReturn(true).when(mSubController).isActiveSubId(eq(1));
+ when(subscriptionManager.isActiveSubscriptionId(eq(1))).thenReturn(true);
mContext.getContentResolver().update(Uri.withAppendedPath(CarrierId.CONTENT_URI,
"1"), cv, null, null);
} catch (Exception e) {
@@ -351,7 +348,6 @@
}
int carrierId = -1;
String carrierName = null;
-
// query carrier id for subId 1
try {
final Cursor c = mContext.getContentResolver().query(
@@ -416,9 +412,6 @@
ContentValues cv = new ContentValues();
cv.put(CarrierId.CARRIER_ID, dummy_cid);
cv.put(CarrierId.CARRIER_NAME, dummy_name);
- doReturn(1).when(mSubController).getDefaultSubId();
- doReturn(true).when(mSubController).isActiveSubId(eq(1));
-
mContext.getContentResolver().update(CarrierId.CONTENT_URI, cv, null, null);
Assert.fail("should throw an exception for wrong uri");
} catch (IllegalArgumentException ex) {
diff --git a/tests/src/com/android/providers/telephony/TelephonyProviderTest.java b/tests/src/com/android/providers/telephony/TelephonyProviderTest.java
index bf85625..4b61798 100644
--- a/tests/src/com/android/providers/telephony/TelephonyProviderTest.java
+++ b/tests/src/com/android/providers/telephony/TelephonyProviderTest.java
@@ -20,6 +20,7 @@
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+
import android.Manifest;
import android.content.ContentUris;
import android.content.ContentValues;
@@ -34,6 +35,7 @@
import android.os.Process;
import android.provider.Telephony;
import android.provider.Telephony.Carriers;
+import android.provider.Telephony.SimInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.test.mock.MockContentResolver;
@@ -349,13 +351,13 @@
return cv;
}).toArray(ContentValues[]::new);
- mContentResolver.bulkInsert(SubscriptionManager.CONTENT_URI, existingSimInfoEntries);
+ mContentResolver.bulkInsert(SimInfo.CONTENT_URI, existingSimInfoEntries);
// Run the upgrade helper on all the sim info entries.
String[] proj = {SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID,
SubscriptionManager.MCC, SubscriptionManager.MNC,
SubscriptionManager.MCC_STRING, SubscriptionManager.MNC_STRING};
- try (Cursor c = mContentResolver.query(SubscriptionManager.CONTENT_URI, proj,
+ try (Cursor c = mContentResolver.query(SimInfo.CONTENT_URI, proj,
null, null, null)) {
while (c.moveToNext()) {
TelephonyProvider.fillInMccMncStringAtCursor(mContext,
@@ -364,7 +366,7 @@
}
// Loop through and make sure that everything got filled in correctly.
- try (Cursor c = mContentResolver.query(SubscriptionManager.CONTENT_URI, proj,
+ try (Cursor c = mContentResolver.query(SimInfo.CONTENT_URI, proj,
null, null, null)) {
while (c.moveToNext()) {
String mcc = c.getString(c.getColumnIndexOrThrow(SubscriptionManager.MCC_STRING));
@@ -567,7 +569,7 @@
contentValues.put(SubscriptionManager.PROFILE_CLASS, insertProfileClass);
Log.d(TAG, "testSimTable Inserting contentValues: " + contentValues);
- mContentResolver.insert(SubscriptionManager.CONTENT_URI, contentValues);
+ mContentResolver.insert(SimInfo.CONTENT_URI, contentValues);
// get values in table
final String[] testProjection =
@@ -581,7 +583,7 @@
String[] selectionArgs = { insertDisplayName };
Log.d(TAG,"\ntestSimTable selection: " + selection
+ "\ntestSimTable selectionArgs: " + selectionArgs.toString());
- Cursor cursor = mContentResolver.query(SubscriptionManager.CONTENT_URI,
+ Cursor cursor = mContentResolver.query(SimInfo.CONTENT_URI,
testProjection, selection, selectionArgs, null);
// verify that inserted values match results of query
@@ -602,12 +604,12 @@
String[] selectionArgsToDelete = { insertDisplayName };
Log.d(TAG, "testSimTable deleting selection: " + selectionToDelete
+ "testSimTable selectionArgs: " + selectionArgs);
- int numRowsDeleted = mContentResolver.delete(SubscriptionManager.CONTENT_URI,
+ int numRowsDeleted = mContentResolver.delete(SimInfo.CONTENT_URI,
selectionToDelete, selectionArgsToDelete);
assertEquals(1, numRowsDeleted);
// verify that deleted values are gone
- cursor = mContentResolver.query(SubscriptionManager.CONTENT_URI,
+ cursor = mContentResolver.query(SimInfo.CONTENT_URI,
testProjection, selection, selectionArgs, null);
assertEquals(0, cursor.getCount());
}
@@ -1453,7 +1455,7 @@
contentValues.put(SubscriptionManager.CARD_ID, insertCardId);
Log.d(TAG, "testSimTable Inserting wfc contentValues: " + contentValues);
- mContentResolver.insert(SubscriptionManager.CONTENT_URI, contentValues);
+ mContentResolver.insert(SimInfo.CONTENT_URI, contentValues);
assertEquals(0, notifyWfcCount);
// update wfc_enabled
@@ -1461,14 +1463,14 @@
values.put(SubscriptionManager.WFC_IMS_ENABLED, true);
final String selection = SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=?";
final String[] selectionArgs = { "" + insertSubId };
- mContentResolver.update(SubscriptionManager.CONTENT_URI, values, selection, selectionArgs);
+ mContentResolver.update(SimInfo.CONTENT_URI, values, selection, selectionArgs);
assertEquals(1, notifyWfcCount);
assertEquals(0, notifyWfcCountWithTestSubId);
// update other fields
values = new ContentValues();
values.put(SubscriptionManager.DISPLAY_NAME, "exampleDisplayNameNew");
- mContentResolver.update(SubscriptionManager.CONTENT_URI, values, selection, selectionArgs);
+ mContentResolver.update(SimInfo.CONTENT_URI, values, selection, selectionArgs);
// expect no change on wfc count
assertEquals(1, notifyWfcCount);
assertEquals(0, notifyWfcCountWithTestSubId);