• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 "chre_host/bt_snoop_log_parser.h"
18 
19 #include <endian.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <fstream>
23 
24 #include "chre/util/time.h"
25 #include "chre_host/daemon_base.h"
26 #include "chre_host/file_stream.h"
27 #include "chre_host/log.h"
28 #include "chre_host/log_message_parser.h"
29 
30 namespace android {
31 namespace chre {
32 
33 namespace {
34 
35 // Some code in this script are copied from the BT HAL snoop log implementation
36 // in packages/modules/Bluetooth/system/gd/hal. We didn't share the code
37 // directly because currently we only need a subset of the entire snoop log
38 // functionalities.
39 using HciPacket = std::vector<uint8_t>;
40 
41 constexpr char kSnoopLogFilePath[] = "/data/vendor/chre/chre_btsnoop_hci.log";
42 constexpr char kLastSnoopLogFilePath[] =
43     "/data/vendor/chre/chre_btsnoop_hci.log.last";
44 
45 constexpr size_t kDefaultBtSnoopMaxPacketsPerFile = 0xffff;
46 
47 const size_t PACKET_TYPE_LENGTH = 1;
48 
49 constexpr uint32_t kBytesToTest = 0x12345678;
50 constexpr uint8_t kFirstByte = (const uint8_t &)kBytesToTest;
51 constexpr bool isLittleEndian = kFirstByte == 0x78;
52 constexpr uint32_t BTSNOOP_VERSION_NUMBER = isLittleEndian ? 0x01000000 : 1;
53 constexpr uint32_t BTSNOOP_DATALINK_TYPE =
54     isLittleEndian ? 0xea030000
55                    : 0x03ea;  // Datalink Type code for HCI UART (H4) is 1002
56 
57 // Epoch in microseconds since 01/01/0000.
58 constexpr uint64_t kBtSnoopEpochDelta = 0x00dcddb30f2f8000ULL;
59 
60 struct FileHeaderType {
61   uint8_t identification_pattern[8];
62   uint32_t version_number;
63   uint32_t datalink_type;
64 } __attribute__((packed));
65 
66 static constexpr FileHeaderType kBtSnoopFileHeader = {
67     .identification_pattern = {'b', 't', 's', 'n', 'o', 'o', 'p', 0x00},
68     .version_number = BTSNOOP_VERSION_NUMBER,
69     .datalink_type = BTSNOOP_DATALINK_TYPE};
70 
htonll(uint64_t ll)71 uint64_t htonll(uint64_t ll) {
72   if constexpr (isLittleEndian) {
73     return static_cast<uint64_t>(htonl(ll & 0xffffffff)) << 32 |
74            htonl(ll >> 32);
75   } else {
76     return ll;
77   }
78 }
79 
80 }  // namespace
81 
log(const char * buffer)82 size_t BtSnoopLogParser::log(const char *buffer) {
83   const auto *message = reinterpret_cast<const BtSnoopLog *>(buffer);
84   capture(message->packet, static_cast<size_t>(message->packetSize),
85           static_cast<BtSnoopDirection>(message->direction));
86   return message->packetSize + 2 * sizeof(uint8_t);
87 }
88 
capture(const uint8_t * packet,size_t packetSize,BtSnoopDirection direction)89 void BtSnoopLogParser::capture(const uint8_t *packet, size_t packetSize,
90                                BtSnoopDirection direction) {
91   uint64_t timestamp = std::chrono::duration_cast<std::chrono::microseconds>(
92                            std::chrono::system_clock::now().time_since_epoch())
93                            .count();
94   std::bitset<32> flags = 0;
95   PacketType type = PacketType::CMD;
96   switch (direction) {
97     case BtSnoopDirection::OUTGOING_TO_ARBITER:
98       flags.set(0, false);
99       flags.set(1, true);
100       type = PacketType::CMD;
101       break;
102     case BtSnoopDirection::INCOMING_FROM_BT_CONTROLLER:
103       flags.set(0, true);
104       flags.set(1, true);
105       type = PacketType::EVT;
106       break;
107   }
108 
109   uint32_t length = packetSize + /* type byte */ PACKET_TYPE_LENGTH;
110   PacketHeaderType header = {
111       .length_original = htonl(length),
112       .length_captured = htonl(length),
113       .flags = htonl(static_cast<uint32_t>(flags.to_ulong())),
114       .dropped_packets = 0,
115       .timestamp = htonll(timestamp + kBtSnoopEpochDelta),
116       .type = type};
117 
118   if (length != ntohl(header.length_original)) {
119     header.length_captured = htonl(length);
120   }
121 
122   mPacketCounter++;
123   if (mPacketCounter > kDefaultBtSnoopMaxPacketsPerFile) {
124     openNextSnoopLogFile();
125     LOGW("Snoop Log file reached maximum size");
126   }
127   if (ensureSnoopLogFileIsOpen()) {
128     if (!mBtSnoopOstream.write(reinterpret_cast<const char *>(&header),
129                                sizeof(PacketHeaderType))) {
130       LOGE("Failed to write packet header for btsnoop, error: \"%s\"",
131            strerror(errno));
132     }
133     if (!mBtSnoopOstream.write(reinterpret_cast<const char *>(packet),
134                                length - 1)) {
135       LOGE("Failed to write packet payload for btsnoop, error: \"%s\"",
136            strerror(errno));
137     }
138   }
139 }
140 
ensureSnoopLogFileIsOpen()141 bool BtSnoopLogParser::ensureSnoopLogFileIsOpen() {
142   if (mBtSnoopOstream.is_open()) {
143     return true;
144   }
145   return openNextSnoopLogFile();
146 }
147 
openNextSnoopLogFile()148 bool BtSnoopLogParser::openNextSnoopLogFile() {
149   closeSnoopLogFile();
150   if (access(kSnoopLogFilePath, F_OK) == 0 &&
151       std::rename(kSnoopLogFilePath, kLastSnoopLogFilePath) != 0) {
152     LOGE("Unable to rename existing snoop log, error: \"%s\"", strerror(errno));
153   }
154 
155   bool success = false;
156   mBtSnoopOstream.open(kSnoopLogFilePath, std::ios::binary | std::ios::out);
157   mBtSnoopOstream.setf(std::ios::unitbuf);
158   if (mBtSnoopOstream.fail()) {
159     LOGE("Fail to create snoop log file, error: \"%s\"", strerror(errno));
160   } else if (!mBtSnoopOstream.write(
161                  reinterpret_cast<const char *>(&kBtSnoopFileHeader),
162                  sizeof(FileHeaderType))) {
163     LOGE("Unable to write file header to \"%s\", error: \"%s\"",
164          kSnoopLogFilePath, strerror(errno));
165   } else {
166     success = true;
167   }
168   return success;
169 }
170 
closeSnoopLogFile()171 void BtSnoopLogParser::closeSnoopLogFile() {
172   if (mBtSnoopOstream.is_open()) {
173     mBtSnoopOstream.close();
174   }
175   mPacketCounter = 0;
176 }
177 
178 }  // namespace chre
179 }  // namespace android
180