diff options
author | 2025-02-21 12:18:23 -0800 | |
---|---|---|
committer | 2025-02-21 12:18:23 -0800 | |
commit | 10dfe15ea08bfa1efc76b369b65dfcf676dda446 (patch) | |
tree | 089125b0cfabda712f5f6bcea4cdb150e425817a /system | |
parent | 40a0132ce9f2ad26a361d10a3ef0d59de16a73f5 (diff) | |
parent | e101f6ae5a31b10133d7d6f43bac888a87713e97 (diff) |
Merge changes Idccdb2ab,Ie109fab6,Ie2de6f03 into main
* changes:
RFCOMM Metrics V2: Collect at port closure
RFCOMM metrics V2: Collect metrics in bta
RFCOMM metrics V2: Add metrics functions
Diffstat (limited to 'system')
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__); } |