summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Lee Shombert <shombert@google.com> 2024-11-05 13:23:57 -0800
committer Lee Shombert <shombert@google.com> 2024-11-05 16:00:07 -0800
commit554e5a011cc482a4cd503146e213c7e40bfe9402 (patch)
treeb5b1b8718a9365e68b57946301405ce7fb2b0771
parent9b9a570882d24f361538f2f637dbc6ea0047e455 (diff)
Add synchronization to PIC shared memory
Add more robust synchronization to the PIC shared memory nonce storage. The updated code follows the standard "double-checked" pattern. Flag: android.app.pic_uses_shared_memory Bug: 360897450 Test: atest * FrameworksCoreTests:PropertyInvalidatedCacheTests * FrameworksCoreTests:IpcDataCacheTest * CtsOsTestCases:IpcDataCacheTest Change-Id: I22ee87f9ea86f1bf17dd5e550dfae237236e3f98
-rw-r--r--core/java/android/app/PropertyInvalidatedCache.java77
1 files changed, 45 insertions, 32 deletions
diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java
index 038dcdb7efc9..f432a22b14ac 100644
--- a/core/java/android/app/PropertyInvalidatedCache.java
+++ b/core/java/android/app/PropertyInvalidatedCache.java
@@ -717,12 +717,10 @@ public class PropertyInvalidatedCache<Query, Result> {
// The shared memory.
private volatile NonceStore mStore;
- // The index of the nonce in shared memory.
+ // The index of the nonce in shared memory. This changes from INVALID only when the local
+ // object is completely initialized.
private volatile int mHandle = NonceStore.INVALID_NONCE_INDEX;
- // True if the string has been stored, ever.
- private volatile boolean mRecorded = false;
-
// A short name that is saved in shared memory. This is the portion of the property name
// that follows the prefix.
private final String mShortName;
@@ -736,48 +734,63 @@ public class PropertyInvalidatedCache<Query, Result> {
}
}
+ // Initialize the mStore and mHandle variables. This function does nothing if the
+ // variables are already initialized. Synchronization ensures that initialization happens
+ // no more than once. The function returns the new value of mHandle.
+ //
+ // If the "update" boolean is true, then the property is registered with the nonce store
+ // before the associated handle is fetched.
+ private int initialize(boolean update) {
+ synchronized (mLock) {
+ int handle = mHandle;
+ if (handle == NonceStore.INVALID_NONCE_INDEX) {
+ if (mStore == null) {
+ mStore = NonceStore.getInstance();
+ if (mStore == null) {
+ return NonceStore.INVALID_NONCE_INDEX;
+ }
+ }
+ if (update) {
+ mStore.storeName(mShortName);
+ }
+ handle = mStore.getHandleForName(mShortName);
+ if (handle == NonceStore.INVALID_NONCE_INDEX) {
+ return NonceStore.INVALID_NONCE_INDEX;
+ }
+ // The handle must be valid.
+ mHandle = handle;
+ }
+ return handle;
+ }
+ }
+
// Fetch the nonce from shared memory. If the shared memory is not available, return
// UNSET. If the shared memory is available but the nonce name is not known (it may not
// have been invalidated by the server yet), return UNSET.
@Override
long getNonceInternal() {
- if (mHandle == NonceStore.INVALID_NONCE_INDEX) {
- if (mStore == null) {
- mStore = NonceStore.getInstance();
- if (mStore == null) {
- return NONCE_UNSET;
- }
- }
- mHandle = mStore.getHandleForName(mShortName);
- if (mHandle == NonceStore.INVALID_NONCE_INDEX) {
+ int handle = mHandle;
+ if (handle == NonceStore.INVALID_NONCE_INDEX) {
+ handle = initialize(false);
+ if (handle == NonceStore.INVALID_NONCE_INDEX) {
return NONCE_UNSET;
}
}
- return mStore.getNonce(mHandle);
+ return mStore.getNonce(handle);
}
- // Set the nonce in shared mmory. If the shared memory is not available, throw an
- // exception. Otherwise, if the nonce name has never been recorded, record it now and
- // fetch the handle for the name. If the handle cannot be created, throw an exception.
+ // Set the nonce in shared memory. If the shared memory is not available or if the nonce
+ // cannot be registered in shared memory, throw an exception.
@Override
void setNonceInternal(long value) {
- if (mHandle == NonceStore.INVALID_NONCE_INDEX || !mRecorded) {
- if (mStore == null) {
- mStore = NonceStore.getInstance();
- if (mStore == null) {
- throw new IllegalStateException("setNonce: shared memory not ready");
- }
- }
- // Always store the name before fetching the handle. storeName() is idempotent
- // but does take a little time, so this code calls it just once.
- mStore.storeName(mShortName);
- mRecorded = true;
- mHandle = mStore.getHandleForName(mShortName);
- if (mHandle == NonceStore.INVALID_NONCE_INDEX) {
- throw new IllegalStateException("setNonce: shared memory store failed");
+ int handle = mHandle;
+ if (handle == NonceStore.INVALID_NONCE_INDEX) {
+ handle = initialize(true);
+ if (handle == NonceStore.INVALID_NONCE_INDEX) {
+ throw new IllegalStateException("unable to assign nonce handle: " + mName);
}
}
- mStore.setNonce(mHandle, value);
+ mStore.setNonce(handle, value);
}
}