Merge "Increase the number of system PIC nonces" into main
diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java
index 660d880..e9b2ffc 100644
--- a/core/java/android/app/PropertyInvalidatedCache.java
+++ b/core/java/android/app/PropertyInvalidatedCache.java
@@ -2321,12 +2321,14 @@
         @GuardedBy("mLock")
         private int mBlockHash = 0;
 
-        // The number of nonces that the native layer can hold.  This is maintained for debug and
-        // logging.
-        private final int mMaxNonce;
+        // The number of nonces that the native layer can hold.  This is maintained for debug,
+        // logging, and testing.
+        @VisibleForTesting
+        public final int mMaxNonce;
 
         // The size of the native byte block.
-        private final int mMaxByte;
+        @VisibleForTesting
+        public final int mMaxByte;
 
         /** @hide */
         @VisibleForTesting
@@ -2483,18 +2485,20 @@
             }
         }
 
-        static final AtomicLong sStoreCount = new AtomicLong();
-
-
         // Add a string to the local copy of the block and write the block to shared memory.
         // Return the index of the new string.  If the string has already been recorded, the
-        // shared memory is not updated but the index of the existing string is returned.
+        // shared memory is not updated but the index of the existing string is returned.  Only
+        // mMaxNonce strings can be stored; if mMaxNonce strings have already been allocated,
+        // the method throws.
         public int storeName(@NonNull String str) {
             synchronized (mLock) {
                 Integer handle = mStringHandle.get(str);
                 if (handle == null) {
                     throwIfImmutable();
                     throwIfBadString(str);
+                    if (mHighestIndex + 1 >= mMaxNonce) {
+                        throw new RuntimeException("nonce limit exceeded");
+                    }
                     byte[] block = new byte[mMaxByte];
                     nativeGetByteBlock(mPtr, 0, block);
                     appendStringToMapLocked(str, block);
diff --git a/core/jni/android_app_PropertyInvalidatedCache.h b/core/jni/android_app_PropertyInvalidatedCache.h
index 00aa281..54a4ac6 100644
--- a/core/jni/android_app_PropertyInvalidatedCache.h
+++ b/core/jni/android_app_PropertyInvalidatedCache.h
@@ -147,10 +147,12 @@
     }
 };
 
-// The CacheNonce for system server holds 64 nonces with a string block of 8192 bytes.  This is
-// more than enough for system_server PropertyInvalidatedCache support.  The configuration
-// values are not defined as visible constants.  Clients should use the accessors on the
-// SystemCacheNonce instance if they need the sizing parameters.
-typedef CacheNonce</* max nonce */ 64, /* byte block size */ 8192> SystemCacheNonce;
+// The CacheNonce for system server.  The configuration values are not defined as visible
+// constants.  Clients should use the accessors on the SystemCacheNonce instance if they need
+// the sizing parameters.
+
+// LINT.IfChange(system_nonce_config)
+typedef CacheNonce</* max nonce */ 128, /* byte block size */ 8192> SystemCacheNonce;
+// LINT.ThenChange(/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java:system_nonce_config)
 
 } // namespace android.app.PropertyInvalidatedCache
diff --git a/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java
index 5da2564..ac78e87 100644
--- a/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java
+++ b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java
@@ -37,8 +37,10 @@
 import android.app.PropertyInvalidatedCache.NonceWatcher;
 import android.app.PropertyInvalidatedCache.NonceStore;
 import android.os.Binder;
+import android.util.Log;
 import com.android.internal.os.ApplicationSharedMemory;
 
+import android.platform.test.annotations.DisabledOnRavenwood;
 import android.platform.test.annotations.IgnoreUnderRavenwood;
 import android.platform.test.annotations.RequiresFlagsEnabled;
 import android.platform.test.flag.junit.CheckFlagsRule;
@@ -410,8 +412,7 @@
 
     // Verify that invalidating the cache from an app process would fail due to lack of permissions.
     @Test
-    @android.platform.test.annotations.DisabledOnRavenwood(
-            reason = "SystemProperties doesn't have permission check")
+    @DisabledOnRavenwood(reason = "SystemProperties doesn't have permission check")
     public void testPermissionFailure() {
         // Create a cache that will write a system nonce.
         TestCache sysCache = new TestCache(MODULE_SYSTEM, "mode1");
@@ -556,8 +557,7 @@
     // storing nonces in shared memory.
     @RequiresFlagsEnabled(FLAG_APPLICATION_SHARED_MEMORY_ENABLED)
     @Test
-    @android.platform.test.annotations.DisabledOnRavenwood(
-            reason = "PIC doesn't use SharedMemory on Ravenwood")
+    @DisabledOnRavenwood(reason = "PIC doesn't use SharedMemory on Ravenwood")
     public void testSharedMemoryStorage() {
         // Fetch a shared memory instance for testing.
         ApplicationSharedMemory shmem = ApplicationSharedMemory.create();
@@ -602,6 +602,49 @@
         shmem.close();
     }
 
+    // Verify that the configured number of nonce slots is actually available.  This test
+    // hard-codes the configured number of slots, which means that this test must be changed
+    // whenever the shared memory configuration changes.
+    @RequiresFlagsEnabled(FLAG_APPLICATION_SHARED_MEMORY_ENABLED)
+    @Test
+    @DisabledOnRavenwood(reason = "PIC doesn't use SharedMemory on Ravenwood")
+    public void testSharedMemoryNonceConfig() {
+        // The two configured constants.  These are private to this method since they are only
+        // used here.
+        // LINT.IfChange(system_nonce_config)
+        final int maxNonce = 128;
+        final int maxByte = 8192;
+        // LINT.ThenChange(/core/jni/android_app_PropertyInvalidatedCache.h:system_nonce_config)
+
+        // Fetch a shared memory instance for testing.
+        ApplicationSharedMemory shmem = ApplicationSharedMemory.create();
+
+        // Create a server-side store.
+        NonceStore server = new NonceStore(shmem.getSystemNonceBlock(), true);
+
+        // Verify that the configured limits are as expected.
+        assertEquals(server.mMaxNonce, maxNonce);
+        assertEquals(server.mMaxByte, maxByte);
+
+        // Create mMaxNonce nonces.  These all succeed.
+        for (int i = 0; i < server.mMaxNonce; i++) {
+            String name = String.format("name_%03d", i);
+            assertEquals(i, server.storeName(name));
+        }
+
+        // Verify that we cannot create a nonce over the limit.
+        try {
+          int i = server.mMaxNonce;
+          String name = String.format("name_%03d", i);
+          server.storeName(name);
+          fail("expected a RuntimeException");
+        } catch (RuntimeException e) {
+          // Okay
+        }
+
+        shmem.close();
+    }
+
     // Verify that an invalid module causes an exception.
     private void testInvalidModule(String module) {
         try {