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