| 157 | |
| 158 | |
| 159 | class Logcat: |
| 160 | def __init__(self, android_log_write): |
| 161 | self.android_log_write = android_log_write |
| 162 | self._lock = RLock() |
| 163 | self._bucket_level = 0 |
| 164 | self._prev_write_time = time() |
| 165 | |
| 166 | def write(self, prio, tag, message): |
| 167 | # Encode null bytes using "modified UTF-8" to avoid them truncating the |
| 168 | # message. |
| 169 | message = message.replace(b"\x00", b"\xc0\x80") |
| 170 | |
| 171 | # On API level 30 and higher, Logcat will strip any number of leading |
| 172 | # newlines. This is visible in all `logcat` modes, even --binary. Work |
| 173 | # around this by adding a leading space, which shouldn't make any |
| 174 | # difference to the log's usability. |
| 175 | if message.startswith(b"\n"): |
| 176 | message = b" " + message |
| 177 | |
| 178 | with self._lock: |
| 179 | now = time() |
| 180 | self._bucket_level += ( |
| 181 | (now - self._prev_write_time) * MAX_BYTES_PER_SECOND) |
| 182 | |
| 183 | # If the bucket level is still below zero, the clock must have gone |
| 184 | # backwards, so reset it to zero and continue. |
| 185 | self._bucket_level = max(0, min(self._bucket_level, BUCKET_SIZE)) |
| 186 | self._prev_write_time = now |
| 187 | |
| 188 | self._bucket_level -= PER_MESSAGE_OVERHEAD + len(tag) + len(message) |
| 189 | if self._bucket_level < 0: |
| 190 | sleep(-self._bucket_level / MAX_BYTES_PER_SECOND) |
| 191 | |
| 192 | self.android_log_write(prio, tag, message) |
no outgoing calls
no test coverage detected
searching dependent graphs…