1 /*
2 * Copyright 2019 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 "hal/snoop_logger.h"
18
19 #include <arpa/inet.h>
20 #include <sys/stat.h>
21
22 #include <algorithm>
23 #include <bitset>
24 #include <chrono>
25 #include <sstream>
26
27 #include "common/circular_buffer.h"
28 #include "common/init_flags.h"
29 #include "common/strings.h"
30 #include "os/fake_timer/fake_timerfd.h"
31 #include "os/files.h"
32 #include "os/log.h"
33 #include "os/parameter_provider.h"
34 #include "os/system_properties.h"
35
36 namespace bluetooth {
37 #ifdef USE_FAKE_TIMERS
38 using os::fake_timer::fake_timerfd_get_clock;
39 #endif
40 namespace hal {
41
42 namespace {
43
44 // Epoch in microseconds since 01/01/0000.
45 constexpr uint64_t kBtSnoopEpochDelta = 0x00dcddb30f2f8000ULL;
46
47 constexpr uint32_t kBytesToTest = 0x12345678;
48 constexpr uint8_t kFirstByte = (const uint8_t&)kBytesToTest;
49 constexpr bool isLittleEndian = kFirstByte == 0x78;
50 constexpr bool isBigEndian = kFirstByte == 0x12;
51 static_assert(isLittleEndian || isBigEndian && isLittleEndian != isBigEndian);
52
53 constexpr uint32_t BTSNOOP_VERSION_NUMBER = isLittleEndian ? 0x01000000 : 1;
54 constexpr uint32_t BTSNOOP_DATALINK_TYPE =
55 isLittleEndian ? 0xea030000 : 0x03ea; // Datalink Type code for HCI UART (H4) is 1002
htonll(uint64_t ll)56 uint64_t htonll(uint64_t ll) {
57 if constexpr (isLittleEndian) {
58 return static_cast<uint64_t>(htonl(ll & 0xffffffff)) << 32 | htonl(ll >> 32);
59 } else {
60 return ll;
61 }
62 }
63
64 constexpr SnoopLogger::FileHeaderType kBtSnoopFileHeader = {
65 .identification_pattern = {'b', 't', 's', 'n', 'o', 'o', 'p', 0x00},
66 .version_number = BTSNOOP_VERSION_NUMBER,
67 .datalink_type = BTSNOOP_DATALINK_TYPE};
68
69 // The number of packets per btsnoop file before we rotate to the next file. As of right now there
70 // are two snoop files that are rotated through. The size can be dynamically configured by setting
71 // the relevant system property
72 constexpr size_t kDefaultBtSnoopMaxPacketsPerFile = 0xffff;
73
74 // We restrict the maximum packet size to 150 bytes
75 constexpr size_t kDefaultBtSnoozMaxBytesPerPacket = 150;
76 constexpr size_t kDefaultBtSnoozMaxPayloadBytesPerPacket =
77 kDefaultBtSnoozMaxBytesPerPacket - sizeof(SnoopLogger::PacketHeaderType);
78
79 using namespace std::chrono_literals;
80 constexpr std::chrono::hours kBtSnoozLogLifeTime = 12h;
81 constexpr std::chrono::hours kBtSnoozLogDeleteRepeatingAlarmInterval = 1h;
82
get_btsnoop_log_path(std::string log_dir,bool filtered)83 std::string get_btsnoop_log_path(std::string log_dir, bool filtered) {
84 if (filtered) {
85 log_dir.append(".filtered");
86 }
87 return log_dir;
88 }
89
get_last_log_path(std::string log_file_path)90 std::string get_last_log_path(std::string log_file_path) {
91 return log_file_path.append(".last");
92 }
93
delete_btsnoop_files(const std::string & log_path)94 void delete_btsnoop_files(const std::string& log_path) {
95 LOG_INFO("Deleting logs if they exist");
96 if (os::FileExists(log_path)) {
97 if (!os::RemoveFile(log_path)) {
98 LOG_ERROR("Failed to remove main log file at \"%s\"", log_path.c_str());
99 }
100 } else {
101 LOG_INFO("Main log file does not exist at \"%s\"", log_path.c_str());
102 }
103 auto last_log_path = get_last_log_path(log_path);
104 if (os::FileExists(last_log_path)) {
105 if (!os::RemoveFile(last_log_path)) {
106 LOG_ERROR("Failed to remove last log file at \"%s\"", log_path.c_str());
107 }
108 } else {
109 LOG_INFO("Last log file does not exist at \"%s\"", log_path.c_str());
110 }
111 }
112
delete_old_btsnooz_files(const std::string & log_path,const std::chrono::milliseconds log_life_time)113 void delete_old_btsnooz_files(const std::string& log_path, const std::chrono::milliseconds log_life_time) {
114 auto opt_created_ts = os::FileCreatedTime(log_path);
115 if (!opt_created_ts) return;
116 #ifdef USE_FAKE_TIMERS
117 auto diff = fake_timerfd_get_clock() - file_creation_time;
118 uint64_t log_lifetime = log_life_time.count();
119 if (diff >= log_lifetime) {
120 #else
121 using namespace std::chrono;
122 auto created_tp = opt_created_ts.value();
123 auto current_tp = std::chrono::system_clock::now();
124
125 auto diff = duration_cast<milliseconds>(current_tp - created_tp);
126 if (diff >= log_life_time) {
127 #endif
128 delete_btsnoop_files(log_path);
129 }
130 }
131
132 size_t get_btsnooz_packet_length_to_write(
133 const HciPacket& packet, SnoopLogger::PacketType type, bool qualcomm_debug_log_enabled) {
134 static const size_t kAclHeaderSize = 4;
135 static const size_t kL2capHeaderSize = 4;
136 static const size_t kL2capCidOffset = (kAclHeaderSize + 2);
137 static const uint16_t kL2capSignalingCid = 0x0001;
138
139 static const size_t kHciAclHandleOffset = 0;
140 static const uint16_t kQualcommDebugLogHandle = 0xedc;
141
142 // Maximum amount of ACL data to log.
143 // Enough for an RFCOMM frame up to the frame check;
144 // not enough for a HID report or audio data.
145 static const size_t kMaxBtsnoozAclSize = 14;
146
147 // Calculate packet length to be included
148 size_t included_length = 0;
149 switch (type) {
150 case SnoopLogger::PacketType::CMD:
151 case SnoopLogger::PacketType::EVT:
152 included_length = packet.size();
153 break;
154
155 case SnoopLogger::PacketType::ACL: {
156 // Log ACL and L2CAP header by default
157 size_t len_hci_acl = kAclHeaderSize + kL2capHeaderSize;
158 // Check if we have enough data for an L2CAP header
159 if (packet.size() > len_hci_acl) {
160 uint16_t l2cap_cid =
161 static_cast<uint16_t>(packet[kL2capCidOffset]) |
162 static_cast<uint16_t>((static_cast<uint16_t>(packet[kL2capCidOffset + 1]) << static_cast<uint16_t>(8)));
163 uint16_t hci_acl_packet_handle =
164 static_cast<uint16_t>(packet[kHciAclHandleOffset]) |
165 static_cast<uint16_t>((static_cast<uint16_t>(packet[kHciAclHandleOffset + 1]) << static_cast<uint16_t>(8)));
166 hci_acl_packet_handle &= 0x0fff;
167
168 if (l2cap_cid == kL2capSignalingCid) {
169 // For the signaling CID, take the full packet.
170 // That way, the PSM setup is captured, allowing decoding of PSMs down
171 // the road.
172 return packet.size();
173 } else if (qualcomm_debug_log_enabled && hci_acl_packet_handle == kQualcommDebugLogHandle) {
174 return packet.size();
175 } else {
176 // Otherwise, return as much as we reasonably can
177 len_hci_acl = kMaxBtsnoozAclSize;
178 }
179 }
180 included_length = std::min(len_hci_acl, packet.size());
181 break;
182 }
183
184 case SnoopLogger::PacketType::ISO:
185 case SnoopLogger::PacketType::SCO:
186 default:
187 // We are not logging SCO and ISO packets in snooz log as they may contain voice data
188 break;
189 }
190 return std::min(included_length, kDefaultBtSnoozMaxPayloadBytesPerPacket);
191 }
192
193 } // namespace
194
195 const std::string SnoopLogger::kBtSnoopLogModeDisabled = "disabled";
196 const std::string SnoopLogger::kBtSnoopLogModeTruncated = "truncated";
197 const std::string SnoopLogger::kBtSnoopLogModeFiltered = "filtered";
198 const std::string SnoopLogger::kBtSnoopLogModeFull = "full";
199 const std::string SnoopLogger::kSoCManufacturerQualcomm = "Qualcomm";
200
201 const std::string SnoopLogger::kBtSnoopMaxPacketsPerFileProperty = "persist.bluetooth.btsnoopsize";
202 const std::string SnoopLogger::kIsDebuggableProperty = "ro.debuggable";
203 const std::string SnoopLogger::kBtSnoopLogModeProperty = "persist.bluetooth.btsnooplogmode";
204 const std::string SnoopLogger::kBtSnoopDefaultLogModeProperty = "persist.bluetooth.btsnoopdefaultmode";
205 const std::string SnoopLogger::kSoCManufacturerProperty = "ro.soc.manufacturer";
206
207 // The max ACL packet size (in bytes) in truncated logging mode. All information
208 // past this point is truncated from a packet.
209 static constexpr uint32_t kMaxTruncatedAclPacketSize = 100;
210
SnoopLogger(std::string snoop_log_path,std::string snooz_log_path,size_t max_packets_per_file,size_t max_packets_per_buffer,const std::string & btsnoop_mode,bool qualcomm_debug_log_enabled,const std::chrono::milliseconds snooz_log_life_time,const std::chrono::milliseconds snooz_log_delete_alarm_interval)211 SnoopLogger::SnoopLogger(
212 std::string snoop_log_path,
213 std::string snooz_log_path,
214 size_t max_packets_per_file,
215 size_t max_packets_per_buffer,
216 const std::string& btsnoop_mode,
217 bool qualcomm_debug_log_enabled,
218 const std::chrono::milliseconds snooz_log_life_time,
219 const std::chrono::milliseconds snooz_log_delete_alarm_interval)
220 : snoop_log_path_(std::move(snoop_log_path)),
221 snooz_log_path_(std::move(snooz_log_path)),
222 max_packets_per_file_(max_packets_per_file),
223 btsnooz_buffer_(max_packets_per_buffer),
224 qualcomm_debug_log_enabled_(qualcomm_debug_log_enabled),
225 snooz_log_life_time_(snooz_log_life_time),
226 snooz_log_delete_alarm_interval_(snooz_log_delete_alarm_interval) {
227 if (false && btsnoop_mode == kBtSnoopLogModeFiltered) {
228 // TODO(b/163733538): implement filtered snoop log in GD, currently filtered == disabled
229 LOG_INFO("Filtered Snoop Logs enabled");
230 is_enabled_ = true;
231 is_filtered_ = true;
232 // delete unfiltered logs
233 delete_btsnoop_files(get_btsnoop_log_path(snoop_log_path_, false));
234 // delete snooz logs
235 delete_btsnoop_files(snooz_log_path_);
236 } else if (btsnoop_mode == kBtSnoopLogModeFull) {
237 LOG_INFO("Snoop Logs fully enabled");
238 is_enabled_ = true;
239 is_filtered_ = false;
240 // delete filtered logs
241 delete_btsnoop_files(get_btsnoop_log_path(snoop_log_path_, true));
242 // delete snooz logs
243 delete_btsnoop_files(snooz_log_path_);
244 } else if (btsnoop_mode == kBtSnoopLogModeTruncated) {
245 LOG_INFO("Snoop Logs truncated. Limiting to %u", kMaxTruncatedAclPacketSize);
246 is_enabled_ = true;
247 is_truncated_ = true;
248 is_filtered_ = false;
249 // delete filtered logs
250 delete_btsnoop_files(get_btsnoop_log_path(snoop_log_path_, true));
251 // delete snooz logs
252 delete_btsnoop_files(snooz_log_path_);
253 } else {
254 LOG_INFO("Snoop Logs disabled");
255 is_enabled_ = false;
256 is_filtered_ = false;
257 // delete both filtered and unfiltered logs
258 delete_btsnoop_files(get_btsnoop_log_path(snoop_log_path_, true));
259 delete_btsnoop_files(get_btsnoop_log_path(snoop_log_path_, false));
260 }
261 // Add ".filtered" extension if necessary
262 snoop_log_path_ = get_btsnoop_log_path(snoop_log_path_, is_filtered_);
263 }
264
CloseCurrentSnoopLogFile()265 void SnoopLogger::CloseCurrentSnoopLogFile() {
266 std::lock_guard<std::recursive_mutex> lock(file_mutex_);
267 if (btsnoop_ostream_.is_open()) {
268 btsnoop_ostream_.flush();
269 btsnoop_ostream_.close();
270 }
271 packet_counter_ = 0;
272 }
273
OpenNextSnoopLogFile()274 void SnoopLogger::OpenNextSnoopLogFile() {
275 std::lock_guard<std::recursive_mutex> lock(file_mutex_);
276 CloseCurrentSnoopLogFile();
277
278 auto last_file_path = get_last_log_path(snoop_log_path_);
279
280 if (os::FileExists(snoop_log_path_)) {
281 if (!os::RenameFile(snoop_log_path_, last_file_path)) {
282 LOG_ERROR(
283 "Unabled to rename existing snoop log from \"%s\" to \"%s\"",
284 snoop_log_path_.c_str(),
285 last_file_path.c_str());
286 }
287 } else {
288 LOG_INFO("Previous log file \"%s\" does not exist, skip renaming", snoop_log_path_.c_str());
289 }
290
291 mode_t prevmask = umask(0);
292 // do not use std::ios::app as we want override the existing file
293 btsnoop_ostream_.open(snoop_log_path_, std::ios::binary | std::ios::out);
294 #ifdef USE_FAKE_TIMERS
295 file_creation_time = fake_timerfd_get_clock();
296 #endif
297 if (!btsnoop_ostream_.good()) {
298 LOG_ALWAYS_FATAL("Unable to open snoop log at \"%s\", error: \"%s\"", snoop_log_path_.c_str(), strerror(errno));
299 }
300 umask(prevmask);
301 if (!btsnoop_ostream_.write(reinterpret_cast<const char*>(&kBtSnoopFileHeader), sizeof(FileHeaderType))) {
302 LOG_ALWAYS_FATAL("Unable to write file header to \"%s\", error: \"%s\"", snoop_log_path_.c_str(), strerror(errno));
303 }
304 if (!btsnoop_ostream_.flush()) {
305 LOG_ERROR("Failed to flush, error: \"%s\"", strerror(errno));
306 }
307 }
308
Capture(const HciPacket & packet,Direction direction,PacketType type)309 void SnoopLogger::Capture(const HciPacket& packet, Direction direction, PacketType type) {
310 uint64_t timestamp_us =
311 std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch())
312 .count();
313 std::bitset<32> flags = 0;
314 switch (type) {
315 case PacketType::CMD:
316 flags.set(0, false);
317 flags.set(1, true);
318 break;
319 case PacketType::ACL:
320 case PacketType::ISO:
321 case PacketType::SCO:
322 flags.set(0, direction == Direction::INCOMING);
323 flags.set(1, false);
324 break;
325 case PacketType::EVT:
326 flags.set(0, true);
327 flags.set(1, true);
328 break;
329 }
330 uint32_t length = packet.size() + /* type byte */ 1;
331 PacketHeaderType header = {.length_original = htonl(length),
332 .length_captured = htonl(length),
333 .flags = htonl(static_cast<uint32_t>(flags.to_ulong())),
334 .dropped_packets = 0,
335 .timestamp = htonll(timestamp_us + kBtSnoopEpochDelta),
336 .type = static_cast<uint8_t>(type)};
337 if (is_truncated_ && type == PacketType::ACL) {
338 header.length_captured = htonl(std::min(length, kMaxTruncatedAclPacketSize));
339 }
340 {
341 std::lock_guard<std::recursive_mutex> lock(file_mutex_);
342 if (!is_enabled_) {
343 // btsnoop disabled, log in-memory btsnooz log only
344 std::stringstream ss;
345 size_t included_length = get_btsnooz_packet_length_to_write(packet, type, qualcomm_debug_log_enabled_);
346 header.length_captured = htonl(included_length + /* type byte */ 1);
347 if (!ss.write(reinterpret_cast<const char*>(&header), sizeof(PacketHeaderType))) {
348 LOG_ERROR("Failed to write packet header for btsnooz, error: \"%s\"", strerror(errno));
349 }
350 if (!ss.write(reinterpret_cast<const char*>(packet.data()), included_length)) {
351 LOG_ERROR("Failed to write packet payload for btsnooz, error: \"%s\"", strerror(errno));
352 }
353 btsnooz_buffer_.Push(ss.str());
354 return;
355 }
356 packet_counter_++;
357 if (packet_counter_ > max_packets_per_file_) {
358 OpenNextSnoopLogFile();
359 }
360 if (!btsnoop_ostream_.write(reinterpret_cast<const char*>(&header), sizeof(PacketHeaderType))) {
361 LOG_ERROR("Failed to write packet header for btsnoop, error: \"%s\"", strerror(errno));
362 }
363 if (!btsnoop_ostream_.write(reinterpret_cast<const char*>(packet.data()), packet.size())) {
364 LOG_ERROR("Failed to write packet payload for btsnoop, error: \"%s\"", strerror(errno));
365 }
366 // std::ofstream::flush() pushes user data into kernel memory. The data will be written even if this process
367 // crashes. However, data will be lost if there is a kernel panic, which is out of scope of BT snoop log.
368 // NOTE: std::ofstream::write() followed by std::ofstream::flush() has similar effect as UNIX write(fd, data, len)
369 // as write() syscall dumps data into kernel memory directly
370 if (!btsnoop_ostream_.flush()) {
371 LOG_ERROR("Failed to flush, error: \"%s\"", strerror(errno));
372 }
373 }
374 }
375
DumpSnoozLogToFile(const std::vector<std::string> & data) const376 void SnoopLogger::DumpSnoozLogToFile(const std::vector<std::string>& data) const {
377 std::lock_guard<std::recursive_mutex> lock(file_mutex_);
378 if (is_enabled_) {
379 LOG_DEBUG("btsnoop log is enabled, skip dumping btsnooz log");
380 return;
381 }
382
383 auto last_file_path = get_last_log_path(snooz_log_path_);
384
385 if (os::FileExists(snooz_log_path_)) {
386 if (!os::RenameFile(snooz_log_path_, last_file_path)) {
387 LOG_ERROR(
388 "Unabled to rename existing snooz log from \"%s\" to \"%s\"",
389 snooz_log_path_.c_str(),
390 last_file_path.c_str());
391 }
392 } else {
393 LOG_INFO("Previous log file \"%s\" does not exist, skip renaming", snooz_log_path_.c_str());
394 }
395
396 mode_t prevmask = umask(0);
397 // do not use std::ios::app as we want override the existing file
398 std::ofstream btsnooz_ostream(snooz_log_path_, std::ios::binary | std::ios::out);
399 if (!btsnooz_ostream.good()) {
400 LOG_ALWAYS_FATAL("Unable to open snoop log at \"%s\", error: \"%s\"", snooz_log_path_.c_str(), strerror(errno));
401 }
402 umask(prevmask);
403 if (!btsnooz_ostream.write(reinterpret_cast<const char*>(&kBtSnoopFileHeader), sizeof(FileHeaderType))) {
404 LOG_ALWAYS_FATAL("Unable to write file header to \"%s\", error: \"%s\"", snooz_log_path_.c_str(), strerror(errno));
405 }
406 for (const auto& packet : data) {
407 if (!btsnooz_ostream.write(packet.data(), packet.size())) {
408 LOG_ERROR("Failed to write packet payload for btsnooz, error: \"%s\"", strerror(errno));
409 }
410 }
411 if (!btsnooz_ostream.flush()) {
412 LOG_ERROR("Failed to flush, error: \"%s\"", strerror(errno));
413 }
414 }
415
ListDependencies(ModuleList * list) const416 void SnoopLogger::ListDependencies(ModuleList* list) const {
417 // We have no dependencies
418 }
419
Start()420 void SnoopLogger::Start() {
421 std::lock_guard<std::recursive_mutex> lock(file_mutex_);
422 if (is_enabled_) {
423 OpenNextSnoopLogFile();
424 }
425 alarm_ = std::make_unique<os::RepeatingAlarm>(GetHandler());
426 alarm_->Schedule(
427 common::Bind(&delete_old_btsnooz_files, snooz_log_path_, snooz_log_life_time_), snooz_log_delete_alarm_interval_);
428 }
429
Stop()430 void SnoopLogger::Stop() {
431 std::lock_guard<std::recursive_mutex> lock(file_mutex_);
432 LOG_DEBUG("Closing btsnoop log data at %s", snoop_log_path_.c_str());
433 CloseCurrentSnoopLogFile();
434 // Cancel the alarm
435 alarm_->Cancel();
436 alarm_.reset();
437 // delete any existing snooz logs
438 delete_btsnoop_files(snooz_log_path_);
439 }
440
GetDumpsysData(flatbuffers::FlatBufferBuilder * builder) const441 DumpsysDataFinisher SnoopLogger::GetDumpsysData(flatbuffers::FlatBufferBuilder* builder) const {
442 LOG_DEBUG("Dumping btsnooz log data to %s", snooz_log_path_.c_str());
443 DumpSnoozLogToFile(btsnooz_buffer_.Pull());
444 return Module::GetDumpsysData(builder);
445 }
446
GetMaxPacketsPerFile()447 size_t SnoopLogger::GetMaxPacketsPerFile() {
448 // Allow override max packet per file via system property
449 auto max_packets_per_file = kDefaultBtSnoopMaxPacketsPerFile;
450 {
451 auto max_packets_per_file_prop = os::GetSystemProperty(kBtSnoopMaxPacketsPerFileProperty);
452 if (max_packets_per_file_prop) {
453 auto max_packets_per_file_number = common::Uint64FromString(max_packets_per_file_prop.value());
454 if (max_packets_per_file_number) {
455 max_packets_per_file = max_packets_per_file_number.value();
456 }
457 }
458 }
459 return max_packets_per_file;
460 }
461
GetMaxPacketsPerBuffer()462 size_t SnoopLogger::GetMaxPacketsPerBuffer() {
463 // We want to use at most 256 KB memory for btsnooz log for release builds
464 // and 512 KB memory for userdebug/eng builds
465 auto is_debuggable = os::GetSystemPropertyBool(kIsDebuggableProperty, false);
466 size_t btsnooz_max_memory_usage_bytes = (is_debuggable ? 1024 : 256) * 1024;
467 // Calculate max number of packets based on max memory usage and max packet size
468 return btsnooz_max_memory_usage_bytes / kDefaultBtSnoozMaxBytesPerPacket;
469 }
470
GetBtSnoopMode()471 std::string SnoopLogger::GetBtSnoopMode() {
472 // Default mode is DISABLED on user build.
473 // In userdebug/eng build, it can also be overwritten by modifying the global setting
474 std::string default_mode = kBtSnoopLogModeDisabled;
475 {
476 auto is_debuggable = os::GetSystemPropertyBool(kIsDebuggableProperty, false);
477 if (is_debuggable) {
478 auto default_mode_property = os::GetSystemProperty(kBtSnoopDefaultLogModeProperty);
479 if (default_mode_property) {
480 default_mode = std::move(default_mode_property.value());
481 }
482 }
483 }
484
485 // Get the actual mode if exist
486 std::string btsnoop_mode = default_mode;
487 {
488 auto btsnoop_mode_prop = os::GetSystemProperty(kBtSnoopLogModeProperty);
489 if (btsnoop_mode_prop) {
490 btsnoop_mode = std::move(btsnoop_mode_prop.value());
491 }
492 }
493 return btsnoop_mode;
494 }
495
IsQualcommDebugLogEnabled()496 bool SnoopLogger::IsQualcommDebugLogEnabled() {
497 // Check system prop if the soc manufacturer is Qualcomm
498 bool qualcomm_debug_log_enabled = false;
499 {
500 auto soc_manufacturer_prop = os::GetSystemProperty(kSoCManufacturerProperty);
501 qualcomm_debug_log_enabled = soc_manufacturer_prop.has_value() &&
502 common::StringTrim(soc_manufacturer_prop.value()) == kSoCManufacturerQualcomm;
503 }
504 return qualcomm_debug_log_enabled;
505 }
506
__anon709052da0202() 507 const ModuleFactory SnoopLogger::Factory = ModuleFactory([]() {
508 return new SnoopLogger(
509 os::ParameterProvider::SnoopLogFilePath(),
510 os::ParameterProvider::SnoozLogFilePath(),
511 GetMaxPacketsPerFile(),
512 GetMaxPacketsPerBuffer(),
513 GetBtSnoopMode(),
514 IsQualcommDebugLogEnabled(),
515 kBtSnoozLogLifeTime,
516 kBtSnoozLogDeleteRepeatingAlarmInterval);
517 });
518
519 } // namespace hal
520 } // namespace bluetooth
521