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 {