diff --git a/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/MatterCommissioningPrompter.java b/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/MatterCommissioningPrompter.java index 4be7f24903f1cd..2e9c36a3dafb81 100644 --- a/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/MatterCommissioningPrompter.java +++ b/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/MatterCommissioningPrompter.java @@ -112,14 +112,7 @@ public void promptCommissioningSucceeded(int vendorId, int productId, String com } public void promptCommissioningFailed(String commissioneeName, String error) { - Log.d( - TAG, - "Received prompt for failure vendor id:" - + vendorId - + " productId:" - + productId - + ". Commissionee: " - + commissioneeName); + Log.d(TAG, "Received prompt for failure Commissionee: " + commissioneeName); NotificationCompat.Builder builder = new NotificationCompat.Builder(activity, CHANNEL_ID) .setSmallIcon(R.drawable.ic_baseline_clear_24) diff --git a/examples/tv-app/android/java/src/com/tcl/chip/tvapp/UserPrompterResolver.java b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/UserPrompterResolver.java index 18c0bd181de770..b3a0ca5f6ed77f 100644 --- a/examples/tv-app/android/java/src/com/tcl/chip/tvapp/UserPrompterResolver.java +++ b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/UserPrompterResolver.java @@ -19,7 +19,7 @@ public class UserPrompterResolver { - private static final String TAG = "UserPrompterResolver"; + protected static final String TAG = "UserPrompterResolver"; public native void OnPinCodeEntered(int pinCode); diff --git a/src/platform/android/AndroidChipPlatform-JNI.cpp b/src/platform/android/AndroidChipPlatform-JNI.cpp index 021849256df7b4..2b8450d23b1f6c 100644 --- a/src/platform/android/AndroidChipPlatform-JNI.cpp +++ b/src/platform/android/AndroidChipPlatform-JNI.cpp @@ -238,11 +238,11 @@ JNI_METHOD(void, nativeSetServiceResolver)(JNIEnv * env, jclass self, jobject re } JNI_MDNSCALLBACK_METHOD(void, handleServiceResolve) -(JNIEnv * env, jclass self, jstring instanceName, jstring serviceType, jstring address, jint port, jlong callbackHandle, - jlong contextHandle) +(JNIEnv * env, jclass self, jstring instanceName, jstring serviceType, jstring address, jint port, jobject attributes, + jlong callbackHandle, jlong contextHandle) { using ::chip::Dnssd::HandleResolve; - HandleResolve(instanceName, serviceType, address, port, callbackHandle, contextHandle); + HandleResolve(instanceName, serviceType, address, port, attributes, callbackHandle, contextHandle); } #if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE diff --git a/src/platform/android/DnssdImpl.cpp b/src/platform/android/DnssdImpl.cpp index 0fa4397d8f39ad..a5b6fae94759ed 100644 --- a/src/platform/android/DnssdImpl.cpp +++ b/src/platform/android/DnssdImpl.cpp @@ -29,6 +29,7 @@ #include #include +#include #include namespace chip { @@ -37,11 +38,14 @@ namespace Dnssd { using namespace chip::Platform; namespace { -jobject sResolverObject = nullptr; -jobject sMdnsCallbackObject = nullptr; -jmethodID sResolveMethod = nullptr; -jmethodID sPublishMethod = nullptr; -jmethodID sRemoveServicesMethod = nullptr; +jobject sResolverObject = nullptr; +jobject sMdnsCallbackObject = nullptr; +jmethodID sResolveMethod = nullptr; +jmethodID sGetTextEntryKeysMethod = nullptr; +jmethodID sGetTextEntryDataMethod = nullptr; +jclass sMdnsCallbackClass = nullptr; +jmethodID sPublishMethod = nullptr; +jmethodID sRemoveServicesMethod = nullptr; } // namespace // Implementation of functions declared in lib/dnssd/platform/Dnssd.h @@ -185,9 +189,14 @@ void InitializeWithObjects(jobject resolverObject, jobject mdnsCallbackObject) sResolverObject = env->NewGlobalRef(resolverObject); sMdnsCallbackObject = env->NewGlobalRef(mdnsCallbackObject); jclass resolverClass = env->GetObjectClass(sResolverObject); + sMdnsCallbackClass = env->GetObjectClass(sMdnsCallbackObject); VerifyOrReturn(resolverClass != nullptr, ChipLogError(Discovery, "Failed to get Resolver Java class")); + sGetTextEntryKeysMethod = env->GetMethodID(sMdnsCallbackClass, "getTextEntryKeys", "(Ljava/util/Map;)[Ljava/lang/String;"); + + sGetTextEntryDataMethod = env->GetMethodID(sMdnsCallbackClass, "getTextEntryData", "(Ljava/util/Map;Ljava/lang/String;)[B"); + sResolveMethod = env->GetMethodID(resolverClass, "resolve", "(Ljava/lang/String;Ljava/lang/String;JJLchip/platform/ChipMdnsCallback;)V"); if (sResolveMethod == nullptr) @@ -196,6 +205,18 @@ void InitializeWithObjects(jobject resolverObject, jobject mdnsCallbackObject) env->ExceptionClear(); } + if (sGetTextEntryKeysMethod == nullptr) + { + ChipLogError(Discovery, "Failed to access MdnsCallback 'getTextEntryKeys' method"); + env->ExceptionClear(); + } + + if (sGetTextEntryDataMethod == nullptr) + { + ChipLogError(Discovery, "Failed to access MdnsCallback 'getTextEntryData' method"); + env->ExceptionClear(); + } + sPublishMethod = env->GetMethodID(resolverClass, "publish", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I[Ljava/lang/String;[[B[Ljava/lang/String;)V"); @@ -213,7 +234,8 @@ void InitializeWithObjects(jobject resolverObject, jobject mdnsCallbackObject) } } -void HandleResolve(jstring instanceName, jstring serviceType, jstring address, jint port, jlong callbackHandle, jlong contextHandle) +void HandleResolve(jstring instanceName, jstring serviceType, jstring address, jint port, jobject textEntries, jlong callbackHandle, + jlong contextHandle) { VerifyOrReturn(callbackHandle != 0, ChipLogError(Discovery, "HandleResolve called with callback equal to nullptr")); @@ -241,9 +263,74 @@ void HandleResolve(jstring instanceName, jstring serviceType, jstring address, j DnssdService service = {}; CopyString(service.mName, jniInstanceName.c_str()); CopyString(service.mType, jniServiceType.c_str()); - service.mPort = static_cast(port); + service.mPort = static_cast(port); + service.mTextEntrySize = 0; + service.mTextEntries = nullptr; + + // Note on alloc/free memory use + // We are only allocating the entries list and the data field of each entry + // so we free these in the exit section + if (textEntries != nullptr) + { + jobjectArray keys = (jobjectArray) env->CallObjectMethod(sMdnsCallbackObject, sGetTextEntryKeysMethod, textEntries); + size_t size = env->GetArrayLength(keys); + TextEntry * entries = new (std::nothrow) TextEntry[size]; + VerifyOrExit(entries != nullptr, ChipLogError(Discovery, "entries alloc failure")); + memset(entries, 0, sizeof(entries[0]) * size); + + service.mTextEntries = entries; + for (size_t i = 0; i < size; i++) + { + jstring jniKeyObject = (jstring) env->GetObjectArrayElement(keys, i); + JniUtfString key(env, jniKeyObject); + entries[i].mKey = strdup(key.c_str()); + + jbyteArray datas = + (jbyteArray) env->CallObjectMethod(sMdnsCallbackObject, sGetTextEntryDataMethod, textEntries, jniKeyObject); + if (datas != nullptr) + { + size_t dataSize = env->GetArrayLength(datas); + uint8_t * data = new (std::nothrow) uint8_t[dataSize]; + VerifyOrExit(data != nullptr, ChipLogError(Discovery, "data alloc failure")); + + jbyte * jnidata = env->GetByteArrayElements(datas, nullptr); + for (size_t j = 0; j < dataSize; j++) + { + data[j] = static_cast(jnidata[j]); + } + entries[i].mDataSize = dataSize; + entries[i].mData = data; + + ChipLogProgress(Discovery, " ----- entry [%u] : %s %s\n", static_cast(i), entries[i].mKey, + std::string(reinterpret_cast(data), dataSize).c_str()); + } + else + { + ChipLogProgress(Discovery, " ----- entry [%u] : %s NULL\n", static_cast(i), entries[i].mKey); + + entries[i].mDataSize = 0; + entries[i].mData = nullptr; + } + service.mTextEntrySize = size; + } + } +exit: dispatch(CHIP_NO_ERROR, &service, &ipAddress); + + if (service.mTextEntries != nullptr) + { + size_t size = service.mTextEntrySize; + for (size_t i = 0; i < size; i++) + { + delete[] service.mTextEntries[i].mKey; + if (service.mTextEntries[i].mData != nullptr) + { + delete[] service.mTextEntries[i].mData; + } + } + delete[] service.mTextEntries; + } } } // namespace Dnssd diff --git a/src/platform/android/DnssdImpl.h b/src/platform/android/DnssdImpl.h index 0a6b30870b081b..688f5cb2a597db 100644 --- a/src/platform/android/DnssdImpl.h +++ b/src/platform/android/DnssdImpl.h @@ -32,7 +32,7 @@ void InitializeWithObjects(jobject resolverObject, jobject chipMdnsCallbackObjec /** * Pass results of the service resolution to the CHIP stack. */ -void HandleResolve(jstring instanceName, jstring serviceType, jstring address, jint port, jlong callbackHandle, +void HandleResolve(jstring instanceName, jstring serviceType, jstring address, jint port, jobject textEntries, jlong callbackHandle, jlong contextHandle); } // namespace Dnssd diff --git a/src/platform/android/java/chip/platform/ChipMdnsCallback.java b/src/platform/android/java/chip/platform/ChipMdnsCallback.java index 58304997a07ef4..bbb6701ec8f633 100644 --- a/src/platform/android/java/chip/platform/ChipMdnsCallback.java +++ b/src/platform/android/java/chip/platform/ChipMdnsCallback.java @@ -17,6 +17,8 @@ */ package chip.platform; +import java.util.Map; + /** Interface for communicating with the CHIP mDNS stack. */ public interface ChipMdnsCallback { void handleServiceResolve( @@ -24,6 +26,7 @@ void handleServiceResolve( String serviceType, String address, int port, + Map textEntries, long callbackHandle, long contextHandle); } diff --git a/src/platform/android/java/chip/platform/ChipMdnsCallbackImpl.java b/src/platform/android/java/chip/platform/ChipMdnsCallbackImpl.java index b57189994dab58..60922641ab55f9 100644 --- a/src/platform/android/java/chip/platform/ChipMdnsCallbackImpl.java +++ b/src/platform/android/java/chip/platform/ChipMdnsCallbackImpl.java @@ -17,12 +17,23 @@ */ package chip.platform; +import java.util.Map; + public class ChipMdnsCallbackImpl implements ChipMdnsCallback { public native void handleServiceResolve( String instanceName, String serviceType, String address, int port, + Map textEntries, long callbackHandle, long contextHandle); + + public String[] getTextEntryKeys(Map textEntries) { + return textEntries.keySet().toArray(new String[textEntries.size()]); + } + + public byte[] getTextEntryData(Map textEntries, String key) { + return textEntries.get(key); + } } diff --git a/src/platform/android/java/chip/platform/NsdManagerServiceResolver.java b/src/platform/android/java/chip/platform/NsdManagerServiceResolver.java index 63a28d3ffd5a8e..780d54662bcfca 100644 --- a/src/platform/android/java/chip/platform/NsdManagerServiceResolver.java +++ b/src/platform/android/java/chip/platform/NsdManagerServiceResolver.java @@ -58,7 +58,13 @@ public void resolve( NsdServiceInfo serviceInfo = new NsdServiceInfo(); serviceInfo.setServiceName(instanceName); serviceInfo.setServiceType(serviceType); - Log.d(TAG, "Starting service resolution for '" + instanceName + "'"); + Log.d( + TAG, + "resolve: Starting service resolution for '" + + instanceName + + "' type '" + + serviceType + + "'"); Runnable timeoutRunnable = new Runnable() { @@ -67,6 +73,7 @@ public void run() { // Ensure we always release the multicast lock. It's possible that we release the // multicast lock here before ResolveListener returns, but since NsdManager has no API // to cancel service resolution, there's not much we can do here. + Log.d(TAG, "resolve: Timing out"); if (multicastLock.isHeld()) { multicastLock.release(); } @@ -82,7 +89,7 @@ public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) { TAG, "Failed to resolve service '" + serviceInfo.getServiceName() + "': " + errorCode); chipMdnsCallback.handleServiceResolve( - instanceName, serviceType, null, 0, callbackHandle, contextHandle); + instanceName, serviceType, null, 0, null, callbackHandle, contextHandle); if (multicastLock.isHeld()) { multicastLock.release(); @@ -104,6 +111,7 @@ public void onServiceResolved(NsdServiceInfo serviceInfo) { serviceType, serviceInfo.getHost().getHostAddress(), serviceInfo.getPort(), + serviceInfo.getAttributes(), callbackHandle, contextHandle);