Merge "Add support to update the throttle time of silent updates" into sc-dev
diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl
index 32fc74f..b0ce6a5 100644
--- a/core/java/android/content/pm/IPackageInstaller.aidl
+++ b/core/java/android/content/pm/IPackageInstaller.aidl
@@ -63,4 +63,5 @@
     void bypassNextStagedInstallerCheck(boolean value);
 
     void setAllowUnlimitedSilentUpdates(String installerPackageName);
+    void setSilentUpdatesThrottleTime(long throttleTimeInSeconds);
 }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 871dd3d..60a7571 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -1117,6 +1117,17 @@
         mSilentUpdatePolicy.setAllowUnlimitedSilentUpdates(installerPackageName);
     }
 
+    /**
+     * Set the silent updates throttle time in seconds.
+     */
+    @Override
+    public void setSilentUpdatesThrottleTime(long throttleTimeInSeconds) {
+        if (!isCalledBySystemOrShell(Binder.getCallingUid())) {
+            throw new SecurityException("Caller not allowed to set silent updates throttle time");
+        }
+        mSilentUpdatePolicy.setSilentUpdatesThrottleTime(throttleTimeInSeconds);
+    }
+
     private static int getSessionCount(SparseArray<PackageInstallerSession> sessions,
             int installerUid) {
         int count = 0;
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index f9c63a9..49559f29 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -307,8 +307,8 @@
                     return runLogVisibility();
                 case "bypass-staged-installer-check":
                     return runBypassStagedInstallerCheck();
-                case "allow-unlimited-silent-updates":
-                    return runAllowUnlimitedSilentUpdates();
+                case "set-silent-updates-policy":
+                    return runSetSilentUpdatesPolicy();
                 default: {
                     Boolean domainVerificationResult =
                             mDomainVerificationShell.runCommand(this, cmd);
@@ -3041,12 +3041,20 @@
         }
     }
 
