Change the APN lockdown to gate on PlatformCompat

Instead of just logging access denials to the APN db with
PlatformCompat, query them for whether the caller should be allowed
through and vary our behavior based off that.

Fixes: 144631034
Test: atest TelephonyProviderHostTest
Change-Id: I209218d1b91df3ea1fac690a1a8570dcc87505a0
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 4ea2dd7..0a9802d 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -26,6 +26,10 @@
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
     <uses-permission android:name="android.permission.USE_RESERVED_DISK" />
 
+    <!-- Used to access PlatformCompat for security fix enforcement -->
+    <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
+    <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE" />
+
     <protected-broadcast android:name="android.provider.action.EXTERNAL_PROVIDER_CHANGE" />
     <protected-broadcast android:name="android.intent.action.CONTENT_CHANGED" />
 
diff --git a/src/com/android/providers/telephony/TelephonyProvider.java b/src/com/android/providers/telephony/TelephonyProvider.java
index c9f4ee7..2626400 100644
--- a/src/com/android/providers/telephony/TelephonyProvider.java
+++ b/src/com/android/providers/telephony/TelephonyProvider.java
@@ -71,6 +71,7 @@
 import static android.provider.Telephony.Carriers._ID;
 
 import android.annotation.NonNull;
+import android.app.compat.CompatChanges;
 import android.content.ComponentName;
 import android.content.ContentProvider;
 import android.content.ContentResolver;
@@ -113,7 +114,6 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.compat.IPlatformCompat;
 import com.android.internal.util.XmlUtils;
 import android.service.carrier.IApnSourceService;
 
@@ -2888,7 +2888,7 @@
         List<String> constraints = new ArrayList<String>();
 
         int match = s_urlMatcher.match(url);
-        checkPermission();
+        checkPermissionCompat(match, projectionIn);
         switch (match) {
             case URL_TELEPHONY_USING_SUBID: {
                 subIdString = url.getLastPathSegment();
@@ -3907,21 +3907,52 @@
             }
         }
 
-        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 permission to access APN settings");
     }
 
+    /**
+     * Check permission to query the database based on PlatformCompat settings -- if the compat
+     * change is enabled, check WRITE_APN_SETTINGS or carrier privs for all queries. Otherwise,
+     * use the legacy checkQueryPermission method to see if the query should be allowed.
+     */
+    private void checkPermissionCompat(int match, String[] projectionIn) {
+        boolean useNewBehavior = CompatChanges.isChangeEnabled(
+                Telephony.Carriers.APN_READING_PERMISSION_CHANGE_ID,
+                Binder.getCallingUid());
+
+        if (!useNewBehavior) {
+            log("Using old permission behavior for telephony provider compat");
+            checkQueryPermission(match, projectionIn);
+        } else {
+            checkPermission();
+        }
+    }
+
+    private void checkQueryPermission(int match, String[] projectionIn) {
+        if (match != URL_SIMINFO) {
+            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)) {
+                        // noop
+                    } else {
+                        checkPermission();
+                        break;
+                    }
+                }
+            } else {
+                // null returns all columns, so need permission check
+                checkPermission();
+            }
+        }
+    }
+
     private DatabaseHelper mOpenHelper;
 
     private void restoreDefaultAPN(int subId) {