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