Merge "Allow URL_DPC and URL_ENFORCE_MANAGED to be called from Phone UID. Add URL_FILTERED_ID for Settings app to call."
am: ee4c9b7ac3

Change-Id: I50afd290d13ce71f277cb23512c8a0afd197667c
diff --git a/src/com/android/providers/telephony/TelephonyProvider.java b/src/com/android/providers/telephony/TelephonyProvider.java
index cce9607..07dfbd0 100644
--- a/src/com/android/providers/telephony/TelephonyProvider.java
+++ b/src/com/android/providers/telephony/TelephonyProvider.java
@@ -147,7 +147,8 @@
     private static final int URL_DPC = 16;
     private static final int URL_DPC_ID = 17;
     private static final int URL_FILTERED = 18;
-    private static final int URL_ENFORCE_MANAGED = 19;
+    private static final int URL_FILTERED_ID = 19;
+    private static final int URL_ENFORCE_MANAGED = 20;
 
 
     private static final String TAG = "TelephonyProvider";
@@ -364,6 +365,9 @@
         // Only called by Settings app, DcTracker and other telephony components to get APN list
         // according to whether DPC records are enforced.
         s_urlMatcher.addURI("telephony", "carriers/filtered", URL_FILTERED);
+        // Only called by Settings app, DcTracker and other telephony components to get a
+        // single APN according to whether DPC records are enforced.
+        s_urlMatcher.addURI("telephony", "carriers/filtered/#", URL_FILTERED_ID);
         // Only Called by DevicePolicyManager to enforce DPC records.
         s_urlMatcher.addURI("telephony", "carriers/enforce_managed", URL_ENFORCE_MANAGED);
 
@@ -2161,12 +2165,13 @@
         }
     }
 
