summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Pomai Ahlo <poahlo@google.com> 2025-02-03 15:09:59 -0800
committer Pomai Ahlo <poahlo@google.com> 2025-02-20 13:26:36 -0800
commit0503ef80d9d1f90c6ed28cda7dae07ec62706a9b (patch)
tree06bb0068c6f70775b1a364010b1fe542bf94b738
parente7e402ea4f4580bc2a116b22ebd93fa7ae4e2e31 (diff)
RFCOMM metrics V2: Add metrics functions
- Collect metrics when sdp fails for HFP and RFCOMM - Collect metrics when port creation fails for HFP and RFCOMM - Collect metrics when port closes Bug: 374989690 Test: m com.android.bt Flag: EXEMPT metrics no-op Change-Id: Ie2de6f0305afad58ab7d2cd7fdcf988c21649a28
-rw-r--r--system/bta/include/bta_rfcomm_metrics.h28
-rw-r--r--system/bta/rfcomm/bta_rfcomm_metrics.cc152
-rw-r--r--system/gd/os/android/metrics.cc38
-rw-r--r--system/gd/os/chromeos/metrics.cc10
-rw-r--r--system/gd/os/host/metrics.cc10
-rw-r--r--system/gd/os/linux/metrics.cc9
-rw-r--r--system/gd/os/metrics.h27
-rw-r--r--system/main/shim/metrics_api.cc14
-rw-r--r--system/main/shim/metrics_api.h19
-rw-r--r--system/stack/include/rfc_metrics.h21
-rw-r--r--system/stack/rfcomm/rfc_metrics.cc176
-rw-r--r--system/test/mock/mock_main_shim_metrics_api.cc13
-rw-r--r--system/test/mock/mock_main_shim_metrics_api.h37
13 files changed, 554 insertions, 0 deletions
diff --git a/system/bta/include/bta_rfcomm_metrics.h b/system/bta/include/bta_rfcomm_metrics.h
new file mode 100644
index 0000000000..0db35f8ba4
--- /dev/null
+++ b/system/bta/include/bta_rfcomm_metrics.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2024 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.
+ */
+
+#pragma once
+
+#include "bta_jv_api.h"
+#include "types/raw_address.h"
+
+void bta_collect_rfc_metrics_after_sdp_fail(tBTA_JV_STATUS sdp_status, RawAddress addr, int app_uid,
+ int security, bool is_server, uint64_t sdp_duration);
+
+void bta_collect_rfc_metrics_after_port_fail(tPORT_RESULT port_result, bool sdp_initiated,
+ tBTA_JV_STATUS sdp_status, RawAddress addr,
+ int app_uid, int security, bool is_server,
+ uint64_t sdp_duration_ms);
diff --git a/system/bta/rfcomm/bta_rfcomm_metrics.cc b/system/bta/rfcomm/bta_rfcomm_metrics.cc
new file mode 100644
index 0000000000..5cbae01471
--- /dev/null
+++ b/system/bta/rfcomm/bta_rfcomm_metrics.cc
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2024 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.
+ */
+#define LOG_TAG "bta_rfcomm_metrics"
+
+#include "bta_rfcomm_metrics.h"
+
+#include <bluetooth/log.h>
+#include <frameworks/proto_logging/stats/enums/bluetooth/rfcomm/enums.pb.h>
+
+#include "bta_sec_api.h"
+#include "main/shim/metrics_api.h"
+#include "stack/include/btm_sec_api_types.h"
+
+using namespace bluetooth;
+
+using namespace android::bluetooth;
+using namespace android::bluetooth::rfcomm;
+
+static BtaStatus toStatus(tBTA_JV_STATUS status);
+static SocketConnectionSecurity toSecurity(int security);
+static PortResult toPortResult(tPORT_RESULT result);
+
+// logged if SDP result is either FAILED or BUSY
+void bta_collect_rfc_metrics_after_sdp_fail(tBTA_JV_STATUS sdp_status, RawAddress addr, int app_uid,
+ int security, bool is_server,
+ uint64_t sdp_duration_ms) {
+ // We only call this function in the case where we started (and failed) sdp
+ bool sdp_initiated = true;
+
+ // We didn't make it to the stage of making a port, so assign default values for these fields
+ PortResult close_reason = PortResult::PORT_RESULT_UNDEFINED;
+ RfcommPortState state_prior = RfcommPortState::PORT_STATE_UNKNOWN;
+ RfcommPortEvent last_event = RfcommPortEvent::PORT_EVENT_UNKNOWN;
+ int open_duration_ms = 0;
+
+ shim::LogMetricRfcommConnectionAtClose(
+ addr, close_reason, toSecurity(security), last_event, state_prior, open_duration_ms,
+ app_uid, toStatus(sdp_status), is_server, sdp_initiated, sdp_duration_ms);
+}
+
+void bta_collect_rfc_metrics_after_port_fail(tPORT_RESULT port_result, bool sdp_initiated,
+ tBTA_JV_STATUS sdp_status, RawAddress addr,
+ int app_uid, int security, bool is_server,
+ uint64_t sdp_duration_ms) {
+ BtaStatus reported_status;
+ if (sdp_status == tBTA_JV_STATUS::SUCCESS && !sdp_initiated) {
+ reported_status = BtaStatus::BTA_STATUS_UNKNOWN;
+ } else {
+ reported_status = toStatus(sdp_status);
+ }
+ RfcommPortState state_prior = RfcommPortState::PORT_STATE_UNKNOWN;
+ RfcommPortEvent last_event = RfcommPortEvent::PORT_EVENT_UNKNOWN;
+ int open_duration_ms = 0;
+
+ shim::LogMetricRfcommConnectionAtClose(
+ addr, toPortResult(port_result), toSecurity(security), last_event, state_prior,
+ open_duration_ms, app_uid, reported_status, is_server, sdp_initiated, sdp_duration_ms);
+}
+
+static BtaStatus toStatus(tBTA_JV_STATUS status) {
+ switch (status) {
+ case tBTA_JV_STATUS::SUCCESS:
+ return BtaStatus::BTA_STATUS_SUCCESS;
+ case tBTA_JV_STATUS::FAILURE:
+ return BtaStatus::BTA_STATUS_FAILURE;
+ case tBTA_JV_STATUS::BUSY:
+ return BtaStatus::BTA_STATUS_BUSY;
+ }
+ return BtaStatus::BTA_STATUS_UNKNOWN;
+}
+
+static SocketConnectionSecurity toSecurity(int security) {
+ if ((security == (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT)) ||
+ (security == (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT)) ||
+ (security == (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT))) {
+ return SocketConnectionSecurity::SOCKET_SECURITY_SECURE;
+ } else if (security == BTM_SEC_NONE) {
+ return SocketConnectionSecurity::SOCKET_SECURITY_INSECURE;
+ }
+ return SocketConnectionSecurity::SOCKET_SECURITY_UNKNOWN;
+}
+
+static PortResult toPortResult(tPORT_RESULT result) {
+ switch (result) {
+ case PORT_SUCCESS:
+ return PortResult::PORT_RESULT_SUCCESS;
+ case PORT_UNKNOWN_ERROR:
+ return PortResult::PORT_RESULT_UNKNOWN_ERROR;
+ case PORT_ALREADY_OPENED:
+ return PortResult::PORT_RESULT_ALREADY_OPENED;
+ case PORT_CMD_PENDING:
+ return PortResult::PORT_RESULT_CMD_PENDING;
+ case PORT_APP_NOT_REGISTERED:
+ return PortResult::PORT_RESULT_APP_NOT_REGISTERED;
+ case PORT_NO_MEM:
+ return PortResult::PORT_RESULT_NO_MEM;
+ case PORT_NO_RESOURCES:
+ return PortResult::PORT_RESULT_NO_RESOURCES;
+ case PORT_BAD_BD_ADDR:
+ return PortResult::PORT_RESULT_BAD_BD_ADDR;
+ case PORT_BAD_HANDLE:
+ return PortResult::PORT_RESULT_BAD_HANDLE;
+ case PORT_NOT_OPENED:
+ return PortResult::PORT_RESULT_NOT_OPENED;
+ case PORT_LINE_ERR:
+ return PortResult::PORT_RESULT_LINE_ERR;
+ case PORT_START_FAILED:
+ return PortResult::PORT_RESULT_START_FAILED;
+ case PORT_PAR_NEG_FAILED:
+ return PortResult::PORT_RESULT_PAR_NEG_FAILED;
+ case PORT_PORT_NEG_FAILED:
+ return PortResult::PORT_RESULT_PORT_NEG_FAILED;
+ case PORT_SEC_FAILED:
+ return PortResult::PORT_RESULT_SEC_FAILED;
+ case PORT_PEER_CONNECTION_FAILED:
+ return PortResult::PORT_RESULT_PEER_CONNECTION_FAILED;
+ case PORT_PEER_FAILED:
+ return PortResult::PORT_RESULT_PEER_FAILED;
+ case PORT_PEER_TIMEOUT:
+ return PortResult::PORT_RESULT_PEER_TIMEOUT;
+ case PORT_CLOSED:
+ return PortResult::PORT_RESULT_CLOSED;
+ case PORT_TX_FULL:
+ return PortResult::PORT_RESULT_TX_FULL;
+ case PORT_LOCAL_CLOSED:
+ return PortResult::PORT_RESULT_LOCAL_CLOSED;
+ case PORT_LOCAL_TIMEOUT:
+ return PortResult::PORT_RESULT_LOCAL_TIMEOUT;
+ case PORT_TX_QUEUE_DISABLED:
+ return PortResult::PORT_RESULT_TX_QUEUE_DISABLED;
+ case PORT_PAGE_TIMEOUT:
+ return PortResult::PORT_RESULT_PAGE_TIMEOUT;
+ case PORT_INVALID_SCN:
+ return PortResult::PORT_RESULT_INVALID_SCN;
+ case PORT_ERR_MAX:
+ return PortResult::PORT_RESULT_ERR_MAX;
+ }
+ return PortResult::PORT_RESULT_UNDEFINED;
+}
diff --git a/system/gd/os/android/metrics.cc b/system/gd/os/android/metrics.cc
index 1a899062cd..ddb9d826f1 100644
--- a/system/gd/os/android/metrics.cc
+++ b/system/gd/os/android/metrics.cc
@@ -30,6 +30,7 @@
#include "common/strings.h"
#include "hardware/bt_av.h"
#include "hci/hci_packets.h"
+#include "main/shim/helpers.h"
namespace std {
template <>
@@ -51,6 +52,20 @@ template <>
struct formatter<android::bluetooth::EventType> : enum_formatter<android::bluetooth::EventType> {};
template <>
struct formatter<android::bluetooth::State> : enum_formatter<android::bluetooth::State> {};
+template <>
+struct formatter<android::bluetooth::rfcomm::PortResult>
+ : enum_formatter<android::bluetooth::rfcomm::PortResult> {};
+template <>
+struct formatter<android::bluetooth::rfcomm::RfcommPortState>
+ : enum_formatter<android::bluetooth::rfcomm::RfcommPortState> {};
+template <>
+struct formatter<android::bluetooth::rfcomm::RfcommPortEvent>
+ : enum_formatter<android::bluetooth::rfcomm::RfcommPortEvent> {};
+template <>
+struct formatter<android::bluetooth::rfcomm::SocketConnectionSecurity>
+ : enum_formatter<android::bluetooth::rfcomm::SocketConnectionSecurity> {};
+template <>
+struct formatter<android::bluetooth::BtaStatus> : enum_formatter<android::bluetooth::BtaStatus> {};
} // namespace std
namespace bluetooth {
@@ -478,5 +493,28 @@ void LogMetricBluetoothEvent(const Address& address, android::bluetooth::EventTy
}
}
+void LogMetricRfcommConnectionAtClose(const Address& address,
+ android::bluetooth::rfcomm::PortResult close_reason,
+ android::bluetooth::rfcomm::SocketConnectionSecurity security,
+ android::bluetooth::rfcomm::RfcommPortEvent last_event,
+ android::bluetooth::rfcomm::RfcommPortState previous_state,
+ int32_t open_duration_ms, int32_t uid,
+ android::bluetooth::BtaStatus sdp_status, bool is_server,
+ bool sdp_initiated, int32_t sdp_duration_ms) {
+ int metric_id = 0;
+ if (address.IsEmpty()) {
+ log::warn("Failed to upload - Address is empty");
+ return;
+ }
+ metric_id = MetricIdManager::GetInstance().AllocateId(address);
+ int ret = stats_write(BLUETOOTH_RFCOMM_CONNECTION_REPORTED_AT_CLOSE, close_reason, security,
+ last_event, previous_state, open_duration_ms, uid, metric_id, sdp_status,
+ is_server, sdp_initiated, sdp_duration_ms);
+ if (ret < 0) {
+ log::warn("Failed to log RFCOMM Connection metric for uid {}, close reason {}", uid,
+ close_reason);
+ }
+}
+
} // namespace os
} // namespace bluetooth
diff --git a/system/gd/os/chromeos/metrics.cc b/system/gd/os/chromeos/metrics.cc
index c5b33a4fce..70258d335a 100644
--- a/system/gd/os/chromeos/metrics.cc
+++ b/system/gd/os/chromeos/metrics.cc
@@ -203,5 +203,15 @@ void LogMetricBluetoothLEConnection(os::LEConnectionSessionOptions /* session_op
void LogMetricBluetoothEvent(const Address& address, android::bluetooth::EventType event_type,
android::bluetooth::State state) {}
+
+void LogMetricRfcommConnectionAtClose(
+ const Address& /* raw_address */, android::bluetooth::rfcomm::PortResult /* close_reason */,
+ android::bluetooth::rfcomm::SocketConnectionSecurity /* security */,
+ android::bluetooth::rfcomm::RfcommPortEvent /* last_event */,
+ android::bluetooth::rfcomm::RfcommPortState /* previous_state */,
+ int32_t /* open_duration_ms */, int32_t /* uid */,
+ android::bluetooth::BtaStatus /* sdp_status */, bool /* is_server */,
+ bool /* sdp_initiated */, int32_t /* sdp_duration_ms */) {}
+
} // namespace os
} // namespace bluetooth
diff --git a/system/gd/os/host/metrics.cc b/system/gd/os/host/metrics.cc
index a019033348..61734e6a81 100644
--- a/system/gd/os/host/metrics.cc
+++ b/system/gd/os/host/metrics.cc
@@ -124,5 +124,15 @@ void LogMetricBluetoothLEConnection(os::LEConnectionSessionOptions /* session_op
void LogMetricBluetoothEvent(const Address& /* address */,
android::bluetooth::EventType /* event type */,
android::bluetooth::State /* state */) {}
+
+void LogMetricRfcommConnectionAtClose(
+ const Address& /* raw_address */, android::bluetooth::rfcomm::PortResult /* close_reason */,
+ android::bluetooth::rfcomm::SocketConnectionSecurity /* security */,
+ android::bluetooth::rfcomm::RfcommPortEvent /* last_event */,
+ android::bluetooth::rfcomm::RfcommPortState /* previous_state */,
+ int32_t /* open_duration_ms */, int32_t /* uid */,
+ android::bluetooth::BtaStatus /* sdp_status */, bool /* is_server */,
+ bool /* sdp_initiated */, int32_t /* sdp_duration_ms */) {}
+
} // namespace os
} // namespace bluetooth
diff --git a/system/gd/os/linux/metrics.cc b/system/gd/os/linux/metrics.cc
index c5e38493da..45fca1f4ee 100644
--- a/system/gd/os/linux/metrics.cc
+++ b/system/gd/os/linux/metrics.cc
@@ -108,6 +108,15 @@ void LogMetricBluetoothCodePathCounterMetrics(int32_t key, int64_t count) {}
void LogMetricBluetoothLEConnection(os::LEConnectionSessionOptions /* session_options */) {}
+void LogMetricRfcommConnectionAtClose(const Address& raw_address,
+ android::bluetooth::rfcomm::PortResult close_reason,
+ android::bluetooth::rfcomm::SocketConnectionSecurity security,
+ android::bluetooth::rfcomm::RfcommPortEvent last_event,
+ android::bluetooth::rfcomm::RfcommPortState previous_state,
+ int32_t open_duration_ms, int32_t uid,
+ android::bluetooth::BtaStatus sdp_status, bool is_server,
+ bool sdp_initiated, int32_t sdp_duration_ms) {}
+
void LogMetricBluetoothEvent(const Address& address, android::bluetooth::EventType event_type,
android::bluetooth::State state) {}
} // namespace os
diff --git a/system/gd/os/metrics.h b/system/gd/os/metrics.h
index 7d89483754..9f372b25af 100644
--- a/system/gd/os/metrics.h
+++ b/system/gd/os/metrics.h
@@ -21,10 +21,12 @@
#include <frameworks/proto_logging/stats/enums/bluetooth/enums.pb.h>
#include <frameworks/proto_logging/stats/enums/bluetooth/hci/enums.pb.h>
#include <frameworks/proto_logging/stats/enums/bluetooth/le/enums.pb.h>
+#include <frameworks/proto_logging/stats/enums/bluetooth/rfcomm/enums.pb.h>
#include <vector>
#include "hci/address.h"
+#include "types/raw_address.h"
namespace bluetooth {
@@ -346,6 +348,31 @@ void LogMetricBluetoothLEConnection(os::LEConnectionSessionOptions session_optio
*/
void LogMetricBluetoothEvent(const hci::Address& address, android::bluetooth::EventType event_type,
android::bluetooth::State state);
+
+/**
+ * Logs an RFCOMM connection when an RFCOMM port closes
+ *
+ * @param address address of the peer device
+ * @param close_reason reason that the port was closed
+ * @param security security level of the connection
+ * @param last_event event processed prior to "CLOSED"
+ * @param previous_state state prior to "CLOSED"
+ * @param open_duration_ms that the socket was opened, 0 if connection failed
+ * @param uid UID of the app that called connect
+ * @param sdp_status status code for sdp
+ * @param is_server true if device is server
+ * @param sdp_initiated true if sdp started for thie connection
+ * @param sdp_duration_ms duration of sdp, 0 if it didn't happen
+ */
+void LogMetricRfcommConnectionAtClose(const hci::Address& address,
+ android::bluetooth::rfcomm::PortResult close_reason,
+ android::bluetooth::rfcomm::SocketConnectionSecurity security,
+ android::bluetooth::rfcomm::RfcommPortEvent last_event,
+ android::bluetooth::rfcomm::RfcommPortState previous_state,
+ int32_t open_duration_ms, int32_t uid,
+ android::bluetooth::BtaStatus sdp_status, bool is_server,
+ bool sdp_initiated, int32_t sdp_duration_ms);
+
} // namespace os
//
} // namespace bluetooth
diff --git a/system/main/shim/metrics_api.cc b/system/main/shim/metrics_api.cc
index 58b99b8831..6d2b317150 100644
--- a/system/main/shim/metrics_api.cc
+++ b/system/main/shim/metrics_api.cc
@@ -187,6 +187,20 @@ void LogMetricLeConnectionCompletion(hci::Address address, hci::ErrorCode reason
bluetooth::metrics::LogLeAclCompletionEvent(address, reason, is_locally_initiated);
}
+void LogMetricRfcommConnectionAtClose(const RawAddress& raw_address,
+ android::bluetooth::rfcomm::PortResult close_reason,
+ android::bluetooth::rfcomm::SocketConnectionSecurity security,
+ android::bluetooth::rfcomm::RfcommPortEvent last_event,
+ android::bluetooth::rfcomm::RfcommPortState previous_state,
+ int32_t open_duration_ms, int32_t uid,
+ android::bluetooth::BtaStatus sdp_status, bool is_server,
+ bool sdp_initiated, int32_t sdp_duration_ms) {
+ Address address = bluetooth::ToGdAddress(raw_address);
+ bluetooth::os::LogMetricRfcommConnectionAtClose(address, close_reason, security, last_event,
+ previous_state, open_duration_ms, uid, sdp_status,
+ is_server, sdp_initiated, sdp_duration_ms);
+}
+
bool CountCounterMetrics(int32_t key, int64_t count) {
auto counter_metrics = GetCounterMetrics();
if (counter_metrics == nullptr) {
diff --git a/system/main/shim/metrics_api.h b/system/main/shim/metrics_api.h
index 6c539d1d1d..a2cd12cf9b 100644
--- a/system/main/shim/metrics_api.h
+++ b/system/main/shim/metrics_api.h
@@ -290,6 +290,25 @@ void LogMetricLeConnectionLifecycle(hci::Address address, bool is_connect, bool
*/
void LogMetricLeConnectionCompletion(hci::Address address, hci::ErrorCode reason,
bool is_locally_initiated);
+/**
+ * Logs an RFCOMM connection when an RFCOMM port closes
+ *
+ * @param address address of peer device
+ * @param close_reason reason that the port was closed
+ * @param security security level of the connection
+ * @param second_previous_state two states prior to "CLOSED"
+ * @param previous_state state prior to "CLOSED"
+ * @param duration_ms that the socket was opened, 0 if connection failed
+ * @param uid UID of the app that called connect
+ */
+void LogMetricRfcommConnectionAtClose(const RawAddress& address,
+ android::bluetooth::rfcomm::PortResult close_reason,
+ android::bluetooth::rfcomm::SocketConnectionSecurity security,
+ android::bluetooth::rfcomm::RfcommPortEvent last_event,
+ android::bluetooth::rfcomm::RfcommPortState previous_state,
+ int32_t open_duration_ms, int32_t uid,
+ android::bluetooth::BtaStatus sdp_status, bool is_server,
+ bool sdp_initiated, int32_t sdp_duration_ms);
bool CountCounterMetrics(int32_t key, int64_t count);
diff --git a/system/stack/include/rfc_metrics.h b/system/stack/include/rfc_metrics.h
new file mode 100644
index 0000000000..66d73ec8d8
--- /dev/null
+++ b/system/stack/include/rfc_metrics.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2024 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.
+ */
+
+#pragma once
+
+#include "stack/rfcomm/port_int.h"
+
+void port_collect_attempt_metrics(tPORT* p_port);
diff --git a/system/stack/rfcomm/rfc_metrics.cc b/system/stack/rfcomm/rfc_metrics.cc
new file mode 100644
index 0000000000..13f6ad2bdd
--- /dev/null
+++ b/system/stack/rfcomm/rfc_metrics.cc
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2024 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.
+ */
+#define LOG_TAG "rfc_metrics"
+
+#include "../include/rfc_metrics.h"
+
+#include <bluetooth/log.h>
+#include <frameworks/proto_logging/stats/enums/bluetooth/rfcomm/enums.pb.h>
+
+#include "bta/include/bta_jv_api.h"
+#include "common/time_util.h"
+#include "main/shim/metrics_api.h"
+#include "stack/btm/security_device_record.h"
+#include "stack/include/btm_sec_api_types.h"
+#include "stack/include/port_api.h"
+#include "stack/rfcomm/port_int.h"
+#include "stack/rfcomm/rfc_event.h"
+#include "stack/rfcomm/rfc_state.h"
+#include "types/raw_address.h"
+
+using namespace bluetooth;
+
+using namespace android::bluetooth;
+using namespace android::bluetooth::rfcomm;
+
+static SocketConnectionSecurity toSecurity(uint16_t sec_mask);
+static PortResult toPortResult(tPORT_RESULT result);
+static RfcommPortState toPortState(tRFC_PORT_STATE state);
+static RfcommPortEvent toPortEvent(tRFC_PORT_EVENT event);
+
+void port_collect_attempt_metrics(tPORT* p_port) {
+ bool is_server = p_port->is_server;
+ bool sdp_initiated = (p_port->sdp_duration_ms > 0);
+ // If we're calling this metrics function, SDP completed with no problems
+ BtaStatus sdp_status = sdp_initiated ? BTA_STATUS_SUCCESS : BTA_STATUS_UNKNOWN;
+ RfcommPortSm sm_cb = p_port->rfc.sm_cb;
+ log::assert_that(sm_cb.state == RFC_STATE_CLOSED, "Assert failed: Port not closed");
+ uint64_t open_duration_ms = (sm_cb.close_timestamp - sm_cb.open_timestamp) / 1000;
+
+ shim::LogMetricRfcommConnectionAtClose(
+ p_port->bd_addr, toPortResult(sm_cb.close_reason), toSecurity(p_port->sec_mask),
+ toPortEvent(sm_cb.last_event), toPortState(sm_cb.state_prior),
+ static_cast<int32_t>(open_duration_ms), static_cast<int32_t>(p_port->app_uid), sdp_status,
+ is_server, sdp_initiated, static_cast<int32_t>(p_port->sdp_duration_ms));
+}
+
+static SocketConnectionSecurity toSecurity(uint16_t sec_mask) {
+ if (((sec_mask & BTM_SEC_IN_FLAGS) == (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT)) ||
+ ((sec_mask & BTM_SEC_OUT_FLAGS) == (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT))) {
+ return SocketConnectionSecurity::SOCKET_SECURITY_SECURE;
+ } else if (((sec_mask & BTM_SEC_IN_FLAGS) == (BTM_SEC_NONE)) ||
+ ((sec_mask & BTM_SEC_OUT_FLAGS) == (BTM_SEC_NONE))) {
+ return SocketConnectionSecurity::SOCKET_SECURITY_INSECURE;
+ }
+
+ return SocketConnectionSecurity::SOCKET_SECURITY_UNKNOWN;
+}
+
+static PortResult toPortResult(tPORT_RESULT result) {
+ switch (result) {
+ case PORT_SUCCESS:
+ return PortResult::PORT_RESULT_SUCCESS;
+ case PORT_UNKNOWN_ERROR:
+ return PortResult::PORT_RESULT_UNKNOWN_ERROR;
+ case PORT_ALREADY_OPENED:
+ return PortResult::PORT_RESULT_ALREADY_OPENED;
+ case PORT_CMD_PENDING:
+ return PortResult::PORT_RESULT_CMD_PENDING;
+ case PORT_APP_NOT_REGISTERED:
+ return PortResult::PORT_RESULT_APP_NOT_REGISTERED;
+ case PORT_NO_MEM:
+ return PortResult::PORT_RESULT_NO_MEM;
+ case PORT_NO_RESOURCES:
+ return PortResult::PORT_RESULT_NO_RESOURCES;
+ case PORT_BAD_BD_ADDR:
+ return PortResult::PORT_RESULT_BAD_BD_ADDR;
+ case PORT_BAD_HANDLE:
+ return PortResult::PORT_RESULT_BAD_HANDLE;
+ case PORT_NOT_OPENED:
+ return PortResult::PORT_RESULT_NOT_OPENED;
+ case PORT_LINE_ERR:
+ return PortResult::PORT_RESULT_LINE_ERR;
+ case PORT_START_FAILED:
+ return PortResult::PORT_RESULT_START_FAILED;
+ case PORT_PAR_NEG_FAILED:
+ return PortResult::PORT_RESULT_PAR_NEG_FAILED;
+ case PORT_PORT_NEG_FAILED:
+ return PortResult::PORT_RESULT_PORT_NEG_FAILED;
+ case PORT_SEC_FAILED:
+ return PortResult::PORT_RESULT_SEC_FAILED;
+ case PORT_PEER_CONNECTION_FAILED:
+ return PortResult::PORT_RESULT_PEER_CONNECTION_FAILED;
+ case PORT_PEER_FAILED:
+ return PortResult::PORT_RESULT_PEER_FAILED;
+ case PORT_PEER_TIMEOUT:
+ return PortResult::PORT_RESULT_PEER_TIMEOUT;
+ case PORT_CLOSED:
+ return PortResult::PORT_RESULT_CLOSED;
+ case PORT_TX_FULL:
+ return PortResult::PORT_RESULT_TX_FULL;
+ case PORT_LOCAL_CLOSED:
+ return PortResult::PORT_RESULT_LOCAL_CLOSED;
+ case PORT_LOCAL_TIMEOUT:
+ return PortResult::PORT_RESULT_LOCAL_TIMEOUT;
+ case PORT_TX_QUEUE_DISABLED:
+ return PortResult::PORT_RESULT_TX_QUEUE_DISABLED;
+ case PORT_PAGE_TIMEOUT:
+ return PortResult::PORT_RESULT_PAGE_TIMEOUT;
+ case PORT_INVALID_SCN:
+ return PortResult::PORT_RESULT_INVALID_SCN;
+ case PORT_ERR_MAX:
+ return PortResult::PORT_RESULT_ERR_MAX;
+ }
+ return PortResult::PORT_RESULT_UNDEFINED;
+}
+
+static RfcommPortState toPortState(tRFC_PORT_STATE state) {
+ switch (state) {
+ case RFC_STATE_SABME_WAIT_UA:
+ return RfcommPortState::PORT_STATE_SABME_WAIT_UA;
+ case RFC_STATE_ORIG_WAIT_SEC_CHECK:
+ return RfcommPortState::PORT_STATE_ORIG_WAIT_SEC_CHECK;
+ case RFC_STATE_TERM_WAIT_SEC_CHECK:
+ return RfcommPortState::PORT_STATE_TERM_WAIT_SEC_CHECK;
+ case RFC_STATE_OPENED:
+ return RfcommPortState::PORT_STATE_OPENED;
+ case RFC_STATE_DISC_WAIT_UA:
+ return RfcommPortState::PORT_STATE_DISC_WAIT_UA;
+ case RFC_STATE_CLOSED:
+ return RfcommPortState::PORT_STATE_CLOSED;
+ }
+ return RfcommPortState::PORT_STATE_UNKNOWN;
+}
+
+static RfcommPortEvent toPortEvent(tRFC_PORT_EVENT event) {
+ switch (event) {
+ case RFC_PORT_EVENT_SABME:
+ return RfcommPortEvent::PORT_EVENT_SABME;
+ case RFC_PORT_EVENT_UA:
+ return RfcommPortEvent::PORT_EVENT_UA;
+ case RFC_PORT_EVENT_DM:
+ return RfcommPortEvent::PORT_EVENT_DM;
+ case RFC_PORT_EVENT_DISC:
+ return RfcommPortEvent::PORT_EVENT_DISC;
+ case RFC_PORT_EVENT_UIH:
+ return RfcommPortEvent::PORT_EVENT_UIH;
+ case RFC_PORT_EVENT_TIMEOUT:
+ return RfcommPortEvent::PORT_EVENT_TIMEOUT;
+ case RFC_PORT_EVENT_OPEN:
+ return RfcommPortEvent::PORT_EVENT_OPEN;
+ case RFC_PORT_EVENT_ESTABLISH_RSP:
+ return RfcommPortEvent::PORT_EVENT_ESTABLISH_RSP;
+ case RFC_PORT_EVENT_CLOSE:
+ return RfcommPortEvent::PORT_EVENT_CLOSE;
+ case RFC_PORT_EVENT_CLEAR:
+ return RfcommPortEvent::PORT_EVENT_CLEAR;
+ case RFC_PORT_EVENT_DATA:
+ return RfcommPortEvent::PORT_EVENT_DATA;
+ case RFC_PORT_EVENT_SEC_COMPLETE:
+ return RfcommPortEvent::PORT_EVENT_SEC_COMPLETE;
+ }
+ return RfcommPortEvent::PORT_EVENT_UNKNOWN;
+}
diff --git a/system/test/mock/mock_main_shim_metrics_api.cc b/system/test/mock/mock_main_shim_metrics_api.cc
index ac64150797..908f258205 100644
--- a/system/test/mock/mock_main_shim_metrics_api.cc
+++ b/system/test/mock/mock_main_shim_metrics_api.cc
@@ -59,6 +59,7 @@ struct LogMetricLeConnectionStatus LogMetricLeConnectionStatus;
struct LogMetricLeDeviceInAcceptList LogMetricLeDeviceInAcceptList;
struct LogMetricLeConnectionLifecycle LogMetricLeConnectionLifecycle;
struct LogMetricLeConnectionCompletion LogMetricLeConnectionCompletion;
+struct LogMetricRfcommConnectionAtClose LogMetricRfcommConnectionAtClose;
} // namespace main_shim_metrics_api
} // namespace mock
@@ -215,4 +216,16 @@ void bluetooth::shim::LogMetricLeConnectionCompletion(bluetooth::hci::Address ad
test::mock::main_shim_metrics_api::LogMetricLeConnectionCompletion(address, reason,
is_locally_initiated);
}
+void bluetooth::shim::LogMetricRfcommConnectionAtClose(
+ const RawAddress& raw_address, android::bluetooth::rfcomm::PortResult close_reason,
+ android::bluetooth::rfcomm::SocketConnectionSecurity security,
+ android::bluetooth::rfcomm::RfcommPortEvent last_event,
+ android::bluetooth::rfcomm::RfcommPortState previous_state, int32_t open_duration_ms,
+ int32_t uid, android::bluetooth::BtaStatus sdp_status, bool is_server, bool sdp_initiated,
+ int32_t sdp_duration_ms) {
+ inc_func_call_count(__func__);
+ test::mock::main_shim_metrics_api::LogMetricRfcommConnectionAtClose(
+ raw_address, close_reason, security, last_event, previous_state, open_duration_ms, uid,
+ sdp_status, is_server, sdp_initiated, sdp_duration_ms);
+}
// END mockcify generation
diff --git a/system/test/mock/mock_main_shim_metrics_api.h b/system/test/mock/mock_main_shim_metrics_api.h
index 6b8d8e5edf..7e8df3c3c8 100644
--- a/system/test/mock/mock_main_shim_metrics_api.h
+++ b/system/test/mock/mock_main_shim_metrics_api.h
@@ -367,6 +367,43 @@ struct LogMetricLeConnectionCompletion {
};
extern struct LogMetricLeConnectionCompletion LogMetricLeConnectionCompletion;
+// Name: LogMetricRfcommConnectionAtClose
+// Params: const RawAddress& raw_address, android::bluetooth::rfcomm::PortResult close_reason,
+// android::bluetooth::rfcomm::SocketConnectionSecurity security,
+// android::bluetooth::rfcomm::RfcommPortEvent last_event,
+// android::bluetooth::rfcomm::RfcommPortState previous_state, int32_t open_duration_ms,
+// int32_t uid, android::bluetooth::BtaStatus sdp_status, bool is_server,
+// bool sdp_initiated, int32_t sdp_duration_ms
+// Returns: void
+struct LogMetricRfcommConnectionAtClose {
+ std::function<void(
+ const RawAddress& raw_address, android::bluetooth::rfcomm::PortResult close_reason,
+ android::bluetooth::rfcomm::SocketConnectionSecurity security,
+ android::bluetooth::rfcomm::RfcommPortEvent last_event,
+ android::bluetooth::rfcomm::RfcommPortState previous_state, int32_t open_duration_ms,
+ int32_t uid, android::bluetooth::BtaStatus sdp_status, bool is_server, bool sdp_initiated,
+ int32_t sdp_duration_ms)>
+ body{[](const RawAddress& /* raw_address */,
+ android::bluetooth::rfcomm::PortResult /* close_reason */,
+ android::bluetooth::rfcomm::SocketConnectionSecurity /* security */,
+ android::bluetooth::rfcomm::RfcommPortEvent /* last_event */,
+ android::bluetooth::rfcomm::RfcommPortState /* previous_state */,
+ int32_t /* open_duration_ms */, int32_t /* uid */,
+ android::bluetooth::BtaStatus /* sdp_status */, bool /* is_server */,
+ bool /* sdp_initiated */, int32_t /* sdp_duration_ms */) {}};
+ void operator()(const RawAddress& raw_address,
+ android::bluetooth::rfcomm::PortResult close_reason,
+ android::bluetooth::rfcomm::SocketConnectionSecurity security,
+ android::bluetooth::rfcomm::RfcommPortEvent last_event,
+ android::bluetooth::rfcomm::RfcommPortState previous_state,
+ int32_t open_duration_ms, int32_t uid, android::bluetooth::BtaStatus sdp_status,
+ bool is_server, bool sdp_initiated, int32_t sdp_duration_ms) {
+ body(raw_address, close_reason, security, last_event, previous_state, open_duration_ms, uid,
+ sdp_status, is_server, sdp_initiated, sdp_duration_ms);
+ }
+};
+extern struct LogMetricRfcommConnectionAtClose LogMetricRfcommConnectionAtClose;
+
} // namespace main_shim_metrics_api
} // namespace mock
} // namespace test