Add null check for clientInfo
If the binder death notification for a INsdManagerCallback was
received before any calls are received by NsdService, the
clientInfo would be cleared and cause NPE. Thus, add a null check
to prevent crash.
Bug: 241741274
Test: atest FrameworksNetTests
Change-Id: Iebe761cd579bf3ee46ead389620bed60a21e3154
diff --git a/service-t/src/com/android/server/NsdService.java b/service-t/src/com/android/server/NsdService.java
index 8818460..1226eea 100644
--- a/service-t/src/com/android/server/NsdService.java
+++ b/service-t/src/com/android/server/NsdService.java
@@ -295,6 +295,13 @@
if (DBG) Log.d(TAG, "Discover services");
args = (ListenerArgs) msg.obj;
clientInfo = mClients.get(args.connector);
+ // If the binder death notification for a INsdManagerCallback was received
+ // before any calls are received by NsdService, the clientInfo would be
+ // cleared and cause NPE. Add a null check here to prevent this corner case.
+ if (clientInfo == null) {
+ Log.e(TAG, "Unknown connector in discovery");
+ break;
+ }
if (requestLimitReached(clientInfo)) {
clientInfo.onDiscoverServicesFailed(
@@ -321,6 +328,13 @@
if (DBG) Log.d(TAG, "Stop service discovery");
args = (ListenerArgs) msg.obj;
clientInfo = mClients.get(args.connector);
+ // If the binder death notification for a INsdManagerCallback was received
+ // before any calls are received by NsdService, the clientInfo would be
+ // cleared and cause NPE. Add a null check here to prevent this corner case.
+ if (clientInfo == null) {
+ Log.e(TAG, "Unknown connector in stop discovery");
+ break;
+ }
try {
id = clientInfo.mClientIds.get(clientId);
@@ -341,6 +355,14 @@
if (DBG) Log.d(TAG, "Register service");
args = (ListenerArgs) msg.obj;
clientInfo = mClients.get(args.connector);
+ // If the binder death notification for a INsdManagerCallback was received
+ // before any calls are received by NsdService, the clientInfo would be
+ // cleared and cause NPE. Add a null check here to prevent this corner case.
+ if (clientInfo == null) {
+ Log.e(TAG, "Unknown connector in registration");
+ break;
+ }
+
if (requestLimitReached(clientInfo)) {
clientInfo.onRegisterServiceFailed(
clientId, NsdManager.FAILURE_MAX_LIMIT);
@@ -363,6 +385,9 @@
if (DBG) Log.d(TAG, "unregister service");
args = (ListenerArgs) msg.obj;
clientInfo = mClients.get(args.connector);
+ // If the binder death notification for a INsdManagerCallback was received
+ // before any calls are received by NsdService, the clientInfo would be
+ // cleared and cause NPE. Add a null check here to prevent this corner case.
if (clientInfo == null) {
Log.e(TAG, "Unknown connector in unregistration");
break;
@@ -380,6 +405,13 @@
if (DBG) Log.d(TAG, "Resolve service");
args = (ListenerArgs) msg.obj;
clientInfo = mClients.get(args.connector);
+ // If the binder death notification for a INsdManagerCallback was received
+ // before any calls are received by NsdService, the clientInfo would be
+ // cleared and cause NPE. Add a null check here to prevent this corner case.
+ if (clientInfo == null) {
+ Log.e(TAG, "Unknown connector in resolution");
+ break;
+ }
if (clientInfo.mResolvedService != null) {
clientInfo.onResolveServiceFailed(
diff --git a/tests/unit/java/com/android/server/NsdServiceTest.java b/tests/unit/java/com/android/server/NsdServiceTest.java
index 1813393..5808beb 100644
--- a/tests/unit/java/com/android/server/NsdServiceTest.java
+++ b/tests/unit/java/com/android/server/NsdServiceTest.java
@@ -536,6 +536,25 @@
.onResolveFailed(any(), eq(FAILURE_INTERNAL_ERROR));
}
+ @Test
+ public void testNoCrashWhenProcessResolutionAfterBinderDied() throws Exception {
+ final NsdManager client = connectClient(mService);
+ final INsdManagerCallback cb = getCallback();
+ final IBinder.DeathRecipient deathRecipient = verifyLinkToDeath(cb);
+ deathRecipient.binderDied();
+
+ final NsdServiceInfo request = new NsdServiceInfo(SERVICE_NAME, SERVICE_TYPE);
+ final ResolveListener resolveListener = mock(ResolveListener.class);
+ client.resolveService(request, resolveListener);
+ waitForIdle();
+
+ verify(mMockMDnsM, never()).registerEventListener(any());
+ verify(mMockMDnsM, never()).startDaemon();
+ verify(mMockMDnsM, never()).resolve(anyInt() /* id */, anyString() /* serviceName */,
+ anyString() /* registrationType */, anyString() /* domain */,
+ anyInt()/* interfaceIdx */);
+ }
+
private void waitForIdle() {
HandlerUtils.waitForIdle(mHandler, TIMEOUT_MS);
}