diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/ContextHubInfo.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/ContextHubInfo.aidl index e5735566e7..c99169eb6f 100644 --- a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/ContextHubInfo.aidl +++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/ContextHubInfo.aidl @@ -45,4 +45,5 @@ parcelable ContextHubInfo { byte chreApiMinorVersion; char chrePatchVersion; String[] supportedPermissions; + boolean supportsReliableMessages; } diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/ContextHubMessage.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/ContextHubMessage.aidl index e38c251928..a6951a8f16 100644 --- a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/ContextHubMessage.aidl +++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/ContextHubMessage.aidl @@ -39,4 +39,6 @@ parcelable ContextHubMessage { int messageType; byte[] messageBody; String[] permissions; + boolean isReliable; + int messageSequenceNumber; } diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/ErrorCode.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/ErrorCode.aidl new file mode 100644 index 0000000000..8924658357 --- /dev/null +++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/ErrorCode.aidl @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.contexthub; +@Backing(type="byte") @VintfStability +enum ErrorCode { + OK = 0, + TRANSIENT_ERROR, + PERMANENT_ERROR, + PERMISSION_DENIED, + DESTINATION_NOT_FOUND, +} diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl index de8d752695..7341e0ec75 100644 --- a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl +++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl @@ -48,5 +48,6 @@ interface IContextHub { long[] getPreloadedNanoappIds(in int contextHubId); void onNanSessionStateChanged(in android.hardware.contexthub.NanSessionStateUpdate update); void setTestMode(in boolean enable); + void sendMessageDeliveryStatusToHub(in int contextHubId, in android.hardware.contexthub.MessageDeliveryStatus messageDeliveryStatus); const int EX_CONTEXT_HUB_UNSPECIFIED = (-1) /* -1 */; } diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHubCallback.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHubCallback.aidl index 4e99082ea8..70f69c608b 100644 --- a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHubCallback.aidl +++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHubCallback.aidl @@ -39,6 +39,7 @@ interface IContextHubCallback { void handleContextHubAsyncEvent(in android.hardware.contexthub.AsyncEventType evt); void handleTransactionResult(in int transactionId, in boolean success); void handleNanSessionRequest(in android.hardware.contexthub.NanSessionRequest request); + void handleMessageDeliveryStatus(in char hostEndpointId, in android.hardware.contexthub.MessageDeliveryStatus messageDeliveryStatus); byte[16] getUuid(); String getName(); const int CONTEXTHUB_NAN_TRANSACTION_TIMEOUT_MS = 10000; diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/MessageDeliveryStatus.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/MessageDeliveryStatus.aidl new file mode 100644 index 0000000000..40dac13f1c --- /dev/null +++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/MessageDeliveryStatus.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.contexthub; +@VintfStability +parcelable MessageDeliveryStatus { + int messageSequenceNumber; + android.hardware.contexthub.ErrorCode errorCode; +} diff --git a/contexthub/aidl/android/hardware/contexthub/ContextHubInfo.aidl b/contexthub/aidl/android/hardware/contexthub/ContextHubInfo.aidl index c0fa702f0b..42dba1053d 100644 --- a/contexthub/aidl/android/hardware/contexthub/ContextHubInfo.aidl +++ b/contexthub/aidl/android/hardware/contexthub/ContextHubInfo.aidl @@ -33,7 +33,9 @@ parcelable ContextHubInfo { /** Peak MIPs this platform can deliver */ float peakMips; - /** The maximum length in bytes of the message that can be sent to the Context Hub. */ + /** + * The maximum length in bytes of a message sent to the Context Hub. + */ int maxSupportedMessageLengthBytes; /** @@ -61,4 +63,11 @@ parcelable ContextHubInfo { * are granted in order to communicate with them. */ String[] supportedPermissions; + + /** + * True if the Context Hub supports reliable messages. False otherwise, in which case + * ContextHubMessage.isReliable must always be set to false. See + * ContextHubMessage.isReliable for more information. + */ + boolean supportsReliableMessages; } diff --git a/contexthub/aidl/android/hardware/contexthub/ContextHubMessage.aidl b/contexthub/aidl/android/hardware/contexthub/ContextHubMessage.aidl index 95d478e6c2..3cd20caa0d 100644 --- a/contexthub/aidl/android/hardware/contexthub/ContextHubMessage.aidl +++ b/contexthub/aidl/android/hardware/contexthub/ContextHubMessage.aidl @@ -50,4 +50,35 @@ parcelable ContextHubMessage { * of the permissions that the sending nanoapp is using. */ String[] permissions; + + /** + * Whether the message is reliable. + * + * For reliable messages, the receiver is expected to acknowledge the reception of + * the message by sending a message delivery status back to the sender. Acknowledgment of + * the message must be returned within 1 second. + * + * For reliable messages sent by the host, the Context Hub invokes + * IContextHubCallback#handleMessageDeliveryStatus to report the status. + * + * For reliable messages sent by the Context Hub, the host calls + * IContextHub#sendMessageDeliveryStatusToHub to report the status. + */ + boolean isReliable; + + /** + * The sequence number for a reliable message. For less than 2^32 messages, each message sent + * from a Context Hub will have a unique sequence number generated by the Context Hub, and the + * sequence numbers are guaranteed to not be reused for unacknowledged messages. For messages + * sent to the Context Hub, sequence numbers are only guaranteed to be unique within the scope + * of a given hostEndPoint. The sequence number may be reused if more than 2^32 messages are + * sent, due to the size limit of int. + * + * The sequence number is used only for reliable messages. There is no guarantee of strict + * ordering of messages. The recipient may receive messages with gaps between the sequence + * numbers. This is not an indication of a missed message. + * + * See isReliable for more information. + */ + int messageSequenceNumber; } diff --git a/contexthub/aidl/android/hardware/contexthub/ErrorCode.aidl b/contexthub/aidl/android/hardware/contexthub/ErrorCode.aidl new file mode 100644 index 0000000000..22e7ea1bb3 --- /dev/null +++ b/contexthub/aidl/android/hardware/contexthub/ErrorCode.aidl @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * 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 android.hardware.contexthub; + +@VintfStability +@Backing(type="byte") +enum ErrorCode { + /** + * No Error. + */ + OK = 0, + + /** + * A generic transient error. The sender may retry the + * operation, but there is no guarantee of success. + */ + TRANSIENT_ERROR, + + /** + * A generic permanent error. The sender should not retry the operation. + */ + PERMANENT_ERROR, + + /** + * The request failed because the sender does not have necessary permissions. + * The sender should not retry the operation. + */ + PERMISSION_DENIED, + + /** + * The request failed because the destination was not found. + * The sender should not retry the operation. + */ + DESTINATION_NOT_FOUND, +} diff --git a/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl b/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl index fea107935f..b146ff814d 100644 --- a/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl +++ b/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl @@ -20,6 +20,7 @@ import android.hardware.contexthub.ContextHubInfo; import android.hardware.contexthub.ContextHubMessage; import android.hardware.contexthub.HostEndpointInfo; import android.hardware.contexthub.IContextHubCallback; +import android.hardware.contexthub.MessageDeliveryStatus; import android.hardware.contexthub.NanSessionStateUpdate; import android.hardware.contexthub.NanoappBinary; import android.hardware.contexthub.NanoappInfo; @@ -235,6 +236,21 @@ interface IContextHub { */ void setTestMode(in boolean enable); + /** + * Sends a message delivery status to the Context Hub in response to receiving a + * ContextHubMessage with isReliable=true. Each reliable message should have a + * messageDeliveryStatus response. This method sends the message delivery status + * back to the Context Hub. + * + * @param contextHubId The identifier of the Context Hub. + * @param messageDeliveryStatus The status to be sent. + * + * @throws EX_UNSUPPORTED_OPERATION if ContextHubInfo.supportsReliableMessages is false for + * this hub. + */ + void sendMessageDeliveryStatusToHub( + in int contextHubId, in MessageDeliveryStatus messageDeliveryStatus); + /** * Error codes that are used as service specific errors with the AIDL return * value EX_SERVICE_SPECIFIC. diff --git a/contexthub/aidl/android/hardware/contexthub/IContextHubCallback.aidl b/contexthub/aidl/android/hardware/contexthub/IContextHubCallback.aidl index ebfc4d8c9f..1aa07768f8 100644 --- a/contexthub/aidl/android/hardware/contexthub/IContextHubCallback.aidl +++ b/contexthub/aidl/android/hardware/contexthub/IContextHubCallback.aidl @@ -18,6 +18,7 @@ package android.hardware.contexthub; import android.hardware.contexthub.AsyncEventType; import android.hardware.contexthub.ContextHubMessage; +import android.hardware.contexthub.MessageDeliveryStatus; import android.hardware.contexthub.NanSessionRequest; import android.hardware.contexthub.NanoappInfo; @@ -90,6 +91,19 @@ interface IContextHubCallback { */ void handleNanSessionRequest(in NanSessionRequest request); + /** + * This callback is passed by the Contexthub service to the HAL + * implementation to allow the HAL to send the response for a reliable message. + * The response is the message delivery status of a recently sent message. See + * sendMessageDeliveryStatusToHub() for more details. + * + * @param hostEndPointId The ID of the host endpoint associated with this message delivery + * status. + * @param messageDeliveryStatus The status to be sent. + */ + void handleMessageDeliveryStatus( + in char hostEndpointId, in MessageDeliveryStatus messageDeliveryStatus); + /** * This callback is passed to the HAL implementation to allow the HAL to request a UUID that * uniquely identifies a client. diff --git a/contexthub/aidl/android/hardware/contexthub/MessageDeliveryStatus.aidl b/contexthub/aidl/android/hardware/contexthub/MessageDeliveryStatus.aidl new file mode 100644 index 0000000000..ae425b322b --- /dev/null +++ b/contexthub/aidl/android/hardware/contexthub/MessageDeliveryStatus.aidl @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * 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 android.hardware.contexthub; + +import android.hardware.contexthub.ErrorCode; + +@VintfStability +parcelable MessageDeliveryStatus { + /** + * The messageSequenceNumber of the ContextHubMessage to which this status applies. + */ + int messageSequenceNumber; + + /** + * The error code associated with this status. + */ + ErrorCode errorCode; +} diff --git a/contexthub/aidl/default/ContextHub.cpp b/contexthub/aidl/default/ContextHub.cpp index 5272957f07..bd483d7101 100644 --- a/contexthub/aidl/default/ContextHub.cpp +++ b/contexthub/aidl/default/ContextHub.cpp @@ -16,10 +16,7 @@ #include "contexthub-impl/ContextHub.h" -namespace aidl { -namespace android { -namespace hardware { -namespace contexthub { +namespace aidl::android::hardware::contexthub { using ::ndk::ScopedAStatus; @@ -34,10 +31,11 @@ ScopedAStatus ContextHub::getContextHubs(std::vector* out_contex hub.chrePlatformId = UINT64_C(0x476f6f6754000000); hub.chreApiMajorVersion = 1; hub.chreApiMinorVersion = 6; + hub.supportsReliableMessages = false; out_contextHubInfos->push_back(hub); - return ndk::ScopedAStatus::ok(); + return ScopedAStatus::ok(); } // We don't expose any nanoapps for the default impl, therefore all nanoapp-related APIs fail. @@ -63,14 +61,14 @@ ScopedAStatus ContextHub::enableNanoapp(int32_t /* in_contextHubId */, int64_t / } ScopedAStatus ContextHub::onSettingChanged(Setting /* in_setting */, bool /*in_enabled */) { - return ndk::ScopedAStatus::ok(); + return ScopedAStatus::ok(); } ScopedAStatus ContextHub::queryNanoapps(int32_t in_contextHubId) { if (in_contextHubId == kMockHubId && mCallback != nullptr) { std::vector nanoapps; mCallback->handleNanoappInfo(nanoapps); - return ndk::ScopedAStatus::ok(); + return ScopedAStatus::ok(); } else { return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } @@ -85,18 +83,18 @@ ScopedAStatus ContextHub::getPreloadedNanoappIds(int32_t /* in_contextHubId */, for (uint64_t i = 0; i < 10; ++i) { out_preloadedNanoappIds->push_back(i); } - return ndk::ScopedAStatus::ok(); + return ScopedAStatus::ok(); } ScopedAStatus ContextHub::onNanSessionStateChanged(const NanSessionStateUpdate& /*in_update*/) { - return ndk::ScopedAStatus::ok(); + return ScopedAStatus::ok(); } ScopedAStatus ContextHub::registerCallback(int32_t in_contextHubId, const std::shared_ptr& in_cb) { if (in_contextHubId == kMockHubId) { mCallback = in_cb; - return ndk::ScopedAStatus::ok(); + return ScopedAStatus::ok(); } else { return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } @@ -108,20 +106,20 @@ ScopedAStatus ContextHub::sendMessageToHub(int32_t in_contextHubId, // Return true here to indicate that the HAL has accepted the message. // Successful delivery of the message to a nanoapp should be handled at // a higher level protocol. - return ndk::ScopedAStatus::ok(); + return ScopedAStatus::ok(); } else { return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } } ScopedAStatus ContextHub::setTestMode(bool /* enable */) { - return ndk::ScopedAStatus::ok(); + return ScopedAStatus::ok(); } ScopedAStatus ContextHub::onHostEndpointConnected(const HostEndpointInfo& in_info) { mConnectedHostEndpoints.insert(in_info.hostEndpointId); - return ndk::ScopedAStatus::ok(); + return ScopedAStatus::ok(); } ScopedAStatus ContextHub::onHostEndpointDisconnected(char16_t in_hostEndpointId) { @@ -129,10 +127,13 @@ ScopedAStatus ContextHub::onHostEndpointDisconnected(char16_t in_hostEndpointId) mConnectedHostEndpoints.erase(in_hostEndpointId); } - return ndk::ScopedAStatus::ok(); + return ScopedAStatus::ok(); } -} // namespace contexthub -} // namespace hardware -} // namespace android -} // namespace aidl +ScopedAStatus ContextHub::sendMessageDeliveryStatusToHub( + int32_t /* in_contextHubId */, + const MessageDeliveryStatus& /* in_messageDeliveryStatus */) { + return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +} + +} // namespace aidl::android::hardware::contexthub diff --git a/contexthub/aidl/default/include/contexthub-impl/ContextHub.h b/contexthub/aidl/default/include/contexthub-impl/ContextHub.h index 7a2cfd1702..72e8b3b66e 100644 --- a/contexthub/aidl/default/include/contexthub-impl/ContextHub.h +++ b/contexthub/aidl/default/include/contexthub-impl/ContextHub.h @@ -49,6 +49,9 @@ class ContextHub : public BnContextHub { ::ndk::ScopedAStatus onHostEndpointDisconnected(char16_t in_hostEndpointId) override; ::ndk::ScopedAStatus onNanSessionStateChanged(const NanSessionStateUpdate& in_update) override; + ::ndk::ScopedAStatus sendMessageDeliveryStatusToHub( + int32_t in_contextHubId, + const MessageDeliveryStatus& in_messageDeliveryStatus) override; private: static constexpr uint32_t kMockHubId = 0; diff --git a/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp b/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp index 76b25b688e..fd55b80fde 100644 --- a/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp +++ b/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp @@ -36,9 +36,11 @@ using ::android::binder::Status; using ::android::hardware::contexthub::AsyncEventType; using ::android::hardware::contexthub::ContextHubInfo; using ::android::hardware::contexthub::ContextHubMessage; +using ::android::hardware::contexthub::ErrorCode; using ::android::hardware::contexthub::HostEndpointInfo; using ::android::hardware::contexthub::IContextHub; using ::android::hardware::contexthub::IContextHubCallbackDefault; +using ::android::hardware::contexthub::MessageDeliveryStatus; using ::android::hardware::contexthub::NanoappBinary; using ::android::hardware::contexthub::NanoappInfo; using ::android::hardware::contexthub::NanoappRpcService; @@ -132,6 +134,12 @@ class EmptyContextHubCallback : public android::hardware::contexthub::BnContextH return Status::ok(); } + Status handleMessageDeliveryStatus( + char16_t /* hostEndPointId */, + const MessageDeliveryStatus& /* messageDeliveryStatus */) override { + return Status::ok(); + } + Status getUuid(std::array* out_uuid) override { *out_uuid = kUuid; return Status::ok(); @@ -172,6 +180,12 @@ class QueryAppsCallback : public android::hardware::contexthub::BnContextHubCall return Status::ok(); } + Status handleMessageDeliveryStatus( + char16_t /* hostEndPointId */, + const MessageDeliveryStatus& /* messageDeliveryStatus */) override { + return Status::ok(); + } + Status getUuid(std::array* out_uuid) override { *out_uuid = kUuid; return Status::ok(); @@ -248,6 +262,12 @@ class TransactionResultCallback : public android::hardware::contexthub::BnContex return Status::ok(); } + Status handleMessageDeliveryStatus( + char16_t /* hostEndPointId */, + const MessageDeliveryStatus& /* messageDeliveryStatus */) override { + return Status::ok(); + } + Status getUuid(std::array* out_uuid) override { *out_uuid = kUuid; return Status::ok(); @@ -431,6 +451,20 @@ TEST_P(ContextHubAidl, TestNanSessionStateChange) { } } +TEST_P(ContextHubAidl, TestSendMessageDeliveryStatusToHub) { + MessageDeliveryStatus messageDeliveryStatus; + messageDeliveryStatus.messageSequenceNumber = 123; + messageDeliveryStatus.errorCode = ErrorCode::OK; + + Status status = contextHub->sendMessageDeliveryStatusToHub(getHubId(), messageDeliveryStatus); + if (status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION || + status.transactionError() == android::UNKNOWN_TRANSACTION) { + GTEST_SKIP() << "Not supported -> old API; or not implemented"; + } else { + EXPECT_TRUE(status.isOk()); + } +} + std::string PrintGeneratedTest(const testing::TestParamInfo& info) { return std::string("CONTEXT_HUB_ID_") + std::to_string(std::get<1>(info.param)); }