From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Dmitry Muhomor <muhomor.dmitry@gmail.com>
Date: Sun, 31 Jul 2022 18:00:35 +0300
Subject: [PATCH] improve compatibility of INTERNET special runtime permission

There are apps that refuse to work when they detect that INTERNET is revoked, usually because of
a library check that reminds the app developer to add INTERNET uses-permission element to app's
AndroidManifest.
Always report that INTERNET is granted unless the app has
<meta-data android:name="android.permission.INTERNET.mode" android:value="runtime" />
declaration inside <application> element in its AndroidManifest, or is a system app.
---
 core/api/system-current.txt                   |  5 +++++
 core/java/android/app/DownloadManager.java    | 13 ++++++++++++
 .../content/pm/AppPermissionUtils.java        |  7 +++++++
 .../pm/SpecialRuntimePermAppUtils.java        | 20 +++++++++++++++++++
 .../permission/SpecialRuntimePermUtils.java   | 17 ++++++++++++++++
 5 files changed, 62 insertions(+)

diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 531b03cd7c0c..64115f76caf4 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -3547,6 +3547,11 @@ package android.content.pm {
   }
 
   public class SpecialRuntimePermAppUtils {
+    method public static boolean awareOfRuntimeInternetPermission();
+    method public static boolean isInternetCompatEnabled();
+    method public static boolean requestsInternetPermission();
+    field public static final int FLAG_AWARE_OF_RUNTIME_INTERNET_PERMISSION = 4; // 0x4
+    field public static final int FLAG_REQUESTS_INTERNET_PERMISSION = 2; // 0x2
   }
 
   public final class SuspendDialogInfo implements android.os.Parcelable {
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index c209660f4197..ee412eb50064 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -34,6 +34,7 @@ import android.content.Context;
 import android.database.Cursor;
 import android.database.CursorWrapper;
 import android.database.DatabaseUtils;
+import android.database.MatrixCursor;
 import android.net.ConnectivityManager;
 import android.net.NetworkPolicyManager;
 import android.net.Uri;
@@ -53,6 +54,8 @@ import android.util.LongSparseArray;
 import android.util.Pair;
 import android.webkit.MimeTypeMap;
 
+import android.content.pm.SpecialRuntimePermAppUtils;
+
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.util.ArrayList;
@@ -1123,6 +1126,11 @@ public class DownloadManager {
      * calls related to this download.
      */
     public long enqueue(Request request) {
+        if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) {
+            // invalid id (DownloadProvider uses SQLite and returns a row id)
+            return -1;
+        }
+
         ContentValues values = request.toContentValues(mPackageName);
         Uri downloadUri = mResolver.insert(Downloads.Impl.CONTENT_URI, values);
         long id = Long.parseLong(downloadUri.getLastPathSegment());
@@ -1170,6 +1178,11 @@ public class DownloadManager {
 
     /** @hide */
     public Cursor query(Query query, String[] projection) {
+        if (SpecialRuntimePermAppUtils.isInternetCompatEnabled()) {
+            // underlying provider is protected by the INTERNET permission
+            return new MatrixCursor(projection);
+        }
+
         Cursor underlyingCursor = query.runQuery(mResolver, projection, mBaseUri);
         if (underlyingCursor == null) {
             return null;
diff --git a/core/java/android/content/pm/AppPermissionUtils.java b/core/java/android/content/pm/AppPermissionUtils.java
index 7dc20eec8485..6a96f70dcfcf 100644
--- a/core/java/android/content/pm/AppPermissionUtils.java
+++ b/core/java/android/content/pm/AppPermissionUtils.java
@@ -24,6 +24,13 @@ public class AppPermissionUtils {
     // android.app.ApplicationPackageManager#checkPermission(String permName, String pkgName)
     // android.app.ContextImpl#checkPermission(String permission, int pid, int uid)
     public static boolean shouldSpoofSelfCheck(String permName) {
+        if (Manifest.permission.INTERNET.equals(permName)
+                && SpecialRuntimePermAppUtils.requestsInternetPermission()
+                && !SpecialRuntimePermAppUtils.awareOfRuntimeInternetPermission())
+        {
+            return true;
+        }
+
         return false;
     }
 }
diff --git a/core/java/android/content/pm/SpecialRuntimePermAppUtils.java b/core/java/android/content/pm/SpecialRuntimePermAppUtils.java
index efd48cb49aa3..2f973a585d5c 100644
--- a/core/java/android/content/pm/SpecialRuntimePermAppUtils.java
+++ b/core/java/android/content/pm/SpecialRuntimePermAppUtils.java
@@ -28,9 +28,29 @@ import android.permission.PermissionManager;
 @SystemApi
 public class SpecialRuntimePermAppUtils {
     private static final int FLAG_INITED = 1;
+    public static final int FLAG_REQUESTS_INTERNET_PERMISSION = 1 << 1;
+    public static final int FLAG_AWARE_OF_RUNTIME_INTERNET_PERMISSION = 1 << 2;
 
     private static volatile int cachedFlags;
 
+    private static boolean hasInternetPermission() {
+        // checkSelfPermission() is spoofed, query the underlying API directly
+        return PermissionManager.checkPermission(Manifest.permission.INTERNET, Process.myPid(), Process.myUid())
+                == PackageManager.PERMISSION_GRANTED;
+    }
+
+    public static boolean requestsInternetPermission() {
+        return (getFlags() & FLAG_REQUESTS_INTERNET_PERMISSION) != 0;
+    }
+
+    public static boolean awareOfRuntimeInternetPermission() {
+        return (getFlags() & FLAG_AWARE_OF_RUNTIME_INTERNET_PERMISSION) != 0;
+    }
+
+    public static boolean isInternetCompatEnabled() {
+        return !hasInternetPermission() && requestsInternetPermission() && !awareOfRuntimeInternetPermission();
+    }
+
     private static int getFlags() {
         int cache = cachedFlags;
         if (cache != 0) {
diff --git a/services/core/java/com/android/server/pm/permission/SpecialRuntimePermUtils.java b/services/core/java/com/android/server/pm/permission/SpecialRuntimePermUtils.java
index fe946ff5d5ca..6f5cabb8a8fc 100644
--- a/services/core/java/com/android/server/pm/permission/SpecialRuntimePermUtils.java
+++ b/services/core/java/com/android/server/pm/permission/SpecialRuntimePermUtils.java
@@ -34,11 +34,28 @@ public class SpecialRuntimePermUtils {
         for (ParsedUsesPermission perm : pkg.getUsesPermissions()) {
             String name = perm.getName();
             switch (name) {
+                case Manifest.permission.INTERNET:
+                    flags |= FLAG_REQUESTS_INTERNET_PERMISSION;
+                    continue;
                 default:
                     continue;
             }
         }
 
+        if ((flags & FLAG_REQUESTS_INTERNET_PERMISSION) != 0) {
+            if (pkg.isSystem()) {
+                flags |= FLAG_AWARE_OF_RUNTIME_INTERNET_PERMISSION;
+            } else {
+                Bundle metadata = pkg.getMetaData();
+                if (metadata != null) {
+                    String key = Manifest.permission.INTERNET + ".mode";
+                    if ("runtime".equals(metadata.getString(key))) {
+                        flags |= FLAG_AWARE_OF_RUNTIME_INTERNET_PERMISSION;
+                    }
+                }
+            }
+        }
+
         return flags;
     }
 
