diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java index 0173861427..b8f4129665 100644 --- a/service/src/com/android/server/ConnectivityService.java +++ b/service/src/com/android/server/ConnectivityService.java @@ -5915,7 +5915,13 @@ public class ConnectivityService extends IConnectivityManager.Stub public void binderDied() { log("ConnectivityService NetworkRequestInfo binderDied(" + "uid/pid:" + mUid + "/" + mPid + ", " + mBinder + ")"); - mHandler.post(() -> handleRemoveNetworkRequest(this)); + // As an immutable collection, mRequests cannot change by the time the + // lambda is evaluated on the handler thread so calling .get() from a binder thread + // is acceptable. Use handleReleaseNetworkRequest and not directly + // handleRemoveNetworkRequest so as to force a lookup in the requests map, in case + // the app already unregistered the request. + mHandler.post(() -> handleReleaseNetworkRequest(mRequests.get(0), + mUid, false /* callOnUnavailable */)); } @Override diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java index 12ad40e804..1b3496f9dd 100644 --- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java @@ -280,6 +280,7 @@ import android.os.HandlerThread; import android.os.IBinder; import android.os.INetworkManagementService; import android.os.Looper; +import android.os.Messenger; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.Parcelable; @@ -2168,6 +2169,45 @@ public class ConnectivityServiceTest { mCm.unregisterNetworkCallback(fgMobileListenCallback); } + @Test + public void testBinderDeathAfterUnregister() throws Exception { + final NetworkCapabilities caps = new NetworkCapabilities.Builder() + .addTransportType(TRANSPORT_WIFI) + .build(); + final Handler handler = new Handler(ConnectivityThread.getInstanceLooper()); + final Messenger messenger = new Messenger(handler); + final CompletableFuture deathRecipient = new CompletableFuture<>(); + final Binder binder = new Binder() { + private DeathRecipient mDeathRecipient; + @Override + public void linkToDeath(@NonNull final DeathRecipient recipient, final int flags) { + synchronized (this) { + mDeathRecipient = recipient; + } + super.linkToDeath(recipient, flags); + deathRecipient.complete(recipient); + } + + @Override + public boolean unlinkToDeath(@NonNull final DeathRecipient recipient, final int flags) { + synchronized (this) { + if (null == mDeathRecipient) { + throw new IllegalStateException(); + } + mDeathRecipient = null; + } + return super.unlinkToDeath(recipient, flags); + } + }; + final NetworkRequest request = mService.listenForNetwork(caps, messenger, binder, + NetworkCallback.FLAG_NONE, mContext.getOpPackageName(), + mContext.getAttributionTag()); + mService.releaseNetworkRequest(request); + deathRecipient.get().binderDied(); + // Wait for the release message to be processed. + waitForIdle(); + } + @Test public void testValidatedCellularOutscoresUnvalidatedWiFi() throws Exception { // Test bringing up unvalidated WiFi