Permission flag updates now notify listeners

Added a version of the onPermissionUpdated and
onInstallPermissionUpdated methods which will notify
OnPermissionChangedListeners, and added this to the
PermissionManagerService "updatePermissionFlags" and
"updatePermissionFlagsForAllApps" methods. Also adds
OnPermissionsChangedListener to @TestApi

Fixes: 135937566
Test: atest PermissionUpdateListenerTest
Change-Id: I906598c366234c3daaa202261678bca04837cb13
diff --git a/api/test-current.txt b/api/test-current.txt
index 0127dfe..bc98bbc 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -694,6 +694,7 @@
   }
 
   public abstract class PackageManager {
+    method @RequiresPermission("android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS") public abstract void addOnPermissionsChangeListener(@NonNull android.content.pm.PackageManager.OnPermissionsChangedListener);
     method public abstract boolean arePermissionsIndividuallyControlled();
     method @Nullable @RequiresPermission("android.permission.INTERACT_ACROSS_USERS_FULL") public abstract String getDefaultBrowserPackageNameAsUser(int);
     method @Nullable public String getIncidentReportApproverPackageName();
@@ -707,6 +708,7 @@
     method @NonNull public abstract String getSharedSystemSharedLibraryPackageName();
     method @Nullable public String getWellbeingPackageName();
     method @RequiresPermission("android.permission.GRANT_RUNTIME_PERMISSIONS") public abstract void grantRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
+    method @RequiresPermission("android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS") public abstract void removeOnPermissionsChangeListener(@NonNull android.content.pm.PackageManager.OnPermissionsChangedListener);
     method @RequiresPermission("android.permission.REVOKE_RUNTIME_PERMISSIONS") public abstract void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
     method @RequiresPermission(anyOf={"android.permission.GRANT_RUNTIME_PERMISSIONS", "android.permission.REVOKE_RUNTIME_PERMISSIONS"}) public abstract void updatePermissionFlags(@NonNull String, @NonNull String, int, int, @NonNull android.os.UserHandle);
     field public static final String FEATURE_ADOPTABLE_STORAGE = "android.software.adoptable_storage";
@@ -729,6 +731,10 @@
     field public static final String SYSTEM_SHARED_LIBRARY_SHARED = "android.ext.shared";
   }
 