-    private int runAllowUnlimitedSilentUpdates() {
+    private int runSetSilentUpdatesPolicy() {
         final PrintWriter pw = getOutPrintWriter();
         String opt;
+        String installerPackageName = null;
+        Long throttleTimeInSeconds = null;
         boolean reset = false;
         while ((opt = getNextOption()) != null) {
             switch (opt) {
+                case "--allow-unlimited-silent-updates":
+                    installerPackageName = getNextArgRequired();
+                    break;
+                case "--throttle-time":
+                    throttleTimeInSeconds = Long.parseLong(getNextArgRequired());
+                    break;
                 case "--reset":
                     reset = true;
                     break;
@@ -3055,10 +3063,24 @@
                     return -1;
             }
         }
+        if (throttleTimeInSeconds != null && throttleTimeInSeconds < 0) {
+            pw.println("Error: Invalid value for \"--throttle-time\":" + throttleTimeInSeconds);
+            return -1;
+        }
 
-        final String installerPackageName = reset ? null : getNextArgRequired();
         try {
-            mInterface.getPackageInstaller().setAllowUnlimitedSilentUpdates(installerPackageName);
+            final IPackageInstaller installer = mInterface.getPackageInstaller();
+            if (reset) {
+                installer.setAllowUnlimitedSilentUpdates(null /* installerPackageName */);
+                installer.setSilentUpdatesThrottleTime(-1 /* restore to the default */);
+            } else {
+                if (installerPackageName != null) {
+                    installer.setAllowUnlimitedSilentUpdates(installerPackageName);
+                }
+                if (throttleTimeInSeconds != null) {
+                    installer.setSilentUpdatesThrottleTime(throttleTimeInSeconds);
+                }
+            }
         } catch (RemoteException e) {
             pw.println("Failure ["
                     + e.getClass().getName() + " - "
@@ -3889,11 +3911,14 @@
         pw.println("      --enable: turn on debug logging (default)");
         pw.println("      --disable: turn off debug logging");
         pw.println("");
-        pw.println("  allow-unlimited-silent-updates (--reset | <INSTALLER>)");
-        pw.println("    Allows unlimited silent updated installation requests from the installer");
-        pw.println("    without the throttle time.");
-        pw.println("      --reset: clear the allowed installer and tracks of silent updates in");
-        pw.println("        the system.");
+        pw.println("  set-silent-updates-policy [--allow-unlimited-silent-updates <INSTALLER>]");
+        pw.println("                            [--throttle-time <SECONDS>] [--reset]");
+        pw.println("    Sets the policies of the silent updates.");
+        pw.println("      --allow-unlimited-silent-updates: allows unlimited silent updated");
+        pw.println("        installation requests from the installer without the throttle time.");
+        pw.println("      --throttle-time: update the silent updates throttle time in seconds.");
+        pw.println("      --reset: restore the installer and throttle time to the default, and");
+        pw.println("        clear tracks of silent updates in the system.");
         pw.println("");
         mDomainVerificationShell.printHelp(pw);
         pw.println("");
diff --git a/services/core/java/com/android/server/pm/SilentUpdatePolicy.java b/services/core/java/com/android/server/pm/SilentUpdatePolicy.java
index 117acab..700f72cf 100644
--- a/services/core/java/com/android/server/pm/SilentUpdatePolicy.java
+++ b/services/core/java/com/android/server/pm/SilentUpdatePolicy.java
@@ -33,7 +33,8 @@
  * in the {@link PackageInstallerSession}.
  */
 public class SilentUpdatePolicy {
-    // A throttle time to prevent the installer from silently updating the same app repeatedly.
+    // The default throttle time to prevent the installer from silently updating the same app
+    // repeatedly.
     private static final long SILENT_UPDATE_THROTTLE_TIME_MS = TimeUnit.SECONDS.toMillis(30);
 
     // Map to the uptime timestamp for each installer and app of the silent update.
@@ -44,6 +45,9 @@
     @GuardedBy("mSilentUpdateInfos")
     private String mAllowUnlimitedSilentUpdatesInstaller;
 
+    @GuardedBy("mSilentUpdateInfos")
+    private long mSilentUpdateThrottleTimeMs = SILENT_UPDATE_THROTTLE_TIME_MS;
+
     /**
      * Checks if the silent update is allowed by the given installer and app package name.
      *
@@ -58,7 +62,11 @@
             return true;
         }
         final long lastSilentUpdatedMs = getTimestampMs(installerPackageName, packageName);
-        return SystemClock.uptimeMillis() - lastSilentUpdatedMs > SILENT_UPDATE_THROTTLE_TIME_MS;
+        final long throttleTimeMs;
+        synchronized (mSilentUpdateInfos) {
+            throttleTimeMs = mSilentUpdateThrottleTimeMs;
+        }
+        return SystemClock.uptimeMillis() - lastSilentUpdatedMs > throttleTimeMs;
     }
 
     /**
@@ -99,11 +107,25 @@
         }
     }
 
+    /**
+     * Set the silent updates throttle time in seconds.
+     *
+     * @param throttleTimeInSeconds The throttle time to set, or <code>-1</code> to restore the
+     *        value to the default.
+     */
+    void setSilentUpdatesThrottleTime(long throttleTimeInSeconds) {
+        synchronized (mSilentUpdateInfos) {
+            mSilentUpdateThrottleTimeMs = throttleTimeInSeconds >= 0
+                    ? TimeUnit.SECONDS.toMillis(throttleTimeInSeconds)
+                    : SILENT_UPDATE_THROTTLE_TIME_MS;
+        }
+    }
+
     private void pruneLocked(long uptime) {
         final int size = mSilentUpdateInfos.size();
         for (int i = size - 1; i >= 0; i--) {
             final long lastSilentUpdatedMs = mSilentUpdateInfos.valueAt(i);
-            if (uptime - lastSilentUpdatedMs > SILENT_UPDATE_THROTTLE_TIME_MS) {
+            if (uptime - lastSilentUpdatedMs > mSilentUpdateThrottleTimeMs) {
                 mSilentUpdateInfos.removeAt(i);
             }
         }