-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Android: Ensuring DNS-SD service is discoverable before calling NsdMa…
…nager.resolveService() (#99) (#25597) * Android: Ensuring DNS-SD service is discoverable before calling NsdManager.resolveService() * Addressing feedback from cliffamzn@ * Stopping discovery and cancelling corresponding ScheduledFuture when service is found * Update src/platform/android/java/chip/platform/NsdServiceFinderAndResolver.java --------- Co-authored-by: Cliff Chung <[email protected]>
- Loading branch information
Showing
3 changed files
with
221 additions
and
56 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
208 changes: 208 additions & 0 deletions
208
src/platform/android/java/chip/platform/NsdServiceFinderAndResolver.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
/* | ||
* Copyright (c) 2023 Project CHIP Authors | ||
* All rights reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
* | ||
*/ | ||
|
||
package chip.platform; | ||
|
||
import android.net.nsd.NsdManager; | ||
import android.net.nsd.NsdServiceInfo; | ||
import android.net.wifi.WifiManager.MulticastLock; | ||
import android.os.Handler; | ||
import android.util.Log; | ||
import androidx.annotation.Nullable; | ||
import java.util.concurrent.Executors; | ||
import java.util.concurrent.ScheduledFuture; | ||
import java.util.concurrent.TimeUnit; | ||
|
||
class NsdServiceFinderAndResolver implements NsdManager.DiscoveryListener { | ||
private static final String TAG = NsdServiceFinderAndResolver.class.getSimpleName(); | ||
|
||
private static final long BROWSE_SERVICE_TIMEOUT_MS = 5000L; | ||
|
||
private final NsdManager nsdManager; | ||
private final NsdServiceInfo targetServiceInfo; | ||
private final long callbackHandle; | ||
private final long contextHandle; | ||
private final ChipMdnsCallback chipMdnsCallback; | ||
private final Runnable timeoutRunnable; | ||
private final MulticastLock multicastLock; | ||
private final Handler mainThreadHandler; | ||
|
||
@Nullable | ||
private final NsdManagerServiceResolver.NsdManagerResolverAvailState nsdManagerResolverAvailState; | ||
|
||
private ScheduledFuture<?> stopDiscoveryRunnable; | ||
|
||
public NsdServiceFinderAndResolver( | ||
final NsdManager nsdManager, | ||
final NsdServiceInfo targetServiceInfo, | ||
final long callbackHandle, | ||
final long contextHandle, | ||
final ChipMdnsCallback chipMdnsCallback, | ||
final Runnable timeoutRunnable, | ||
final MulticastLock multicastLock, | ||
final Handler mainThreadHandler, | ||
final NsdManagerServiceResolver.NsdManagerResolverAvailState nsdManagerResolverAvailState) { | ||
this.nsdManager = nsdManager; | ||
this.targetServiceInfo = targetServiceInfo; | ||
this.callbackHandle = callbackHandle; | ||
this.contextHandle = contextHandle; | ||
this.chipMdnsCallback = chipMdnsCallback; | ||
this.timeoutRunnable = timeoutRunnable; | ||
this.multicastLock = multicastLock; | ||
this.mainThreadHandler = mainThreadHandler; | ||
this.nsdManagerResolverAvailState = nsdManagerResolverAvailState; | ||
} | ||
|
||
public void start() { | ||
multicastLock.acquire(); | ||
|
||
this.nsdManager.discoverServices( | ||
targetServiceInfo.getServiceType(), NsdManager.PROTOCOL_DNS_SD, this); | ||
|
||
NsdServiceFinderAndResolver serviceFinderResolver = this; | ||
this.stopDiscoveryRunnable = | ||
Executors.newSingleThreadScheduledExecutor() | ||
.schedule( | ||
new Runnable() { | ||
@Override | ||
public void run() { | ||
Log.d( | ||
TAG, | ||
"Service discovery timed out after " + BROWSE_SERVICE_TIMEOUT_MS + " ms"); | ||
nsdManager.stopServiceDiscovery(serviceFinderResolver); | ||
if (multicastLock.isHeld()) { | ||
multicastLock.release(); | ||
} | ||
} | ||
}, | ||
BROWSE_SERVICE_TIMEOUT_MS, | ||
TimeUnit.MILLISECONDS); | ||
} | ||
|
||
@Override | ||
public void onServiceFound(NsdServiceInfo service) { | ||
if (targetServiceInfo.getServiceName().equals(service.getServiceName())) { | ||
Log.d(TAG, "onServiceFound: found target service " + service); | ||
|
||
if (stopDiscoveryRunnable.cancel(false)) { | ||
nsdManager.stopServiceDiscovery(this); | ||
if (multicastLock.isHeld()) { | ||
multicastLock.release(); | ||
} | ||
} | ||
|
||
if (nsdManagerResolverAvailState != null) { | ||
nsdManagerResolverAvailState.acquireResolver(); | ||
} | ||
|
||
resolveService(service, callbackHandle, contextHandle, chipMdnsCallback, timeoutRunnable); | ||
} else { | ||
Log.d(TAG, "onServiceFound: found service not a target for resolution, ignoring " + service); | ||
} | ||
} | ||
|
||
private void resolveService( | ||
NsdServiceInfo serviceInfo, | ||
final long callbackHandle, | ||
final long contextHandle, | ||
final ChipMdnsCallback chipMdnsCallback, | ||
Runnable timeoutRunnable) { | ||
this.nsdManager.resolveService( | ||
serviceInfo, | ||
new NsdManager.ResolveListener() { | ||
@Override | ||
public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) { | ||
Log.w( | ||
TAG, | ||
"Failed to resolve service '" + serviceInfo.getServiceName() + "': " + errorCode); | ||
chipMdnsCallback.handleServiceResolve( | ||
serviceInfo.getServiceName(), | ||
serviceInfo.getServiceType(), | ||
null, | ||
null, | ||
0, | ||
null, | ||
callbackHandle, | ||
contextHandle); | ||
|
||
if (multicastLock.isHeld()) { | ||
multicastLock.release(); | ||
|
||
if (nsdManagerResolverAvailState != null) { | ||
nsdManagerResolverAvailState.signalFree(); | ||
} | ||
} | ||
mainThreadHandler.removeCallbacks(timeoutRunnable); | ||
} | ||
|
||
@Override | ||
public void onServiceResolved(NsdServiceInfo serviceInfo) { | ||
Log.i( | ||
TAG, | ||
"Resolved service '" | ||
+ serviceInfo.getServiceName() | ||
+ "' to " | ||
+ serviceInfo.getHost()); | ||
// TODO: Find out if DNS-SD results for Android should contain interface ID | ||
chipMdnsCallback.handleServiceResolve( | ||
serviceInfo.getServiceName(), | ||
serviceInfo.getServiceType(), | ||
serviceInfo.getHost().getHostName(), | ||
serviceInfo.getHost().getHostAddress(), | ||
serviceInfo.getPort(), | ||
serviceInfo.getAttributes(), | ||
callbackHandle, | ||
contextHandle); | ||
|
||
if (multicastLock.isHeld()) { | ||
multicastLock.release(); | ||
|
||
if (nsdManagerResolverAvailState != null) { | ||
nsdManagerResolverAvailState.signalFree(); | ||
} | ||
} | ||
mainThreadHandler.removeCallbacks(timeoutRunnable); | ||
} | ||
}); | ||
} | ||
|
||
@Override | ||
public void onDiscoveryStarted(String regType) { | ||
Log.d(TAG, "Service discovery started. regType: " + regType); | ||
} | ||
|
||
@Override | ||
public void onServiceLost(NsdServiceInfo service) { | ||
Log.e(TAG, "Service lost: " + service); | ||
} | ||
|
||
@Override | ||
public void onDiscoveryStopped(String serviceType) { | ||
Log.i(TAG, "Discovery stopped: " + serviceType); | ||
} | ||
|
||
@Override | ||
public void onStartDiscoveryFailed(String serviceType, int errorCode) { | ||
Log.e(TAG, "Discovery failed to start: Error code: " + errorCode); | ||
} | ||
|
||
@Override | ||
public void onStopDiscoveryFailed(String serviceType, int errorCode) { | ||
Log.e(TAG, "Discovery failed to stop: Error code: " + errorCode); | ||
} | ||
} |