Merge "Fix a Rare Race In Clearing ResourceId" into main
diff --git a/framework-t/src/android/net/IpSecTransform.java b/framework-t/src/android/net/IpSecTransform.java
index 4e10a96..70c9bc8 100644
--- a/framework-t/src/android/net/IpSecTransform.java
+++ b/framework-t/src/android/net/IpSecTransform.java
@@ -124,7 +124,7 @@
     private IpSecTransform activate()
             throws IOException, IpSecManager.ResourceUnavailableException,
                     IpSecManager.SpiUnavailableException {
-        synchronized (this) {
+        synchronized (mLock) {
             try {
                 IpSecTransformResponse result = getIpSecManager(mContext).createTransform(
                         mConfig, new Binder(), mContext.getOpPackageName());
@@ -164,20 +164,23 @@
     public void close() {
         Log.d(TAG, "Removing Transform with Id " + mResourceId);
 
-        // Always safe to attempt cleanup
-        if (mResourceId == INVALID_RESOURCE_ID) {
-            mCloseGuard.close();
-            return;
-        }
-        try {
-            getIpSecManager(mContext).deleteTransform(mResourceId);
-        } catch (Exception e) {
-            // On close we swallow all random exceptions since failure to close is not
-            // actionable by the user.
-            Log.e(TAG, "Failed to close " + this + ", Exception=" + e);
-        } finally {
-            mResourceId = INVALID_RESOURCE_ID;
-            mCloseGuard.close();
+        synchronized(mLock) {
+            // Always safe to attempt cleanup
+            if (mResourceId == INVALID_RESOURCE_ID) {
+                mCloseGuard.close();
+                return;
+            }
+
+            try {
+                    getIpSecManager(mContext).deleteTransform(mResourceId);
+            } catch (Exception e) {
+                // On close we swallow all random exceptions since failure to close is not
+                // actionable by the user.
+                Log.e(TAG, "Failed to close " + this + ", Exception=" + e);
+            } finally {
+                mResourceId = INVALID_RESOURCE_ID;
+                mCloseGuard.close();
+            }
         }
     }
 
@@ -196,14 +199,17 @@
     }
 
     private final IpSecConfig mConfig;
-    private int mResourceId;
+    private final Object mLock = new Object();
+    private int mResourceId; // Partly guarded by mLock to ensure basic safety, not correctness
     private final Context mContext;
     private final CloseGuard mCloseGuard = CloseGuard.get();
 
     /** @hide */
     @VisibleForTesting
     public int getResourceId() {
-        return mResourceId;
+        synchronized(mLock) {
+            return mResourceId;
+        }
     }
 
     /**
@@ -224,8 +230,10 @@
         // TODO: Consider adding check to prevent DDoS attack.
 
         try {
-            final IpSecTransformState ipSecTransformState =
-                    getIpSecManager(mContext).getTransformState(mResourceId);
+            IpSecTransformState ipSecTransformState;
+            synchronized(mLock) {
+                ipSecTransformState = getIpSecManager(mContext).getTransformState(mResourceId);
+            }
             executor.execute(
                     () -> {
                         callback.onResult(ipSecTransformState);