More trace parsers
- SurfaceFlinger dump - WindowManager dump - screen recording - Minor renaming to keep code semantic consistent also with ParserScreenRecording Fixes: 238097667 Fixes: 238097628 Fixes: 238078364 Test: npm run build:unit && npm run test:unit Change-Id: I01aa22c1bb030da21f6fb44eb1b159a4431191ce
This commit is contained in:
23
tools/winscope-ng/src/common/trace/screen_recording.ts
Normal file
23
tools/winscope-ng/src/common/trace/screen_recording.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
class ScreenRecordingTraceEntry {
|
||||
constructor(public timestamp: number,
|
||||
public videoTimeSeconds: number,
|
||||
public videoData: Uint8Array) {
|
||||
}
|
||||
};
|
||||
|
||||
export {ScreenRecordingTraceEntry};
|
||||
@@ -17,8 +17,6 @@ enum TraceTypeId {
|
||||
ACCESSIBILITY,
|
||||
WINDOW_MANAGER,
|
||||
SURFACE_FLINGER,
|
||||
WINDOW_MANAGER_DUMP,
|
||||
SURFACE_FLINGER_DUMP,
|
||||
SCREEN_RECORDING,
|
||||
TRANSACTIONS,
|
||||
TRANSACTIONS_LEGACY,
|
||||
|
||||
@@ -38,6 +38,24 @@ describe("ArrayUtils", () => {
|
||||
expect(ArrayUtils.equal(new Uint8Array([1, 2, 3]), new Uint8Array([1, 2, 3]))).toBeTrue();
|
||||
});
|
||||
|
||||
it("searchSubarray", () => {
|
||||
expect(ArrayUtils.searchSubarray([], [0])).toEqual(undefined);
|
||||
expect(ArrayUtils.searchSubarray([], [])).toEqual(0);
|
||||
expect(ArrayUtils.searchSubarray([0], [])).toEqual(0);
|
||||
|
||||
expect(ArrayUtils.searchSubarray([0, 1, 2], [-1])).toEqual(undefined);
|
||||
expect(ArrayUtils.searchSubarray([0, 1, 2], [])).toEqual(0);
|
||||
expect(ArrayUtils.searchSubarray([0, 1, 2], [0])).toEqual(0);
|
||||
expect(ArrayUtils.searchSubarray([0, 1, 2], [1])).toEqual(1);
|
||||
expect(ArrayUtils.searchSubarray([0, 1, 2], [2])).toEqual(2);
|
||||
|
||||
expect(ArrayUtils.searchSubarray([0, 1, 2], [0, 1])).toEqual(0);
|
||||
expect(ArrayUtils.searchSubarray([0, 1, 2], [1, 2])).toEqual(1);
|
||||
expect(ArrayUtils.searchSubarray([0, 1, 2], [2])).toEqual(2);
|
||||
expect(ArrayUtils.searchSubarray([0, 1, 2], [2, 3])).toEqual(undefined);
|
||||
|
||||
});
|
||||
|
||||
it("binarySearchLowerOrEqual", () => {
|
||||
// no match
|
||||
expect(ArrayUtils.binarySearchLowerOrEqual([], 5)).toBeUndefined();
|
||||
@@ -59,4 +77,19 @@ describe("ArrayUtils", () => {
|
||||
expect(ArrayUtils.binarySearchLowerOrEqual([3, 4, 5, 6], 5)).toEqual(2);
|
||||
expect(ArrayUtils.binarySearchLowerOrEqual([3, 4, 5, 6, 7], 5)).toEqual(2);
|
||||
});
|
||||
|
||||
it("toUintLittleEndian", () => {
|
||||
const buffer = new Uint8Array([0, 0, 1, 1]);
|
||||
|
||||
expect(ArrayUtils.toUintLittleEndian(buffer, 0, -1)).toEqual(0);
|
||||
expect(ArrayUtils.toUintLittleEndian(buffer, 0, 0)).toEqual(0);
|
||||
|
||||
expect(ArrayUtils.toUintLittleEndian(buffer, 0, 1)).toEqual(0);
|
||||
expect(ArrayUtils.toUintLittleEndian(buffer, 0, 2)).toEqual(0);
|
||||
|
||||
expect(ArrayUtils.toUintLittleEndian(buffer, 3, 4)).toEqual(1);
|
||||
expect(ArrayUtils.toUintLittleEndian(buffer, 2, 4)).toEqual(1 + 256);
|
||||
expect(ArrayUtils.toUintLittleEndian(buffer, 1, 4)).toEqual(256 + 256*256);
|
||||
expect(ArrayUtils.toUintLittleEndian(buffer, 0, 3)).toEqual(256*256);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -39,6 +39,25 @@ class ArrayUtils {
|
||||
return true;
|
||||
}
|
||||
|
||||
static searchSubarray<T>(array: T[] | TypedArray, subarray: T[] | TypedArray): number|undefined {
|
||||
for (let i = 0; i + subarray.length <= array.length; ++i) {
|
||||
let match = true;
|
||||
|
||||
for (let j = 0; j < subarray.length; ++j) {
|
||||
if (array[i + j] != subarray[j]) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
static binarySearchLowerOrEqual<T>(values: T[] | TypedArray, target: T): number|undefined {
|
||||
if (values.length == 0) {
|
||||
return undefined;
|
||||
@@ -66,6 +85,15 @@ class ArrayUtils {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static toUintLittleEndian(buffer: Uint8Array, start: number, end: number) {
|
||||
let result = 0;
|
||||
for (let i = end-1; i>=start; --i) {
|
||||
result *= 256;
|
||||
result += buffer[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
export {ArrayUtils};
|
||||
|
||||
@@ -19,13 +19,16 @@ import {TraceTypeId} from "common/trace/type_id";
|
||||
abstract class Parser {
|
||||
constructor(buffer: Uint8Array) {
|
||||
const magicNumber = this.getMagicNumber();
|
||||
const bufferContainsMagicNumber = ArrayUtils.equal(magicNumber, buffer.slice(0, magicNumber.length));
|
||||
if (!bufferContainsMagicNumber) {
|
||||
throw TypeError("buffer doesn't contain expected magic number");
|
||||
if (magicNumber !== undefined)
|
||||
{
|
||||
const bufferContainsMagicNumber = ArrayUtils.equal(magicNumber, buffer.slice(0, magicNumber.length));
|
||||
if (!bufferContainsMagicNumber) {
|
||||
throw TypeError("buffer doesn't contain expected magic number");
|
||||
}
|
||||
}
|
||||
|
||||
this.traceEntriesProto = this.decodeProto(buffer);
|
||||
this.timestamps = this.traceEntriesProto.map((entryProto: any) => this.getTimestamp(entryProto));
|
||||
this.decodedEntries = this.decodeTrace(buffer);
|
||||
this.timestamps = this.decodedEntries.map((entry: any) => this.getTimestamp(entry));
|
||||
}
|
||||
|
||||
public abstract getTraceTypeId(): TraceTypeId;
|
||||
@@ -34,20 +37,20 @@ abstract class Parser {
|
||||
return this.timestamps;
|
||||
}
|
||||
|
||||
public getTraceEntry(timestamp: number): any|undefined {
|
||||
public getTraceEntry(timestamp: number): undefined|any {
|
||||
const index = ArrayUtils.binarySearchLowerOrEqual(this.getTimestamps(), timestamp);
|
||||
if (index === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
return this.processTraceEntryProto(this.traceEntriesProto[index]);
|
||||
return this.processDecodedEntry(this.decodedEntries[index]);
|
||||
}
|
||||
|
||||
protected abstract getMagicNumber(): number[];
|
||||
protected abstract decodeProto(buffer: Uint8Array): any[];
|
||||
protected abstract getTimestamp(entryProto: any): number;
|
||||
protected abstract processTraceEntryProto(entryProto: any): any;
|
||||
protected abstract getMagicNumber(): undefined|number[];
|
||||
protected abstract decodeTrace(buffer: Uint8Array): any[];
|
||||
protected abstract getTimestamp(decodedEntry: any): number;
|
||||
protected abstract processDecodedEntry(decodedEntry: any): any;
|
||||
|
||||
private traceEntriesProto: any[];
|
||||
private decodedEntries: any[];
|
||||
private timestamps: number[];
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ class ParserAccessibility extends Parser {
|
||||
return ParserAccessibility.MAGIC_NUMBER;
|
||||
}
|
||||
|
||||
override decodeProto(buffer: Uint8Array): any[] {
|
||||
override decodeTrace(buffer: Uint8Array): any[] {
|
||||
return (<any>AccessibilityTraceFileProto.decode(buffer)).entry;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ class ParserAccessibility extends Parser {
|
||||
return Number(entryProto.elapsedRealtimeNanos);
|
||||
}
|
||||
|
||||
override processTraceEntryProto(entryProto: any): any {
|
||||
override processDecodedEntry(entryProto: any): any {
|
||||
return entryProto;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,9 +19,11 @@ import {ParserInputMethodClients} from "./parser_input_method_clients";
|
||||
import {ParserInputMethodManagerService} from "./parser_input_method_manager_service";
|
||||
import {ParserInputMethodService} from "./parser_input_method_service";
|
||||
import {ParserProtoLog} from "./parser_protolog"
|
||||
import {ParserScreenRecording} from "./parser_screen_recording"
|
||||
import {ParserSurfaceFlinger} from "./parser_surface_flinger"
|
||||
import {ParserTransactions} from "./parser_transactions";
|
||||
import {ParserWindowManager} from "./parser_window_manager"
|
||||
import {ParserWindowManagerDump} from "./parser_window_manager_dump"
|
||||
|
||||
class ParserFactory {
|
||||
static readonly PARSERS = [
|
||||
@@ -30,9 +32,11 @@ class ParserFactory {
|
||||
ParserInputMethodManagerService,
|
||||
ParserInputMethodService,
|
||||
ParserProtoLog,
|
||||
ParserScreenRecording,
|
||||
ParserSurfaceFlinger,
|
||||
ParserTransactions,
|
||||
ParserWindowManager,
|
||||
ParserWindowManagerDump,
|
||||
]
|
||||
|
||||
createParsers(buffers: Uint8Array[]): Parser[] {
|
||||
|
||||
@@ -30,7 +30,7 @@ class ParserInputMethodClients extends Parser {
|
||||
return ParserInputMethodClients.MAGIC_NUMBER;
|
||||
}
|
||||
|
||||
override decodeProto(buffer: Uint8Array): any[] {
|
||||
override decodeTrace(buffer: Uint8Array): any[] {
|
||||
return (<any>InputMethodClientsTraceFileProto.decode(buffer)).entry;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ class ParserInputMethodClients extends Parser {
|
||||
return Number(entryProto.elapsedRealtimeNanos);
|
||||
}
|
||||
|
||||
override processTraceEntryProto(entryProto: any): any {
|
||||
override processDecodedEntry(entryProto: any): any {
|
||||
return entryProto;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ class ParserInputMethodManagerService extends Parser {
|
||||
return ParserInputMethodManagerService.MAGIC_NUMBER;
|
||||
}
|
||||
|
||||
override decodeProto(buffer: Uint8Array): any[] {
|
||||
override decodeTrace(buffer: Uint8Array): any[] {
|
||||
return (<any>InputMethodManagerServiceTraceFileProto.decode(buffer)).entry;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ class ParserInputMethodManagerService extends Parser {
|
||||
return Number(entryProto.elapsedRealtimeNanos);
|
||||
}
|
||||
|
||||
protected override processTraceEntryProto(entryProto: any): any {
|
||||
protected override processDecodedEntry(entryProto: any): any {
|
||||
return entryProto;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ class ParserInputMethodService extends Parser {
|
||||
return ParserInputMethodService.MAGIC_NUMBER;
|
||||
}
|
||||
|
||||
override decodeProto(buffer: Uint8Array): any[] {
|
||||
override decodeTrace(buffer: Uint8Array): any[] {
|
||||
return (<any>InputMethodServiceTraceFileProto.decode(buffer)).entry;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ class ParserInputMethodService extends Parser {
|
||||
return Number(entryProto.elapsedRealtimeNanos);
|
||||
}
|
||||
|
||||
override processTraceEntryProto(entryProto: any): any {
|
||||
override processDecodedEntry(entryProto: any): any {
|
||||
return entryProto;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ class ParserProtoLog extends Parser {
|
||||
return ParserProtoLog.MAGIC_NUMBER;
|
||||
}
|
||||
|
||||
override decodeProto(buffer: Uint8Array): any[] {
|
||||
override decodeTrace(buffer: Uint8Array): any[] {
|
||||
const fileProto: any = ProtoLogFileProto.decode(buffer);
|
||||
|
||||
if (fileProto.version !== ParserProtoLog.PROTOLOG_VERSION) {
|
||||
@@ -58,7 +58,7 @@ class ParserProtoLog extends Parser {
|
||||
return Number(entryProto.elapsedRealtimeNanos);
|
||||
}
|
||||
|
||||
override processTraceEntryProto(entryProto: any): LogMessage {
|
||||
override processDecodedEntry(entryProto: any): LogMessage {
|
||||
const message = (<any>configJson).messages[entryProto.messageHash];
|
||||
if (!message) {
|
||||
return new FormattedLogMessage(entryProto);
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import {ScreenRecordingTraceEntry} from "common/trace/screen_recording";
|
||||
import {TraceTypeId} from "common/trace/type_id";
|
||||
import {TestUtils} from 'test/test_utils';
|
||||
import {Parser} from './parser';
|
||||
import {ParserFactory} from './parser_factory';
|
||||
|
||||
describe("ParserScreenRecording", () => {
|
||||
let parser: Parser;
|
||||
|
||||
beforeAll(() => {
|
||||
const buffer = TestUtils.loadFixture("screen_recording.mp4");
|
||||
const parsers = new ParserFactory().createParsers([buffer]);
|
||||
expect(parsers.length).toEqual(1);
|
||||
parser = parsers[0];
|
||||
});
|
||||
|
||||
it("has expected trace type", () => {
|
||||
expect(parser.getTraceTypeId()).toEqual(TraceTypeId.SCREEN_RECORDING);
|
||||
});
|
||||
|
||||
it("provides timestamps", () => {
|
||||
const timestamps = parser.getTimestamps();
|
||||
|
||||
expect(timestamps.length)
|
||||
.toEqual(85);
|
||||
|
||||
expect(timestamps.slice(0, 3))
|
||||
.toEqual([19446131807000, 19446158500000, 19446167117000]);
|
||||
|
||||
expect(timestamps.slice(timestamps.length-3, timestamps.length))
|
||||
.toEqual([19448470076000, 19448487525000, 19448501007000]);
|
||||
});
|
||||
|
||||
it("retrieves trace entry", () => {
|
||||
{
|
||||
const entry = parser.getTraceEntry(19446131807000)!
|
||||
expect(entry).toBeInstanceOf(ScreenRecordingTraceEntry);
|
||||
expect(Number(entry.videoTimeSeconds)).toBeCloseTo(0);
|
||||
}
|
||||
|
||||
{
|
||||
const entry = parser.getTraceEntry(19448501007000)!
|
||||
expect(entry).toBeInstanceOf(ScreenRecordingTraceEntry);
|
||||
expect(Number(entry.videoTimeSeconds)).toBeCloseTo(2.37, 0.001);
|
||||
}
|
||||
});
|
||||
});
|
||||
85
tools/winscope-ng/src/parsers/parser_screen_recording.ts
Normal file
85
tools/winscope-ng/src/parsers/parser_screen_recording.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import {TraceTypeId} from "common/trace/type_id";
|
||||
import {ArrayUtils} from "common/utils/array_utils";
|
||||
import {Parser} from "./parser"
|
||||
import {ScreenRecordingTraceEntry} from "common/trace/screen_recording";
|
||||
|
||||
class ParserScreenRecording extends Parser {
|
||||
constructor(private videoData: Uint8Array) {
|
||||
super(videoData);
|
||||
}
|
||||
|
||||
override getTraceTypeId(): TraceTypeId {
|
||||
return TraceTypeId.SCREEN_RECORDING;
|
||||
}
|
||||
|
||||
override getMagicNumber(): number[] {
|
||||
return ParserScreenRecording.MPEG4_MAGIC_NMBER;
|
||||
}
|
||||
|
||||
override decodeTrace(videoData: Uint8Array): number[] {
|
||||
let posCount = this.searchMagicString(videoData);
|
||||
let [posTimestamps, count] = this.parseTimestampsCount(videoData, posCount);
|
||||
return this.parseTimestamps(videoData, posTimestamps, count);
|
||||
}
|
||||
|
||||
override getTimestamp(decodedEntry: number): number {
|
||||
return decodedEntry;
|
||||
}
|
||||
|
||||
override processDecodedEntry(timestamp: number): ScreenRecordingTraceEntry {
|
||||
const videoTimeSeconds = (timestamp - this.timestamps[0]) / 1000000000 + ParserScreenRecording.EPSILON;
|
||||
return new ScreenRecordingTraceEntry(timestamp, videoTimeSeconds, this.videoData);
|
||||
}
|
||||
|
||||
private searchMagicString(videoData: Uint8Array): number {
|
||||
let pos = ArrayUtils.searchSubarray(videoData, ParserScreenRecording.WINSCOPE_META_MAGIC_STRING);
|
||||
if (pos === undefined) {
|
||||
throw new TypeError("video data doesn't contain winscope magic string");
|
||||
}
|
||||
pos += ParserScreenRecording.WINSCOPE_META_MAGIC_STRING.length;
|
||||
return pos;
|
||||
}
|
||||
|
||||
private parseTimestampsCount(videoData: Uint8Array, pos: number) : [number, number] {
|
||||
if (pos + 4 >= videoData.length) {
|
||||
throw new TypeError("video data is too short. Expected timestamps count doesn't fit");
|
||||
}
|
||||
const timestampsCount = ArrayUtils.toUintLittleEndian(videoData, pos, pos+4);
|
||||
pos += 4;
|
||||
return [pos, timestampsCount];
|
||||
}
|
||||
|
||||
private parseTimestamps(videoData: Uint8Array, pos: number, count: number): number[] {
|
||||
if (pos + count * 8 >= videoData.length) {
|
||||
throw new TypeError("video data is too short. Expected timestamps do not fit");
|
||||
}
|
||||
const timestamps: number[] = [];
|
||||
for (let i = 0; i < count; ++i) {
|
||||
const timestamp = ArrayUtils.toUintLittleEndian(videoData, pos, pos+8) * 1000;
|
||||
pos += 8;
|
||||
timestamps.push(timestamp);
|
||||
}
|
||||
return timestamps;
|
||||
}
|
||||
|
||||
private static readonly MPEG4_MAGIC_NMBER = [0x00, 0x00, 0x00, 0x18, 0x66, 0x74, 0x79, 0x70, 0x6d, 0x70, 0x34, 0x32]; // ....ftypmp42
|
||||
private static readonly WINSCOPE_META_MAGIC_STRING = [0x23, 0x56, 0x56, 0x31, 0x4e, 0x53, 0x43, 0x30, 0x50, 0x45, 0x54, 0x31, 0x4d, 0x45, 0x21, 0x23]; // #VV1NSC0PET1ME!#
|
||||
private static readonly EPSILON = 0.00001;
|
||||
}
|
||||
|
||||
export {ParserScreenRecording};
|
||||
@@ -31,7 +31,7 @@ class ParserSurfaceFlinger extends Parser {
|
||||
return ParserSurfaceFlinger.MAGIC_NUMBER;
|
||||
}
|
||||
|
||||
override decodeProto(buffer: Uint8Array): any[] {
|
||||
override decodeTrace(buffer: Uint8Array): any[] {
|
||||
return (<any>LayersTraceFileProto.decode(buffer)).entry;
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ class ParserSurfaceFlinger extends Parser {
|
||||
return Number(entryProto.elapsedRealtimeNanos);
|
||||
}
|
||||
|
||||
override processTraceEntryProto(entryProto: any): any {
|
||||
override processDecodedEntry(entryProto: any): any {
|
||||
return LayerTraceEntry.fromProto(entryProto.layers.layers, entryProto.displays, entryProto.elapsedRealtimeNanos, entryProto.hwcBlob);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import {TraceTypeId} from "common/trace/type_id";
|
||||
import {LayerTraceEntry} from 'common/trace/flickerlib/layers/LayerTraceEntry';
|
||||
import {TestUtils} from 'test/test_utils';
|
||||
import {Parser} from './parser';
|
||||
import {ParserFactory} from './parser_factory';
|
||||
|
||||
describe("ParserSurfaceFlingerDump", () => {
|
||||
let parser: Parser;
|
||||
|
||||
beforeAll(() => {
|
||||
const buffer = TestUtils.loadFixture("dump_SurfaceFlinger.pb");
|
||||
const parsers = new ParserFactory().createParsers([buffer]);
|
||||
expect(parsers.length).toEqual(1);
|
||||
parser = parsers[0];
|
||||
});
|
||||
|
||||
it("has expected trace type", () => {
|
||||
expect(parser.getTraceTypeId()).toEqual(TraceTypeId.SURFACE_FLINGER);
|
||||
});
|
||||
|
||||
it("provides timestamp", () => {
|
||||
expect(parser.getTimestamps()).toEqual([0]);
|
||||
});
|
||||
|
||||
it("retrieves trace entry", () => {
|
||||
const entry = parser.getTraceEntry(0)!
|
||||
expect(entry).toBeInstanceOf(LayerTraceEntry);
|
||||
expect(Number(entry.timestampMs)).toEqual(0);
|
||||
});
|
||||
});
|
||||
@@ -30,7 +30,7 @@ class ParserTransactions extends Parser {
|
||||
return ParserTransactions.MAGIC_NUMBER;
|
||||
}
|
||||
|
||||
override decodeProto(buffer: Uint8Array): any[] {
|
||||
override decodeTrace(buffer: Uint8Array): any[] {
|
||||
return (<any>TransactionsTraceFileProto.decode(buffer)).entry;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ class ParserTransactions extends Parser {
|
||||
return Number(entryProto.elapsedRealtimeNanos);
|
||||
}
|
||||
|
||||
override processTraceEntryProto(entryProto: any): any {
|
||||
override processDecodedEntry(entryProto: any): any {
|
||||
return entryProto;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ class ParserWindowManager extends Parser {
|
||||
return ParserWindowManager.MAGIC_NUMBER;
|
||||
}
|
||||
|
||||
override decodeProto(buffer: Uint8Array): any {
|
||||
override decodeTrace(buffer: Uint8Array): any[] {
|
||||
return (<any>WindowManagerTraceFileProto.decode(buffer)).entry;
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ class ParserWindowManager extends Parser {
|
||||
return Number(entryProto.elapsedRealtimeNanos);
|
||||
}
|
||||
|
||||
override processTraceEntryProto(entryProto: any): WindowManagerState {
|
||||
override processDecodedEntry(entryProto: any): WindowManagerState {
|
||||
return WindowManagerState.fromProto(entryProto.windowManagerService, entryProto.elapsedRealtimeNanos, entryProto.where);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import {WindowManagerState} from 'common/trace/flickerlib/windows/WindowManagerState';
|
||||
import {TraceTypeId} from "common/trace/type_id";
|
||||
import {ParserFactory} from "./parser_factory";
|
||||
import {Parser} from "./parser";
|
||||
import {TestUtils} from "test/test_utils";
|
||||
|
||||
describe("ParserWindowManagerDump", () => {
|
||||
let parser: Parser;
|
||||
|
||||
beforeAll(() => {
|
||||
const buffer = TestUtils.loadFixture("dump_WindowManager.pb");
|
||||
const parsers = new ParserFactory().createParsers([buffer]);
|
||||
expect(parsers.length).toEqual(1);
|
||||
parser = parsers[0];
|
||||
});
|
||||
|
||||
it("has expected trace type", () => {
|
||||
expect(parser.getTraceTypeId()).toEqual(TraceTypeId.WINDOW_MANAGER);
|
||||
});
|
||||
|
||||
it("provides timestamps", () => {
|
||||
expect(parser.getTimestamps())
|
||||
.toEqual([0]);
|
||||
});
|
||||
|
||||
it("retrieves trace entry", () => {
|
||||
const entry = parser.getTraceEntry(0)!;
|
||||
expect(entry).toBeInstanceOf(WindowManagerState);
|
||||
expect(Number(entry.timestampMs)).toEqual(0);
|
||||
});
|
||||
});
|
||||
47
tools/winscope-ng/src/parsers/parser_window_manager_dump.ts
Normal file
47
tools/winscope-ng/src/parsers/parser_window_manager_dump.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import {TraceTypeId} from "common/trace/type_id";
|
||||
import {Parser} from './parser'
|
||||
import {WindowManagerServiceDumpProto} from './proto_types';
|
||||
import {WindowManagerState} from 'common/trace/flickerlib/windows/WindowManagerState';
|
||||
|
||||
class ParserWindowManagerDump extends Parser {
|
||||
constructor(buffer: Uint8Array) {
|
||||
super(buffer);
|
||||
}
|
||||
|
||||
override getTraceTypeId(): TraceTypeId {
|
||||
return TraceTypeId.WINDOW_MANAGER;
|
||||
}
|
||||
|
||||
override getMagicNumber(): undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
override decodeTrace(buffer: Uint8Array): any[] {
|
||||
return [WindowManagerServiceDumpProto.decode(buffer)];
|
||||
}
|
||||
|
||||
override getTimestamp(entryProto: any): number {
|
||||
return 0;
|
||||
}
|
||||
|
||||
override processDecodedEntry(entryProto: any): WindowManagerState {
|
||||
return WindowManagerState.fromProto(entryProto);
|
||||
}
|
||||
}
|
||||
|
||||
export {ParserWindowManagerDump};
|
||||
@@ -14,6 +14,7 @@ const InputMethodServiceTraceFileProto = protobuf.Root.fromJSON(inputMethodClien
|
||||
const LayersTraceFileProto = protobuf.Root.fromJSON(layersJson).lookupType("android.surfaceflinger.LayersTraceFileProto");
|
||||
const ProtoLogFileProto = protobuf.Root.fromJSON(protoLogJson).lookupType("com.android.internal.protolog.ProtoLogFileProto");
|
||||
const TransactionsTraceFileProto = protobuf.Root.fromJSON(transactionsJson).lookupType("android.surfaceflinger.proto.TransactionTraceFile");
|
||||
const WindowManagerServiceDumpProto = protobuf.Root.fromJSON(windowManagerJson).lookupType("com.android.server.wm.WindowManagerServiceDumpProto");
|
||||
const WindowManagerTraceFileProto = protobuf.Root.fromJSON(windowManagerJson).lookupType("com.android.server.wm.WindowManagerTraceFileProto");
|
||||
|
||||
export {
|
||||
@@ -24,5 +25,6 @@ export {
|
||||
LayersTraceFileProto,
|
||||
ProtoLogFileProto,
|
||||
TransactionsTraceFileProto,
|
||||
WindowManagerServiceDumpProto,
|
||||
WindowManagerTraceFileProto
|
||||
};
|
||||
|
||||
BIN
tools/winscope-ng/src/test/fixtures/dump_SurfaceFlinger.pb
vendored
Normal file
BIN
tools/winscope-ng/src/test/fixtures/dump_SurfaceFlinger.pb
vendored
Normal file
Binary file not shown.
BIN
tools/winscope-ng/src/test/fixtures/dump_WindowManager.pb
vendored
Normal file
BIN
tools/winscope-ng/src/test/fixtures/dump_WindowManager.pb
vendored
Normal file
Binary file not shown.
BIN
tools/winscope-ng/src/test/fixtures/screen_recording.mp4
vendored
Normal file
BIN
tools/winscope-ng/src/test/fixtures/screen_recording.mp4
vendored
Normal file
Binary file not shown.
Reference in New Issue
Block a user