Only allow whitelisted app to access ContactMetadataProvider

Bug 26822055

Change-Id: I215bee01b1262ec269653161cd9e36cbe69d885e
diff --git a/res/values/config.xml b/res/values/config.xml
new file mode 100644
index 0000000..d31e259
--- /dev/null
+++ b/res/values/config.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+           xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Package name for the contacts metadata syncadapter [DO NOT TRANSLATE] -->
+    <string name="metadata_sync_pacakge" translatable="false"></string>
+</resources>
diff --git a/src/com/android/providers/contacts/ContactMetadataProvider.java b/src/com/android/providers/contacts/ContactMetadataProvider.java
index d33da4d..4396ea6 100644
--- a/src/com/android/providers/contacts/ContactMetadataProvider.java
+++ b/src/com/android/providers/contacts/ContactMetadataProvider.java
@@ -90,6 +90,8 @@
     private ContactsDatabaseHelper mDbHelper;
     private ContactsProvider2 mContactsProvider;
 
+    private String mAllowedPackage;
+
     @Override
     public boolean onCreate() {
         final Context context = getContext();
@@ -99,6 +101,8 @@
         final ContentProvider provider = ContentProvider.coerceToLocalContentProvider(
                 iContentProvider);
         mContactsProvider = (ContactsProvider2) provider;
+
+        mAllowedPackage = getContext().getResources().getString(R.string.metadata_sync_pacakge);
         return true;
     }
 
@@ -115,13 +119,14 @@
     public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
             String sortOrder) {
 
+        ensureCaller();
+
         if (VERBOSE_LOGGING) {
             Log.v(TAG, "query: uri=" + uri + "  projection=" + Arrays.toString(projection) +
                     "  selection=[" + selection + "]  args=" + Arrays.toString(selectionArgs) +
                     "  order=[" + sortOrder + "] CPID=" + Binder.getCallingPid() +
                     " User=" + UserUtils.getCurrentUserHandle(getContext()));
         }
-
         final SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
         String limit = getLimit(uri);
 
@@ -172,6 +177,9 @@
      * Insert or update if the raw is already existing.
      */
     public Uri insert(Uri uri, ContentValues values) {
+
+        ensureCaller();
+
         final SQLiteDatabase db = mDbHelper.getWritableDatabase();
         db.beginTransaction();
         try {
@@ -200,6 +208,9 @@
 
     @Override
     public int delete(Uri uri, String selection, String[] selectionArgs) {
+
+        ensureCaller();
+
         final SQLiteDatabase db = mDbHelper.getWritableDatabase();
         db.beginTransaction();
         try {
@@ -245,6 +256,9 @@
 
     @Override
     public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+
+        ensureCaller();
+
         final SQLiteDatabase db = mDbHelper.getWritableDatabase();
         db.beginTransaction();
         try {
@@ -275,6 +289,9 @@
     @Override
     public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
             throws OperationApplicationException {
+
+        ensureCaller();
+
         if (VERBOSE_LOGGING) {
             Log.v(TAG, "applyBatch: " + operations.size() + " ops");
         }
@@ -291,6 +308,9 @@
 
     @Override
     public int bulkInsert(Uri uri, ContentValues[] values) {
+
+        ensureCaller();
+
         if (VERBOSE_LOGGING) {
             Log.v(TAG, "bulkInsert: " + values.length + " inserts");
         }
@@ -411,4 +431,13 @@
 
         return id;
     }
+
+    @VisibleForTesting
+    void ensureCaller() {
+        final String caller = getCallingPackage();
+        if (mAllowedPackage.equals(caller)) {
+            return; // Okay.
+        }
+        throw new SecurityException("Caller " + caller + " can't access ContactMetadataProvider");
+    }
 }
diff --git a/tests/src/com/android/providers/contacts/ContactMetadataProviderTest.java b/tests/src/com/android/providers/contacts/ContactMetadataProviderTest.java
index 5ee4450..8c2a754 100644
--- a/tests/src/com/android/providers/contacts/ContactMetadataProviderTest.java
+++ b/tests/src/com/android/providers/contacts/ContactMetadataProviderTest.java
@@ -99,8 +99,8 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        mContactMetadataProvider = (ContactMetadataProvider) addProvider(
-                ContactMetadataProvider.class, MetadataSync.METADATA_AUTHORITY);
+        mContactMetadataProvider = addProvider(
+                ContactMetadataProviderTestable.class, MetadataSync.METADATA_AUTHORITY);
         // Reset the dbHelper to be the one ContactsProvider2 is using. Before this, two providers
         // are using different dbHelpers.
         mContactMetadataProvider.setDatabaseHelper(((SynchronousContactsProvider2)
diff --git a/tests/src/com/android/providers/contacts/ContactMetadataProviderTestable.java b/tests/src/com/android/providers/contacts/ContactMetadataProviderTestable.java
new file mode 100644
index 0000000..c46643f
--- /dev/null
+++ b/tests/src/com/android/providers/contacts/ContactMetadataProviderTestable.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2016 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.contacts;
+
+public class ContactMetadataProviderTestable extends ContactMetadataProvider {
+    @Override
+    void ensureCaller() {
+        // Not testable, skip.
+    }
+}