mirror of
https://github.com/yume-chan/ya-webadb.git
synced 2025-10-05 19:42:15 +02:00
parent
ca551a2414
commit
6158745ef5
3 changed files with 65 additions and 30 deletions
|
@ -1,7 +1,7 @@
|
||||||
import { ICommandBarItemProps, Stack, StackItem } from "@fluentui/react";
|
import { ICommandBarItemProps, Stack, StackItem } from "@fluentui/react";
|
||||||
import { makeStyles, mergeClasses, shorthands } from "@griffel/react";
|
import { makeStyles, mergeClasses, shorthands } from "@griffel/react";
|
||||||
import { AbortController, decodeUtf8, ReadableStream, WritableStream } from '@yume-chan/adb';
|
import { AbortController, ReadableStream, WritableStream } from '@yume-chan/adb';
|
||||||
import { Logcat, LogMessage, LogPriority } from '@yume-chan/android-bin';
|
import { AndroidLogEntry, AndroidLogPriority, Logcat } from '@yume-chan/android-bin';
|
||||||
import { action, autorun, makeAutoObservable, observable, runInAction } from "mobx";
|
import { action, autorun, makeAutoObservable, observable, runInAction } from "mobx";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { NextPage } from "next";
|
import { NextPage } from "next";
|
||||||
|
@ -45,9 +45,8 @@ export interface Column extends GridColumn {
|
||||||
title: string;
|
title: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LogRow extends LogMessage {
|
export interface LogRow extends AndroidLogEntry {
|
||||||
timeString?: string;
|
timeString?: string;
|
||||||
payloadString?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const state = makeAutoObservable({
|
const state = makeAutoObservable({
|
||||||
|
@ -57,7 +56,7 @@ const state = makeAutoObservable({
|
||||||
flushRequested: false,
|
flushRequested: false,
|
||||||
list: [] as LogRow[],
|
list: [] as LogRow[],
|
||||||
count: 0,
|
count: 0,
|
||||||
stream: undefined as ReadableStream<LogMessage> | undefined,
|
stream: undefined as ReadableStream<AndroidLogEntry> | undefined,
|
||||||
stopSignal: undefined as AbortController | undefined,
|
stopSignal: undefined as AbortController | undefined,
|
||||||
selectedCount: 0,
|
selectedCount: 0,
|
||||||
animationFrameId: undefined as number | undefined,
|
animationFrameId: undefined as number | undefined,
|
||||||
|
@ -166,7 +165,7 @@ const state = makeAutoObservable({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
width: 80,
|
width: 60,
|
||||||
title: 'PID',
|
title: 'PID',
|
||||||
CellComponent: ({ rowIndex, columnIndex, className, ...rest }) => {
|
CellComponent: ({ rowIndex, columnIndex, className, ...rest }) => {
|
||||||
const item = this.list[rowIndex];
|
const item = this.list[rowIndex];
|
||||||
|
@ -181,7 +180,7 @@ const state = makeAutoObservable({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
width: 80,
|
width: 60,
|
||||||
title: 'TID',
|
title: 'TID',
|
||||||
CellComponent: ({ rowIndex, columnIndex, className, ...rest }) => {
|
CellComponent: ({ rowIndex, columnIndex, className, ...rest }) => {
|
||||||
const item = this.list[rowIndex];
|
const item = this.list[rowIndex];
|
||||||
|
@ -196,7 +195,7 @@ const state = makeAutoObservable({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
width: 100,
|
width: 80,
|
||||||
title: 'Priority',
|
title: 'Priority',
|
||||||
CellComponent: ({ rowIndex, columnIndex, className, ...rest }) => {
|
CellComponent: ({ rowIndex, columnIndex, className, ...rest }) => {
|
||||||
const item = this.list[rowIndex];
|
const item = this.list[rowIndex];
|
||||||
|
@ -205,7 +204,22 @@ const state = makeAutoObservable({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={mergeClasses(classes.code, className)} {...rest}>
|
<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>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -213,18 +227,14 @@ const state = makeAutoObservable({
|
||||||
{
|
{
|
||||||
width: 300,
|
width: 300,
|
||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
title: 'Payload',
|
title: 'Message',
|
||||||
CellComponent: ({ rowIndex, columnIndex, className, ...rest }) => {
|
CellComponent: ({ rowIndex, columnIndex, className, ...rest }) => {
|
||||||
const item = this.list[rowIndex];
|
const item = this.list[rowIndex];
|
||||||
if (!item.payloadString) {
|
|
||||||
item.payloadString = decodeUtf8(item.payload);
|
|
||||||
}
|
|
||||||
|
|
||||||
const classes = useClasses();
|
const classes = useClasses();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={mergeClasses(classes.code, className)} {...rest}>
|
<div className={mergeClasses(classes.code, className)} {...rest}>
|
||||||
{item.payloadString}
|
{item.message}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ export enum DemoModeSignalStrength {
|
||||||
Level4 = '4',
|
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+',
|
export const DemoModeMobileDataTypes = ['1x', '3g', '4g', '4g+', '5g', '5ge', '5g+',
|
||||||
'e', 'g', 'h', 'h+', 'lte', 'lte+', 'dis', 'not', 'null'] as const;
|
'e', 'g', 'h', 'h+', 'lte', 'lte+', 'dis', 'not', 'null'] as const;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// cspell: ignore logcat
|
// cspell: ignore logcat
|
||||||
|
|
||||||
import { AdbCommandBase, AdbSubprocessNoneProtocol, BufferedStream, BufferedStreamEndedError, DecodeUtf8Stream, ReadableStream, SplitLineStream, WritableStream } from "@yume-chan/adb";
|
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`
|
// `adb logcat` is an alias to `adb shell logcat`
|
||||||
// so instead of adding to core library, it's implemented here
|
// so instead of adding to core library, it's implemented here
|
||||||
|
@ -19,7 +19,8 @@ export enum LogId {
|
||||||
Kernel,
|
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,
|
Unknown,
|
||||||
Default,
|
Default,
|
||||||
Verbose,
|
Verbose,
|
||||||
|
@ -56,21 +57,45 @@ export const LoggerEntry =
|
||||||
|
|
||||||
export type LoggerEntry = typeof LoggerEntry['TDeserializeResult'];
|
export type LoggerEntry = typeof LoggerEntry['TDeserializeResult'];
|
||||||
|
|
||||||
export interface LogMessage extends LoggerEntry {
|
// https://cs.android.com/android/platform/superproject/+/master:system/logging/liblog/logprint.cpp;drc=bbe77d66e7bee8bd1f0bc7e5492b5376b0207ef6;bpv=0
|
||||||
priority: LogPriority;
|
export interface AndroidLogEntry extends LoggerEntry {
|
||||||
payload: Uint8Array;
|
priority: AndroidLogPriority;
|
||||||
|
tag: string;
|
||||||
|
message: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deserializeLogMessage(stream: StructAsyncDeserializeStream): Promise<LogMessage> {
|
function findTagEnd(payload: Uint8Array) {
|
||||||
const entry = await LoggerEntry.deserialize(stream);
|
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) {
|
if (entry.headerSize !== LoggerEntry.size) {
|
||||||
await stream.read(entry.headerSize - LoggerEntry.size);
|
await stream.read(entry.headerSize - LoggerEntry.size);
|
||||||
}
|
}
|
||||||
const priority = (await stream.read(1))[0] as LogPriority;
|
let payload = await stream.read(entry.payloadSize);
|
||||||
const payload = await stream.read(entry.payloadSize - 1);
|
|
||||||
(entry as any).priority = priority;
|
// https://cs.android.com/android/platform/superproject/+/master:system/logging/logcat/logcat.cpp;l=193-194;drc=bbe77d66e7bee8bd1f0bc7e5492b5376b0207ef6
|
||||||
(entry as any).payload = payload;
|
// TODO: payload for some log IDs are in binary format.
|
||||||
return entry as LogMessage;
|
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 {
|
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;
|
let bufferedStream: BufferedStream;
|
||||||
return new ReadableStream({
|
return new ReadableStream({
|
||||||
start: async () => {
|
start: async () => {
|
||||||
|
@ -175,7 +200,7 @@ export class Logcat extends AdbCommandBase {
|
||||||
},
|
},
|
||||||
async pull(controller) {
|
async pull(controller) {
|
||||||
try {
|
try {
|
||||||
const entry = await deserializeLogMessage(bufferedStream);
|
const entry = await deserializeAndroidLogEntry(bufferedStream);
|
||||||
controller.enqueue(entry);
|
controller.enqueue(entry);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof BufferedStreamEndedError) {
|
if (e instanceof BufferedStreamEndedError) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue