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 LOG_INFO(
160 "LEConnectionMetricsRemoteDevice: The session is uploaded for %s\n",
161 ADDRESS_TO_LOGGABLE_CSTR(address));
162 opened_devices.erase(it);
163 }
164 }
165
166 // 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)167 void LEConnectionMetricsRemoteDevice::AddStateChangedEvent(
168 const hci::Address& address,
169 LeConnectionOriginType origin_type,
170 LeConnectionType connection_type,
171 LeConnectionState transaction_state,
172 std::vector<std::pair<os::ArgumentType, int>> argument_list) {
173 LOG_INFO(
174 "LEConnectionMetricsRemoteDevice: Transaction State %s, Connection Type %s, Origin Type %s\n",
175 common::ToHexString(transaction_state).c_str(),
176 common::ToHexString(connection_type).c_str(),
177 common::ToHexString(origin_type).c_str());
178 if (address.IsEmpty()) {
179 LOG_INFO(
180 "LEConnectionMetricsRemoteDevice: Empty Address Cancellation %s, %s, %s\n",
181 common::ToHexString(transaction_state).c_str(),
182 common::ToHexString(connection_type).c_str(),
183 common::ToHexString(transaction_state).c_str());
184 for (auto& device_metric : device_metrics) {
185 if (device_metric->IsStarted() &&
186 transaction_state == LeConnectionState::STATE_LE_ACL_CANCEL) {
187 LOG_INFO("LEConnectionMetricsRemoteDevice: Cancellation Begin");
188 // cancel the connection
189 device_metric->AddStateChangedEvent(
190 origin_type, connection_type, transaction_state, argument_list);
191 continue;
192 }
193
194 if (device_metric->IsCancelled() &&
195 transaction_state == LeConnectionState::STATE_LE_ACL_END) {
196 LOG_INFO("LEConnectionMetricsRemoteDevice: Session is now complete after cancellation");
197 // complete the connection
198 device_metric->AddStateChangedEvent(
199 origin_type, connection_type, transaction_state, argument_list);
200 UploadLEConnectionSession(address);
201 continue;
202 }
203 }
204 return;
205 }
206
207 std::unique_lock<std::mutex> lock(le_connection_metrics_remote_device_guard);
208 auto it = opened_devices.find(address);
209 if (it == opened_devices.end()) {
210 device_metrics.push_back(std::make_unique<LEConnectionMetricState>(address));
211 it = opened_devices.insert(std::begin(opened_devices), {address, device_metrics.back().get()});
212 }
213
214 it->second->AddStateChangedEvent(origin_type, connection_type, transaction_state, argument_list);
215
216 // Connection is finished
217 if (it->second->IsEnded()) {
218 UploadLEConnectionSession(address);
219 }
220 }
221
222
223 // MetricsLoggerModule class
LogMetricBluetoothLESession(os::LEConnectionSessionOptions session_options)224 void MetricsLoggerModule::LogMetricBluetoothLESession(
225 os::LEConnectionSessionOptions session_options) {
226 os::LogMetricBluetoothLEConnection(session_options);
227 }
228
229 // Instance of Metrics Collector for LEConnectionMetricsRemoteDeviceImpl
230 LEConnectionMetricsRemoteDevice* MetricsCollector::le_connection_metrics_remote_device =
231 new LEConnectionMetricsRemoteDevice();
232
GetLEConnectionMetricsCollector()233 LEConnectionMetricsRemoteDevice* MetricsCollector::GetLEConnectionMetricsCollector() {
234 return MetricsCollector::le_connection_metrics_remote_device;
235 }
236
237 } // namespace metrics
238
239 } // namespace bluetooth
240