• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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