-    boolean isCallingFromSystemUid() {
-        return mInjector.binderGetCallingUid() == Process.SYSTEM_UID;
+    boolean isCallingFromSystemOrPhoneUid() {
+        return mInjector.binderGetCallingUid() == Process.SYSTEM_UID ||
+                mInjector.binderGetCallingUid() == Process.PHONE_UID;
     }
 
-    void ensureCallingFromSystemUid(String message) {
-        if (!isCallingFromSystemUid()) {
+    void ensureCallingFromSystemOrPhoneUid(String message) {
+        if (!isCallingFromSystemOrPhoneUid()) {
             throw new SecurityException(message);
         }
     }
@@ -2252,12 +2257,16 @@
             }
 
             case URL_DPC: {
-                ensureCallingFromSystemUid("URL_DPC called from non SYSTEM_UID.");
+                ensureCallingFromSystemOrPhoneUid("URL_DPC called from non SYSTEM_UID.");
                 // DPC query only returns DPC records.
                 constraints.add(IS_OWNED_BY_DPC);
                 break;
             }
 
+            case URL_FILTERED_ID: {
+                constraints.add("_id = " + url.getLastPathSegment());
+            }
+            //intentional fall through from above case
             case URL_FILTERED: {
                 if(isManagedApnEnforced()) {
                     // If enforced, return DPC records only.
@@ -2270,7 +2279,8 @@
             }
 
             case URL_ENFORCE_MANAGED: {
-                ensureCallingFromSystemUid("URL_ENFORCE_MANAGED called from non SYSTEM_UID.");
+                ensureCallingFromSystemOrPhoneUid(
+                        "URL_ENFORCE_MANAGED called from non SYSTEM_UID.");
                 MatrixCursor cursor = new MatrixCursor(new String[]{ENFORCED_KEY});
                 cursor.addRow(new Object[]{isManagedApnEnforced() ? 1 : 0});
                 return cursor;
@@ -2345,6 +2355,7 @@
             return "vnd.android.cursor.dir/telephony-carrier";
 
         case URL_ID:
+        case URL_FILTERED_ID:
             return "vnd.android.cursor.item/telephony-carrier";
 
         case URL_PREFERAPN_USING_SUBID:
@@ -2546,7 +2557,7 @@
             }
 
             case URL_DPC: {
-                ensureCallingFromSystemUid("URL_DPC called from non SYSTEM_UID.");
+                ensureCallingFromSystemOrPhoneUid("URL_DPC called from non SYSTEM_UID.");
 
                 ContentValues values;
                 if (initialValues != null) {
@@ -2708,7 +2719,7 @@
             }
 
             case URL_DPC_ID: {
-                ensureCallingFromSystemUid("URL_DPC_ID called from non SYSTEM_UID.");
+                ensureCallingFromSystemOrPhoneUid("URL_DPC_ID called from non SYSTEM_UID.");
 
                 // Only delete if owned by DPC.
                 count = db.delete(CARRIERS_TABLE, "(" + _ID + "=?)" + " and " + IS_OWNED_BY_DPC,
@@ -2869,7 +2880,7 @@
 
             case URL_DPC_ID:
             {
-                ensureCallingFromSystemUid("URL_DPC_ID called from non SYSTEM_UID.");
+                ensureCallingFromSystemOrPhoneUid("URL_DPC_ID called from non SYSTEM_UID.");
 
                 if (where != null || whereArgs != null) {
                     throw new UnsupportedOperationException(
@@ -2882,7 +2893,8 @@
             }
 
             case URL_ENFORCE_MANAGED: {
-                ensureCallingFromSystemUid("URL_ENFORCE_MANAGED called from non SYSTEM_UID.");
+                ensureCallingFromSystemOrPhoneUid(
+                        "URL_ENFORCE_MANAGED called from non SYSTEM_UID.");
                 if (values != null) {
                     if (values.containsKey(ENFORCED_KEY)) {
                         setManagedApnEnforced(values.getAsBoolean(ENFORCED_KEY));
diff --git a/tests/src/com/android/providers/telephony/TelephonyProviderTest.java b/tests/src/com/android/providers/telephony/TelephonyProviderTest.java
index 7fd7f61..df331db 100644
--- a/tests/src/com/android/providers/telephony/TelephonyProviderTest.java
+++ b/tests/src/com/android/providers/telephony/TelephonyProviderTest.java
@@ -467,9 +467,9 @@
     /**
      * Test URL_ENFORCE_MANAGED and URL_FILTERED works correctly.
      * Verify that when enforce is set true via URL_ENFORCE_MANAGED, only DPC records are returned
-     * for URL_FILTERED.
+     * for URL_FILTERED and URL_FILTERED_ID.
      * Verify that when enforce is set false via URL_ENFORCE_MANAGED, only non-DPC records
-     * are returned for URL_FILTERED.
+     * are returned for URL_FILTERED and URL_FILTERED_ID.
      */
     @Test
     @SmallTest
@@ -522,6 +522,17 @@
         assertEquals(othersRecordId, cursorNotEnforced.getInt(0));
         assertEquals(Carriers.OWNED_BY_OTHERS, cursorNotEnforced.getInt(1));
 
+        // Verify that URL_FILTERED_ID cannot get DPC record.
+        Cursor cursorNotEnforcedDpc = mContentResolver.query(Uri.withAppendedPath(URI_FILTERED,
+                Integer.toString(dpcRecordId)), null, null, null, null);
+        assertNotNull(cursorNotEnforcedDpc);
+        assertTrue(cursorNotEnforcedDpc.getCount() == 0);
+        // Verify that URL_FILTERED_ID can get non-DPC record.
+        Cursor cursorNotEnforcedOthers = mContentResolver.query(Uri.withAppendedPath(URI_FILTERED,
+                Integer.toString(othersRecordId)), null, null, null, null);
+        assertNotNull(cursorNotEnforcedOthers);
+        assertTrue(cursorNotEnforcedOthers.getCount() == 1);
+
         // Set enforced = true.
         enforceManagedValue.put(ENFORCED_KEY, true);
         Log.d(TAG, "testEnforceManagedUri Updating enforced = true: "
@@ -545,6 +556,17 @@
         assertEquals(dpcRecordId, cursorEnforced.getInt(0));
         assertEquals(Carriers.OWNED_BY_DPC, cursorEnforced.getInt(1));
 
+        // Verify that URL_FILTERED_ID can get DPC record.
+        cursorNotEnforcedDpc = mContentResolver.query(Uri.withAppendedPath(URI_FILTERED,
+                Integer.toString(dpcRecordId)), null, null, null, null);
+        assertNotNull(cursorNotEnforcedDpc);
+        assertTrue(cursorNotEnforcedDpc.getCount() == 1);
+        // Verify that URL_FILTERED_ID cannot get non-DPC record.
+        cursorNotEnforcedOthers = mContentResolver.query(Uri.withAppendedPath(URI_FILTERED,
+                Integer.toString(othersRecordId)), null, null, null, null);
+        assertNotNull(cursorNotEnforcedOthers);
+        assertTrue(cursorNotEnforcedOthers.getCount() == 0);
+
         // Delete testing records.
         int numRowsDeleted = mContentResolver.delete(URI_TELEPHONY, selection, selectionArgs);
         assertEquals(1, numRowsDeleted);
@@ -750,19 +772,19 @@
 
     /**
      * Verify that SecurityException is thrown if URL_DPC, URL_FILTERED and
-     * URL_ENFORCE_MANAGED is accessed from non-SYSTEM_UID.
+     * URL_ENFORCE_MANAGED is accessed from neither SYSTEM_UID nor PHONE_UID.
      */
     @Test
     @SmallTest
     public void testAccessURLDPCThrowSecurityExceptionFromOtherUid() {
-        mTelephonyProviderTestable.fakeCallingUid(Process.SYSTEM_UID + 1);
+        mTelephonyProviderTestable.fakeCallingUid(Process.SYSTEM_UID + 123456);
 
         // Test insert().
         ContentValues contentValuesDPC = new ContentValues();
         try {
             mContentResolver.insert(URI_DPC, contentValuesDPC);
             assertFalse("SecurityException should be thrown when URI_DPC is called from"
-                    + " non-SYSTEM_UID", true);
+                    + " neither SYSTEM_UID nor PHONE_UID", true);
         } catch (SecurityException e) {
             // Should catch SecurityException.
         }
@@ -772,15 +794,15 @@
             mContentResolver.query(URI_DPC,
                     new String[]{}, "", new String[]{}, null);
             assertFalse("SecurityException should be thrown when URI_DPC is called from"
-                    + " non-SYSTEM_UID", true);
+                    + " neither SYSTEM_UID nor PHONE_UID", true);
         } catch (SecurityException e) {
             // Should catch SecurityException.
         }
         try {
             mContentResolver.query(URI_ENFORCE_MANAGED,
             new String[]{}, "", new String[]{}, null);
-            assertFalse("SecurityException should be thrown when URI_ENFORCE_MANAGED is called "
-                + "from non-SYSTEM_UID", true);
+            assertFalse("SecurityException should be thrown when URI_ENFORCE_MANAGED is "
+                    + "called from neither SYSTEM_UID nor PHONE_UID", true);
         } catch (SecurityException e) {
             // Should catch SecurityException.
         }
@@ -792,7 +814,7 @@
                     Uri.parse(URI_DPC + "/1"),
                     contentValuesDPCUpdate, "", new String[]{});
             assertFalse("SecurityException should be thrown when URI_DPC is called"
-                    + " from non-SYSTEM_UID", true);
+                    + " from neither SYSTEM_UID nor PHONE_UID", true);
         } catch (SecurityException e) {
             // Should catch SecurityException.
         }
@@ -800,7 +822,7 @@
             mContentResolver.update(URI_ENFORCE_MANAGED, contentValuesDPCUpdate,
                     "", new String[]{});
             assertFalse("SecurityException should be thrown when URI_DPC is called"
-                    + " from non-SYSTEM_UID", true);
+                    + " from neither SYSTEM_UID nor PHONE_UID", true);
         } catch (SecurityException e) {
             // Should catch SecurityException.
         }
@@ -810,7 +832,7 @@
             mContentResolver.delete(
                     Uri.parse(URI_DPC + "/0"), "", new String[]{});
             assertFalse("SecurityException should be thrown when URI_DPC is called"
-                    + " from non-SYSTEM_UID", true);
+                    + " from neither SYSTEM_UID nor PHONE_UID", true);
         } catch (SecurityException e) {
             // Should catch SecurityException.
         }