summaryrefslogtreecommitdiff
path: root/system
diff options
context:
space:
mode:
Diffstat (limited to 'system')
-rw-r--r--system/bta/Android.bp3
-rw-r--r--system/bta/BUILD.gn1
-rw-r--r--system/bta/ag/bta_ag_rfc.cc8
-rw-r--r--system/bta/ag/bta_ag_sdp.cc3
-rw-r--r--system/bta/hf_client/bta_hf_client_rfc.cc18
-rw-r--r--system/bta/hf_client/bta_hf_client_sdp.cc3
-rw-r--r--system/bta/include/bta_rfcomm_metrics.h28
-rw-r--r--system/bta/jv/bta_jv_act.cc36
-rw-r--r--system/bta/rfcomm/bta_rfcomm_metrics.cc152
-rw-r--r--system/btif/Android.bp2
-rw-r--r--system/btif/src/btif_sock_rfc.cc3
-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/Android.bp2
-rw-r--r--system/stack/BUILD.gn1
-rw-r--r--system/stack/include/rfc_metrics.h21
-rw-r--r--system/stack/rfcomm/port_rfc.cc2
-rw-r--r--system/stack/rfcomm/rfc_metrics.cc176
-rw-r--r--system/test/Android.bp15
-rw-r--r--system/test/mock/mock_bta_rfc_metrics.cc34
-rw-r--r--system/test/mock/mock_main_shim_metrics_api.cc13
-rw-r--r--system/test/mock/mock_main_shim_metrics_api.h37
-rw-r--r--system/test/mock/mock_stack_rfcomm_metrics.cc21
28 files changed, 692 insertions, 14 deletions
diff --git a/system/bta/Android.bp b/system/bta/Android.bp
index f4685744ec..9eaf7c84b2 100644
--- a/system/bta/Android.bp
+++ b/system/bta/Android.bp
@@ -194,6 +194,7 @@ cc_library_static {
"gatt/database_builder.cc",
"jv/bta_jv_act.cc",
"jv/bta_jv_api.cc",
+ "rfcomm/bta_rfcomm_metrics.cc",
"rfcomm/bta_rfcomm_scn.cc",
"sdp/bta_sdp.cc",
"sdp/bta_sdp_act.cc",
@@ -459,6 +460,7 @@ cc_test {
srcs: [
":TestCommonMockFunctions",
":TestFakeOsi",
+ ":TestMockBtaRfcMetrics",
":TestMockBtaSys",
":TestMockBtif",
":TestMockStackBtm",
@@ -1462,6 +1464,7 @@ cc_test {
":TestFakeOsi",
":TestMockBtaGatt",
":TestMockBtaLeAudio",
+ ":TestMockBtaRfcMetrics",
":TestMockBtaScn",
":TestMockBtaSdp",
":TestMockBtaSys",
diff --git a/system/bta/BUILD.gn b/system/bta/BUILD.gn
index 425289338b..9c28016617 100644
--- a/system/bta/BUILD.gn
+++ b/system/bta/BUILD.gn
@@ -121,6 +121,7 @@ static_library("bta") {
"ras/ras_client.cc",
"ras/ras_server.cc",
"ras/ras_utils.cc",
+ "rfcomm/bta_rfcomm_metrics.cc",
"rfcomm/bta_rfcomm_scn.cc",
"sdp/bta_sdp.cc",
"sdp/bta_sdp_act.cc",
diff --git a/system/bta/ag/bta_ag_rfc.cc b/system/bta/ag/bta_ag_rfc.cc
index 58b7215a04..860709341c 100644
--- a/system/bta/ag/bta_ag_rfc.cc
+++ b/system/bta/ag/bta_ag_rfc.cc
@@ -29,6 +29,7 @@
#include <cstdint>
#include "bta/ag/bta_ag_int.h"
+#include "bta/include/bta_rfcomm_metrics.h"
#include "bta/include/bta_sec_api.h"
#include "bta_api.h"
#include "stack/include/main_thread.h"
@@ -257,6 +258,9 @@ void bta_ag_start_servers(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK services) {
bta_ag_setup_port(p_scb, p_scb->serv_handle[i]);
} else {
/* TODO: CR#137125 to handle to error properly */
+ bta_collect_rfc_metrics_after_port_fail(static_cast<tPORT_RESULT>(status), false,
+ tBTA_JV_STATUS::SUCCESS, p_scb->peer_addr, 0,
+ BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT, true, 0);
log::error(
"RFCOMM_CreateConnectionWithSecurity ERROR {}, p_scb={}, "
"services=0x{:x}, mgmt_cback_index={}",
@@ -336,6 +340,10 @@ void bta_ag_rfc_do_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) {
bta_ag_setup_port(p_scb, p_scb->conn_handle);
} else {
/* RFCOMM create connection failed; send ourselves RFCOMM close event */
+ bta_collect_rfc_metrics_after_port_fail(
+ static_cast<tPORT_RESULT>(status), p_scb->sdp_metrics.sdp_initiated,
+ p_scb->sdp_metrics.status, p_scb->peer_addr, 0, BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT,
+ true, p_scb->sdp_metrics.sdp_start_ms - p_scb->sdp_metrics.sdp_end_ms);
log::error("RFCOMM_CreateConnection ERROR {} for {}", status, p_scb->peer_addr);
bta_ag_sm_execute(p_scb, BTA_AG_RFC_CLOSE_EVT, data);
}
diff --git a/system/bta/ag/bta_ag_sdp.cc b/system/bta/ag/bta_ag_sdp.cc
index 3172d8d45f..3870e01c4e 100644
--- a/system/bta/ag/bta_ag_sdp.cc
+++ b/system/bta/ag/bta_ag_sdp.cc
@@ -32,6 +32,7 @@
#include "bta/ag/bta_ag_int.h"
#include "bta/include/bta_hfp_api.h"
+#include "bta/include/bta_rfcomm_metrics.h"
#include "bta/include/bta_rfcomm_scn.h"
#include "bta_ag_api.h"
#include "bta_api.h"
@@ -540,6 +541,8 @@ void bta_ag_do_disc(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK service) {
return;
} else {
log::error("failed to start SDP discovery for {}", p_scb->peer_addr);
+ bta_collect_rfc_metrics_after_sdp_fail(tBTA_JV_STATUS::FAILURE, p_scb->peer_addr, 0,
+ BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT, false, 0);
}
} else {
log::error("failed to init SDP discovery database for {}", p_scb->peer_addr);
diff --git a/system/bta/hf_client/bta_hf_client_rfc.cc b/system/bta/hf_client/bta_hf_client_rfc.cc
index 6e9655ac38..69d1525cfe 100644
--- a/system/bta/hf_client/bta_hf_client_rfc.cc
+++ b/system/bta/hf_client/bta_hf_client_rfc.cc
@@ -30,6 +30,7 @@
#include <cstdint>
#include "bta/hf_client/bta_hf_client_int.h"
+#include "bta/include/bta_rfcomm_metrics.h"
#include "bta/include/bta_sec_api.h"
#include "bta_sys.h"
#include "osi/include/allocator.h"
@@ -195,6 +196,9 @@ void bta_hf_client_start_server() {
if (port_status == PORT_SUCCESS) {
bta_hf_client_setup_port(bta_hf_client_cb_arr.serv_handle);
} else {
+ bta_collect_rfc_metrics_after_port_fail(static_cast<tPORT_RESULT>(port_status), false,
+ tBTA_JV_STATUS::SUCCESS, RawAddress::kAny, 0,
+ BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT, true, 0);
log::verbose("RFCOMM_CreateConnection returned error:{}", port_status);
}
}
@@ -240,14 +244,20 @@ void bta_hf_client_rfc_do_open(tBTA_HF_CLIENT_DATA* p_data) {
return;
}
- if (RFCOMM_CreateConnectionWithSecurity(
- UUID_SERVCLASS_HF_HANDSFREE, client_cb->peer_scn, false, BTA_HF_CLIENT_MTU,
- client_cb->peer_addr, &(client_cb->conn_handle), bta_hf_client_mgmt_cback,
- BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT, RfcommCfgInfo{}) == PORT_SUCCESS) {
+ int status = RFCOMM_CreateConnectionWithSecurity(
+ UUID_SERVCLASS_HF_HANDSFREE, client_cb->peer_scn, false, BTA_HF_CLIENT_MTU,
+ client_cb->peer_addr, &(client_cb->conn_handle), bta_hf_client_mgmt_cback,
+ BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT, RfcommCfgInfo{});
+ if (status == PORT_SUCCESS) {
bta_hf_client_setup_port(client_cb->conn_handle);
log::verbose("bta_hf_client_rfc_do_open : conn_handle = {}", client_cb->conn_handle);
} else {
/* RFCOMM create connection failed; send ourselves RFCOMM close event */
+ bta_collect_rfc_metrics_after_port_fail(
+ static_cast<tPORT_RESULT>(status), client_cb->sdp_metrics.sdp_initiated,
+ client_cb->sdp_metrics.status, client_cb->peer_addr, 0,
+ BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT, true,
+ client_cb->sdp_metrics.sdp_start_ms - client_cb->sdp_metrics.sdp_end_ms);
bta_hf_client_sm_execute(BTA_HF_CLIENT_RFC_CLOSE_EVT, p_data);
}
}
diff --git a/system/bta/hf_client/bta_hf_client_sdp.cc b/system/bta/hf_client/bta_hf_client_sdp.cc
index 02dfb37c85..c7b5ce7ceb 100644
--- a/system/bta/hf_client/bta_hf_client_sdp.cc
+++ b/system/bta/hf_client/bta_hf_client_sdp.cc
@@ -33,6 +33,7 @@
#include "bta/hf_client/bta_hf_client_int.h"
#include "bta/include/bta_hf_client_api.h"
+#include "bta/include/bta_rfcomm_metrics.h"
#include "bta/include/bta_rfcomm_scn.h"
#include "bta/sys/bta_sys.h"
#include "bta_hfp_api.h"
@@ -386,6 +387,8 @@ void bta_hf_client_do_disc(tBTA_HF_CLIENT_CB* client_cb) {
if (!db_inited) {
log::warn("Unable to start SDP service search request peer:{}", client_cb->peer_addr);
+ bta_collect_rfc_metrics_after_sdp_fail(tBTA_JV_STATUS::FAILURE, client_cb->peer_addr, 0,
+ BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT, false, 0);
/*free discover db */
osi_free_and_reset((void**)&client_cb->p_disc_db);
/* sent failed event */
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/jv/bta_jv_act.cc b/system/bta/jv/bta_jv_act.cc
index 1182411dd5..f0ccf28cf0 100644
--- a/system/bta/jv/bta_jv_act.cc
+++ b/system/bta/jv/bta_jv_act.cc
@@ -31,6 +31,7 @@
#include <unordered_set>
#include "bta/include/bta_jv_co.h"
+#include "bta/include/bta_rfcomm_metrics.h"
#include "bta/include/bta_rfcomm_scn.h"
#include "bta/jv/bta_jv_int.h"
#include "bta/sys/bta_sys.h"
@@ -1515,6 +1516,7 @@ void bta_jv_rfcomm_connect(tBTA_SEC sec_mask, uint8_t remote_scn, const RawAddre
RfcommCfgInfo cfg, uint32_t app_uid, uint64_t sdp_duration_ms) {
uint16_t handle = 0;
uint32_t event_mask = BTA_JV_RFC_EV_MASK;
+ int port_status;
PortSettings port_settings;
tBTA_JV bta_jv = {
@@ -1534,10 +1536,14 @@ void bta_jv_rfcomm_connect(tBTA_SEC sec_mask, uint8_t remote_scn, const RawAddre
sec_mask, BT_PSM_RFCOMM,
BTM_SEC_PROTO_RFCOMM, 0);
- if (RFCOMM_CreateConnectionWithSecurity(
- UUID_SERVCLASS_SERIAL_PORT, remote_scn, false, BTA_JV_DEF_RFC_MTU, peer_bd_addr,
- &handle, bta_jv_port_mgmt_cl_cback, sec_mask, cfg) != PORT_SUCCESS) {
+ port_status = RFCOMM_CreateConnectionWithSecurity(UUID_SERVCLASS_SERIAL_PORT, remote_scn, false,
+ BTA_JV_DEF_RFC_MTU, peer_bd_addr, &handle,
+ bta_jv_port_mgmt_cl_cback, sec_mask, cfg);
+ if (port_status != PORT_SUCCESS) {
log::error("RFCOMM_CreateConnection failed");
+ bta_collect_rfc_metrics_after_port_fail(
+ static_cast<tPORT_RESULT>(port_status), sdp_duration_ms > 0, tBTA_JV_STATUS::SUCCESS,
+ peer_bd_addr, static_cast<int>(app_uid), sec_mask, false, sdp_duration_ms);
bta_jv.rfc_cl_init.status = tBTA_JV_STATUS::FAILURE;
} else {
tBTA_JV_PCB* p_pcb;
@@ -1765,6 +1771,7 @@ static void bta_jv_port_event_sr_cback(uint32_t code, uint16_t port_handle) {
static tBTA_JV_PCB* bta_jv_add_rfc_port(tBTA_JV_RFC_CB* p_cb, tBTA_JV_PCB* p_pcb_open) {
uint8_t used = 0, i, listen = 0;
uint32_t si = 0;
+ int port_status;
PortSettings port_settings;
uint32_t event_mask = BTA_JV_RFC_EV_MASK;
tBTA_JV_PCB* p_pcb = NULL;
@@ -1802,10 +1809,10 @@ static tBTA_JV_PCB* bta_jv_add_rfc_port(tBTA_JV_RFC_CB* p_cb, tBTA_JV_PCB* p_pcb
log::error("RFCOMM_CreateConnection failed: invalid port_handle");
}
- if (RFCOMM_CreateConnectionWithSecurity(p_cb->sec_id, p_cb->scn, true, BTA_JV_DEF_RFC_MTU,
- RawAddress::kAny, &(p_cb->rfc_hdl[si]),
- bta_jv_port_mgmt_sr_cback, sec_mask,
- RfcommCfgInfo{}) == PORT_SUCCESS) {
+ port_status = RFCOMM_CreateConnectionWithSecurity(
+ p_cb->sec_id, p_cb->scn, true, BTA_JV_DEF_RFC_MTU, RawAddress::kAny,
+ &(p_cb->rfc_hdl[si]), bta_jv_port_mgmt_sr_cback, sec_mask, RfcommCfgInfo{});
+ if (port_status == PORT_SUCCESS) {
p_cb->curr_sess++;
p_pcb = &bta_jv_cb.port_cb[p_cb->rfc_hdl[si] - 1];
p_pcb->state = BTA_JV_ST_SR_LISTEN;
@@ -1837,6 +1844,10 @@ static tBTA_JV_PCB* bta_jv_add_rfc_port(tBTA_JV_RFC_CB* p_cb, tBTA_JV_PCB* p_pcb
log::verbose("p_pcb->handle=0x{:x}, curr_sess={}", p_pcb->handle, p_cb->curr_sess);
} else {
log::error("RFCOMM_CreateConnection failed");
+ bta_collect_rfc_metrics_after_port_fail(static_cast<tPORT_RESULT>(port_status), false,
+ tBTA_JV_STATUS::SUCCESS, RawAddress::kAny, 0,
+ sec_mask, true, 0);
+
return NULL;
}
} else {
@@ -1854,6 +1865,7 @@ void bta_jv_rfcomm_start_server(tBTA_SEC sec_mask, uint8_t local_scn, uint8_t ma
RfcommCfgInfo cfg, uint32_t app_uid) {
uint16_t handle = 0;
uint32_t event_mask = BTA_JV_RFC_EV_MASK;
+ int port_status;
PortSettings port_settings;
tBTA_JV_RFC_CB* p_cb = NULL;
tBTA_JV_PCB* p_pcb;
@@ -1863,10 +1875,14 @@ void bta_jv_rfcomm_start_server(tBTA_SEC sec_mask, uint8_t local_scn, uint8_t ma
evt_data.status = tBTA_JV_STATUS::FAILURE;
do {
- if (RFCOMM_CreateConnectionWithSecurity(0, local_scn, true, BTA_JV_DEF_RFC_MTU,
- RawAddress::kAny, &handle, bta_jv_port_mgmt_sr_cback,
- sec_mask, cfg) != PORT_SUCCESS) {
+ port_status = RFCOMM_CreateConnectionWithSecurity(0, local_scn, true, BTA_JV_DEF_RFC_MTU,
+ RawAddress::kAny, &handle,
+ bta_jv_port_mgmt_sr_cback, sec_mask, cfg);
+ if (port_status != PORT_SUCCESS) {
log::error("RFCOMM_CreateConnection failed");
+ bta_collect_rfc_metrics_after_port_fail(static_cast<tPORT_RESULT>(port_status), false,
+ tBTA_JV_STATUS::SUCCESS, RawAddress::kAny,
+ static_cast<int>(app_uid), sec_mask, true, 0);
break;
}
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/btif/Android.bp b/system/btif/Android.bp
index 5c82878a86..cbb42f1587 100644
--- a/system/btif/Android.bp
+++ b/system/btif/Android.bp
@@ -542,6 +542,7 @@ cc_test {
":TestMockBtaLeAudioHalVerifier",
":TestMockBtaPan",
":TestMockBtaRas",
+ ":TestMockBtaRfcMetrics",
":TestMockBtaScn",
":TestMockBtaSdp",
":TestMockBtaSys",
@@ -661,6 +662,7 @@ cc_test {
":TestMockBtaLeAudioHalVerifier",
":TestMockBtaPan",
":TestMockBtaRas",
+ ":TestMockBtaRfcMetrics",
":TestMockBtaScn",
":TestMockBtaSdp",
":TestMockBtaSys",
diff --git a/system/btif/src/btif_sock_rfc.cc b/system/btif/src/btif_sock_rfc.cc
index 27db388700..1a115c4cac 100644
--- a/system/btif/src/btif_sock_rfc.cc
+++ b/system/btif/src/btif_sock_rfc.cc
@@ -28,6 +28,7 @@
#include <mutex>
#include "bta/include/bta_jv_api.h"
+#include "bta/include/bta_rfcomm_metrics.h"
#include "bta/include/bta_rfcomm_scn.h"
#include "btif/include/btif_metrics_logging.h"
#include "btif/include/btif_sock.h"
@@ -1134,6 +1135,8 @@ static void handle_discovery_comp(tBTA_JV_STATUS status, int scn, uint32_t id) {
"SDP service discovery completed for slot_id: {} with the result "
"status: {}, scn: {}",
id, bta_jv_status_text(status), scn);
+ bta_collect_rfc_metrics_after_sdp_fail(status, slot->addr, slot->app_uid, slot->security,
+ static_cast<bool>(slot->f.server), sdp_duration_ms);
cleanup_rfc_slot(slot);
return;
}
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/Android.bp b/system/stack/Android.bp
index c5a828b34b..13d7984359 100644
--- a/system/stack/Android.bp
+++ b/system/stack/Android.bp
@@ -294,6 +294,7 @@ cc_library_static {
"rfcomm/port_rfc.cc",
"rfcomm/port_utils.cc",
"rfcomm/rfc_l2cap_if.cc",
+ "rfcomm/rfc_metrics.cc",
"rfcomm/rfc_mx_fsm.cc",
"rfcomm/rfc_port_fsm.cc",
"rfcomm/rfc_port_if.cc",
@@ -869,6 +870,7 @@ cc_test {
":TestMockStackBtm",
":TestMockStackL2capInterface",
":TestMockStackMetrics",
+ ":TestMockStackRfcommMetrics",
"rfcomm/port_api.cc",
"rfcomm/port_rfc.cc",
"rfcomm/port_utils.cc",
diff --git a/system/stack/BUILD.gn b/system/stack/BUILD.gn
index ab902f7b5e..d078d1bc14 100644
--- a/system/stack/BUILD.gn
+++ b/system/stack/BUILD.gn
@@ -157,6 +157,7 @@ source_set("stack") {
"rfcomm/port_rfc.cc",
"rfcomm/port_utils.cc",
"rfcomm/rfc_l2cap_if.cc",
+ "rfcomm/rfc_metrics.cc",
"rfcomm/rfc_mx_fsm.cc",
"rfcomm/rfc_port_fsm.cc",
"rfcomm/rfc_port_if.cc",
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/port_rfc.cc b/system/stack/rfcomm/port_rfc.cc
index 4dc7590d96..ac206257bf 100644
--- a/system/stack/rfcomm/port_rfc.cc
+++ b/system/stack/rfcomm/port_rfc.cc
@@ -40,6 +40,7 @@
#include "osi/include/mutex.h"
#include "stack/include/bt_hdr.h"
#include "stack/include/bt_uuid16.h"
+#include "stack/include/rfc_metrics.h"
#include "stack/include/stack_metrics_logging.h"
#include "stack/l2cap/l2c_int.h"
#include "stack/rfcomm/port_int.h"
@@ -1051,6 +1052,7 @@ void port_rfc_closed(tPORT* p_port, uint8_t res) {
rfc_set_state(RFC_STATE_CLOSED, p_port);
p_port->rfc.sm_cb.close_reason = static_cast<tPORT_RESULT>(res);
+ port_collect_attempt_metrics(p_port);
log::info(
"RFCOMM connection closed, port_handle={}, state={}, reason={}[{}], "
"UUID=0x{:x}, bd_addr={}, is_server={}",
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/Android.bp b/system/test/Android.bp
index c965355dcc..fabb5e9847 100644
--- a/system/test/Android.bp
+++ b/system/test/Android.bp
@@ -142,6 +142,13 @@ filegroup {
}
filegroup {
+ name: "TestMockBtaRfcMetrics",
+ srcs: [
+ "mock/mock_bta_rfc_metrics.cc",
+ ],
+}
+
+filegroup {
name: "TestMockBtaScn",
srcs: [
"mock/mock_bta_scn.cc",
@@ -189,6 +196,7 @@ filegroup {
":TestMockBtaLeAudioHalVerifier",
":TestMockBtaPan",
":TestMockBtaRas",
+ ":TestMockBtaRfcMetrics",
":TestMockBtaSdp",
":TestMockBtaSys",
":TestMockBtaVc",
@@ -290,6 +298,13 @@ filegroup {
}
filegroup {
+ name: "TestMockStackRfcommMetrics",
+ srcs: [
+ "mock/mock_stack_rfcomm_metrics.cc",
+ ],
+}
+
+filegroup {
name: "TestMockStackRnr",
srcs: [
"mock/mock_stack_rnr_interface.cc",
diff --git a/system/test/mock/mock_bta_rfc_metrics.cc b/system/test/mock/mock_bta_rfc_metrics.cc
new file mode 100644
index 0000000000..9c1c0cced2
--- /dev/null
+++ b/system/test/mock/mock_bta_rfc_metrics.cc
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2025 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.
+ */
+
+#include "bta/include/bta_jv_api.h"
+#include "bta/include/bta_rfcomm_metrics.h"
+#include "test/common/mock_functions.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 */) {
+ inc_func_call_count(__func__);
+}
+
+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 */) {
+ inc_func_call_count(__func__);
+}
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
diff --git a/system/test/mock/mock_stack_rfcomm_metrics.cc b/system/test/mock/mock_stack_rfcomm_metrics.cc
new file mode 100644
index 0000000000..f44af222b1
--- /dev/null
+++ b/system/test/mock/mock_stack_rfcomm_metrics.cc
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2025 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.
+ */
+
+#include "rfc_metrics.h"
+#include "stack/rfcomm/port_int.h"
+#include "test/common/mock_functions.h"
+
+void port_collect_attempt_metrics(tPORT* /* p_port */) { inc_func_call_count(__func__); }