1 /*
2 * Copyright 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "metrics_state.h"
18
19 #include <bluetooth/log.h>
20 #include <frameworks/proto_logging/stats/enums/bluetooth/hci/enums.pb.h>
21 #include <frameworks/proto_logging/stats/enums/bluetooth/le/enums.pb.h>
22
23 #include <chrono>
24 #include <climits>
25 #include <memory>
26 #include <unordered_map>
27 #include <utility>
28
29 #include "common/strings.h"
30 #include "hci/address.h"
31 #include "metrics/utils.h"
32 #include "os/log.h"
33 #include "os/metrics.h"
34
35 namespace bluetooth {
36 namespace metrics {
37
38 using android::bluetooth::le::LeConnectionOriginType;
39 using android::bluetooth::le::LeConnectionState;
40 using android::bluetooth::le::LeConnectionType;
41
42 // const static ClockTimePoint kInvalidTimePoint{};
43
44 /*
45 * This is the device level metrics state, which will be modified based on
46 * incoming state events.
47 *
48 */
AddStateChangedEvent(LeConnectionOriginType origin_type,LeConnectionType connection_type,LeConnectionState transaction_state,std::vector<std::pair<os::ArgumentType,int>> argument_list)49 void LEConnectionMetricState::AddStateChangedEvent(
50 LeConnectionOriginType origin_type,
51 LeConnectionType connection_type,
52 LeConnectionState transaction_state,
53 std::vector<std::pair<os::ArgumentType, int>> argument_list) {
54
55 ClockTimePoint current_timestamp = std::chrono::high_resolution_clock::now();
56 state = transaction_state;
57
58 // Assign the origin of the connection
59 if (connection_origin_type == LeConnectionOriginType::ORIGIN_UNSPECIFIED) {
60 connection_origin_type = origin_type;
61 }
62
63 if (input_connection_type == LeConnectionType::CONNECTION_TYPE_UNSPECIFIED) {
64 input_connection_type = connection_type;
65 }
66
67 if (start_timepoint == kInvalidTimePoint) {
68 start_timepoint = current_timestamp;
69 }
70 end_timepoint = current_timestamp;
71
72 switch (state) {
73 case LeConnectionState::STATE_LE_ACL_START: {
74 int connection_type_cid = GetArgumentTypeFromList(argument_list, os::ArgumentType::L2CAP_CID);
75 if (connection_type_cid != -1) {
76 LeConnectionType connection_type = GetLeConnectionTypeFromCID(connection_type_cid);
77 if (connection_type != LeConnectionType::CONNECTION_TYPE_UNSPECIFIED) {
78 log::info("LEConnectionMetricsRemoteDevice: Populating the connection type");
79 input_connection_type = connection_type;
80 }
81 }
82 break;
83 }
84 case LeConnectionState::STATE_LE_ACL_END: {
85 int acl_status_code_from_args =
86 GetArgumentTypeFromList(argument_list, os::ArgumentType::ACL_STATUS_CODE);
87 acl_status_code = static_cast<android::bluetooth::hci::StatusEnum>(acl_status_code_from_args);
88 acl_state = LeAclConnectionState::LE_ACL_SUCCESS;
89
90 if (acl_status_code != android::bluetooth::hci::StatusEnum::STATUS_SUCCESS) {
91 acl_state = LeAclConnectionState::LE_ACL_FAILED;
92 }
93 break;
94 }
95 case LeConnectionState::STATE_LE_ACL_TIMEOUT: {
96 int acl_status_code_from_args =
97 GetArgumentTypeFromList(argument_list, os::ArgumentType::ACL_STATUS_CODE);
98 acl_status_code = static_cast<android::bluetooth::hci::StatusEnum>(acl_status_code_from_args);
99 acl_state = LeAclConnectionState::LE_ACL_FAILED;
100 break;
101 }
102 case LeConnectionState::STATE_LE_ACL_CANCEL: {
103 acl_state = LeAclConnectionState::LE_ACL_FAILED;
104 is_cancelled = true;
105 break;
106 }
107 [[fallthrough]];
108 default: {
109 // do nothing
110 }
111 }
112 }
113
IsEnded()114 bool LEConnectionMetricState::IsEnded() {
115 return acl_state == LeAclConnectionState::LE_ACL_SUCCESS ||
116 acl_state == LeAclConnectionState::LE_ACL_FAILED;
117 }
118
IsStarted()119 bool LEConnectionMetricState::IsStarted() {
120 return state == LeConnectionState::STATE_LE_ACL_START;
121 }
122
IsCancelled()123 bool LEConnectionMetricState::IsCancelled() {
124 return is_cancelled;
125 }
126
127 // Initialize the LEConnectionMetricsRemoteDevice
LEConnectionMetricsRemoteDevice()128 LEConnectionMetricsRemoteDevice::LEConnectionMetricsRemoteDevice() {
129 metrics_logger_module = new MetricsLoggerModule();
130 }
131
LEConnectionMetricsRemoteDevice(BaseMetricsLoggerModule * baseMetricsLoggerModule)132 LEConnectionMetricsRemoteDevice::LEConnectionMetricsRemoteDevice(
133 BaseMetricsLoggerModule* baseMetricsLoggerModule) {
134 metrics_logger_module = baseMetricsLoggerModule;
135 }
136
137 // Uploading the session
UploadLEConnectionSession(const hci::Address & address)138 void LEConnectionMetricsRemoteDevice::UploadLEConnectionSession(const hci::Address& address) {
139 auto it = opened_devices.find(address);
140 if (it != opened_devices.end()) {
141 os::LEConnectionSessionOptions session_options;
142 session_options.acl_connection_state = it->second->acl_state;
143 session_options.origin_type = it->second->connection_origin_type;
144 session_options.transaction_type = it->second->input_connection_type;
145 session_options.latency = bluetooth::metrics::get_timedelta_nanos(
146 it->second->start_timepoint, it->second->end_timepoint);
147 session_options.remote_address = address;
148 session_options.status = it->second->acl_status_code;
149 // TODO: keep the acl latency the same as the overall latency for now
150 // When more events are added, we will an overall latency
151 session_options.acl_latency = session_options.latency;
152 session_options.is_cancelled = it->second->is_cancelled;
153 metrics_logger_module->LogMetricBluetoothLESession(session_options);
154 log::info("LEConnectionMetricsRemoteDevice: The session is uploaded for {}", address);
155 opened_devices.erase(it);
156 }
157 }
158
159 // Implementation of metrics per remote device
AddStateChangedEvent(const hci::Address & address,LeConnectionOriginType origin_type,LeConnectionType connection_type,LeConnectionState transaction_state,std::vector<std::pair<os::ArgumentType,int>> argument_list)160 void LEConnectionMetricsRemoteDevice::AddStateChangedEvent(
161 const hci::Address& address,
162 LeConnectionOriginType origin_type,
163 LeConnectionType connection_type,
164 LeConnectionState transaction_state,
165 std::vector<std::pair<os::ArgumentType, int>> argument_list) {
166 log::info(
167 "LEConnectionMetricsRemoteDevice: Transaction State {}, Connection Type {}, Origin Type {}",
168 common::ToHexString(transaction_state),
169 common::ToHexString(connection_type),
170 common::ToHexString(origin_type));
171
172 std::unique_lock<std::mutex> lock(le_connection_metrics_remote_device_guard);
173 if (address.IsEmpty()) {
174 log::info(
175 "LEConnectionMetricsRemoteDevice: Empty Address Cancellation {}, {}, {}",
176 common::ToHexString(transaction_state),
177 common::ToHexString(connection_type),
178 common::ToHexString(transaction_state));
179 for (auto& device_metric : device_metrics) {
180 if (device_metric->IsStarted() &&
181 transaction_state == LeConnectionState::STATE_LE_ACL_CANCEL) {
182 log::info("LEConnectionMetricsRemoteDevice: Cancellation Begin");
183 // cancel the connection
184 device_metric->AddStateChangedEvent(
185 origin_type, connection_type, transaction_state, argument_list);
186 continue;
187 }
188
189 if (device_metric->IsCancelled() &&
190 transaction_state == LeConnectionState::STATE_LE_ACL_END) {
191 // complete the connection
192 device_metric->AddStateChangedEvent(
193 origin_type, connection_type, transaction_state, argument_list);
194 UploadLEConnectionSession(address);
195 continue;
196 }
197 }
198 return;
199 }
200
201 auto it = opened_devices.find(address);
202 if (it == opened_devices.end()) {
203 device_metrics.push_back(std::make_unique<LEConnectionMetricState>(address));
204 it = opened_devices.insert(std::begin(opened_devices), {address, device_metrics.back().get()});
205 }
206
207 it->second->AddStateChangedEvent(origin_type, connection_type, transaction_state, argument_list);
208
209 // Connection is finished
210 if (it->second->IsEnded()) {
211 UploadLEConnectionSession(address);
212 }
213 }
214
215
216 // MetricsLoggerModule class
LogMetricBluetoothLESession(os::LEConnectionSessionOptions session_options)217 void MetricsLoggerModule::LogMetricBluetoothLESession(
218 os::LEConnectionSessionOptions session_options) {
219 os::LogMetricBluetoothLEConnection(session_options);
220 }
221
222 // Instance of Metrics Collector for LEConnectionMetricsRemoteDeviceImpl
223 LEConnectionMetricsRemoteDevice* MetricsCollector::le_connection_metrics_remote_device =
224 new LEConnectionMetricsRemoteDevice();
225
GetLEConnectionMetricsCollector()226 LEConnectionMetricsRemoteDevice* MetricsCollector::GetLEConnectionMetricsCollector() {
227 return MetricsCollector::le_connection_metrics_remote_device;
228 }
229
230 } // namespace metrics
231
232 } // namespace bluetooth
233