aboutsummaryrefslogtreecommitdiff
path: root/src/android/otdaemon_telemetry.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/android/otdaemon_telemetry.cpp')
-rw-r--r--src/android/otdaemon_telemetry.cpp671
1 files changed, 671 insertions, 0 deletions
diff --git a/src/android/otdaemon_telemetry.cpp b/src/android/otdaemon_telemetry.cpp
new file mode 100644
index 00000000..6026a1e3
--- /dev/null
+++ b/src/android/otdaemon_telemetry.cpp
@@ -0,0 +1,671 @@
+/*
+ * Copyright (c) 2023, The OpenThread Authors.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "android/otdaemon_telemetry.hpp"
+
+#include <openthread/openthread-system.h>
+#include <openthread/thread.h>
+#include <openthread/thread_ftd.h>
+#include <openthread/platform/radio.h>
+
+#if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY
+#include <openthread/dnssd_server.h>
+#endif
+#if OTBR_ENABLE_SRP_ADVERTISING_PROXY
+#include <openthread/srp_server.h>
+#endif
+
+#include "statslog_threadnetwork.h"
+#include "common/code_utils.hpp"
+#include "mdns/mdns.hpp"
+#include "proto/threadnetwork_atoms.pb.h"
+
+namespace otbr {
+namespace Android {
+using android::os::statsd::threadnetwork::ThreadnetworkDeviceInfoReported;
+using android::os::statsd::threadnetwork::ThreadnetworkTelemetryDataReported;
+using android::os::statsd::threadnetwork::ThreadnetworkTopoEntryRepeated;
+
+static uint32_t TelemetryNodeTypeFromRoleAndLinkMode(const otDeviceRole &aRole, const otLinkModeConfig &aLinkModeCfg)
+{
+ uint32_t nodeType;
+
+ switch (aRole)
+ {
+ case OT_DEVICE_ROLE_DISABLED:
+ nodeType = ThreadnetworkTelemetryDataReported::NODE_TYPE_DISABLED;
+ break;
+ case OT_DEVICE_ROLE_DETACHED:
+ nodeType = ThreadnetworkTelemetryDataReported::NODE_TYPE_DETACHED;
+ break;
+ case OT_DEVICE_ROLE_ROUTER:
+ nodeType = ThreadnetworkTelemetryDataReported::NODE_TYPE_ROUTER;
+ break;
+ case OT_DEVICE_ROLE_LEADER:
+ nodeType = ThreadnetworkTelemetryDataReported::NODE_TYPE_LEADER;
+ break;
+ case OT_DEVICE_ROLE_CHILD:
+ if (!aLinkModeCfg.mRxOnWhenIdle)
+ {
+ nodeType = ThreadnetworkTelemetryDataReported::NODE_TYPE_SLEEPY_END;
+ }
+ else if (!aLinkModeCfg.mDeviceType)
+ {
+ // If it's not an FTD, return as minimal end device.
+ nodeType = ThreadnetworkTelemetryDataReported::NODE_TYPE_MINIMAL_END;
+ }
+ else
+ {
+ nodeType = ThreadnetworkTelemetryDataReported::NODE_TYPE_END;
+ }
+ break;
+ default:
+ nodeType = ThreadnetworkTelemetryDataReported::NODE_TYPE_UNSPECIFIED;
+ }
+
+ return nodeType;
+}
+
+#if OTBR_ENABLE_SRP_ADVERTISING_PROXY
+ThreadnetworkTelemetryDataReported::SrpServerState SrpServerStateFromOtSrpServerState(otSrpServerState aSrpServerState)
+{
+ ThreadnetworkTelemetryDataReported::SrpServerState srpServerState;
+
+ switch (aSrpServerState)
+ {
+ case OT_SRP_SERVER_STATE_DISABLED:
+ srpServerState = ThreadnetworkTelemetryDataReported::SRP_SERVER_STATE_DISABLED;
+ break;
+ case OT_SRP_SERVER_STATE_RUNNING:
+ srpServerState = ThreadnetworkTelemetryDataReported::SRP_SERVER_STATE_RUNNING;
+ break;
+ case OT_SRP_SERVER_STATE_STOPPED:
+ srpServerState = ThreadnetworkTelemetryDataReported::SRP_SERVER_STATE_STOPPED;
+ break;
+ default:
+ srpServerState = ThreadnetworkTelemetryDataReported::SRP_SERVER_STATE_UNSPECIFIED;
+ }
+ return srpServerState;
+}
+
+ThreadnetworkTelemetryDataReported::SrpServerAddressMode SrpServerAddressModeFromOtSrpServerAddressMode(
+ otSrpServerAddressMode aSrpServerAddressMode)
+{
+ ThreadnetworkTelemetryDataReported::SrpServerAddressMode srpServerAddressMode;
+
+ switch (aSrpServerAddressMode)
+ {
+ case OT_SRP_SERVER_ADDRESS_MODE_ANYCAST:
+ srpServerAddressMode = ThreadnetworkTelemetryDataReported::SRP_SERVER_ADDRESS_MODE_STATE_ANYCAST;
+ break;
+ case OT_SRP_SERVER_ADDRESS_MODE_UNICAST:
+ srpServerAddressMode = ThreadnetworkTelemetryDataReported::SRP_SERVER_ADDRESS_MODE_UNICAST;
+ break;
+ default:
+ srpServerAddressMode = ThreadnetworkTelemetryDataReported::SRP_SERVER_ADDRESS_MODE_UNSPECIFIED;
+ }
+ return srpServerAddressMode;
+}
+#endif // OTBR_ENABLE_SRP_ADVERTISING_PROXY
+
+void CopyMdnsResponseCounters(const MdnsResponseCounters &from,
+ ThreadnetworkTelemetryDataReported::MdnsResponseCounters *to)
+{
+ to->set_success_count(from.mSuccess);
+ to->set_not_found_count(from.mNotFound);
+ to->set_invalid_args_count(from.mInvalidArgs);
+ to->set_duplicated_count(from.mDuplicated);
+ to->set_not_implemented_count(from.mNotImplemented);
+ to->set_unknown_error_count(from.mUnknownError);
+ to->set_aborted_count(from.mAborted);
+ to->set_invalid_state_count(from.mInvalidState);
+}
+
+otError RetrieveTelemetryAtom(otInstance *otInstance,
+ Mdns::Publisher *aPublisher,
+ ThreadnetworkTelemetryDataReported &telemetryDataReported,
+ ThreadnetworkTopoEntryRepeated &topoEntryRepeated,
+ ThreadnetworkDeviceInfoReported &deviceInfoReported)
+{
+ otError error = OT_ERROR_NONE;
+ std::vector<otNeighborInfo> neighborTable;
+
+ // Begin of WpanStats section.
+ auto wpanStats = telemetryDataReported.mutable_wpan_stats();
+
+ {
+ otDeviceRole role = otThreadGetDeviceRole(otInstance);
+ otLinkModeConfig otCfg = otThreadGetLinkMode(otInstance);
+
+ wpanStats->set_node_type(TelemetryNodeTypeFromRoleAndLinkMode(role, otCfg));
+ }
+
+ wpanStats->set_channel(otLinkGetChannel(otInstance));
+
+ {
+ uint16_t ccaFailureRate = otLinkGetCcaFailureRate(otInstance);
+
+ wpanStats->set_mac_cca_fail_rate(static_cast<float>(ccaFailureRate) / 0xffff);
+ }
+
+ {
+ int8_t radioTxPower;
+
+ if (otPlatRadioGetTransmitPower(otInstance, &radioTxPower) == OT_ERROR_NONE)
+ {
+ wpanStats->set_radio_tx_power(radioTxPower);
+ }
+ else
+ {
+ error = OT_ERROR_FAILED;
+ }
+ }
+
+ {
+ const otMacCounters *linkCounters = otLinkGetCounters(otInstance);
+
+ wpanStats->set_phy_rx(linkCounters->mRxTotal);
+ wpanStats->set_phy_tx(linkCounters->mTxTotal);
+ wpanStats->set_mac_unicast_rx(linkCounters->mRxUnicast);
+ wpanStats->set_mac_unicast_tx(linkCounters->mTxUnicast);
+ wpanStats->set_mac_broadcast_rx(linkCounters->mRxBroadcast);
+ wpanStats->set_mac_broadcast_tx(linkCounters->mTxBroadcast);
+ wpanStats->set_mac_tx_ack_req(linkCounters->mTxAckRequested);
+ wpanStats->set_mac_tx_no_ack_req(linkCounters->mTxNoAckRequested);
+ wpanStats->set_mac_tx_acked(linkCounters->mTxAcked);
+ wpanStats->set_mac_tx_data(linkCounters->mTxData);
+ wpanStats->set_mac_tx_data_poll(linkCounters->mTxDataPoll);
+ wpanStats->set_mac_tx_beacon(linkCounters->mTxBeacon);
+ wpanStats->set_mac_tx_beacon_req(linkCounters->mTxBeaconRequest);
+ wpanStats->set_mac_tx_other_pkt(linkCounters->mTxOther);
+ wpanStats->set_mac_tx_retry(linkCounters->mTxRetry);
+ wpanStats->set_mac_rx_data(linkCounters->mRxData);
+ wpanStats->set_mac_rx_data_poll(linkCounters->mRxDataPoll);
+ wpanStats->set_mac_rx_beacon(linkCounters->mRxBeacon);
+ wpanStats->set_mac_rx_beacon_req(linkCounters->mRxBeaconRequest);
+ wpanStats->set_mac_rx_other_pkt(linkCounters->mRxOther);
+ wpanStats->set_mac_rx_filter_whitelist(linkCounters->mRxAddressFiltered);
+ wpanStats->set_mac_rx_filter_dest_addr(linkCounters->mRxDestAddrFiltered);
+ wpanStats->set_mac_tx_fail_cca(linkCounters->mTxErrCca);
+ wpanStats->set_mac_rx_fail_decrypt(linkCounters->mRxErrSec);
+ wpanStats->set_mac_rx_fail_no_frame(linkCounters->mRxErrNoFrame);
+ wpanStats->set_mac_rx_fail_unknown_neighbor(linkCounters->mRxErrUnknownNeighbor);
+ wpanStats->set_mac_rx_fail_invalid_src_addr(linkCounters->mRxErrInvalidSrcAddr);
+ wpanStats->set_mac_rx_fail_fcs(linkCounters->mRxErrFcs);
+ wpanStats->set_mac_rx_fail_other(linkCounters->mRxErrOther);
+ }
+
+ {
+ const otIpCounters *ipCounters = otThreadGetIp6Counters(otInstance);
+
+ wpanStats->set_ip_tx_success(ipCounters->mTxSuccess);
+ wpanStats->set_ip_rx_success(ipCounters->mRxSuccess);
+ wpanStats->set_ip_tx_failure(ipCounters->mTxFailure);
+ wpanStats->set_ip_rx_failure(ipCounters->mRxFailure);
+ }
+ // End of WpanStats section.
+
+ {
+ // Begin of WpanTopoFull section.
+ auto wpanTopoFull = telemetryDataReported.mutable_wpan_topo_full();
+ uint16_t rloc16 = otThreadGetRloc16(otInstance);
+
+ wpanTopoFull->set_rloc16(rloc16);
+
+ {
+ otRouterInfo info;
+
+ if (otThreadGetRouterInfo(otInstance, rloc16, &info) == OT_ERROR_NONE)
+ {
+ wpanTopoFull->set_router_id(info.mRouterId);
+ }
+ else
+ {
+ error = OT_ERROR_FAILED;
+ }
+ }
+
+ {
+ otNeighborInfoIterator iter = OT_NEIGHBOR_INFO_ITERATOR_INIT;
+ otNeighborInfo neighborInfo;
+
+ while (otThreadGetNextNeighborInfo(otInstance, &iter, &neighborInfo) == OT_ERROR_NONE)
+ {
+ neighborTable.push_back(neighborInfo);
+ }
+ }
+ wpanTopoFull->set_neighbor_table_size(neighborTable.size());
+
+ uint16_t childIndex = 0;
+ otChildInfo childInfo;
+ std::vector<otChildInfo> childTable;
+
+ while (otThreadGetChildInfoByIndex(otInstance, childIndex, &childInfo) == OT_ERROR_NONE)
+ {
+ childTable.push_back(childInfo);
+ childIndex++;
+ }
+ wpanTopoFull->set_child_table_size(childTable.size());
+
+ {
+ struct otLeaderData leaderData;
+
+ if (otThreadGetLeaderData(otInstance, &leaderData) == OT_ERROR_NONE)
+ {
+ wpanTopoFull->set_leader_router_id(leaderData.mLeaderRouterId);
+ wpanTopoFull->set_leader_weight(leaderData.mWeighting);
+ // Do not log network_data_version.
+ }
+ else
+ {
+ error = OT_ERROR_FAILED;
+ }
+ }
+
+ uint8_t weight = otThreadGetLocalLeaderWeight(otInstance);
+
+ wpanTopoFull->set_leader_local_weight(weight);
+
+ int8_t rssi = otPlatRadioGetRssi(otInstance);
+
+ wpanTopoFull->set_instant_rssi(rssi);
+
+ const otExtendedPanId *extPanId = otThreadGetExtendedPanId(otInstance);
+ uint64_t extPanIdVal;
+
+ extPanIdVal = ConvertOpenThreadUint64(extPanId->m8);
+ wpanTopoFull->set_has_extended_pan_id(extPanIdVal != 0);
+ // Note: Used leader_router_id instead of leader_rloc16.
+ // Note: Network level info (e.g., extended_pan_id, partition_id, is_active_br) is not logged.
+ // TODO: populate is_active_srp_server, sum_on_link_prefix_changes, preferred_router_id
+ // if needed.
+ // End of WpanTopoFull section.
+
+ // Begin of TopoEntry section.
+ std::map<uint16_t, const otChildInfo *> childMap;
+
+ for (const otChildInfo &childInfo : childTable)
+ {
+ auto pair = childMap.insert({childInfo.mRloc16, &childInfo});
+ if (!pair.second)
+ {
+ // This shouldn't happen, so log an error. It doesn't matter which
+ // duplicate is kept.
+ otbrLogErr("Children with duplicate RLOC16 found: 0x%04x", static_cast<int>(childInfo.mRloc16));
+ }
+ }
+
+ for (const otNeighborInfo &neighborInfo : neighborTable)
+ {
+ auto topoEntry = topoEntryRepeated.mutable_topo_entry_repeated()->add_topo_entries();
+
+ // 0~15: uint16_t rloc_16
+ // 16~31: uint16_t version Thread version of the neighbor
+ uint32_t comboTelemetry1 = 0;
+ comboTelemetry1 |= (((uint32_t)neighborInfo.mRloc16) & 0x0000FFFF);
+ comboTelemetry1 |= ((((uint32_t)neighborInfo.mVersion) & 0x0000FFFF) << 16);
+ topoEntry->set_combo_telemetry1(comboTelemetry1);
+
+ topoEntry->set_age_sec(neighborInfo.mAge);
+
+ // 0~7: uint8_t link_quality_in
+ // 8~15: int8_t average_rssi
+ // 16~23: int8_t last_rssi
+ // 24~31: uint8_t network_data_version
+ uint32_t comboTelemetry2 = 0;
+ comboTelemetry2 |= (((uint32_t)neighborInfo.mLinkQualityIn) & 0x000000FF);
+ comboTelemetry2 |= ((((uint32_t)neighborInfo.mAverageRssi) & 0x000000FF) << 8);
+ comboTelemetry2 |= ((((uint32_t)neighborInfo.mLastRssi) & 0x000000FF) << 16);
+ // network_data_version is populated in the next section.
+ topoEntry->set_combo_telemetry2(comboTelemetry2);
+
+ // Each bit on the flag represents a bool flag
+ // 0: rx_on_when_idle
+ // 1: full_function
+ // 2: secure_data_request
+ // 3: full_network_data
+ // 4: is_child
+ uint32_t topoEntryFlags = 0;
+ topoEntryFlags |= (neighborInfo.mRxOnWhenIdle ? 1 : 0);
+ topoEntryFlags |= ((neighborInfo.mFullThreadDevice ? 1 : 0) << 1);
+ topoEntryFlags |= ((/* secure_data_request */ true ? 1 : 0) << 2);
+ topoEntryFlags |= ((neighborInfo.mFullNetworkData ? 1 : 0) << 3);
+ topoEntry->set_topo_entry_flags(topoEntryFlags);
+
+ topoEntry->set_link_frame_counter(neighborInfo.mLinkFrameCounter);
+ topoEntry->set_mle_frame_counter(neighborInfo.mMleFrameCounter);
+
+ // 0~15: uint16_t mac_frame_error_rate. Frame error rate (0xffff->100%). Requires error tracking feature.
+ // 16~31: uint16_t ip_message_error_rate. (IPv6) msg error rate (0xffff->100%). Requires error tracking
+ // feature.
+ uint32_t comboTelemetry3 = 0;
+ comboTelemetry3 |= ((uint32_t)(neighborInfo.mFrameErrorRate) & 0x0000FFFF);
+ comboTelemetry3 |= ((((uint32_t)neighborInfo.mMessageErrorRate) & 0x0000FFFF) << 16);
+ topoEntry->set_combo_telemetry3(comboTelemetry3);
+
+ if (!neighborInfo.mIsChild)
+ {
+ continue;
+ }
+
+ auto it = childMap.find(neighborInfo.mRloc16);
+ if (it == childMap.end())
+ {
+ otbrLogErr("Neighbor 0x%04x not found in child table", static_cast<int>(neighborInfo.mRloc16));
+ continue;
+ }
+ const otChildInfo *childInfo = it->second;
+
+ comboTelemetry2 |= ((((uint32_t)childInfo->mNetworkDataVersion) & 0x000000FF) << 24);
+ topoEntry->set_combo_telemetry2(comboTelemetry2);
+
+ topoEntryFlags |= ((/* is_child */ true ? 1 : 0) << 4);
+ topoEntry->set_topo_entry_flags(topoEntryFlags);
+
+ topoEntry->set_timeout_sec(childInfo->mTimeout);
+ }
+ // End of TopoEntry section.
+ }
+
+ {
+ // Begin of WpanBorderRouter section.
+ auto wpanBorderRouter = telemetryDataReported.mutable_wpan_border_router();
+ // Begin of BorderRoutingCounters section.
+ auto borderRoutingCouters = wpanBorderRouter->mutable_border_routing_counters();
+ const otBorderRoutingCounters *otBorderRoutingCounters = otIp6GetBorderRoutingCounters(otInstance);
+
+ borderRoutingCouters->mutable_inbound_unicast()->set_packet_count(
+ otBorderRoutingCounters->mInboundUnicast.mPackets);
+ borderRoutingCouters->mutable_inbound_unicast()->set_byte_count(
+ otBorderRoutingCounters->mInboundUnicast.mBytes);
+ borderRoutingCouters->mutable_inbound_multicast()->set_packet_count(
+ otBorderRoutingCounters->mInboundMulticast.mPackets);
+ borderRoutingCouters->mutable_inbound_multicast()->set_byte_count(
+ otBorderRoutingCounters->mInboundMulticast.mBytes);
+ borderRoutingCouters->mutable_outbound_unicast()->set_packet_count(
+ otBorderRoutingCounters->mOutboundUnicast.mPackets);
+ borderRoutingCouters->mutable_outbound_unicast()->set_byte_count(
+ otBorderRoutingCounters->mOutboundUnicast.mBytes);
+ borderRoutingCouters->mutable_outbound_multicast()->set_packet_count(
+ otBorderRoutingCounters->mOutboundMulticast.mPackets);
+ borderRoutingCouters->mutable_outbound_multicast()->set_byte_count(
+ otBorderRoutingCounters->mOutboundMulticast.mBytes);
+ borderRoutingCouters->set_ra_rx(otBorderRoutingCounters->mRaRx);
+ borderRoutingCouters->set_ra_tx_success(otBorderRoutingCounters->mRaTxSuccess);
+ borderRoutingCouters->set_ra_tx_failure(otBorderRoutingCounters->mRaTxFailure);
+ borderRoutingCouters->set_rs_rx(otBorderRoutingCounters->mRsRx);
+ borderRoutingCouters->set_rs_tx_success(otBorderRoutingCounters->mRsTxSuccess);
+ borderRoutingCouters->set_rs_tx_failure(otBorderRoutingCounters->mRsTxFailure);
+
+ // End of BorderRoutingCounters section.
+
+#if OTBR_ENABLE_SRP_ADVERTISING_PROXY
+ // Begin of SrpServerInfo section.
+ {
+ auto srpServer = wpanBorderRouter->mutable_srp_server();
+ otSrpServerLeaseInfo leaseInfo;
+ const otSrpServerHost *host = nullptr;
+ const otSrpServerResponseCounters *responseCounters = otSrpServerGetResponseCounters(otInstance);
+
+ srpServer->set_state(SrpServerStateFromOtSrpServerState(otSrpServerGetState(otInstance)));
+ srpServer->set_port(otSrpServerGetPort(otInstance));
+ srpServer->set_address_mode(
+ SrpServerAddressModeFromOtSrpServerAddressMode(otSrpServerGetAddressMode(otInstance)));
+
+ auto srpServerHosts = srpServer->mutable_hosts();
+ auto srpServerServices = srpServer->mutable_services();
+ auto srpServerResponseCounters = srpServer->mutable_response_counters();
+
+ while ((host = otSrpServerGetNextHost(otInstance, host)))
+ {
+ const otSrpServerService *service = nullptr;
+
+ if (otSrpServerHostIsDeleted(host))
+ {
+ srpServerHosts->set_deleted_count(srpServerHosts->deleted_count() + 1);
+ }
+ else
+ {
+ srpServerHosts->set_fresh_count(srpServerHosts->fresh_count() + 1);
+ otSrpServerHostGetLeaseInfo(host, &leaseInfo);
+ srpServerHosts->set_lease_time_total_ms(srpServerHosts->lease_time_total_ms() + leaseInfo.mLease);
+ srpServerHosts->set_key_lease_time_total_ms(srpServerHosts->key_lease_time_total_ms() +
+ leaseInfo.mKeyLease);
+ srpServerHosts->set_remaining_lease_time_total_ms(srpServerHosts->remaining_lease_time_total_ms() +
+ leaseInfo.mRemainingLease);
+ srpServerHosts->set_remaining_key_lease_time_total_ms(
+ srpServerHosts->remaining_key_lease_time_total_ms() + leaseInfo.mRemainingKeyLease);
+ }
+
+ while ((service = otSrpServerHostGetNextService(host, service)))
+ {
+ if (otSrpServerServiceIsDeleted(service))
+ {
+ srpServerServices->set_deleted_count(srpServerServices->deleted_count() + 1);
+ }
+ else
+ {
+ srpServerServices->set_fresh_count(srpServerServices->fresh_count() + 1);
+ otSrpServerServiceGetLeaseInfo(service, &leaseInfo);
+ srpServerServices->set_lease_time_total_ms(srpServerServices->lease_time_total_ms() +
+ leaseInfo.mLease);
+ srpServerServices->set_key_lease_time_total_ms(srpServerServices->key_lease_time_total_ms() +
+ leaseInfo.mKeyLease);
+ srpServerServices->set_remaining_lease_time_total_ms(
+ srpServerServices->remaining_lease_time_total_ms() + leaseInfo.mRemainingLease);
+ srpServerServices->set_remaining_key_lease_time_total_ms(
+ srpServerServices->remaining_key_lease_time_total_ms() + leaseInfo.mRemainingKeyLease);
+ }
+ }
+ }
+
+ srpServerResponseCounters->set_success_count(responseCounters->mSuccess);
+ srpServerResponseCounters->set_server_failure_count(responseCounters->mServerFailure);
+ srpServerResponseCounters->set_format_error_count(responseCounters->mFormatError);
+ srpServerResponseCounters->set_name_exists_count(responseCounters->mNameExists);
+ srpServerResponseCounters->set_refused_count(responseCounters->mRefused);
+ srpServerResponseCounters->set_other_count(responseCounters->mOther);
+ }
+ // End of SrpServerInfo section.
+#endif // OTBR_ENABLE_SRP_ADVERTISING_PROXY
+
+#if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY
+ // Begin of DnsServerInfo section.
+ {
+ auto dnsServer = wpanBorderRouter->mutable_dns_server();
+ auto dnsServerResponseCounters = dnsServer->mutable_response_counters();
+ otDnssdCounters otDnssdCounters = *otDnssdGetCounters(otInstance);
+
+ dnsServerResponseCounters->set_success_count(otDnssdCounters.mSuccessResponse);
+ dnsServerResponseCounters->set_server_failure_count(otDnssdCounters.mServerFailureResponse);
+ dnsServerResponseCounters->set_format_error_count(otDnssdCounters.mFormatErrorResponse);
+ dnsServerResponseCounters->set_name_error_count(otDnssdCounters.mNameErrorResponse);
+ dnsServerResponseCounters->set_not_implemented_count(otDnssdCounters.mNotImplementedResponse);
+ dnsServerResponseCounters->set_other_count(otDnssdCounters.mOtherResponse);
+
+ dnsServer->set_resolved_by_local_srp_count(otDnssdCounters.mResolvedBySrp);
+ }
+ // End of DnsServerInfo section.
+#endif // OTBR_ENABLE_DNSSD_DISCOVERY_PROXY
+
+ // Start of MdnsInfo section.
+ if (aPublisher != nullptr)
+ {
+ auto mdns = wpanBorderRouter->mutable_mdns();
+ const MdnsTelemetryInfo &mdnsInfo = aPublisher->GetMdnsTelemetryInfo();
+
+ CopyMdnsResponseCounters(mdnsInfo.mHostRegistrations, mdns->mutable_host_registration_responses());
+ CopyMdnsResponseCounters(mdnsInfo.mServiceRegistrations, mdns->mutable_service_registration_responses());
+ CopyMdnsResponseCounters(mdnsInfo.mHostResolutions, mdns->mutable_host_resolution_responses());
+ CopyMdnsResponseCounters(mdnsInfo.mServiceResolutions, mdns->mutable_service_resolution_responses());
+
+ mdns->set_host_registration_ema_latency_ms(mdnsInfo.mHostRegistrationEmaLatency);
+ mdns->set_service_registration_ema_latency_ms(mdnsInfo.mServiceRegistrationEmaLatency);
+ mdns->set_host_resolution_ema_latency_ms(mdnsInfo.mHostResolutionEmaLatency);
+ mdns->set_service_resolution_ema_latency_ms(mdnsInfo.mServiceResolutionEmaLatency);
+ }
+ // End of MdnsInfo section.
+
+ // End of WpanBorderRouter section.
+
+ // Start of WpanRcp section.
+ {
+ auto wpanRcp = telemetryDataReported.mutable_wpan_rcp();
+ const otRadioSpinelMetrics *otRadioSpinelMetrics = otSysGetRadioSpinelMetrics();
+ auto rcpStabilityStatistics = wpanRcp->mutable_rcp_stability_statistics();
+
+ if (otRadioSpinelMetrics != nullptr)
+ {
+ rcpStabilityStatistics->set_rcp_timeout_count(otRadioSpinelMetrics->mRcpTimeoutCount);
+ rcpStabilityStatistics->set_rcp_reset_count(otRadioSpinelMetrics->mRcpUnexpectedResetCount);
+ rcpStabilityStatistics->set_rcp_restoration_count(otRadioSpinelMetrics->mRcpRestorationCount);
+ rcpStabilityStatistics->set_spinel_parse_error_count(otRadioSpinelMetrics->mSpinelParseErrorCount);
+ }
+
+ // TODO: provide rcp_firmware_update_count info.
+ rcpStabilityStatistics->set_thread_stack_uptime(otInstanceGetUptime(otInstance));
+
+ const otRcpInterfaceMetrics *otRcpInterfaceMetrics = otSysGetRcpInterfaceMetrics();
+
+ if (otRcpInterfaceMetrics != nullptr)
+ {
+ auto rcpInterfaceStatistics = wpanRcp->mutable_rcp_interface_statistics();
+
+ rcpInterfaceStatistics->set_rcp_interface_type(otRcpInterfaceMetrics->mRcpInterfaceType);
+ rcpInterfaceStatistics->set_transferred_frames_count(otRcpInterfaceMetrics->mTransferredFrameCount);
+ rcpInterfaceStatistics->set_transferred_valid_frames_count(
+ otRcpInterfaceMetrics->mTransferredValidFrameCount);
+ rcpInterfaceStatistics->set_transferred_garbage_frames_count(
+ otRcpInterfaceMetrics->mTransferredGarbageFrameCount);
+ rcpInterfaceStatistics->set_rx_frames_count(otRcpInterfaceMetrics->mRxFrameCount);
+ rcpInterfaceStatistics->set_rx_bytes_count(otRcpInterfaceMetrics->mRxFrameByteCount);
+ rcpInterfaceStatistics->set_tx_frames_count(otRcpInterfaceMetrics->mTxFrameCount);
+ rcpInterfaceStatistics->set_tx_bytes_count(otRcpInterfaceMetrics->mTxFrameByteCount);
+ }
+ }
+ // End of WpanRcp section.
+
+ // Start of CoexMetrics section.
+ {
+ auto coexMetrics = telemetryDataReported.mutable_coex_metrics();
+ otRadioCoexMetrics otRadioCoexMetrics;
+
+ if (otPlatRadioGetCoexMetrics(otInstance, &otRadioCoexMetrics) == OT_ERROR_NONE)
+ {
+ coexMetrics->set_count_tx_request(otRadioCoexMetrics.mNumTxRequest);
+ coexMetrics->set_count_tx_grant_immediate(otRadioCoexMetrics.mNumTxGrantImmediate);
+ coexMetrics->set_count_tx_grant_wait(otRadioCoexMetrics.mNumTxGrantWait);
+ coexMetrics->set_count_tx_grant_wait_activated(otRadioCoexMetrics.mNumTxGrantWaitActivated);
+ coexMetrics->set_count_tx_grant_wait_timeout(otRadioCoexMetrics.mNumTxGrantWaitTimeout);
+ coexMetrics->set_count_tx_grant_deactivated_during_request(
+ otRadioCoexMetrics.mNumTxGrantDeactivatedDuringRequest);
+ coexMetrics->set_tx_average_request_to_grant_time_us(otRadioCoexMetrics.mAvgTxRequestToGrantTime);
+ coexMetrics->set_count_rx_request(otRadioCoexMetrics.mNumRxRequest);
+ coexMetrics->set_count_rx_grant_immediate(otRadioCoexMetrics.mNumRxGrantImmediate);
+ coexMetrics->set_count_rx_grant_wait(otRadioCoexMetrics.mNumRxGrantWait);
+ coexMetrics->set_count_rx_grant_wait_activated(otRadioCoexMetrics.mNumRxGrantWaitActivated);
+ coexMetrics->set_count_rx_grant_wait_timeout(otRadioCoexMetrics.mNumRxGrantWaitTimeout);
+ coexMetrics->set_count_rx_grant_deactivated_during_request(
+ otRadioCoexMetrics.mNumRxGrantDeactivatedDuringRequest);
+ coexMetrics->set_count_rx_grant_none(otRadioCoexMetrics.mNumRxGrantNone);
+ coexMetrics->set_rx_average_request_to_grant_time_us(otRadioCoexMetrics.mAvgRxRequestToGrantTime);
+ }
+ else
+ {
+ error = OT_ERROR_FAILED;
+ }
+ }
+ // End of CoexMetrics section.
+ }
+
+ deviceInfoReported.set_thread_version(otThreadGetVersion());
+ deviceInfoReported.set_ot_rcp_version(otGetRadioVersionString(otInstance));
+ // TODO: populate ot_host_version, thread_daemon_version.
+
+ return error;
+}
+
+int PushAtom(const ThreadnetworkTelemetryDataReported &telemetryDataReported)
+{
+ const std::string &wpanStats = telemetryDataReported.wpan_stats().SerializeAsString();
+ const std::string &wpanTopoFull = telemetryDataReported.wpan_topo_full().SerializeAsString();
+ const std::string &wpanBorderRouter = telemetryDataReported.wpan_border_router().SerializeAsString();
+ const std::string &wpanRcp = telemetryDataReported.wpan_rcp().SerializeAsString();
+ const std::string &coexMetrics = telemetryDataReported.coex_metrics().SerializeAsString();
+ threadnetwork::BytesField wpanStatsBytesField{wpanStats.c_str(), wpanStats.size()};
+ threadnetwork::BytesField wpanTopoFullBytesField{wpanTopoFull.c_str(), wpanTopoFull.size()};
+ threadnetwork::BytesField wpanBorderRouterBytesField{wpanBorderRouter.c_str(), wpanBorderRouter.size()};
+ threadnetwork::BytesField wpanRcpBytesField{wpanRcp.c_str(), wpanRcp.size()};
+ threadnetwork::BytesField coexMetricsBytesField{coexMetrics.c_str(), coexMetrics.size()};
+ return threadnetwork::stats_write(threadnetwork::THREADNETWORK_TELEMETRY_DATA_REPORTED, wpanStatsBytesField,
+ wpanTopoFullBytesField, wpanBorderRouterBytesField, wpanRcpBytesField,
+ coexMetricsBytesField);
+}
+
+int PushAtom(const ThreadnetworkTopoEntryRepeated &topoEntryRepeated)
+{
+ const std::string &topoEntryField = topoEntryRepeated.topo_entry_repeated().SerializeAsString();
+ threadnetwork::BytesField topoEntryFieldBytesField{topoEntryField.c_str(), topoEntryField.size()};
+ return threadnetwork::stats_write(threadnetwork::THREADNETWORK_TOPO_ENTRY_REPEATED, topoEntryFieldBytesField);
+}
+
+int PushAtom(const ThreadnetworkDeviceInfoReported &deviceInfoReported)
+{
+ const std::string &otHostVersion = deviceInfoReported.ot_host_version();
+ const std::string &otRcpVersion = deviceInfoReported.ot_rcp_version();
+ const int32_t &threadVersion = deviceInfoReported.thread_version();
+ const std::string &threadDaemonVersion = deviceInfoReported.thread_daemon_version();
+ return threadnetwork::stats_write(threadnetwork::THREADNETWORK_DEVICE_INFO_REPORTED, otHostVersion.c_str(),
+ otRcpVersion.c_str(), threadVersion, threadDaemonVersion.c_str());
+}
+
+void RetrieveAndPushAtoms(otInstance *otInstance)
+{
+ ThreadnetworkTelemetryDataReported telemetryDataReported;
+ ThreadnetworkTopoEntryRepeated topoEntryRepeated;
+ ThreadnetworkDeviceInfoReported deviceInfoReported;
+
+ if (RetrieveTelemetryAtom(otInstance, nullptr, telemetryDataReported, topoEntryRepeated, deviceInfoReported) !=
+ OTBR_ERROR_NONE)
+ {
+ otbrLogWarning("Some telemetries are not populated");
+ }
+ if (PushAtom(telemetryDataReported) <= 0)
+ {
+ otbrLogWarning("Failed to push ThreadnetworkTelemetryDataReported");
+ }
+ if (PushAtom(topoEntryRepeated) <= 0)
+ {
+ otbrLogWarning("Failed to push ThreadnetworkTopoEntryRepeated");
+ }
+ if (PushAtom(deviceInfoReported) <= 0)
+ {
+ otbrLogWarning("Failed to push ThreadnetworkDeviceInfoReported");
+ }
+}
+} // namespace Android
+} // namespace otbr