From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: inthewaves <inthewaves@pm.me>
Date: Sat, 12 Sep 2020 22:28:34 +0300
Subject: [PATCH] support new special runtime permissions

Ported from 12: b294a2ce1d0d185dbc438ac3c06c90386d5f5949
---
 .../PermissionManagerServiceImpl.java         | 39 ++++++++++++++-----
 1 file changed, 30 insertions(+), 9 deletions(-)

diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index 9ed5aa7158ab..79980a274dec 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -1409,7 +1409,8 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
             // their permissions as always granted runtime ones since we need
             // to keep the review required permission flag per user while an
             // install permission's state is shared across all users.
-            if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M && bp.isRuntime()) {
+            if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M && bp.isRuntime() &&
+                    !isSpecialRuntimePermission(permName)) {
                 return;
             }
 
@@ -1452,7 +1453,8 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
                             + " for package " + packageName);
                 }
 
-                if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M) {
+                if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M &&
+                        !isSpecialRuntimePermission(permName)) {
                     Slog.w(TAG, "Cannot grant runtime permission to a legacy app");
                     return;
                 }
@@ -1598,7 +1600,8 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
             // their permissions as always granted runtime ones since we need
             // to keep the review required permission flag per user while an
             // install permission's state is shared across all users.
-            if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M && bp.isRuntime()) {
+            if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M && bp.isRuntime()  &&
+                    !isSpecialRuntimePermission(permName)) {
                 return;
             }
 
@@ -1785,7 +1788,8 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
             // permission as requiring a review as this is the initial state.
             final int uid = mPackageManagerInt.getPackageUid(packageName, 0, userId);
             final int targetSdk = mPackageManagerInt.getUidTargetSdkVersion(uid);
-            final int flags = (targetSdk < Build.VERSION_CODES.M && isRuntimePermission)
+            final int flags = (targetSdk < Build.VERSION_CODES.M && isRuntimePermission
+                    && !isSpecialRuntimePermission(permName))
                     ? FLAG_PERMISSION_REVIEW_REQUIRED | FLAG_PERMISSION_REVOKED_COMPAT
                     : 0;
 
@@ -1805,7 +1809,8 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
 
             // If this permission was granted by default or role, make sure it is.
             if ((oldFlags & FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0
-                    || (oldFlags & FLAG_PERMISSION_GRANTED_BY_ROLE) != 0) {
+                    || (oldFlags & FLAG_PERMISSION_GRANTED_BY_ROLE) != 0
+                    || isSpecialRuntimePermission(permName)) {
                 // PermissionPolicyService will handle the app op for runtime permissions later.
                 grantRuntimePermissionInternal(packageName, permName, false,
                         Process.SYSTEM_UID, userId, delayingPermCallback);
@@ -2518,6 +2523,10 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
         }
     }
 
+    public static boolean isSpecialRuntimePermission(final String permission) {
+        return false;
+    }
+
     /**
      * Restore the permission state for a package.
      *
@@ -2642,6 +2651,8 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
         synchronized (mLock) {
             for (final int userId : userIds) {
                 final UserPermissionState userState = mState.getOrCreateUserState(userId);
+                // "replace" parameter is set to true even when the app is first installed
+                final boolean uidStateWasPresent = userState.getUidState(ps.getAppId()) != null;
                 final UidPermissionState uidState = userState.getOrCreateUidState(ps.getAppId());
 
                 if (uidState.isMissing()) {
@@ -2658,7 +2669,7 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
                                         FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT,
                                         FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT);
                             }
-                            if (uidTargetSdkVersion < Build.VERSION_CODES.M) {
+                            if (uidTargetSdkVersion < Build.VERSION_CODES.M && !isSpecialRuntimePermission(permissionName)) {
                                 uidState.updatePermissionFlags(permission,
                                         PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED
                                                 | PackageManager.FLAG_PERMISSION_REVOKED_COMPAT,
@@ -2828,7 +2839,7 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
                         boolean restrictionApplied = (origState.getPermissionFlags(
                                 bp.getName()) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
 
-                        if (appSupportsRuntimePermissions) {
+                        if (appSupportsRuntimePermissions || isSpecialRuntimePermission(bp.getName())) {
                             // If hard restricted we don't allow holding it
                             if (permissionPolicyInitialized && hardRestricted) {
                                 if (!restrictionExempt) {
@@ -2881,6 +2892,16 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
                                     }
                                 }
                             }
+
+                            if (isSpecialRuntimePermission(permName) &&
+                                    origPermState == null &&
+                                    // don't grant special runtime permission after update,
+                                    // unless app comes from the system image
+                                    (!uidStateWasPresent || ps.isSystem())) {
+                                if (uidState.grantPermission(bp)) {
+                                    wasChanged = true;
+                                }
+                            }
                         } else {
                             if (origPermState == null) {
                                 // New permission
@@ -2915,7 +2936,7 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
                                 if (restrictionApplied) {
                                     flags &= ~FLAG_PERMISSION_APPLY_RESTRICTION;
                                     // Dropping restriction on a legacy app implies a review
-                                    if (!appSupportsRuntimePermissions) {
+                                    if (!appSupportsRuntimePermissions && !isSpecialRuntimePermission(bp.getName())) {
                                         flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
                                     }
                                     wasChanged = true;
@@ -3646,7 +3667,7 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
             if (shouldGrantPermission) {
                 final int flags = getPermissionFlagsInternal(pkg.getPackageName(), permission,
                         myUid, userId);
-                if (supportsRuntimePermissions) {
+                if (supportsRuntimePermissions || isSpecialRuntimePermission(permission)) {
                     // Installer cannot change immutable permissions.
                     if ((flags & immutableFlags) == 0) {
                         grantRuntimePermissionInternal(pkg.getPackageName(), permission, false,
