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 <frameworks/proto_logging/stats/enums/bluetooth/hci/enums.pb.h>
20 #include <frameworks/proto_logging/stats/enums/bluetooth/le/enums.pb.h>
21
22 #include <chrono>
23 #include <climits>
24 #include <memory>
25 #include <unordered_map>
26 #include <utility>
27
28 #include "common/strings.h"
29 #include "hci/address.h"
30 #include "metrics/utils.h"
31 #include "os/log.h"
32 #include "os/metrics.h"
33
34 namespace bluetooth {
35 namespace metrics {
36
37 using android::bluetooth::le::LeConnectionOriginType;
38 using android::bluetooth::le::LeConnectionState;
39 using android::bluetooth::le::LeConnectionType;
40
41 // const static ClockTimePoint kInvalidTimePoint{};
42
43 /*
44 * This is the device level metrics state, which will be modified based on
45 * incoming state events.
46 *
47 */
AddStateChangedEvent(LeConnectionOriginType origin_type,LeConnectionType connection_type,LeConnectionState transaction_state,std::vector<std::pair<os::ArgumentType,int>> argument_list)48 void LEConnectionMetricState::AddStateChangedEvent(
49 LeConnectionOriginType origin_type,
50 LeConnectionType connection_type,
51 LeConnectionState transaction_state,
52 std::vector<std::pair<os::ArgumentType, int>> argument_list) {
53 LOG_INFO(
54 "LEConnectionMetricState: Origin Type: %s, Connection Type: %s, Transaction State: "
55 "%s",
56 common::ToHexString(origin_type).c_str(),
57 common::ToHexString(connection_type).c_str(),
58 common::ToHexString(transaction_state).c_str());
59
60 ClockTimePoint current_timestamp = std::chrono::high_resolution_clock::now();
61 state = transaction_state;
62
63 // Assign the origin of the connection
64 if (connection_origin_type == LeConnectionOriginType::ORIGIN_UNSPECIFIED) {
65 connection_origin_type = origin_type;
66 }
67
68 if (input_connection_type == LeConnectionType::CONNECTION_TYPE_UNSPECIFIED) {
69 input_connection_type = connection_type;
70 }
71
72 if (start_timepoint == kInvalidTimePoint) {
73 start_timepoint = current_timestamp;
74 }
75 end_timepoint = current_timestamp;
76
77 switch (state) {
78 case LeConnectionState::STATE_LE_ACL_START: {
79 int connection_type_cid = GetArgumentTypeFromList(argument_list, os::ArgumentType::L2CAP_CID);
80 if (connection_type_cid != -1) {
81 LeConnectionType connection_type = GetLeConnectionTypeFromCID(connection_type_cid);
82 if (connection_type != LeConnectionType::CONNECTION_TYPE_UNSPECIFIED) {
83 LOG_INFO("LEConnectionMetricsRemoteDevice: Populating the connection type\n");
84 input_connection_type = connection_type;
85 }
86 }
87 break;
88 }
89 case LeConnectionState::STATE_LE_ACL_END: {
90 int acl_status_code_from_args =
91 GetArgumentTypeFromList(argument_list, os::ArgumentType::ACL_STATUS_CODE);
92 acl_status_code = static_cast<android::bluetooth::hci::StatusEnum>(acl_status_code_from_args);
93 acl_state = LeAclConnectionState::LE_ACL_SUCCESS;
94
95 if (acl_status_code != android::bluetooth::hci::StatusEnum::STATUS_SUCCESS) {
96 acl_state = LeAclConnectionState::LE_ACL_FAILED;
97 }
98 break;
99 }
100 case LeConnectionState::STATE_LE_ACL_TIMEOUT: {
101 int acl_status_code_from_args =
102 GetArgumentTypeFromList(argument_list, os::ArgumentType::ACL_STATUS_CODE);
103 acl_status_code = static_cast<android::bluetooth::hci::StatusEnum>(acl_status_code_from_args);
104 acl_state = LeAclConnectionState::LE_ACL_FAILED;
105 break;
106 }
107 case LeConnectionState::STATE_LE_ACL_CANCEL: {
108 acl_state = LeAclConnectionState::LE_ACL_FAILED;
109 is_cancelled = true;
110 break;
111 }
112 [[fallthrough]];
113 default: {
114 // do nothing
115 }
116 }
117 }
118
IsEnded()119 bool LEConnectionMetricState::IsEnded() {
120 return acl_state == LeAclConnectionState::LE_ACL_SUCCESS ||
121 acl_state == LeAclConnectionState::LE_ACL_FAILED;
122 }
123
IsStarted()124 bool LEConnectionMetricState::IsStarted() {
125 return state == LeConnectionState::STATE_LE_ACL_START;
126 }
127
IsCancelled()128 bool LEConnectionMetricState::IsCancelled() {
129 return is_cancelled;
130 }
131
132 // Initialize the LEConnectionMetricsRemoteDevice
LEConnectionMetricsRemoteDevice()133 LEConnectionMetricsRemoteDevice::LEConnectionMetricsRemoteDevice() {
134 metrics_logger_module = new MetricsLoggerModule();
135 }
136
LEConnectionMetricsRemoteDevice(BaseMetricsLoggerModule * baseMetricsLoggerModule)137 LEConnectionMetricsRemoteDevice::LEConnectionMetricsRemoteDevice(
138 BaseMetricsLoggerModule* baseMetricsLoggerModule) {
139 metrics_logger_module = baseMetricsLoggerModule;
140 }
141
142 // Uploading the session
UploadLEConnectionSession(const hci::Address & address)143 void LEConnectionMetricsRemoteDevice::UploadLEConnectionSession(const hci::Address& address) {
144 auto it = opened_devices.find(address);
145 if (it != opened_devices.end()) {
146 os::LEConnectionSessionOptions session_options;
147 session_options.acl_connection_state = it->second->acl_state;
148 session_options.origin_type = it->second->connection_origin_type;
149 session_options.transaction_type = it->second->input_connection_type;
150 session_options.latency = bluetooth::metrics::get_timedelta_nanos(
151 it->second->start_timepoint, it->second->end_timepoint);
152 session_options.remote_address = address;
153 session_options.status = it->second->acl_status_code;
154 // TODO: keep the acl latency the same as the overall latency for now
155 // When more events are added, we will an overall latency
156 session_options.acl_latency = session_options.latency;
157 session_options.is_cancelled = it->second->is_cancelled;
158 metrics_logger_module->LogMetricBluetoothLESession(session_options);
159 opened_devices.erase(it);
160 }
161 }
162
163 // 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)164 void LEConnectionMetricsRemoteDevice::AddStateChangedEvent(
165 const hci::Address& address,
166 LeConnectionOriginType origin_type,
167 LeConnectionType connection_type,
168 LeConnectionState transaction_state,
169 std::vector<std::pair<os::ArgumentType, int>> argument_list) {
170 LOG_INFO(
171 "LEConnectionMetricsRemoteDevice: Transaction State %s, Connection Type %s, Origin Type %s\n",
172 common::ToHexString(transaction_state).c_str(),
173 common::ToHexString(connection_type).c_str(),
174 common::ToHexString(origin_type).c_str());
175 if (address.IsEmpty()) {
176 LOG_INFO(
177 "LEConnectionMetricsRemoteDevice: Empty Address Cancellation %s, %s, %s\n",
178 common::ToHexString(transaction_state).c_str(),
179 common::ToHexString(connection_type).c_str(),
180 common::ToHexString(transaction_state).c_str());
181 for (auto& device_metric : device_metrics) {
182 if (device_metric->IsStarted() &&
183 transaction_state == LeConnectionState::STATE_LE_ACL_CANCEL) {
184 LOG_INFO("LEConnectionMetricsRemoteDevice: Cancellation Begin");
185 // cancel the connection
186 device_metric->AddStateChangedEvent(
187 origin_type, connection_type, transaction_state, argument_list);
188 continue;
189 }
190
191 if (device_metric->IsCancelled() &&
192 transaction_state == LeConnectionState::STATE_LE_ACL_END) {
193 LOG_INFO("LEConnectionMetricsRemoteDevice: Session is now complete after cancellation");
194 // complete the connection
195 device_metric->AddStateChangedEvent(
196 origin_type, connection_type, transaction_state, argument_list);
197 UploadLEConnectionSession(address);
198 continue;
199 }
200 }
201 return;
202 }
203
204 auto it = opened_devices.find(address);
205 if (it == opened_devices.end()) {
206 device_metrics.push_back(std::make_unique<LEConnectionMetricState>(address));
207 it = opened_devices.insert(std::begin(opened_devices), {address, device_metrics.back().get()});
208 }
209
210 it->second->AddStateChangedEvent(origin_type, connection_type, transaction_state, argument_list);
211
212 // Connection is finished
213 if (it->second->IsEnded()) {
214 UploadLEConnectionSession(address);
215 }
216 }
217
218
219 // MetricsLoggerModule class
LogMetricBluetoothLESession(os::LEConnectionSessionOptions session_options)220 void MetricsLoggerModule::LogMetricBluetoothLESession(
221 os::LEConnectionSessionOptions session_options) {
222 os::LogMetricBluetoothLEConnection(session_options);
223 }
224
225 // Instance of Metrics Collector for LEConnectionMetricsRemoteDeviceImpl
226 LEConnectionMetricsRemoteDevice* MetricsCollector::le_connection_metrics_remote_device =
227 new LEConnectionMetricsRemoteDevice();
228
GetLEConnectionMetricsCollector()229 LEConnectionMetricsRemoteDevice* MetricsCollector::GetLEConnectionMetricsCollector() {
230 return MetricsCollector::le_connection_metrics_remote_device;
231 }
232
233 } // namespace metrics
234
235 } // namespace bluetooth
236