feat(bin): parse tag for logcat

refs #424
This commit is contained in:
Simon Chan 2022-06-07 00:07:50 +08:00
parent ca551a2414
commit 6158745ef5
No known key found for this signature in database
GPG key ID: A8B69F750B9BCEDD
3 changed files with 65 additions and 30 deletions

View file

@ -1,7 +1,7 @@
import { ICommandBarItemProps, Stack, StackItem } from "@fluentui/react";
import { makeStyles, mergeClasses, shorthands } from "@griffel/react";
import { AbortController, decodeUtf8, ReadableStream, WritableStream } from '@yume-chan/adb';
import { Logcat, LogMessage, LogPriority } from '@yume-chan/android-bin';
import { AbortController, ReadableStream, WritableStream } from '@yume-chan/adb';
import { AndroidLogEntry, AndroidLogPriority, Logcat } from '@yume-chan/android-bin';
import { action, autorun, makeAutoObservable, observable, runInAction } from "mobx";
import { observer } from "mobx-react-lite";
import { NextPage } from "next";
@ -45,9 +45,8 @@ export interface Column extends GridColumn {
title: string;
}
export interface LogRow extends LogMessage {
export interface LogRow extends AndroidLogEntry {
timeString?: string;
payloadString?: string;
}
const state = makeAutoObservable({
@ -57,7 +56,7 @@ const state = makeAutoObservable({
flushRequested: false,
list: [] as LogRow[],
count: 0,
stream: undefined as ReadableStream<LogMessage> | undefined,
stream: undefined as ReadableStream<AndroidLogEntry> | undefined,
stopSignal: undefined as AbortController | undefined,
selectedCount: 0,
animationFrameId: undefined as number | undefined,
@ -166,7 +165,7 @@ const state = makeAutoObservable({
}
},
{
width: 80,
width: 60,
title: 'PID',
CellComponent: ({ rowIndex, columnIndex, className, ...rest }) => {
const item = this.list[rowIndex];
@ -181,7 +180,7 @@ const state = makeAutoObservable({
}
},
{
width: 80,
width: 60,
title: 'TID',
CellComponent: ({ rowIndex, columnIndex, className, ...rest }) => {
const item = this.list[rowIndex];
@ -196,7 +195,7 @@ const state = makeAutoObservable({
}
},
{
width: 100,
width: 80,
title: 'Priority',
CellComponent: ({ rowIndex, columnIndex, className, ...rest }) => {
const item = this.list[rowIndex];
@ -205,7 +204,22 @@ const state = makeAutoObservable({
return (
<div className={mergeClasses(classes.code, className)} {...rest}>
{LogPriority[item.priority]}
{AndroidLogPriority[item.priority]}
</div>
);
}
},
{
width: 300,
title: 'Tag',
CellComponent: ({ rowIndex, columnIndex, className, ...rest }) => {
const item = this.list[rowIndex];
const classes = useClasses();
return (
<div className={mergeClasses(classes.code, className)} {...rest}>
{item.tag}
</div>
);
}
@ -213,18 +227,14 @@ const state = makeAutoObservable({
{
width: 300,
flexGrow: 1,
title: 'Payload',
title: 'Message',
CellComponent: ({ rowIndex, columnIndex, className, ...rest }) => {
const item = this.list[rowIndex];
if (!item.payloadString) {
item.payloadString = decodeUtf8(item.payload);
}
const classes = useClasses();
return (
<div className={mergeClasses(classes.code, className)} {...rest}>
{item.payloadString}
{item.message}
</div>
);
}

View file

@ -16,7 +16,7 @@ export enum DemoModeSignalStrength {
Level4 = '4',
}
// https://cs.android.com/android/platform/superproject/+/master:frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java;l=1073
// https://cs.android.com/android/platform/superproject/+/master:frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java;l=1362;drc=3b775bf7ad89902f94e03d191b0d8fbdebf2bdbf
export const DemoModeMobileDataTypes = ['1x', '3g', '4g', '4g+', '5g', '5ge', '5g+',
'e', 'g', 'h', 'h+', 'lte', 'lte+', 'dis', 'not', 'null'] as const;

View file

@ -1,7 +1,7 @@
// cspell: ignore logcat
import { AdbCommandBase, AdbSubprocessNoneProtocol, BufferedStream, BufferedStreamEndedError, DecodeUtf8Stream, ReadableStream, SplitLineStream, WritableStream } from "@yume-chan/adb";
import Struct, { StructAsyncDeserializeStream } from "@yume-chan/struct";
import Struct, { decodeUtf8, StructAsyncDeserializeStream } from "@yume-chan/struct";
// `adb logcat` is an alias to `adb shell logcat`
// so instead of adding to core library, it's implemented here
@ -19,7 +19,8 @@ export enum LogId {
Kernel,
}
export enum LogPriority {
// https://cs.android.com/android/platform/superproject/+/master:system/logging/liblog/include/android/log.h;l=73;drc=82b5738732161dbaafb2e2f25cce19cd26b9157d
export enum AndroidLogPriority {
Unknown,
Default,
Verbose,
@ -56,21 +57,45 @@ export const LoggerEntry =
export type LoggerEntry = typeof LoggerEntry['TDeserializeResult'];
export interface LogMessage extends LoggerEntry {
priority: LogPriority;
payload: Uint8Array;
// https://cs.android.com/android/platform/superproject/+/master:system/logging/liblog/logprint.cpp;drc=bbe77d66e7bee8bd1f0bc7e5492b5376b0207ef6;bpv=0
export interface AndroidLogEntry extends LoggerEntry {
priority: AndroidLogPriority;
tag: string;
message: string;
}
export async function deserializeLogMessage(stream: StructAsyncDeserializeStream): Promise<LogMessage> {
const entry = await LoggerEntry.deserialize(stream);
function findTagEnd(payload: Uint8Array) {
for (const separator of [0, ' '.charCodeAt(0), ':'.charCodeAt(0)]) {
const index = payload.indexOf(separator);
if (index !== -1) {
return index;
}
}
const index = payload.findIndex(x => x >= 0x7f);
if (index !== -1) {
return index;
}
return payload.length;
}
export async function deserializeAndroidLogEntry(stream: StructAsyncDeserializeStream): Promise<AndroidLogEntry> {
const entry = await LoggerEntry.deserialize(stream) as unknown as AndroidLogEntry;
if (entry.headerSize !== LoggerEntry.size) {
await stream.read(entry.headerSize - LoggerEntry.size);
}
const priority = (await stream.read(1))[0] as LogPriority;
const payload = await stream.read(entry.payloadSize - 1);
(entry as any).priority = priority;
(entry as any).payload = payload;
return entry as LogMessage;
let payload = await stream.read(entry.payloadSize);
// https://cs.android.com/android/platform/superproject/+/master:system/logging/logcat/logcat.cpp;l=193-194;drc=bbe77d66e7bee8bd1f0bc7e5492b5376b0207ef6
// TODO: payload for some log IDs are in binary format.
entry.priority = payload[0] as AndroidLogPriority;
payload = payload.subarray(1);
const tagEnd = findTagEnd(payload);
entry.tag = decodeUtf8(payload.subarray(0, tagEnd));
entry.message = tagEnd < payload.length - 1 ? decodeUtf8(payload.subarray(tagEnd + 1)) : '';
return entry;
}
export interface LogSize {
@ -158,7 +183,7 @@ export class Logcat extends AdbCommandBase {
]);
}
public binary(options?: LogcatOptions): ReadableStream<LogMessage> {
public binary(options?: LogcatOptions): ReadableStream<AndroidLogEntry> {
let bufferedStream: BufferedStream;
return new ReadableStream({
start: async () => {
@ -175,7 +200,7 @@ export class Logcat extends AdbCommandBase {
},
async pull(controller) {
try {
const entry = await deserializeLogMessage(bufferedStream);
const entry = await deserializeAndroidLogEntry(bufferedStream);
controller.enqueue(entry);
} catch (e) {
if (e instanceof BufferedStreamEndedError) {