From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Dmitry Muhomor <muhomor.dmitry@gmail.com>
Date: Mon, 27 Mar 2023 16:00:00 +0300
Subject: [PATCH] add hooks for modifying PackageManagerService behavior

---
 .../server/ext/PackageManagerHooks.java       | 90 +++++++++++++++++++
 .../com/android/server/pm/AppsFilterBase.java |  6 ++
 .../java/com/android/server/pm/Settings.java  |  8 +-
 .../PermissionManagerServiceImpl.java         | 13 +++
 .../pm/pkg/parsing/ParsingPackageUtils.java   |  3 +
 5 files changed, 118 insertions(+), 2 deletions(-)
 create mode 100644 services/core/java/com/android/server/ext/PackageManagerHooks.java

diff --git a/services/core/java/com/android/server/ext/PackageManagerHooks.java b/services/core/java/com/android/server/ext/PackageManagerHooks.java
new file mode 100644
index 000000000000..007b65349e55
--- /dev/null
+++ b/services/core/java/com/android/server/ext/PackageManagerHooks.java
@@ -0,0 +1,90 @@
+package com.android.server.ext;
+
+import android.Manifest;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.os.Build;
+import android.os.UserHandle;
+import android.util.ArraySet;
+
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.permission.Permission;
+import com.android.server.pm.pkg.PackageStateInternal;
+import com.android.server.pm.pkg.parsing.ParsingPackage;
+
+public class PackageManagerHooks {
+
+    // Called when package enabled setting is deserialized from storage
+    @Nullable
+    public static Integer maybeOverridePackageEnabledSetting(String pkgName, @UserIdInt int userId) {
+        switch (pkgName) {
+            default:
+                return null;
+        }
+    }
+
+    // Called when package parsing is completed
+    public static void amendParsedPackage(ParsingPackage pkg) {
+        String pkgName = pkg.getPackageName();
+
+        switch (pkgName) {
+            default:
+                return;
+        }
+    }
+
+    public static void removeUsesPermissions(ParsingPackage pkg, String... perms) {
+        var set = new ArraySet<>(perms);
+        pkg.getRequestedPermissions().removeAll(set);
+        pkg.getUsesPermissions().removeIf(p -> set.contains(p.getName()));
+    }
+
+    public static boolean shouldBlockGrantRuntimePermission(
+            PackageManagerInternal pm, String permName, String packageName, int userId)
+    {
+        return false;
+    }
+
+    public static boolean shouldForciblyGrantPermission(AndroidPackage pkg, Permission perm) {
+        if (!Build.IS_DEBUGGABLE) {
+            return false;
+        }
+
+        String permName = perm.getName();
+
+        switch (pkg.getPackageName()) {
+            default:
+                return false;
+        }
+    }
+
+    // Called when AppsFilter decides whether to restrict package visibility
+    public static boolean shouldFilterAccess(@Nullable PackageStateInternal callingPkgSetting,
+                                             ArraySet<PackageStateInternal> callingSharedPkgSettings,
+                                             PackageStateInternal targetPkgSetting) {
+        if (callingPkgSetting != null && restrictedVisibilityPackages.contains(callingPkgSetting.getPackageName())) {
+            if (!targetPkgSetting.isSystem()) {
+                return true;
+            }
+        }
+
+        if (restrictedVisibilityPackages.contains(targetPkgSetting.getPackageName())) {
+            if (callingPkgSetting != null) {
+                return !callingPkgSetting.isSystem();
+            } else {
+                for (int i = callingSharedPkgSettings.size() - 1; i >= 0; i--) {
+                    if (!callingSharedPkgSettings.valueAt(i).isSystem()) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    // Packages in this array are restricted from interacting with and being interacted by non-system apps
+    private static final ArraySet<String> restrictedVisibilityPackages = new ArraySet<>(new String[] {
+    });
+}
diff --git a/services/core/java/com/android/server/pm/AppsFilterBase.java b/services/core/java/com/android/server/pm/AppsFilterBase.java
index 07746236320e..e2d413419d6a 100644
--- a/services/core/java/com/android/server/pm/AppsFilterBase.java
+++ b/services/core/java/com/android/server/pm/AppsFilterBase.java
@@ -39,6 +39,7 @@ import android.util.SparseArray;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.function.QuadFunction;
+import com.android.server.ext.PackageManagerHooks;
 import com.android.server.om.OverlayReferenceMapper;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
@@ -414,6 +415,11 @@ public abstract class AppsFilterBase implements AppsFilterSnapshot {
                 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
             }
 
+            if (PackageManagerHooks.shouldFilterAccess(callingPkgSetting, callingSharedPkgSettings,
+                    targetPkgSetting)) {
+                return true;
+            }
+
             if (callingPkgSetting != null) {
                 if (callingPkgSetting.getPkg() != null
                         && !mFeatureConfig.packageIsEnabled(callingPkgSetting.getPkg())) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index a9b624653b92..9cac3e75a698 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -100,6 +100,7 @@ import com.android.permission.persistence.RuntimePermissionsPersistence;
 import com.android.permission.persistence.RuntimePermissionsState;
 import com.android.server.LocalServices;
 import com.android.server.backup.PreferredActivityBackupHelper;
+import com.android.server.ext.PackageManagerHooks;
 import com.android.server.pm.Installer.InstallerException;
 import com.android.server.pm.parsing.PackageInfoUtils;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
@@ -1810,8 +1811,11 @@ public final class Settings implements Watchable, Snappable {
                             parser.getAttributeBoolean(null, ATTR_INSTANT_APP, false);
                     final boolean virtualPreload =
                             parser.getAttributeBoolean(null, ATTR_VIRTUAL_PRELOAD, false);
-                    final int enabled = parser.getAttributeInt(null, ATTR_ENABLED,
-                            COMPONENT_ENABLED_STATE_DEFAULT);
+                    final Integer enabledOverride =
+                            PackageManagerHooks.maybeOverridePackageEnabledSetting(name, userId);
+                    final int enabled = (enabledOverride != null) ?
+                            enabledOverride.intValue() :
+                            parser.getAttributeInt(null, ATTR_ENABLED, COMPONENT_ENABLED_STATE_DEFAULT);
                     final String enabledCaller = parser.getAttributeValue(null,
                             ATTR_ENABLED_CALLER);
                     final String harmfulAppWarning =
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 5d2bb41c4b4d..fae8dc90371a 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -127,6 +127,7 @@ import com.android.server.LocalServices;
 import com.android.server.ServiceThread;
 import com.android.server.SystemConfig;
 import com.android.server.Watchdog;
+import com.android.server.ext.PackageManagerHooks;
 import com.android.server.pm.ApexManager;
 import com.android.server.pm.KnownPackages;
 import com.android.server.pm.UserManagerInternal;
@@ -1363,6 +1364,13 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
             isRolePermission = permission.isRole();
             isSoftRestrictedPermission = permission.isSoftRestricted();
         }
+
+        if (PackageManagerHooks.shouldBlockGrantRuntimePermission(mPackageManagerInt, permName, packageName, userId)) {
+            // this method is called from within system_server and from critical system processes,
+            // do not throw an exception, just return
+            return;
+        }
+
         final boolean mayGrantRolePermission = isRolePermission
                 && mayManageRolePermission(callingUid);
         final boolean mayGrantSoftRestrictedPermission = isSoftRestrictedPermission
@@ -2982,6 +2990,11 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
                         Slog.wtf(LOG_TAG, "Unknown permission protection " + bp.getProtection()
                                 + " for permission " + bp.getName());
                     }
+
+                    if (Build.IS_DEBUGGABLE && PackageManagerHooks.shouldForciblyGrantPermission(pkg, bp)) {
+                        uidState.grantPermission(bp);
+                        Slog.d(TAG, "forcibly granted " + bp.getName() + " to " + pkg.getPackageName());
+                    }
                 }
 
                 if ((changedInstallPermission || replace)
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
index 17ac255e60f6..8fd1e6058133 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
@@ -91,6 +91,7 @@ import com.android.internal.R;
 import com.android.internal.os.ClassLoaderFactory;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.XmlUtils;
+import com.android.server.ext.PackageManagerHooks;
 import com.android.server.pm.SharedUidMigration;
 import com.android.server.pm.permission.CompatibilityPermissionInfo;
 import com.android.server.pm.pkg.component.ComponentMutateUtils;
@@ -2203,6 +2204,8 @@ public class ParsingPackageUtils {
             pkg.addActivity(a.getResult());
         }
 
+        PackageManagerHooks.amendParsedPackage(pkg);
+
         if (hasActivityOrder) {
             pkg.sortActivities();
         }