+  public static interface PackageManager.OnPermissionsChangedListener {
+    method public void onPermissionsChanged(int);
+  }
+
   public class PermissionInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
     field public static final int FLAG_REMOVED = 2; // 0x2
     field public static final int PROTECTION_FLAG_APP_PREDICTOR = 2097152; // 0x200000
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index e08f4a2..b845a37 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -105,6 +105,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public interface OnPermissionsChangedListener {
 
         /**
@@ -6413,6 +6414,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     @RequiresPermission(Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS)
     public abstract void addOnPermissionsChangeListener(
             @NonNull OnPermissionsChangedListener listener);
@@ -6425,6 +6427,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     @RequiresPermission(Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS)
     public abstract void removeOnPermissionsChangeListener(
             @NonNull OnPermissionsChangedListener listener);
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index ff4e100..dfff67f 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -268,6 +268,8 @@
         <permission name="android.permission.INSTALL_PACKAGES"/>
         <!-- Needed for test only -->
         <permission name="android.permission.INTERACT_ACROSS_PROFILES"/>
+        <!-- Permission required to test onPermissionsChangedListener -->
+        <permission name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS"/>
         <permission name="android.permission.INTERACT_ACROSS_USERS"/>
         <permission name="android.permission.LOCAL_MAC_ADDRESS"/>
         <permission name="android.permission.MANAGE_ACCESSIBILITY"/>
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 98c6702..8689eef 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -101,6 +101,8 @@
     <uses-permission android:name="android.permission.REVOKE_RUNTIME_PERMISSIONS" />
     <uses-permission android:name="android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS" />
     <uses-permission android:name="android.permission.WHITELIST_RESTRICTED_PERMISSIONS" />
+    <!-- Permission required to test onPermissionsChangedListener -->
+    <uses-permission android:name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS" />
     <uses-permission android:name="android.permission.SET_KEYBOARD_LAYOUT" />
     <uses-permission android:name="android.permission.GET_DETAILED_TASKS" />
     <uses-permission android:name="android.permission.SET_SCREEN_COMPATIBILITY" />
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 62dd3fb..86b1044 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1765,11 +1765,12 @@
 
     private PermissionCallback mPermissionCallback = new PermissionCallback() {
         @Override
-        public void onGidsChanged(int appId, int userId) {
+        public void onGidsChanged(int appId, @UserIdInt int userId) {
             mHandler.post(() -> killUid(appId, userId, KILL_APP_REASON_GIDS_CHANGED));
         }
+
         @Override
-        public void onPermissionGranted(int uid, int userId) {
+        public void onPermissionGranted(int uid, @UserIdInt int userId) {
             mOnPermissionChangeListeners.onPermissionsChanged(uid);
 
             // Not critical; if this is lost, the application has to request again.
@@ -1777,14 +1778,16 @@
                 mSettings.writeRuntimePermissionsForUserLPr(userId, false);
             }
         }
+
         @Override
         public void onInstallPermissionGranted() {
             synchronized (mPackages) {
                 scheduleWriteSettingsLocked();
             }
         }
+
         @Override
-        public void onPermissionRevoked(int uid, int userId) {
+        public void onPermissionRevoked(int uid, @UserIdInt int userId) {
             mOnPermissionChangeListeners.onPermissionsChanged(uid);
 
             synchronized (mPackages) {
@@ -1795,26 +1798,43 @@
             final int appId = UserHandle.getAppId(uid);
             killUid(appId, userId, KILL_APP_REASON_PERMISSIONS_REVOKED);
         }
+
         @Override
         public void onInstallPermissionRevoked() {
             synchronized (mPackages) {
                 scheduleWriteSettingsLocked();
             }
         }
+
         @Override
-        public void onPermissionUpdated(int[] updatedUserIds, boolean sync) {
+        public void onPermissionUpdated(@UserIdInt int[] updatedUserIds, boolean sync) {
             synchronized (mPackages) {
                 for (int userId : updatedUserIds) {
                     mSettings.writeRuntimePermissionsForUserLPr(userId, sync);
                 }
             }
         }
+
+        @Override
+        public void onPermissionUpdatedNotifyListener(@UserIdInt int[] updatedUserIds, boolean sync,
+                int uid) {
+            onPermissionUpdated(updatedUserIds, sync);
+            mOnPermissionChangeListeners.onPermissionsChanged(uid);
+        }
+
         @Override
         public void onInstallPermissionUpdated() {
             synchronized (mPackages) {
                 scheduleWriteSettingsLocked();
             }
         }
+
+        @Override
+        public void onInstallPermissionUpdatedNotifyListener(int uid) {
+            onInstallPermissionUpdated();
+            mOnPermissionChangeListeners.onPermissionsChanged(uid);
+        }
+
         @Override
         public void onPermissionRemoved() {
             synchronized (mPackages) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 890a3c3..6a8f1ed 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -2926,10 +2926,11 @@
             // Install and runtime permissions are stored in different places,
             // so figure out what permission changed and persist the change.
             if (permissionsState.getInstallPermissionState(permName) != null) {
-                callback.onInstallPermissionUpdated();
+                callback.onInstallPermissionUpdatedNotifyListener(pkg.applicationInfo.uid);
             } else if (permissionsState.getRuntimePermissionState(permName, userId) != null
                     || hadState) {
-                callback.onPermissionUpdated(new int[] { userId }, false);
+                callback.onPermissionUpdatedNotifyListener(new int[] { userId }, false,
+                        pkg.applicationInfo.uid);
             }
         }
     }
@@ -2963,6 +2964,8 @@
             PermissionsState permissionsState = ps.getPermissionsState();
             changed |= permissionsState.updatePermissionFlagsForAllPermissions(
                     userId, flagMask, flagValues);
+            callback.onPermissionUpdatedNotifyListener(new int[] { userId }, false,
+                    pkg.applicationInfo.uid);
         }
         return changed;
     }
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 98781e8..8428477 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -16,6 +16,7 @@
 
 package com.android.server.pm.permission;
 
+import android.annotation.AppIdInt;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
@@ -44,24 +45,29 @@
      * callback methods.
      */
     public static class PermissionCallback {
-        public void onGidsChanged(int appId, int userId) {
+        public void onGidsChanged(@AppIdInt int appId, @UserIdInt int userId) {
         }
         public void onPermissionChanged() {
         }
-        public void onPermissionGranted(int uid, int userId) {
+        public void onPermissionGranted(int uid, @UserIdInt int userId) {
         }
         public void onInstallPermissionGranted() {
         }
-        public void onPermissionRevoked(int uid, int userId) {
+        public void onPermissionRevoked(int uid, @UserIdInt int userId) {
         }
         public void onInstallPermissionRevoked() {
         }
-        public void onPermissionUpdated(int[] updatedUserIds, boolean sync) {
+        public void onPermissionUpdated(@UserIdInt int[] updatedUserIds, boolean sync) {
+        }
+        public void onPermissionUpdatedNotifyListener(@UserIdInt int[] updatedUserIds, boolean sync,
+                int uid) {
         }
         public void onPermissionRemoved() {
         }
         public void onInstallPermissionUpdated() {
         }
+        public void onInstallPermissionUpdatedNotifyListener(int uid) {
+        }
     }
 
     public abstract void systemReady();
diff --git a/test-mock/api/test-current.txt b/test-mock/api/test-current.txt
index a87e2f5..cc260ac 100644
--- a/test-mock/api/test-current.txt
+++ b/test-mock/api/test-current.txt
@@ -7,6 +7,7 @@
   }
 
   @Deprecated public class MockPackageManager extends android.content.pm.PackageManager {
+    method public void addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
     method public boolean arePermissionsIndividuallyControlled();
     method public String getDefaultBrowserPackageNameAsUser(int);
     method public int getInstallReason(String, android.os.UserHandle);
@@ -18,6 +19,7 @@
     method @NonNull public String getServicesSystemSharedLibraryPackageName();
     method @NonNull public String getSharedSystemSharedLibraryPackageName();
     method public void grantRuntimePermission(String, String, android.os.UserHandle);
+    method public void removeOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
     method public void revokeRuntimePermission(String, String, android.os.UserHandle);
     method public void updatePermissionFlags(String, String, int, int, android.os.UserHandle);
   }