From 2169445afc3183baa9b3c17d330e07c2dc4deb73 Mon Sep 17 00:00:00 2001 From: Yufeng Wang Date: Mon, 15 May 2023 19:53:07 -0700 Subject: [PATCH] [Java] Add API pairDeviceWithCode to test pair with setup code (#26494) * [Java] Add pairDeviceWithCode API * Address review comments --- .github/workflows/tests.yaml | 24 +++++++++++++++++++ .../commands/pairing/PairCodeCommand.kt | 2 ++ .../commands/pairing/PairCodeThreadCommand.kt | 2 ++ .../commands/pairing/PairCodeWifiCommand.kt | 2 ++ .../commands/pairing/PairingCommand.kt | 12 ++++++++-- scripts/tests/java/commissioning_test.py | 22 ++++++++++++++++- src/controller/CHIPDeviceController.cpp | 1 + src/controller/CHIPDeviceController.h | 1 + .../java/CHIPDeviceController-JNI.cpp | 17 +++++++++++-- .../ChipDeviceController.java | 16 ++++++++++++- 10 files changed, 93 insertions(+), 6 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 4266a3abe945dc..5d3555383992f5 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -674,6 +674,30 @@ jobs: --tool-args "address-paseonly --nodeid 1 --setup-pin-code 20202021 --address ::1 --port 5540 -t 1000" \ --factoryreset \ ' + - name: Run Pairing SetupQRCode Test + timeout-minutes: 10 + run: | + scripts/run_in_build_env.sh \ + './scripts/tests/run_java_test.py \ + --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app \ + --app-args "--discriminator 3840 --interface-id -1" \ + --tool-path out/linux-x64-java-matter-controller \ + --tool-cluster "pairing" \ + --tool-args "code --nodeid 1 --setup-payload MT:-24J0AFN00KA0648G00 --discover-once 1 --use-only-onnetwork-discovery 0 -t 1000" \ + --factoryreset \ + ' + - name: Run Pairing ManualCode Test + timeout-minutes: 10 + run: | + scripts/run_in_build_env.sh \ + './scripts/tests/run_java_test.py \ + --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app \ + --app-args "--discriminator 3840 --interface-id -1" \ + --tool-path out/linux-x64-java-matter-controller \ + --tool-cluster "pairing" \ + --tool-args "code --nodeid 1 --setup-payload 34970112332 --discover-once 1 --use-only-onnetwork-discovery 0 -t 1000" \ + --factoryreset \ + ' - name: Uploading core files uses: actions/upload-artifact@v3 if: ${{ failure() && !env.ACT }} diff --git a/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairCodeCommand.kt b/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairCodeCommand.kt index bf6e18cceedafd..4c4d191d83fcb0 100644 --- a/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairCodeCommand.kt +++ b/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairCodeCommand.kt @@ -27,6 +27,8 @@ class PairCodeCommand(controller: ChipDeviceController, credsIssue: CredentialsI .pairDeviceWithCode( getNodeId(), getOnboardingPayload(), + getDiscoverOnce(), + getUseOnlyOnNetworkDiscovery(), null, getWifiNetworkCredentials(), ) diff --git a/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairCodeThreadCommand.kt b/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairCodeThreadCommand.kt index 419525733c496a..1168f7f93e30a2 100644 --- a/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairCodeThreadCommand.kt +++ b/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairCodeThreadCommand.kt @@ -27,6 +27,8 @@ class PairCodeThreadCommand(controller: ChipDeviceController, credsIssue: Creden .pairDeviceWithCode( getNodeId(), getOnboardingPayload(), + getDiscoverOnce(), + getUseOnlyOnNetworkDiscovery(), null, getThreadNetworkCredentials(), ) diff --git a/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairCodeWifiCommand.kt b/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairCodeWifiCommand.kt index ffecb2e9529df8..09b639b1c251c1 100644 --- a/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairCodeWifiCommand.kt +++ b/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairCodeWifiCommand.kt @@ -27,6 +27,8 @@ class PairCodeWifiCommand(controller: ChipDeviceController, credsIssue: Credenti .pairDeviceWithCode( getNodeId(), getOnboardingPayload(), + getDiscoverOnce(), + getUseOnlyOnNetworkDiscovery(), null, getWifiNetworkCredentials(), ) diff --git a/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairingCommand.kt b/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairingCommand.kt index e7f90832d0c25c..e2112c7486a9ba 100644 --- a/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairingCommand.kt +++ b/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairingCommand.kt @@ -70,8 +70,8 @@ abstract class PairingCommand( PairingModeType.NONE -> {} PairingModeType.CODE, PairingModeType.CODE_PASE_ONLY -> { addArgument("payload", onboardingPayload, null, false) - addArgument("discover-once", discoverOnce, null, false) - addArgument("use-only-onnetwork-discovery", useOnlyOnNetworkDiscovery, null, false) + addArgument("discover-once", discoverOnce, null, true) + addArgument("use-only-onnetwork-discovery", useOnlyOnNetworkDiscovery, null, true) } PairingModeType.ADDRESS_PASE_ONLY -> { @@ -244,6 +244,14 @@ abstract class PairingCommand( return chunked(2).map { byteStr -> byteStr.toUByte(16).toByte() }.toByteArray() } + fun getDiscoverOnce(): Boolean { + return discoverOnce.get() + } + + fun getUseOnlyOnNetworkDiscovery(): Boolean { + return useOnlyOnNetworkDiscovery.get() + } + companion object { private val logger = Logger.getLogger(PairingCommand::class.java.name) } diff --git a/scripts/tests/java/commissioning_test.py b/scripts/tests/java/commissioning_test.py index 138c9efa49065a..806f64d8746659 100755 --- a/scripts/tests/java/commissioning_test.py +++ b/scripts/tests/java/commissioning_test.py @@ -47,7 +47,10 @@ def __init__(self, thread_list: typing.List[threading.Thread], queue: queue.Queu "session establishment (PASE) with the Commissionee")) parser.add_argument('-n', '--nodeid', help="The Node ID issued to the device", default='1') parser.add_argument('-d', '--discriminator', help="Discriminator of the device", default='3840') - parser.add_argument('-u', '--paa-trust-store-path', dest='paa_trust_store_path', + parser.add_argument('-o', '--discover-once', help="Enable to disable PASE auto retry mechanism", default='false') + parser.add_argument('-u', '--use-only-onnetwork-discovery', + help="Enable when the commissionable device is available on the network", default='false') + parser.add_argument('-r', '--paa-trust-store-path', dest='paa_trust_store_path', help="Path that contains valid and trusted PAA Root Certificates") args = parser.parse_args(args.split()) @@ -59,6 +62,8 @@ def __init__(self, thread_list: typing.List[threading.Thread], queue: queue.Queu self.setup_payload = args.setup_payload self.setup_pin_code = args.setup_pin_code self.discriminator = args.discriminator + self.discover_once = args.discover_once + self.use_only_onnetwork_discovery = args.use_only_onnetwork_discovery self.timeout = args.timeout logging.basicConfig(level=logging.INFO) @@ -87,6 +92,15 @@ def TestCmdAddressPaseOnly(self, nodeid, setuppin, address, port, timeout): DumpProgramOutputToQueue(self.thread_list, Fore.GREEN + "JAVA " + Style.RESET_ALL, java_process, self.queue) return java_process.wait() + def TestCmdCode(self, nodeid, setup_payload, discover_once, use_only_onnetwork_discovery, timeout): + java_command = self.command + ['pairing', 'code', nodeid, setup_payload, timeout, + '--discover-once', discover_once, '--use-only-onnetwork-discovery', use_only_onnetwork_discovery] + logging.info(f"Execute: {java_command}") + java_process = subprocess.Popen( + java_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + DumpProgramOutputToQueue(self.thread_list, Fore.GREEN + "JAVA " + Style.RESET_ALL, java_process, self.queue) + return java_process.wait() + def RunTest(self): if self.command_name == 'onnetwork-long': logging.info("Testing pairing onnetwork-long") @@ -103,5 +117,11 @@ def RunTest(self): code = self.TestCmdAddressPaseOnly(self.nodeid, self.setup_pin_code, self.address, self.port, self.timeout) if code != 0: raise Exception(f"Testing pairing address-paseonly failed with error {code}") + elif self.command_name == 'code': + logging.info("Testing pairing setup-code") + code = self.TestCmdCode(self.nodeid, self.setup_payload, self.discover_once, + self.use_only_onnetwork_discovery, self.timeout) + if code != 0: + raise Exception(f"Testing pairing code failed with error {code}") else: raise Exception(f"Unsupported command {self.command_name}") diff --git a/src/controller/CHIPDeviceController.cpp b/src/controller/CHIPDeviceController.cpp index e483a83b140d06..8fd93b36d28559 100644 --- a/src/controller/CHIPDeviceController.cpp +++ b/src/controller/CHIPDeviceController.cpp @@ -590,6 +590,7 @@ CHIP_ERROR DeviceCommissioner::PairDevice(NodeId remoteDeviceId, const char * se DiscoveryType discoveryType) { MATTER_TRACE_EVENT_SCOPE("PairDevice", "DeviceCommissioner"); + if (mDefaultCommissioner == nullptr) { ChipLogError(Controller, "No default commissioner is specified"); diff --git a/src/controller/CHIPDeviceController.h b/src/controller/CHIPDeviceController.h index c3f6cd3ff49f41..3f6f5c65c89fc0 100644 --- a/src/controller/CHIPDeviceController.h +++ b/src/controller/CHIPDeviceController.h @@ -443,6 +443,7 @@ class DLL_EXPORT DeviceCommissioner : public DeviceController, * @param[in] rendezvousParams The Rendezvous connection parameters */ CHIP_ERROR PairDevice(NodeId remoteDeviceId, RendezvousParameters & rendezvousParams); + /** * @overload * @param[in] remoteDeviceId The remote device Id. diff --git a/src/controller/java/CHIPDeviceController-JNI.cpp b/src/controller/java/CHIPDeviceController-JNI.cpp index 9b40721795d0a4..d7bb27b126b3f3 100644 --- a/src/controller/java/CHIPDeviceController-JNI.cpp +++ b/src/controller/java/CHIPDeviceController-JNI.cpp @@ -654,7 +654,8 @@ JNI_METHOD(void, pairDeviceWithAddress) } JNI_METHOD(void, pairDeviceWithCode) -(JNIEnv * env, jobject self, jlong handle, jlong deviceId, jstring setUpCode, jbyteArray csrNonce, jobject networkCredentials) +(JNIEnv * env, jobject self, jlong handle, jlong deviceId, jstring setUpCode, jboolean discoverOnce, + jboolean useOnlyOnNetworkDiscovery, jbyteArray csrNonce, jobject networkCredentials) { chip::DeviceLayer::StackLock lock; CHIP_ERROR err = CHIP_NO_ERROR; @@ -665,6 +666,18 @@ JNI_METHOD(void, pairDeviceWithCode) JniUtfString setUpCodeJniString(env, setUpCode); CommissioningParameters commissioningParams = wrapper->GetCommissioningParameters(); + + auto discoveryType = DiscoveryType::kAll; + if (useOnlyOnNetworkDiscovery) + { + discoveryType = DiscoveryType::kDiscoveryNetworkOnly; + } + + if (discoverOnce) + { + discoveryType = DiscoveryType::kDiscoveryNetworkOnlyWithoutPASEAutoRetry; + } + if (csrNonce != nullptr) { JniByteArray jniCsrNonce(env, csrNonce); @@ -680,7 +693,7 @@ JNI_METHOD(void, pairDeviceWithCode) { commissioningParams.SetDeviceAttestationDelegate(wrapper->GetDeviceAttestationDelegateBridge()); } - err = wrapper->Controller()->PairDevice(deviceId, setUpCodeJniString.c_str(), commissioningParams, DiscoveryType::kAll); + err = wrapper->Controller()->PairDevice(deviceId, setUpCodeJniString.c_str(), commissioningParams, discoveryType); if (err != CHIP_NO_ERROR) { diff --git a/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java b/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java index ed8e09873fc02e..438f4a107dc62d 100644 --- a/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java +++ b/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java @@ -180,6 +180,9 @@ public void pairDeviceWithAddress( * * @param deviceId the node ID to assign to the device * @param setupCode the scanned QR code or manual entry code + * @param discoverOnce the flag to enable/disable PASE auto retry mechanism + * @param useOnlyOnNetworkDiscovery the flag to indicate the commissionable device is available on + * the network * @param csrNonce the 32-byte CSR nonce to use, or null if we want to use an internally randomly * generated CSR nonce. * @param networkCredentials the credentials (Wi-Fi or Thread) to be provisioned @@ -187,9 +190,18 @@ public void pairDeviceWithAddress( public void pairDeviceWithCode( long deviceId, String setupCode, + boolean discoverOnce, + boolean useOnlyOnNetworkDiscovery, @Nullable byte[] csrNonce, @Nullable NetworkCredentials networkCredentials) { - pairDeviceWithCode(deviceControllerPtr, deviceId, setupCode, csrNonce, networkCredentials); + pairDeviceWithCode( + deviceControllerPtr, + deviceId, + setupCode, + discoverOnce, + useOnlyOnNetworkDiscovery, + csrNonce, + networkCredentials); } public void establishPaseConnection(long deviceId, int connId, long setupPincode) { @@ -1017,6 +1029,8 @@ private native void pairDeviceWithCode( long deviceControllerPtr, long deviceId, String setupCode, + boolean discoverOnce, + boolean useOnlyOnNetworkDiscovery, @Nullable byte[] csrNonce, @Nullable NetworkCredentials networkCredentials);