Merge "winscope-ng initial commit"
This commit is contained in:
committed by
Android (Google) Code Review
commit
dc2d967182
44
tools/winscope-ng/.gitignore
vendored
Normal file
44
tools/winscope-ng/.gitignore
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# Compiled output
|
||||
/dist
|
||||
/tmp
|
||||
/out-tsc
|
||||
/bazel-out
|
||||
|
||||
# Node
|
||||
/node_modules
|
||||
npm-debug.log
|
||||
|
||||
# Kotlin transpiled code
|
||||
/kotlin_build
|
||||
|
||||
# IDEs and editors
|
||||
.idea/
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# Visual Studio Code
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
.history/*
|
||||
|
||||
# Miscellaneous
|
||||
/.angular/cache
|
||||
.sass-cache/
|
||||
/connect.lock
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
testem.log
|
||||
/typings
|
||||
|
||||
# System files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
42
tools/winscope-ng/README.md
Normal file
42
tools/winscope-ng/README.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# Tool for visualizing window manager traces
|
||||
|
||||
## Developing WinScope
|
||||
When the trace is enabled, Window Manager and Surface Flinger capture and
|
||||
save current state to a file at each point of interest.
|
||||
`frameworks/base/core/proto/android/server/windowmanagertrace.proto`
|
||||
and `frameworks/native/services/surfaceflinger/layerproto/layerstrace.proto`
|
||||
contain the proto definitions for their internal states.
|
||||
|
||||
### Checking out code and setting up environment
|
||||
* [Download Android source](https://source.android.com/setup/build/downloading)
|
||||
* Navigate to `development/tools/winscope`
|
||||
* Run `npm install`
|
||||
|
||||
### Build & test & deploy changes
|
||||
* Navigate to `development/tools/winscope`
|
||||
* Run `npm run` to get the list of available commands
|
||||
|
||||
### Update IntDefMapping
|
||||
* Build `framework-minus-apex-intdefs` module and a preprocessor will
|
||||
generate the latest IntDefMapping. From the `ANDROID_ROOT` run:
|
||||
```
|
||||
. build/envsetup.sh
|
||||
m framework-minus-apex-intdefs
|
||||
```
|
||||
|
||||
* Copy the generated `intDefMapping.json` files to the `prebuilts` repo.
|
||||
```
|
||||
python3 -c 'import sys,json,collections; print(json.dumps(collections.OrderedDict(sorted(collections.ChainMap(*map(lambda x:json.load(open(x)), sys.argv[1:])).items())), indent=2))' $(find out/soong/.intermediates/frameworks/base -iname intDefMapping.json) > ./prebuilts/misc/common/winscope/intDefMapping.json
|
||||
```
|
||||
|
||||
* Upload the changes.
|
||||
```
|
||||
cd ./prebuilts/misc/common/winscope
|
||||
repo start intdef-update
|
||||
git commit -am "Update intdef mapping" "Test: N/A"
|
||||
repo upload --cbr .
|
||||
```
|
||||
|
||||
### Building with internal extensions
|
||||
Internal paths in vendor/ which are not available in AOSP must be replaced by
|
||||
stub files. See getWaylandSafePath for an example
|
||||
39
tools/winscope-ng/karma.conf.js
Normal file
39
tools/winscope-ng/karma.conf.js
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
const glob = require("glob");
|
||||
|
||||
let webpackConfig = require("./webpack.config.common");
|
||||
delete webpackConfig.entry;
|
||||
delete webpackConfig.output;
|
||||
|
||||
module.exports = (config) => {
|
||||
config.set({
|
||||
frameworks: ["jasmine", "webpack"],
|
||||
plugins: [
|
||||
"karma-webpack",
|
||||
"karma-chrome-launcher",
|
||||
"karma-jasmine",
|
||||
"karma-sourcemap-loader",
|
||||
],
|
||||
files: [{ pattern: "src/main.component.spec.ts", watched: false }],
|
||||
preprocessors: {
|
||||
'src/main.component.spec.ts': ['webpack', 'sourcemap']
|
||||
},
|
||||
singleRun: true,
|
||||
browsers: ["ChromeHeadless"],
|
||||
webpack: webpackConfig
|
||||
});
|
||||
}
|
||||
51
tools/winscope-ng/loaders/proto-loader.js
Normal file
51
tools/winscope-ng/loaders/proto-loader.js
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
const fs = require('fs');
|
||||
const protobuf = require('protobufjs');
|
||||
const loaderUtils = require('loader-utils');
|
||||
|
||||
module.exports = function(source) {
|
||||
const webpackContext = this;
|
||||
const root = new protobuf.Root();
|
||||
const paths = loaderUtils.getOptions(this)['paths'] || [];
|
||||
|
||||
root.resolvePath = function resolvePath(origin, target) {
|
||||
const normOrigin = protobuf.util.path.normalize(origin);
|
||||
const normTarget = protobuf.util.path.normalize(target);
|
||||
|
||||
let candidates = [
|
||||
protobuf.util.path.resolve(normOrigin, normTarget, true)
|
||||
];
|
||||
candidates = candidates.concat(
|
||||
paths.map(path => protobuf.util.path.resolve(path + "/", target))
|
||||
);
|
||||
|
||||
for (const path of candidates) {
|
||||
if (fs.existsSync(path)) {
|
||||
webpackContext.addDependency(path);
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
throw Error(`Failed to resolve path: origin=${origin}, target=${target}, candidates=${candidates}`);
|
||||
};
|
||||
|
||||
root.loadSync(webpackContext.resourcePath).resolveAll();
|
||||
|
||||
const result = JSON.stringify(root, null, 2);
|
||||
|
||||
return `module.exports = ${result}`;
|
||||
};
|
||||
21555
tools/winscope-ng/package-lock.json
generated
Normal file
21555
tools/winscope-ng/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
52
tools/winscope-ng/package.json
Normal file
52
tools/winscope-ng/package.json
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"name": "winscope-ng",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"build:kotlin": "npx kotlinc-js -source-map -source-map-embed-sources always -module-kind commonjs -output kotlin_build/flicker.js ../../../platform_testing/libraries/flicker/src/com/android/server/wm/traces/common",
|
||||
"build:prod": "npm run build:kotlin && cross-env NODE_ENV=production webpack --progress",
|
||||
"start": "cross-env NODE_ENV=development webpack serve --open --hot",
|
||||
"test:unit": "cross-env NODE_ENV=development webpack --config webpack.config.spec.js && jasmine dist/bundle.spec.js",
|
||||
"test:component": "npx karma start",
|
||||
"test:all": "npm run test:unit && npm run test:component"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^14.0.0",
|
||||
"@angular/common": "^14.0.0",
|
||||
"@angular/compiler": "^14.0.0",
|
||||
"@angular/core": "^14.0.1",
|
||||
"@angular/elements": "^14.0.1",
|
||||
"@angular/forms": "^14.0.0",
|
||||
"@angular/platform-browser": "^14.0.0",
|
||||
"@angular/platform-browser-dynamic": "^14.0.0",
|
||||
"@angular/router": "^14.0.0",
|
||||
"angular2-template-loader": "^0.6.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"html-loader": "^3.1.0",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"kotlin": "^1.7.0",
|
||||
"kotlin-compiler": "^1.7.0",
|
||||
"loader-utils": "^2.0.0",
|
||||
"protobufjs": "^6.11.3",
|
||||
"rxjs": "~7.5.0",
|
||||
"tslib": "^2.3.0",
|
||||
"ts-loader": "^9.3.0",
|
||||
"typescript": "~4.7.2",
|
||||
"webpack": "^5.73.0",
|
||||
"webpack-cli": "^4.10.0",
|
||||
"zone.js": "~0.11.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^14.0.0",
|
||||
"@angular/cli": "~14.0.0",
|
||||
"@angular/compiler-cli": "^14.0.0",
|
||||
"@types/jasmine": "~4.0.0",
|
||||
"jasmine": "^4.2.1",
|
||||
"jasmine-core": "~4.1.0",
|
||||
"karma": "~6.3.0",
|
||||
"karma-chrome-launcher": "~3.1.0",
|
||||
"karma-jasmine": "~5.0.0",
|
||||
"karma-sourcemap-loader": "^0.3.8",
|
||||
"karma-webpack": "^5.0.0"
|
||||
}
|
||||
}
|
||||
47
tools/winscope-ng/src/app/app.component.spec.ts
Normal file
47
tools/winscope-ng/src/app/app.component.spec.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 {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
import {AppComponent} from './app.component';
|
||||
|
||||
describe("AppComponent", () => {
|
||||
let fixture: ComponentFixture<AppComponent>;
|
||||
let component: AppComponent;
|
||||
let htmlElement: HTMLElement;
|
||||
|
||||
beforeAll(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [
|
||||
AppComponent
|
||||
],
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(AppComponent);
|
||||
component = fixture.componentInstance;
|
||||
htmlElement = fixture.nativeElement;
|
||||
});
|
||||
|
||||
it("can be created", () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it("has the expected title", () => {
|
||||
expect(component.title).toEqual("winscope-ng");
|
||||
});
|
||||
|
||||
it("renders the title", () => {
|
||||
expect(htmlElement.querySelector("div#title")?.innerHTML).toContain("Winscope Viewer 2.0");
|
||||
});
|
||||
});
|
||||
95
tools/winscope-ng/src/app/app.component.ts
Normal file
95
tools/winscope-ng/src/app/app.component.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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 {Component, Injector, Inject} from '@angular/core';
|
||||
import {createCustomElement} from '@angular/elements';
|
||||
import {ViewerWindowManagerComponent} from 'viewers/viewer_window_manager/viewer_window_manager.component';
|
||||
import {Core} from './core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
template: `
|
||||
<div id="title">
|
||||
<span>Winscope Viewer 2.0</span>
|
||||
</div>
|
||||
|
||||
<div id="inputfile">
|
||||
<input type="file" (change)="onInputFile($event)" #fileUpload>
|
||||
</div>
|
||||
|
||||
<div id="timescrub">
|
||||
<button (click)="notifyCurrentTimestamp()">Update current timestamp</button>
|
||||
</div>
|
||||
|
||||
<div id="viewers">
|
||||
</div>
|
||||
|
||||
<div id="timestamps">
|
||||
</div>
|
||||
`
|
||||
})
|
||||
export class AppComponent {
|
||||
title = 'winscope-ng';
|
||||
|
||||
private core!: Core;
|
||||
|
||||
constructor(@Inject(Injector) injector: Injector) {
|
||||
customElements.define('viewer-window-manager',
|
||||
createCustomElement(ViewerWindowManagerComponent, {injector}));
|
||||
}
|
||||
|
||||
public async onInputFile(event: Event) {
|
||||
const buffers = await this.readInputFiles(event);
|
||||
|
||||
|
||||
this.core = new Core();
|
||||
await this.core.bootstrap(buffers);
|
||||
|
||||
const viewersDiv = document.querySelector("div#viewers")!;
|
||||
viewersDiv.innerHTML = "";
|
||||
this.core.getViews().forEach(view => viewersDiv!.appendChild(view) );
|
||||
|
||||
const timestampsDiv = document.querySelector("div#timestamps")!;
|
||||
timestampsDiv.innerHTML = `Retrieved ${this.core.getTimestamps().length} unique timestamps`;
|
||||
}
|
||||
|
||||
public notifyCurrentTimestamp() {
|
||||
const dummyTimestamp = 1000000; //TODO: get timestamp from time scrub
|
||||
this.core.notifyCurrentTimestamp(dummyTimestamp)
|
||||
}
|
||||
|
||||
//TODO: extend with support for multiple files, archives, etc...
|
||||
private async readInputFiles(event: Event): Promise<Uint8Array[]> {
|
||||
const files: any = (event?.target as HTMLInputElement)?.files;
|
||||
|
||||
if (!files || !files[0]) {
|
||||
console.log("Invalid input file");
|
||||
return [];
|
||||
}
|
||||
|
||||
const file: File = files[0];
|
||||
|
||||
const buffer: Uint8Array = await new Promise((resolve, _) => {
|
||||
const reader = new FileReader();
|
||||
reader.onloadend = async (e) => {
|
||||
const buffer = new Uint8Array(<ArrayBuffer> e.target!.result);
|
||||
resolve(buffer);
|
||||
};
|
||||
reader.readAsArrayBuffer(file);
|
||||
});
|
||||
|
||||
return [buffer];
|
||||
}
|
||||
}
|
||||
18
tools/winscope-ng/src/app/app.module.ts
Normal file
18
tools/winscope-ng/src/app/app.module.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
import { ViewerWindowManagerComponent} from 'viewers/viewer_window_manager/viewer_window_manager.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
ViewerWindowManagerComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule
|
||||
],
|
||||
providers: [],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
||||
76
tools/winscope-ng/src/app/core.ts
Normal file
76
tools/winscope-ng/src/app/core.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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 'parsers/parser'
|
||||
import {ParserFactory} from 'parsers/parser_factory'
|
||||
import {Viewer} from 'viewers/viewer'
|
||||
import {ViewerFactory} from 'viewers/viewer_factory'
|
||||
|
||||
class Core {
|
||||
private parsers: Parser[];
|
||||
private viewers: Viewer[];
|
||||
|
||||
constructor() {
|
||||
this.parsers = [];
|
||||
this.viewers = [];
|
||||
}
|
||||
|
||||
async bootstrap(buffers: Uint8Array[]) {
|
||||
this.parsers = new ParserFactory().createParsers(buffers);
|
||||
console.log("created parsers: ", this.parsers);
|
||||
|
||||
const activeTraceTypes = this.parsers.map(parser => parser.getTraceTypeId());
|
||||
console.log("active trace types: ", activeTraceTypes);
|
||||
|
||||
this.viewers = new ViewerFactory().createViewers(new Set<TraceTypeId>(activeTraceTypes));
|
||||
console.log("created viewers: ", this.viewers);
|
||||
}
|
||||
|
||||
getViews(): HTMLElement[] {
|
||||
return this.viewers.map(viewer => viewer.getView());
|
||||
}
|
||||
|
||||
getTimestamps(): number[] {
|
||||
const mergedTimestamps: number[] = [];
|
||||
|
||||
this.parsers
|
||||
.map(parser => parser.getTimestamps())
|
||||
.forEach(timestamps => {
|
||||
mergedTimestamps.push(...timestamps);
|
||||
});
|
||||
|
||||
const uniqueTimestamps = [... new Set<number>(mergedTimestamps)];
|
||||
|
||||
return uniqueTimestamps;
|
||||
}
|
||||
|
||||
notifyCurrentTimestamp(timestamp: number) {
|
||||
const traceEntries: Map<TraceTypeId, any> = new Map<TraceTypeId, any>();
|
||||
|
||||
this.parsers.forEach(parser => {
|
||||
const entry = parser.getTraceEntry(timestamp);
|
||||
if (entry != undefined) {
|
||||
traceEntries.set(parser.getTraceTypeId(), entry);
|
||||
}
|
||||
});
|
||||
|
||||
this.viewers.forEach(viewer => {
|
||||
viewer.notifyCurrentTraceEntries(traceEntries);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export { Core };
|
||||
0
tools/winscope-ng/src/assets/.gitkeep
Normal file
0
tools/winscope-ng/src/assets/.gitkeep
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"invalidProperties": [
|
||||
"length",
|
||||
"prototype",
|
||||
"ref",
|
||||
"diff",
|
||||
"rects",
|
||||
"chips",
|
||||
"parent",
|
||||
"timestamp",
|
||||
"shortName",
|
||||
"kind",
|
||||
"resolvedChildren",
|
||||
"visibilityReason",
|
||||
"absoluteZ",
|
||||
"children",
|
||||
"stableId"
|
||||
],
|
||||
"intDefColumn": {
|
||||
"WindowLayoutParams.type": "android.view.WindowManager.LayoutParams.WindowType",
|
||||
"WindowLayoutParams.flags": "android.view.WindowManager.LayoutParams.Flags",
|
||||
"WindowLayoutParams.privateFlags": "android.view.WindowManager.LayoutParams.PrivateFlags",
|
||||
"WindowLayoutParams.gravity": "android.view.Gravity.GravityFlags",
|
||||
"WindowLayoutParams.softInputMode": "android.view.WindowManager.LayoutParams.WindowType",
|
||||
"WindowLayoutParams.systemUiVisibilityFlags": "android.view.WindowManager.LayoutParams.SystemUiVisibilityFlags",
|
||||
"WindowLayoutParams.subtreeSystemUiVisibilityFlags": "android.view.WindowManager.LayoutParams.SystemUiVisibilityFlags",
|
||||
"WindowLayoutParams.behavior": "android.view.WindowInsetsController.Behavior",
|
||||
"WindowLayoutParams.fitInsetsSides": "android.view.WindowInsets.Side.InsetsSide",
|
||||
"Configuration.windowingMode": "android.app.WindowConfiguration.WindowingMode",
|
||||
"WindowConfiguration.windowingMode": "android.app.WindowConfiguration.WindowingMode",
|
||||
"Configuration.orientation": "android.content.pm.ActivityInfo.ScreenOrientation",
|
||||
"WindowConfiguration.orientation": "android.content.pm.ActivityInfo.ScreenOrientation",
|
||||
"WindowState.orientation": "android.content.pm.ActivityInfo.ScreenOrientation"
|
||||
}
|
||||
}
|
||||
278
tools/winscope-ng/src/common/trace/flickerlib/ObjectFormatter.ts
Normal file
278
tools/winscope-ng/src/common/trace/flickerlib/ObjectFormatter.ts
Normal file
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* Copyright 2021, 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 {toSize, toActiveBuffer, toColor, toColor3, toPoint, toRect,
|
||||
toRectF, toRegion, toMatrix22, toTransform} from './common';
|
||||
import intDefMapping from
|
||||
'../../../../../../../prebuilts/misc/common/winscope/intDefMapping.json';
|
||||
import config from './Configuration.json'
|
||||
|
||||
function readIntdefMap(): Map<string, string> {
|
||||
const map = new Map<string, string>();
|
||||
const keys = Object.keys(config.intDefColumn);
|
||||
|
||||
keys.forEach(key => {
|
||||
const value = config.intDefColumn[<keyof typeof config.intDefColumn>key];
|
||||
map.set(key, value);
|
||||
});
|
||||
|
||||
return map;
|
||||
}
|
||||
export default class ObjectFormatter {
|
||||
static displayDefaults: boolean = false
|
||||
private static INVALID_ELEMENT_PROPERTIES = config.invalidProperties;
|
||||
|
||||
private static FLICKER_INTDEF_MAP = readIntdefMap();
|
||||
|
||||
static cloneObject(entry: any): any {
|
||||
let obj: any = {}
|
||||
const properties = ObjectFormatter.getProperties(entry);
|
||||
properties.forEach(prop => obj[prop] = entry[prop]);
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the true properties of an entry excluding functions, kotlin gernerated
|
||||
* variables, explicitly excluded properties, and flicker objects already in
|
||||
* the hierarchy that shouldn't be traversed when formatting the entry
|
||||
* @param entry The entry for which we want to get the properties for
|
||||
* @return The "true" properties of the entry as described above
|
||||
*/
|
||||
static getProperties(entry: any): string[] {
|
||||
const props: string[] = [];
|
||||
let obj = entry;
|
||||
|
||||
do {
|
||||
const properties = Object.getOwnPropertyNames(obj).filter(it => {
|
||||
// filter out functions
|
||||
if (typeof(entry[it]) === 'function') return false;
|
||||
// internal propertires from kotlinJs
|
||||
if (it.includes(`$`)) return false;
|
||||
// private kotlin variables from kotlin
|
||||
if (it.startsWith(`_`)) return false;
|
||||
// some predefined properties used only internally (e.g., children, ref, diff)
|
||||
if (this.INVALID_ELEMENT_PROPERTIES.includes(it)) return false;
|
||||
|
||||
const value = entry[it];
|
||||
// only non-empty arrays of non-flicker objects (otherwise they are in hierarchy)
|
||||
if (Array.isArray(value) && value.length > 0) return !value[0].stableId;
|
||||
// non-flicker object
|
||||
return !(value?.stableId);
|
||||
});
|
||||
properties.forEach(function (prop) {
|
||||
if (typeof(entry[prop]) !== 'function' && props.indexOf(prop) === -1) {
|
||||
props.push(prop);
|
||||
}
|
||||
});
|
||||
} while (obj = Object.getPrototypeOf(obj));
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a Winscope entry to be displayed in the UI
|
||||
* Accounts for different user display settings (e.g. hiding empty/default values)
|
||||
* @param obj The raw object to format
|
||||
* @return The formatted object
|
||||
*/
|
||||
static format(obj: any): {} {
|
||||
const properties = this.getProperties(obj);
|
||||
const sortedProperties = properties.sort()
|
||||
|
||||
const result: any = {}
|
||||
sortedProperties.forEach(entry => {
|
||||
const key = entry;
|
||||
const value: any = obj[key];
|
||||
|
||||
if (value === null || value === undefined) {
|
||||
if (this.displayDefaults) {
|
||||
result[key] = value;
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (value || this.displayDefaults) {
|
||||
// raw values (e.g., false or 0)
|
||||
if (!value) {
|
||||
result[key] = value
|
||||
// flicker obj
|
||||
} else if (value.prettyPrint) {
|
||||
const isEmpty = value.isEmpty === true;
|
||||
if (!isEmpty || this.displayDefaults) {
|
||||
result[key] = value.prettyPrint();
|
||||
}
|
||||
} else {
|
||||
// converted proto to flicker
|
||||
const translatedObject = this.translateObject(value);
|
||||
if (translatedObject) {
|
||||
if (translatedObject.prettyPrint) {
|
||||
result[key] = translatedObject.prettyPrint();
|
||||
}
|
||||
else {
|
||||
result[key] = translatedObject;
|
||||
}
|
||||
// objects - recursive call
|
||||
} else if (value && typeof(value) == `object`) {
|
||||
const childObj = this.format(value) as any;
|
||||
const isEmpty = Object.entries(childObj).length == 0 || childObj.isEmpty;
|
||||
if (!isEmpty || this.displayDefaults) {
|
||||
result[key] = childObj;
|
||||
}
|
||||
} else {
|
||||
// values
|
||||
result[key] = this.translateIntDef(obj, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate some predetermined proto objects into their flicker equivalent
|
||||
*
|
||||
* Returns null if the object cannot be translated
|
||||
*
|
||||
* @param obj Object to translate
|
||||
*/
|
||||
private static translateObject(obj: any) {
|
||||
const type = obj?.$type?.name;
|
||||
switch(type) {
|
||||
case `SizeProto`: return toSize(obj);
|
||||
case `ActiveBufferProto`: return toActiveBuffer(obj);
|
||||
case `Color3`: return toColor3(obj);
|
||||
case `ColorProto`: return toColor(obj);
|
||||
case `PointProto`: return toPoint(obj);
|
||||
case `RectProto`: return toRect(obj);
|
||||
case `Matrix22`: return toMatrix22(obj);
|
||||
case `FloatRectProto`: return toRectF(obj);
|
||||
case `RegionProto`: return toRegion(obj);
|
||||
case `TransformProto`: return toTransform(obj);
|
||||
case 'ColorTransformProto': {
|
||||
const formatted = this.formatColorTransform(obj.val);
|
||||
return `${formatted}`;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static formatColorTransform(vals: any) {
|
||||
const fixedVals = vals.map((v: any) => v.toFixed(1));
|
||||
let formatted = ``;
|
||||
for (let i = 0; i < fixedVals.length; i += 4) {
|
||||
formatted += `[`;
|
||||
formatted += fixedVals.slice(i, i + 4).join(', ');
|
||||
formatted += `] `;
|
||||
}
|
||||
return formatted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains from the proto field, the metadata related to the typedef type (if any)
|
||||
*
|
||||
* @param obj Proto object
|
||||
* @param propertyName Property to search
|
||||
*/
|
||||
private static getTypeDefSpec(obj: any, propertyName: string): string|null {
|
||||
const fields = obj?.$type?.fields;
|
||||
if (!fields) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const options = fields[propertyName]?.options;
|
||||
if (!options) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return options["(.android.typedef)"];
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate intdef properties into their string representation
|
||||
*
|
||||
* For proto objects check the
|
||||
*
|
||||
* @param parentObj Object containing the value to parse
|
||||
* @param propertyName Property to search
|
||||
* @param value Property value
|
||||
*/
|
||||
private static translateIntDef(parentObj: any, propertyName: string, value: any): string {
|
||||
const parentClassName = parentObj.constructor.name;
|
||||
const propertyPath = `${parentClassName}.${propertyName}`;
|
||||
|
||||
let translatedValue: string = value;
|
||||
// Parse Flicker objects (no intdef annotation supported)
|
||||
if (this.FLICKER_INTDEF_MAP.has(propertyPath)) {
|
||||
translatedValue = this.getIntFlagsAsStrings(value,
|
||||
<string>this.FLICKER_INTDEF_MAP.get(propertyPath));
|
||||
} else {
|
||||
// If it's a proto, search on the proto definition for the intdef type
|
||||
const typeDefSpec = this.getTypeDefSpec(parentObj, propertyName);
|
||||
if (typeDefSpec) {
|
||||
translatedValue = this.getIntFlagsAsStrings(value, typeDefSpec);
|
||||
}
|
||||
}
|
||||
|
||||
return translatedValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate a property from its numerical value into its string representation
|
||||
*
|
||||
* @param intFlags Property value
|
||||
* @param annotationType IntDef type to use
|
||||
*/
|
||||
private static getIntFlagsAsStrings(intFlags: any, annotationType: string): string {
|
||||
const flags = [];
|
||||
|
||||
const mapping = intDefMapping[<keyof typeof intDefMapping>annotationType].values;
|
||||
const knownFlagValues = Object.keys(mapping).reverse().map(x => parseInt(x));
|
||||
|
||||
if (knownFlagValues.length == 0) {
|
||||
console.warn("No mapping for type", annotationType)
|
||||
return intFlags + ""
|
||||
}
|
||||
|
||||
// Will only contain bits that have not been associated with a flag.
|
||||
const parsedIntFlags = parseInt(intFlags);
|
||||
let leftOver = parsedIntFlags;
|
||||
|
||||
for (const flagValue of knownFlagValues) {
|
||||
if (((leftOver & flagValue) && ((intFlags & flagValue) === flagValue))
|
||||
|| (parsedIntFlags === 0 && flagValue === 0)) {
|
||||
flags.push(mapping[<keyof typeof mapping>flagValue]);
|
||||
|
||||
leftOver = leftOver & ~flagValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags.length === 0) {
|
||||
console.error('No valid flag mappings found for ',
|
||||
intFlags, 'of type', annotationType);
|
||||
}
|
||||
|
||||
if (leftOver) {
|
||||
// If 0 is a valid flag value that isn't in the intDefMapping
|
||||
// it will be ignored
|
||||
flags.push(leftOver);
|
||||
}
|
||||
|
||||
return flags.join(' | ');
|
||||
}
|
||||
}
|
||||
12
tools/winscope-ng/src/common/trace/flickerlib/README.md
Normal file
12
tools/winscope-ng/src/common/trace/flickerlib/README.md
Normal file
@@ -0,0 +1,12 @@
|
||||
This directory contains all the code extending the common Flicker library
|
||||
to make it fully compatible with Winscope. The common Flicker library is
|
||||
written is Kotlin and compiled to JavaScript and then extended by the code in
|
||||
this directory.
|
||||
|
||||
To use flickerlib in the rest of the Winscope source code use
|
||||
`import { ... } from '@/flickerlib'` rather than importing the compiled
|
||||
common Flicker library directly.
|
||||
|
||||
The flickerlib classes are extended through mixins (functions, getter, and
|
||||
setters) that are injected into the original compiled common Flicker library
|
||||
classes.
|
||||
313
tools/winscope-ng/src/common/trace/flickerlib/common.js
Normal file
313
tools/winscope-ng/src/common/trace/flickerlib/common.js
Normal file
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
* Copyright 2020, 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.
|
||||
*/
|
||||
|
||||
// Imports all the compiled common Flicker library classes and exports them
|
||||
// as clean es6 modules rather than having them be commonjs modules
|
||||
|
||||
// WM
|
||||
const WindowManagerTrace = require('flicker').com.android.server.wm.traces.
|
||||
common.windowmanager.WindowManagerTrace;
|
||||
const WindowManagerState = require('flicker').com.android.server.wm.traces.
|
||||
common.windowmanager.WindowManagerState;
|
||||
const Activity = require('flicker').com.android.server.wm.traces.common.
|
||||
windowmanager.windows.Activity;
|
||||
const Configuration = require('flicker').com.android.server.wm.traces.common.
|
||||
windowmanager.windows.Configuration;
|
||||
const ConfigurationContainer = require('flicker').com.android.server.wm.traces.
|
||||
common.windowmanager.windows.ConfigurationContainer;
|
||||
const DisplayArea = require('flicker').com.android.server.wm.traces.common.
|
||||
windowmanager.windows.DisplayArea;
|
||||
const DisplayContent = require('flicker').com.android.server.wm.traces.common.
|
||||
windowmanager.windows.DisplayContent;
|
||||
const KeyguardControllerState = require('flicker').com.android.server.wm.
|
||||
traces.common.windowmanager.windows.KeyguardControllerState;
|
||||
const RootWindowContainer = require('flicker').com.android.server.wm.traces.
|
||||
common.windowmanager.windows.RootWindowContainer;
|
||||
const Task = require('flicker').com.android.server.wm.traces.common.
|
||||
windowmanager.windows.Task;
|
||||
const TaskFragment = require('flicker').com.android.server.wm.traces.common.
|
||||
windowmanager.windows.TaskFragment;
|
||||
const WindowConfiguration = require('flicker').com.android.server.wm.traces.
|
||||
common.windowmanager.windows.WindowConfiguration;
|
||||
const WindowContainer = require('flicker').com.android.server.wm.traces.common.
|
||||
windowmanager.windows.WindowContainer;
|
||||
const WindowLayoutParams= require('flicker').com.android.server.wm.traces.
|
||||
common.windowmanager.windows.WindowLayoutParams;
|
||||
const WindowManagerPolicy = require('flicker').com.android.server.wm.traces.
|
||||
common.windowmanager.windows.WindowManagerPolicy;
|
||||
const WindowState = require('flicker').com.android.server.wm.traces.common.
|
||||
windowmanager.windows.WindowState;
|
||||
const WindowToken = require('flicker').com.android.server.wm.traces.common.
|
||||
windowmanager.windows.WindowToken;
|
||||
|
||||
// SF
|
||||
const Layer = require('flicker').com.android.server.wm.traces.common.
|
||||
layers.Layer;
|
||||
const BaseLayerTraceEntry = require('flicker').com.android.server.wm.traces.common.
|
||||
layers.BaseLayerTraceEntry;
|
||||
const LayerTraceEntry = require('flicker').com.android.server.wm.traces.common.
|
||||
layers.LayerTraceEntry;
|
||||
const LayerTraceEntryBuilder = require('flicker').com.android.server.wm.traces.
|
||||
common.layers.LayerTraceEntryBuilder;
|
||||
const LayersTrace = require('flicker').com.android.server.wm.traces.common.
|
||||
layers.LayersTrace;
|
||||
const Matrix22 = require('flicker').com.android.server.wm.traces.common
|
||||
.Matrix22;
|
||||
const Matrix33 = require('flicker').com.android.server.wm.traces.common
|
||||
.Matrix33;
|
||||
const Transform = require('flicker').com.android.server.wm.traces.common.
|
||||
layers.Transform;
|
||||
const Display = require('flicker').com.android.server.wm.traces.common.
|
||||
layers.Display;
|
||||
|
||||
// Common
|
||||
const Size = require('flicker').com.android.server.wm.traces.common.Size;
|
||||
const ActiveBuffer = require('flicker').com.android.server.wm.traces.common
|
||||
.ActiveBuffer;
|
||||
const Color3 = require('flicker').com.android.server.wm.traces.common.Color3;
|
||||
const Color = require('flicker').com.android.server.wm.traces.common.Color;
|
||||
const Point = require('flicker').com.android.server.wm.traces.common.Point;
|
||||
const Rect = require('flicker').com.android.server.wm.traces.common.Rect;
|
||||
const RectF = require('flicker').com.android.server.wm.traces.common.RectF;
|
||||
const Region = require('flicker').com.android.server.wm.traces.common.region.Region;
|
||||
|
||||
//Tags
|
||||
const Tag = require('flicker').com.android.server.wm.traces.common.tags.Tag;
|
||||
const TagState = require('flicker').com.android.server.wm.traces.common.tags.TagState;
|
||||
const TagTrace = require('flicker').com.android.server.wm.traces.common.tags.TagTrace;
|
||||
|
||||
//Errors
|
||||
const Error = require('flicker').com.android.server.wm.traces.common.errors.Error;
|
||||
const ErrorState = require('flicker').com.android.server.wm.traces.common.errors.ErrorState;
|
||||
const ErrorTrace = require('flicker').com.android.server.wm.traces.common.errors.ErrorTrace;
|
||||
|
||||
// Service
|
||||
const TaggingEngine = require('flicker').com.android.server.wm.traces.common.service.TaggingEngine;
|
||||
|
||||
const EMPTY_BUFFER = new ActiveBuffer(0, 0, 0, 0);
|
||||
const EMPTY_COLOR3 = new Color3(-1, -1, -1);
|
||||
const EMPTY_COLOR = new Color(-1, -1, -1, 0);
|
||||
const EMPTY_RECT = new Rect(0, 0, 0, 0);
|
||||
const EMPTY_RECTF = new RectF(0, 0, 0, 0);
|
||||
const EMPTY_POINT = new Point(0, 0);
|
||||
const EMPTY_MATRIX22 = new Matrix22(0, 0, 0, 0, 0, 0);
|
||||
const EMPTY_MATRIX33 = new Matrix33(0, 0, 0, 0, 0, 0);
|
||||
const EMPTY_TRANSFORM = new Transform(0, EMPTY_MATRIX33);
|
||||
|
||||
function toSize(proto) {
|
||||
if (proto == null) {
|
||||
return EMPTY_BOUNDS;
|
||||
}
|
||||
const width = proto.width ?? proto.w ?? 0;
|
||||
const height = proto.height ?? proto.h ?? 0;
|
||||
if (width || height) {
|
||||
return new Size(width, height);
|
||||
}
|
||||
return EMPTY_BOUNDS;
|
||||
}
|
||||
|
||||
function toActiveBuffer(proto) {
|
||||
const width = proto?.width ?? 0;
|
||||
const height = proto?.height ?? 0;
|
||||
const stride = proto?.stride ?? 0;
|
||||
const format = proto?.format ?? 0;
|
||||
|
||||
if (width || height || stride || format) {
|
||||
return new ActiveBuffer(width, height, stride, format);
|
||||
}
|
||||
return EMPTY_BUFFER;
|
||||
}
|
||||
|
||||
function toColor3(proto) {
|
||||
if (proto == null) {
|
||||
return EMPTY_COLOR;
|
||||
}
|
||||
const r = proto.r ?? 0;
|
||||
const g = proto.g ?? 0;
|
||||
const b = proto.b ?? 0;
|
||||
if (r || g || b) {
|
||||
return new Color3(r, g, b);
|
||||
}
|
||||
return EMPTY_COLOR3;
|
||||
}
|
||||
|
||||
function toColor(proto) {
|
||||
if (proto == null) {
|
||||
return EMPTY_COLOR;
|
||||
}
|
||||
const r = proto.r ?? 0;
|
||||
const g = proto.g ?? 0;
|
||||
const b = proto.b ?? 0;
|
||||
const a = proto.a ?? 0;
|
||||
if (r || g || b || a) {
|
||||
return new Color(r, g, b, a);
|
||||
}
|
||||
return EMPTY_COLOR;
|
||||
}
|
||||
|
||||
function toPoint(proto) {
|
||||
if (proto == null) {
|
||||
return null;
|
||||
}
|
||||
const x = proto.x ?? 0;
|
||||
const y = proto.y ?? 0;
|
||||
if (x || y) {
|
||||
return new Point(x, y);
|
||||
}
|
||||
return EMPTY_POINT;
|
||||
}
|
||||
|
||||
function toRect(proto) {
|
||||
if (proto == null) {
|
||||
return EMPTY_RECT;
|
||||
}
|
||||
|
||||
const left = proto?.left ?? 0;
|
||||
const top = proto?.top ?? 0;
|
||||
const right = proto?.right ?? 0;
|
||||
const bottom = proto?.bottom ?? 0;
|
||||
if (left || top || right || bottom) {
|
||||
return new Rect(left, top, right, bottom);
|
||||
}
|
||||
return EMPTY_RECT;
|
||||
}
|
||||
|
||||
function toRectF(proto) {
|
||||
if (proto == null) {
|
||||
return EMPTY_RECTF;
|
||||
}
|
||||
|
||||
const left = proto?.left ?? 0;
|
||||
const top = proto?.top ?? 0;
|
||||
const right = proto?.right ?? 0;
|
||||
const bottom = proto?.bottom ?? 0;
|
||||
if (left || top || right || bottom) {
|
||||
return new RectF(left, top, right, bottom);
|
||||
}
|
||||
return EMPTY_RECTF;
|
||||
}
|
||||
|
||||
function toRegion(proto) {
|
||||
if (proto == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const rects = [];
|
||||
for (let x = 0; x < proto.rect.length; x++) {
|
||||
const rect = proto.rect[x];
|
||||
const parsedRect = toRect(rect);
|
||||
rects.push(parsedRect);
|
||||
}
|
||||
|
||||
return new Region(rects);
|
||||
}
|
||||
|
||||
function toTransform(proto) {
|
||||
if (proto == null) {
|
||||
return EMPTY_TRANSFORM;
|
||||
}
|
||||
const dsdx = proto.dsdx ?? 0;
|
||||
const dtdx = proto.dtdx ?? 0;
|
||||
const tx = proto.tx ?? 0;
|
||||
const dsdy = proto.dsdy ?? 0;
|
||||
const dtdy = proto.dtdy ?? 0;
|
||||
const ty = proto.ty ?? 0;
|
||||
|
||||
if (dsdx || dtdx || tx || dsdy || dtdy || ty) {
|
||||
const matrix = new Matrix33(dsdx, dtdx, tx, dsdy, dtdy, ty);
|
||||
return new Transform(proto.type ?? 0, matrix);
|
||||
}
|
||||
|
||||
if (proto.type) {
|
||||
return new Transform(proto.type ?? 0, EMPTY_MATRIX33);
|
||||
}
|
||||
return EMPTY_TRANSFORM;
|
||||
}
|
||||
|
||||
function toMatrix22(proto) {
|
||||
if (proto == null) {
|
||||
return EMPTY_MATRIX22;
|
||||
}
|
||||
const dsdx = proto.dsdx ?? 0;
|
||||
const dtdx = proto.dtdx ?? 0;
|
||||
const dsdy = proto.dsdy ?? 0;
|
||||
const dtdy = proto.dtdy ?? 0;
|
||||
|
||||
if (dsdx || dtdx || dsdy || dtdy) {
|
||||
return new Matrix22(dsdx, dtdx, dsdy, dtdy);
|
||||
}
|
||||
|
||||
return EMPTY_MATRIX22;
|
||||
}
|
||||
|
||||
export {
|
||||
Activity,
|
||||
Configuration,
|
||||
ConfigurationContainer,
|
||||
DisplayArea,
|
||||
DisplayContent,
|
||||
KeyguardControllerState,
|
||||
RootWindowContainer,
|
||||
Task,
|
||||
TaskFragment,
|
||||
WindowConfiguration,
|
||||
WindowContainer,
|
||||
WindowState,
|
||||
WindowToken,
|
||||
WindowLayoutParams,
|
||||
WindowManagerPolicy,
|
||||
WindowManagerTrace,
|
||||
WindowManagerState,
|
||||
// SF
|
||||
BaseLayerTraceEntry,
|
||||
Layer,
|
||||
LayerTraceEntry,
|
||||
LayerTraceEntryBuilder,
|
||||
LayersTrace,
|
||||
Transform,
|
||||
Matrix22,
|
||||
Matrix33,
|
||||
Display,
|
||||
// Tags
|
||||
Tag,
|
||||
TagState,
|
||||
TagTrace,
|
||||
// Errors
|
||||
Error,
|
||||
ErrorState,
|
||||
ErrorTrace,
|
||||
// Common
|
||||
Size,
|
||||
ActiveBuffer,
|
||||
Color,
|
||||
Color3,
|
||||
Point,
|
||||
Rect,
|
||||
RectF,
|
||||
Region,
|
||||
// Service
|
||||
TaggingEngine,
|
||||
toSize,
|
||||
toActiveBuffer,
|
||||
toColor,
|
||||
toColor3,
|
||||
toPoint,
|
||||
toRect,
|
||||
toRectF,
|
||||
toRegion,
|
||||
toMatrix22,
|
||||
toTransform,
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2021, 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 { Error } from "../common"
|
||||
|
||||
Error.fromProto = function (proto: any): Error {
|
||||
const error = new Error(
|
||||
proto.stacktrace,
|
||||
proto.message,
|
||||
proto.layerId,
|
||||
proto.windowToken,
|
||||
proto.taskId,
|
||||
proto.assertionName
|
||||
);
|
||||
return error;
|
||||
}
|
||||
|
||||
export default Error;
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2020, 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 { ErrorState } from "../common";
|
||||
import Error from './Error';
|
||||
|
||||
ErrorState.fromProto = function (protos: any[], timestamp: number): ErrorState {
|
||||
const errors = protos.map(it => Error.fromProto(it));
|
||||
const state = new ErrorState(errors, `${timestamp}`);
|
||||
return state;
|
||||
}
|
||||
|
||||
export default ErrorState;
|
||||
109
tools/winscope-ng/src/common/trace/flickerlib/layers/Layer.ts
Normal file
109
tools/winscope-ng/src/common/trace/flickerlib/layers/Layer.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2021, 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 { Layer, Rect, toActiveBuffer, toColor, toRect, toRectF, toRegion } from "../common"
|
||||
import { shortenName } from '../mixin'
|
||||
import { RELATIVE_Z_CHIP, GPU_CHIP, HWC_CHIP } from '../treeview/Chips'
|
||||
import Transform from './Transform'
|
||||
|
||||
Layer.fromProto = function (proto: any): Layer {
|
||||
const visibleRegion = toRegion(proto.visibleRegion)
|
||||
const activeBuffer = toActiveBuffer(proto.activeBuffer)
|
||||
const bounds = toRectF(proto.bounds)
|
||||
const color = toColor(proto.color)
|
||||
const screenBounds = toRectF(proto.screenBounds)
|
||||
const sourceBounds = toRectF(proto.sourceBounds)
|
||||
const transform = Transform.fromProto(proto.transform, proto.position)
|
||||
const bufferTransform = Transform.fromProto(proto.bufferTransform, /* position */ null)
|
||||
const hwcCrop = toRectF(proto.hwcCrop)
|
||||
const hwcFrame = toRect(proto.hwcFrame)
|
||||
const requestedColor = toColor(proto.requestedColor)
|
||||
const requestedTransform =
|
||||
Transform.fromProto(proto.requestedTransform, proto.requestedPosition)
|
||||
const cornerRadiusCrop = toRectF(proto.cornerRadiusCrop)
|
||||
const inputTransform =
|
||||
Transform.fromProto(proto.inputWindowInfo ? proto.inputWindowInfo.transform : null)
|
||||
const inputRegion =
|
||||
toRegion(proto.inputWindowInfo ? proto.inputWindowInfo.touchableRegion : null)
|
||||
let crop: Rect
|
||||
if (proto.crop) {
|
||||
crop = toRect(proto.crop)
|
||||
};
|
||||
|
||||
const entry = new Layer(
|
||||
proto.name ?? ``,
|
||||
proto.id,
|
||||
proto.parent,
|
||||
proto.z,
|
||||
visibleRegion,
|
||||
activeBuffer,
|
||||
proto.flags,
|
||||
bounds,
|
||||
color,
|
||||
proto.isOpaque,
|
||||
proto.shadowRadius,
|
||||
proto.cornerRadius,
|
||||
proto.type ?? ``,
|
||||
screenBounds,
|
||||
transform,
|
||||
sourceBounds,
|
||||
proto.currFrame,
|
||||
proto.effectiveScalingMode,
|
||||
bufferTransform,
|
||||
proto.hwcCompositionType,
|
||||
hwcCrop,
|
||||
hwcFrame,
|
||||
proto.backgroundBlurRadius,
|
||||
crop,
|
||||
proto.isRelativeOf,
|
||||
proto.zOrderRelativeOf,
|
||||
proto.layerStack,
|
||||
requestedTransform,
|
||||
requestedColor,
|
||||
cornerRadiusCrop,
|
||||
inputTransform,
|
||||
inputRegion,
|
||||
);
|
||||
|
||||
addAttributes(entry, proto);
|
||||
return entry
|
||||
}
|
||||
|
||||
function addAttributes(entry: Layer, proto: any) {
|
||||
entry.kind = `${entry.id}`;
|
||||
entry.shortName = shortenName(entry.name);
|
||||
entry.proto = proto;
|
||||
entry.rect = entry.bounds;
|
||||
entry.rect.transform = entry.transform;
|
||||
entry.rect.ref = entry;
|
||||
entry.rect.label = entry.name;
|
||||
entry.chips = [];
|
||||
updateChips(entry);
|
||||
}
|
||||
|
||||
function updateChips(entry: Layer) {
|
||||
if ((entry.zOrderRelativeOf || -1) !== -1) {
|
||||
entry.chips.push(RELATIVE_Z_CHIP);
|
||||
}
|
||||
if (entry.hwcCompositionType === 'CLIENT') {
|
||||
entry.chips.push(GPU_CHIP);
|
||||
} else if (entry.hwcCompositionType === 'DEVICE' || entry.hwcCompositionType === 'SOLID_COLOR') {
|
||||
entry.chips.push(HWC_CHIP);
|
||||
}
|
||||
}
|
||||
|
||||
export default Layer;
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2021, 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 { Display, LayerTraceEntry, LayerTraceEntryBuilder, toRect, toSize, toTransform } from "../common"
|
||||
import Layer from './Layer'
|
||||
import { VISIBLE_CHIP, RELATIVE_Z_PARENT_CHIP, MISSING_LAYER } from '../treeview/Chips'
|
||||
|
||||
LayerTraceEntry.fromProto = function (protos: any[], displayProtos: any[],
|
||||
timestamp: number, hwcBlob: string, where: string = ''): LayerTraceEntry {
|
||||
const layers = protos.map(it => Layer.fromProto(it));
|
||||
const displays = (displayProtos || []).map(it => newDisplay(it));
|
||||
const builder = new LayerTraceEntryBuilder(timestamp, layers, displays, hwcBlob, where);
|
||||
const entry: LayerTraceEntry = builder.build();
|
||||
|
||||
updateChildren(entry);
|
||||
addAttributes(entry, protos);
|
||||
return entry;
|
||||
}
|
||||
|
||||
function addAttributes(entry: LayerTraceEntry, protos: any) {
|
||||
entry.kind = "entry"
|
||||
// There no JVM/JS translation for Longs yet
|
||||
entry.timestampMs = entry.timestamp.toString()
|
||||
entry.rects = entry.visibleLayers
|
||||
.sort((a: any, b: any) => (b.absoluteZ > a.absoluteZ) ? 1 : (a.absoluteZ == b.absoluteZ) ? 0 : -1)
|
||||
.map((it: any) => it.rect);
|
||||
|
||||
// Avoid parsing the entry root because it is an array of layers
|
||||
// containing all trace information, this slows down the property tree.
|
||||
// Instead parse only key properties for debugging
|
||||
const entryIds: any = {}
|
||||
protos.forEach((it: any) =>
|
||||
entryIds[<keyof typeof entryIds>it.id] = `\nparent=${it.parent}\ntype=${it.type}\nname=${it.name}`
|
||||
);
|
||||
entry.proto = entryIds;
|
||||
entry.shortName = entry.name;
|
||||
entry.chips = [];
|
||||
entry.isVisible = true;
|
||||
}
|
||||
|
||||
function updateChildren(entry: LayerTraceEntry) {
|
||||
entry.flattenedLayers.forEach((it: any) => {
|
||||
if (it.isVisible) {
|
||||
it.chips.push(VISIBLE_CHIP);
|
||||
}
|
||||
if (it.zOrderRelativeOf) {
|
||||
it.chips.push(RELATIVE_Z_PARENT_CHIP);
|
||||
}
|
||||
if (it.isMissing) {
|
||||
it.chips.push(MISSING_LAYER);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function newDisplay(proto: any): Display {
|
||||
return new Display(
|
||||
proto.id,
|
||||
proto.name,
|
||||
proto.layerStack,
|
||||
toSize(proto.size),
|
||||
toRect(proto.layerStackSpaceRect),
|
||||
toTransform(proto.transform),
|
||||
proto.isVirtual
|
||||
)
|
||||
}
|
||||
|
||||
export {LayerTraceEntry};
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2021, 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 { Transform, Matrix33 } from "../common"
|
||||
|
||||
Transform.fromProto = function (transformProto: any, positionProto: any): Transform {
|
||||
const entry = new Transform(
|
||||
transformProto?.type ?? 0,
|
||||
getMatrix(transformProto, positionProto))
|
||||
|
||||
return entry
|
||||
}
|
||||
|
||||
function getMatrix(transform: any, position: any): Matrix33 {
|
||||
const x = position?.x ?? 0
|
||||
const y = position?.y ?? 0
|
||||
|
||||
if (transform == null || isSimpleTransform(transform.type)) {
|
||||
return getDefaultTransform(transform?.type, x, y)
|
||||
}
|
||||
|
||||
return new Matrix33(transform.dsdx, transform.dtdx, x, transform.dsdy, transform.dtdy, y)
|
||||
}
|
||||
|
||||
function getDefaultTransform(type: number, x: number, y: number): Matrix33 {
|
||||
// IDENTITY
|
||||
if (!type) {
|
||||
return new Matrix33(1, 0, x, 0, 1, y)
|
||||
}
|
||||
|
||||
// ROT_270 = ROT_90|FLIP_H|FLIP_V
|
||||
if (isFlagSet(type, ROT_90_VAL | FLIP_V_VAL | FLIP_H_VAL)) {
|
||||
return new Matrix33(0, -1, x, 1, 0, y)
|
||||
}
|
||||
|
||||
// ROT_180 = FLIP_H|FLIP_V
|
||||
if (isFlagSet(type, FLIP_V_VAL | FLIP_H_VAL)) {
|
||||
return new Matrix33(-1, 0, x, 0, -1, y)
|
||||
}
|
||||
|
||||
// ROT_90
|
||||
if (isFlagSet(type, ROT_90_VAL)) {
|
||||
return new Matrix33(0, 1, x, -1, 0, y)
|
||||
}
|
||||
|
||||
// IDENTITY
|
||||
if (isFlagClear(type, SCALE_VAL | ROTATE_VAL)) {
|
||||
return new Matrix33(1, 0, x, 0, 1, y)
|
||||
}
|
||||
|
||||
throw new Error(`Unknown transform type ${type}`)
|
||||
}
|
||||
|
||||
export function isFlagSet(type: number, bits: number): Boolean {
|
||||
var type = type || 0;
|
||||
return (type & bits) === bits;
|
||||
}
|
||||
|
||||
export function isFlagClear(type: number, bits: number): Boolean {
|
||||
return (type & bits) === 0;
|
||||
}
|
||||
|
||||
export function isSimpleTransform(type: number): Boolean {
|
||||
return isFlagClear(type, ROT_INVALID_VAL | SCALE_VAL)
|
||||
}
|
||||
|
||||
/* transform type flags */
|
||||
const ROTATE_VAL = 0x0002
|
||||
const SCALE_VAL = 0x0004
|
||||
|
||||
/* orientation flags */
|
||||
const FLIP_H_VAL = 0x0100 // (1 << 0 << 8)
|
||||
const FLIP_V_VAL = 0x0200 // (1 << 1 << 8)
|
||||
const ROT_90_VAL = 0x0400 // (1 << 2 << 8)
|
||||
const ROT_INVALID_VAL = 0x8000 // (0x80 << 8)
|
||||
|
||||
export default Transform
|
||||
61
tools/winscope-ng/src/common/trace/flickerlib/mixin.ts
Normal file
61
tools/winscope-ng/src/common/trace/flickerlib/mixin.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2020, 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 ObjectFormatter from "./ObjectFormatter"
|
||||
|
||||
/**
|
||||
* Get the properties of a WM object for display.
|
||||
*
|
||||
* @param entry WM hierarchy element
|
||||
* @param proto Associated proto object
|
||||
*/
|
||||
export function getPropertiesForDisplay(entry: any): any {
|
||||
if (!entry) {
|
||||
return
|
||||
}
|
||||
|
||||
let obj: any = {}
|
||||
const properties = ObjectFormatter.getProperties(entry)
|
||||
properties.forEach(prop => obj[prop] = entry[prop]);
|
||||
|
||||
// we remove the children property from the object to avoid it showing the
|
||||
// the properties view of the element as we can always see those elements'
|
||||
// properties by changing the target element in the hierarchy tree view.
|
||||
if (obj.children) delete obj.children
|
||||
if (obj.proto) delete obj.proto
|
||||
|
||||
obj.proto = Object.assign({}, entry.proto)
|
||||
if (obj.proto.children) delete obj.proto.children
|
||||
if (obj.proto.childWindows) delete obj.proto.childWindows
|
||||
if (obj.proto.childrenWindows) delete obj.proto.childrenWindows
|
||||
if (obj.proto.childContainers) delete obj.proto.childContainers
|
||||
if (obj.proto.windowToken) delete obj.proto.windowToken
|
||||
if (obj.proto.rootDisplayArea) delete obj.proto.rootDisplayArea
|
||||
if (obj.proto.rootWindowContainer) delete obj.proto.rootWindowContainer
|
||||
if (obj.proto.windowContainer?.children) delete obj.proto.windowContainer.children
|
||||
obj = ObjectFormatter.format(obj)
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
export function shortenName(name: any): string {
|
||||
const classParts = (name + "").split(".")
|
||||
if (classParts.length <= 3) {
|
||||
return name
|
||||
}
|
||||
const className = classParts.slice(-1)[0] // last element
|
||||
return `${classParts[0]}.${classParts[1]}.(...).${className}`
|
||||
}
|
||||
47
tools/winscope-ng/src/common/trace/flickerlib/tags/Tag.ts
Normal file
47
tools/winscope-ng/src/common/trace/flickerlib/tags/Tag.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2021, 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 { Tag } from "../common";
|
||||
import TransitionType from "./TransitionType";
|
||||
|
||||
const transitionTypeMap = new Map([
|
||||
['ROTATION', TransitionType.ROTATION],
|
||||
['PIP_ENTER', TransitionType.PIP_ENTER],
|
||||
['PIP_RESIZE', TransitionType.PIP_RESIZE],
|
||||
['PIP_EXPAND', TransitionType.PIP_EXPAND],
|
||||
['PIP_EXIT', TransitionType.PIP_EXIT],
|
||||
['APP_LAUNCH', TransitionType.APP_LAUNCH],
|
||||
['APP_CLOSE', TransitionType.APP_CLOSE],
|
||||
['IME_APPEAR', TransitionType.IME_APPEAR],
|
||||
['IME_DISAPPEAR', TransitionType.IME_DISAPPEAR],
|
||||
['APP_PAIRS_ENTER', TransitionType.APP_PAIRS_ENTER],
|
||||
['APP_PAIRS_EXIT', TransitionType.APP_PAIRS_EXIT],
|
||||
]);
|
||||
|
||||
Tag.fromProto = function (proto: any): Tag {
|
||||
const tag = new Tag(
|
||||
proto.id,
|
||||
transitionTypeMap.get(proto.transition),
|
||||
proto.isStartTag,
|
||||
proto.layerId,
|
||||
proto.windowToken,
|
||||
proto.taskId
|
||||
);
|
||||
return tag;
|
||||
};
|
||||
|
||||
export default Tag;
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2020, 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 { TagState } from "../common";
|
||||
import Tag from './Tag';
|
||||
|
||||
TagState.fromProto = function (timestamp: number, protos: any[]): TagState {
|
||||
const tags = protos.map(it => Tag.fromProto(it));
|
||||
const state = new TagState(`${timestamp}`, tags);
|
||||
return state;
|
||||
}
|
||||
|
||||
export default TagState;
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2021, 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.
|
||||
*/
|
||||
|
||||
enum TransitionType {
|
||||
ROTATION = 'ROTATION',
|
||||
PIP_ENTER = 'PIP_ENTER',
|
||||
PIP_RESIZE ='PIP_RESIZE',
|
||||
PIP_EXPAND = 'PIP_EXPAND',
|
||||
PIP_EXIT = 'PIP_EXIT',
|
||||
APP_LAUNCH = 'APP_LAUNCH',
|
||||
APP_CLOSE = 'APP_CLOSE',
|
||||
IME_APPEAR = 'IME_APPEAR',
|
||||
IME_DISAPPEAR = 'IME_DISAPPEAR',
|
||||
APP_PAIRS_ENTER = 'APP_PAIRS_ENTER',
|
||||
APP_PAIRS_EXIT = 'APP_PAIRS_EXIT',
|
||||
};
|
||||
|
||||
export default TransitionType;
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2020, 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 ChipType from "./ChipType"
|
||||
|
||||
export default class Chip {
|
||||
short: String
|
||||
long: String
|
||||
type: ChipType
|
||||
|
||||
constructor(short: String, long: String, type: ChipType) {
|
||||
this.short = short
|
||||
this.long = long
|
||||
this.type = type
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2020, 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.
|
||||
*/
|
||||
|
||||
enum ChipType {
|
||||
DEFAULT = 'default'
|
||||
}
|
||||
|
||||
export default ChipType
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2020, 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 Chip from "./Chip"
|
||||
import ChipType from "./ChipType"
|
||||
|
||||
export const VISIBLE_CHIP = new Chip("V", "visible", ChipType.DEFAULT)
|
||||
|
||||
export const RELATIVE_Z_CHIP = {
|
||||
short: 'RelZ',
|
||||
long: 'Is relative Z-ordered to another surface',
|
||||
class: 'warn',
|
||||
};
|
||||
|
||||
export const RELATIVE_Z_PARENT_CHIP = {
|
||||
short: 'RelZParent',
|
||||
long: 'Something is relative Z-ordered to this surface',
|
||||
class: 'warn',
|
||||
};
|
||||
|
||||
export const MISSING_LAYER = {
|
||||
short: 'MissingLayer',
|
||||
long: 'This layer was referenced from the parent, but not present in the trace',
|
||||
class: 'error',
|
||||
};
|
||||
|
||||
export const GPU_CHIP = {
|
||||
short: 'GPU',
|
||||
long: 'This layer was composed on the GPU',
|
||||
class: 'gpu',
|
||||
};
|
||||
|
||||
export const HWC_CHIP = {
|
||||
short: 'HWC',
|
||||
long: 'This layer was composed by Hardware Composer',
|
||||
class: 'hwc',
|
||||
};
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2020, 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 { shortenName } from '../mixin'
|
||||
import { Activity } from "../common"
|
||||
import { VISIBLE_CHIP } from '../treeview/Chips'
|
||||
import WindowContainer from "./WindowContainer"
|
||||
|
||||
Activity.fromProto = function (proto: any): Activity {
|
||||
if (proto == null) {
|
||||
return null;
|
||||
} else {
|
||||
const windowContainer = WindowContainer.fromProto(
|
||||
/* proto */ proto.windowToken.windowContainer,
|
||||
/* protoChildren */ proto.windowToken.windowContainer?.children?.reverse() ?? [],
|
||||
/* isActivityInTree */ true,
|
||||
/* nameOverride */ null,
|
||||
/* identifierOverride */ proto.identifier
|
||||
);
|
||||
|
||||
const entry = new Activity(
|
||||
proto.name,
|
||||
proto.state,
|
||||
proto.visible,
|
||||
proto.frontOfTask,
|
||||
proto.procId,
|
||||
proto.translucent,
|
||||
windowContainer
|
||||
);
|
||||
|
||||
addAttributes(entry, proto);
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
function addAttributes(entry: Activity, proto: any) {
|
||||
entry.proto = proto;
|
||||
entry.kind = entry.constructor.name;
|
||||
entry.shortName = shortenName(entry.name);
|
||||
entry.chips = entry.isVisible ? [VISIBLE_CHIP] : [];
|
||||
}
|
||||
|
||||
export default Activity;
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2020, 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 { shortenName } from '../mixin'
|
||||
import { DisplayArea } from "../common"
|
||||
import WindowContainer from "./WindowContainer"
|
||||
|
||||
DisplayArea.fromProto = function (proto: any, isActivityInTree: Boolean): DisplayArea {
|
||||
if (proto == null) {
|
||||
return null;
|
||||
} else {
|
||||
const windowContainer = WindowContainer.fromProto(
|
||||
/* proto */ proto.windowContainer,
|
||||
/* protoChildren */ proto.windowContainer?.children?.reverse() ?? [],
|
||||
/* isActivityInTree */ isActivityInTree,
|
||||
/* nameOverride */ proto.name
|
||||
);
|
||||
|
||||
const entry = new DisplayArea(proto.isTaskDisplayArea, windowContainer);
|
||||
|
||||
addAttributes(entry, proto);
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
function addAttributes(entry: DisplayArea, proto: any) {
|
||||
entry.proto = proto;
|
||||
entry.kind = entry.constructor.name;
|
||||
entry.shortName = shortenName(entry.name);
|
||||
}
|
||||
|
||||
export default DisplayArea;
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2020, 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 { shortenName } from '../mixin'
|
||||
import { toRect, DisplayContent, Rect } from "../common"
|
||||
import WindowContainer from "./WindowContainer"
|
||||
|
||||
DisplayContent.fromProto = function (proto: any, isActivityInTree: Boolean): DisplayContent {
|
||||
if (proto == null) {
|
||||
return null;
|
||||
} else {
|
||||
const windowContainer = WindowContainer.fromProto(
|
||||
/* proto */ proto.rootDisplayArea.windowContainer,
|
||||
/* protoChildren */ proto.rootDisplayArea.windowContainer?.children?.reverse() ?? [],
|
||||
/* isActivityInTree */ isActivityInTree,
|
||||
/* nameOverride */ proto.displayInfo?.name ?? null
|
||||
);
|
||||
const displayRectWidth = proto.displayInfo?.logicalWidth ?? 0;
|
||||
const displayRectHeight = proto.displayInfo?.logicalHeight ?? 0;
|
||||
const appRectWidth = proto.displayInfo?.appWidth ?? 0;
|
||||
const appRectHeight = proto.displayInfo?.appHeight ?? 0;
|
||||
const defaultBounds = proto.pinnedStackController?.defaultBounds ?? null;
|
||||
const movementBounds = proto.pinnedStackController?.movementBounds ?? null;
|
||||
|
||||
const entry = new DisplayContent(
|
||||
proto.id,
|
||||
proto.focusedRootTaskId,
|
||||
proto.resumedActivity?.title ?? "",
|
||||
proto.singleTaskInstance,
|
||||
toRect(defaultBounds),
|
||||
toRect(movementBounds),
|
||||
new Rect(0, 0, displayRectWidth, displayRectHeight),
|
||||
new Rect(0, 0, appRectWidth, appRectHeight),
|
||||
proto.dpi,
|
||||
proto.displayInfo?.flags ?? 0,
|
||||
toRect(proto.displayFrames?.stableBounds),
|
||||
proto.surfaceSize,
|
||||
proto.focusedApp,
|
||||
proto.appTransition?.lastUsedAppTransition ?? "",
|
||||
proto.appTransition?.appTransitionState ?? "",
|
||||
proto.displayRotation?.rotation ?? 0,
|
||||
proto.displayRotation?.lastOrientation ?? 0,
|
||||
windowContainer
|
||||
);
|
||||
|
||||
addAttributes(entry, proto);
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
function addAttributes(entry: DisplayContent, proto: any) {
|
||||
entry.proto = proto;
|
||||
entry.kind = entry.constructor.name;
|
||||
entry.shortName = shortenName(entry.name);
|
||||
}
|
||||
|
||||
export default DisplayContent;
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2020, 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 { shortenName } from '../mixin'
|
||||
import { Task, toRect } from "../common"
|
||||
import WindowContainer from "./WindowContainer"
|
||||
|
||||
Task.fromProto = function (proto: any, isActivityInTree: Boolean): Task {
|
||||
if (proto == null) {
|
||||
return null;
|
||||
} else {
|
||||
const windowContainerProto = proto.taskFragment?.windowContainer ?? proto.windowContainer;
|
||||
const windowContainer = WindowContainer.fromProto(
|
||||
/* proto */ windowContainerProto,
|
||||
/* protoChildren */ windowContainerProto?.children?.reverse() ?? [],
|
||||
/* isActivityInTree */ isActivityInTree
|
||||
);
|
||||
|
||||
const entry = new Task(
|
||||
proto.taskFragment?.activityType ?? proto.activityType,
|
||||
proto.fillsParent,
|
||||
toRect(proto.bounds),
|
||||
proto.id,
|
||||
proto.rootTaskId,
|
||||
proto.taskFragment?.displayId,
|
||||
toRect(proto.lastNonFullscreenBounds),
|
||||
proto.realActivity,
|
||||
proto.origActivity,
|
||||
proto.resizeMode,
|
||||
proto.resumedActivity?.title ?? "",
|
||||
proto.animatingBounds,
|
||||
proto.surfaceWidth,
|
||||
proto.surfaceHeight,
|
||||
proto.createdByOrganizer,
|
||||
proto.taskFragment?.minWidth ?? proto.minWidth,
|
||||
proto.taskFragment?.minHeight ?? proto.minHeight,
|
||||
windowContainer
|
||||
);
|
||||
|
||||
addAttributes(entry, proto);
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
function addAttributes(entry: Task, proto: any) {
|
||||
entry.proto = proto;
|
||||
entry.kind = entry.constructor.name;
|
||||
entry.shortName = shortenName(entry.name);
|
||||
}
|
||||
|
||||
export default Task;
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2021, 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 { shortenName } from '../mixin'
|
||||
import { TaskFragment } from "../common"
|
||||
import WindowContainer from "./WindowContainer"
|
||||
|
||||
TaskFragment.fromProto = function (proto: any, isActivityInTree: Boolean): TaskFragment {
|
||||
if (proto == null) {
|
||||
return null;
|
||||
} else {
|
||||
const windowContainer = WindowContainer.fromProto(
|
||||
/* proto */ proto.windowContainer,
|
||||
/* protoChildren */ proto.windowContainer?.children?.reverse() ?? [],
|
||||
/* isActivityInTree */ isActivityInTree);
|
||||
const entry = new TaskFragment(
|
||||
proto.activityType,
|
||||
proto.displayId,
|
||||
proto.minWidth,
|
||||
proto.minHeight,
|
||||
windowContainer
|
||||
);
|
||||
|
||||
addAttributes(entry, proto);
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
function addAttributes(entry: TaskFragment, proto: any) {
|
||||
entry.proto = proto;
|
||||
entry.kind = entry.constructor.name;
|
||||
entry.shortName = shortenName(entry.name);
|
||||
}
|
||||
|
||||
export default TaskFragment;
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright 2020, 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 { shortenName } from '../mixin'
|
||||
|
||||
import {
|
||||
Configuration,
|
||||
ConfigurationContainer,
|
||||
toRect,
|
||||
WindowConfiguration,
|
||||
WindowContainer
|
||||
} from "../common"
|
||||
|
||||
import Activity from "./Activity"
|
||||
import DisplayArea from "./DisplayArea"
|
||||
import DisplayContent from "./DisplayContent"
|
||||
import Task from "./Task"
|
||||
import TaskFragment from "./TaskFragment"
|
||||
import WindowState from "./WindowState"
|
||||
import WindowToken from "./WindowToken"
|
||||
|
||||
WindowContainer.fromProto = function (
|
||||
proto: any,
|
||||
protoChildren: any[],
|
||||
isActivityInTree: boolean,
|
||||
nameOverride: string|null = null,
|
||||
identifierOverride: string|null = null,
|
||||
tokenOverride: any = null,
|
||||
): WindowContainer {
|
||||
if (proto == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const children = protoChildren
|
||||
.filter(it => it != null)
|
||||
.map(it => WindowContainer.childrenFromProto(it, isActivityInTree))
|
||||
.filter(it => it != null);
|
||||
|
||||
const identifier: any = identifierOverride ?? proto.identifier;
|
||||
const name: string = nameOverride ?? identifier?.title ?? "";
|
||||
const token: string = tokenOverride?.toString(16) ?? identifier?.hashCode?.toString(16) ?? "";
|
||||
|
||||
const config = createConfigurationContainer(proto.configurationContainer);
|
||||
const entry = new WindowContainer(
|
||||
name,
|
||||
token,
|
||||
proto.orientation,
|
||||
proto.surfaceControl?.layerId ?? 0,
|
||||
proto.visible,
|
||||
config,
|
||||
children
|
||||
);
|
||||
|
||||
addAttributes(entry, proto);
|
||||
return entry;
|
||||
}
|
||||
|
||||
function addAttributes(entry: WindowContainer, proto: any) {
|
||||
entry.proto = proto;
|
||||
entry.kind = entry.constructor.name;
|
||||
entry.shortName = shortenName(entry.name);
|
||||
}
|
||||
|
||||
type WindowContainerChildType = DisplayContent|DisplayArea|Task|TaskFragment|Activity|WindowToken|WindowState|WindowContainer;
|
||||
|
||||
WindowContainer.childrenFromProto = function(proto: any, isActivityInTree: Boolean): WindowContainerChildType {
|
||||
return DisplayContent.fromProto(proto.displayContent, isActivityInTree) ??
|
||||
DisplayArea.fromProto(proto.displayArea, isActivityInTree) ??
|
||||
Task.fromProto(proto.task, isActivityInTree) ??
|
||||
TaskFragment.fromProto(proto.taskFragment, isActivityInTree) ??
|
||||
Activity.fromProto(proto.activity) ??
|
||||
WindowToken.fromProto(proto.windowToken, isActivityInTree) ??
|
||||
WindowState.fromProto(proto.window, isActivityInTree) ??
|
||||
WindowContainer.fromProto(proto.windowContainer);
|
||||
}
|
||||
|
||||
function createConfigurationContainer(proto: any): ConfigurationContainer {
|
||||
const entry = new ConfigurationContainer(
|
||||
createConfiguration(proto?.overrideConfiguration ?? null),
|
||||
createConfiguration(proto?.fullConfiguration ?? null),
|
||||
createConfiguration(proto?.mergedOverrideConfiguration ?? null)
|
||||
);
|
||||
|
||||
entry.obj = entry;
|
||||
return entry;
|
||||
}
|
||||
|
||||
function createConfiguration(proto: any): Configuration {
|
||||
if (proto == null) {
|
||||
return null;
|
||||
}
|
||||
var windowConfiguration = null;
|
||||
|
||||
if (proto != null && proto.windowConfiguration != null) {
|
||||
windowConfiguration = createWindowConfiguration(proto.windowConfiguration);
|
||||
}
|
||||
|
||||
return new Configuration(
|
||||
windowConfiguration,
|
||||
proto?.densityDpi ?? 0,
|
||||
proto?.orientation ?? 0,
|
||||
proto?.screenHeightDp ?? 0,
|
||||
proto?.screenHeightDp ?? 0,
|
||||
proto?.smallestScreenWidthDp ?? 0,
|
||||
proto?.screenLayout ?? 0,
|
||||
proto?.uiMode ?? 0
|
||||
);
|
||||
}
|
||||
|
||||
function createWindowConfiguration(proto: any): WindowConfiguration {
|
||||
return new WindowConfiguration(
|
||||
toRect(proto.appBounds),
|
||||
toRect(proto.bounds),
|
||||
toRect(proto.maxBounds),
|
||||
proto.windowingMode,
|
||||
proto.activityType
|
||||
);
|
||||
}
|
||||
|
||||
export default WindowContainer;
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2020, 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 {
|
||||
KeyguardControllerState,
|
||||
RootWindowContainer,
|
||||
WindowManagerPolicy,
|
||||
WindowManagerState
|
||||
} from "../common"
|
||||
|
||||
import WindowContainer from "./WindowContainer"
|
||||
|
||||
WindowManagerState.fromProto = function (proto: any, timestamp: number = 0, where: string = ""): WindowManagerState {
|
||||
var inputMethodWIndowAppToken = "";
|
||||
if (proto.inputMethodWindow != null) {
|
||||
proto.inputMethodWindow.hashCode.toString(16)
|
||||
};
|
||||
|
||||
const rootWindowContainer = createRootWindowContainer(proto.rootWindowContainer);
|
||||
const keyguardControllerState = createKeyguardControllerState(
|
||||
proto.rootWindowContainer.keyguardController);
|
||||
const policy = createWindowManagerPolicy(proto.policy);
|
||||
|
||||
const entry = new WindowManagerState(
|
||||
where,
|
||||
policy,
|
||||
proto.focusedApp,
|
||||
proto.focusedDisplayId,
|
||||
proto.focusedWindow?.title ?? "",
|
||||
inputMethodWIndowAppToken,
|
||||
proto.rootWindowContainer.isHomeRecentsComponent,
|
||||
proto.displayFrozen,
|
||||
proto.rootWindowContainer.pendingActivities.map((it: any) => it.title),
|
||||
rootWindowContainer,
|
||||
keyguardControllerState,
|
||||
/*timestamp */ `${timestamp}`
|
||||
);
|
||||
|
||||
addAttributes(entry, proto);
|
||||
return entry
|
||||
}
|
||||
|
||||
function addAttributes(entry: WindowManagerState, proto: any) {
|
||||
entry.kind = entry.constructor.name;
|
||||
// There no JVM/JS translation for Longs yet
|
||||
entry.timestampMs = entry.timestamp.toString();
|
||||
entry.rects = entry.windowStates.reverse().map((it: any) => it.rect);
|
||||
if (!entry.isComplete()) {
|
||||
entry.isIncompleteReason = entry.getIsIncompleteReason();
|
||||
}
|
||||
entry.proto = proto;
|
||||
entry.shortName = entry.name;
|
||||
entry.chips = [];
|
||||
entry.isVisible = true;
|
||||
}
|
||||
|
||||
function createWindowManagerPolicy(proto: any): WindowManagerPolicy {
|
||||
return new WindowManagerPolicy(
|
||||
proto.focusedAppToken ?? "",
|
||||
proto.forceStatusBar,
|
||||
proto.forceStatusBarFromKeyguard,
|
||||
proto.keyguardDrawComplete,
|
||||
proto.keyguardOccluded,
|
||||
proto.keyguardOccludedChanged,
|
||||
proto.keyguardOccludedPending,
|
||||
proto.lastSystemUiFlags,
|
||||
proto.orientation,
|
||||
proto.rotation,
|
||||
proto.rotationMode,
|
||||
proto.screenOnFully,
|
||||
proto.windowManagerDrawComplete
|
||||
);
|
||||
}
|
||||
|
||||
function createRootWindowContainer(proto: any): RootWindowContainer {
|
||||
const windowContainer = WindowContainer.fromProto(
|
||||
/* proto */ proto.windowContainer,
|
||||
/* childrenProto */ proto.windowContainer?.children?.reverse() ?? [],
|
||||
/* isActivityInTree */ false
|
||||
);
|
||||
|
||||
if (windowContainer == null) {
|
||||
throw new Error(`Window container should not be null.\n${JSON.stringify(proto)}`);
|
||||
}
|
||||
const entry = new RootWindowContainer(windowContainer);
|
||||
return entry;
|
||||
}
|
||||
|
||||
function createKeyguardControllerState(proto: any): KeyguardControllerState {
|
||||
const keyguardOccludedStates: any = {};
|
||||
|
||||
if (proto) {
|
||||
proto.keyguardOccludedStates.forEach((it: any) =>
|
||||
keyguardOccludedStates[<keyof typeof keyguardOccludedStates>it.displayId] = it.keyguardOccluded);
|
||||
}
|
||||
|
||||
return new KeyguardControllerState(
|
||||
proto?.isAodShowing ?? false,
|
||||
proto?.isKeyguardShowing ?? false,
|
||||
keyguardOccludedStates
|
||||
);
|
||||
}
|
||||
|
||||
export {WindowManagerState};
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright 2020, 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 { shortenName } from '../mixin'
|
||||
import { toRect, Size, WindowState, WindowLayoutParams } from "../common"
|
||||
import { VISIBLE_CHIP } from '../treeview/Chips'
|
||||
import WindowContainer from "./WindowContainer"
|
||||
|
||||
WindowState.fromProto = function (proto: any, isActivityInTree: Boolean): WindowState {
|
||||
if (proto == null) {
|
||||
return null;
|
||||
} else {
|
||||
const windowParams = createWindowLayoutParams(proto.attributes);
|
||||
const identifierName = getIdentifier(proto);
|
||||
const windowType = getWindowType(proto, identifierName);
|
||||
const name = getName(identifierName);
|
||||
const windowContainer = WindowContainer.fromProto(
|
||||
/* proto */ proto.windowContainer,
|
||||
/* protoChildren */ proto.windowContainer?.children.reverse() ?? [],
|
||||
/* isActivityInTree */ isActivityInTree,
|
||||
/* nameOverride */ name,
|
||||
/* identifierOverride */ proto.identifier
|
||||
);
|
||||
|
||||
const entry = new WindowState(
|
||||
windowParams,
|
||||
proto.displayId,
|
||||
proto.stackId,
|
||||
proto.animator?.surface?.layer ?? 0,
|
||||
proto.animator?.surface?.shown ?? false,
|
||||
windowType,
|
||||
new Size(proto.requestedWidth, proto.requestedHeight),
|
||||
toRect(proto.surfacePosition),
|
||||
toRect(proto.windowFrames?.frame ?? null),
|
||||
toRect(proto.windowFrames?.containingFrame ?? null),
|
||||
toRect(proto.windowFrames?.parentFrame ?? null),
|
||||
toRect(proto.windowFrames?.contentFrame ?? null),
|
||||
toRect(proto.windowFrames?.contentInsets ?? null),
|
||||
toRect(proto.surfaceInsets),
|
||||
toRect(proto.givenContentInsets),
|
||||
toRect(proto.animator?.lastClipRect ?? null),
|
||||
windowContainer,
|
||||
/* isAppWindow */ isActivityInTree
|
||||
);
|
||||
|
||||
addAttributes(entry, proto);
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
function createWindowLayoutParams(proto: any): WindowLayoutParams {
|
||||
return new WindowLayoutParams(
|
||||
/* type */ proto?.type ?? 0,
|
||||
/* x */ proto?.x ?? 0,
|
||||
/* y */ proto?.y ?? 0,
|
||||
/* width */ proto?.width ?? 0,
|
||||
/* height */ proto?.height ?? 0,
|
||||
/* horizontalMargin */ proto?.horizontalMargin ?? 0,
|
||||
/* verticalMargin */ proto?.verticalMargin ?? 0,
|
||||
/* gravity */ proto?.gravity ?? 0,
|
||||
/* softInputMode */ proto?.softInputMode ?? 0,
|
||||
/* format */ proto?.format ?? 0,
|
||||
/* windowAnimations */ proto?.windowAnimations ?? 0,
|
||||
/* alpha */ proto?.alpha ?? 0,
|
||||
/* screenBrightness */ proto?.screenBrightness ?? 0,
|
||||
/* buttonBrightness */ proto?.buttonBrightness ?? 0,
|
||||
/* rotationAnimation */ proto?.rotationAnimation ?? 0,
|
||||
/* preferredRefreshRate */ proto?.preferredRefreshRate ?? 0,
|
||||
/* preferredDisplayModeId */ proto?.preferredDisplayModeId ?? 0,
|
||||
/* hasSystemUiListeners */ proto?.hasSystemUiListeners ?? false,
|
||||
/* inputFeatureFlags */ proto?.inputFeatureFlags ?? 0,
|
||||
/* userActivityTimeout */ proto?.userActivityTimeout ?? 0,
|
||||
/* colorMode */ proto?.colorMode ?? 0,
|
||||
/* flags */ proto?.flags ?? 0,
|
||||
/* privateFlags */ proto?.privateFlags ?? 0,
|
||||
/* systemUiVisibilityFlags */ proto?.systemUiVisibilityFlags ?? 0,
|
||||
/* subtreeSystemUiVisibilityFlags */ proto?.subtreeSystemUiVisibilityFlags ?? 0,
|
||||
/* appearance */ proto?.appearance ?? 0,
|
||||
/* behavior */ proto?.behavior ?? 0,
|
||||
/* fitInsetsTypes */ proto?.fitInsetsTypes ?? 0,
|
||||
/* fitInsetsSides */ proto?.fitInsetsSides ?? 0,
|
||||
/* fitIgnoreVisibility */ proto?.fitIgnoreVisibility ?? false
|
||||
)
|
||||
}
|
||||
|
||||
function getWindowType(proto: any, identifierName: string): number {
|
||||
if (identifierName.startsWith(WindowState.STARTING_WINDOW_PREFIX)) {
|
||||
return WindowState.WINDOW_TYPE_STARTING;
|
||||
} else if (proto.animatingExit) {
|
||||
return WindowState.WINDOW_TYPE_EXITING;
|
||||
} else if (identifierName.startsWith(WindowState.DEBUGGER_WINDOW_PREFIX)) {
|
||||
return WindowState.WINDOW_TYPE_STARTING;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function getName(identifierName: string): string {
|
||||
var name = identifierName;
|
||||
|
||||
if (identifierName.startsWith(WindowState.STARTING_WINDOW_PREFIX)) {
|
||||
name = identifierName.substring(WindowState.STARTING_WINDOW_PREFIX.length);
|
||||
} else if (identifierName.startsWith(WindowState.DEBUGGER_WINDOW_PREFIX)) {
|
||||
name = identifierName.substring(WindowState.DEBUGGER_WINDOW_PREFIX.length);
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
function getIdentifier(proto: any): string {
|
||||
return proto.windowContainer.identifier?.title ?? proto.identifier?.title ?? "";
|
||||
}
|
||||
|
||||
function addAttributes(entry: WindowState, proto: any) {
|
||||
entry.kind = entry.constructor.name;
|
||||
entry.rect = entry.frame;
|
||||
entry.rect.ref = entry;
|
||||
entry.rect.label = entry.name;
|
||||
entry.proto = proto;
|
||||
entry.shortName = shortenName(entry.name);
|
||||
entry.chips = entry.isVisible ? [VISIBLE_CHIP] : [];
|
||||
}
|
||||
|
||||
export default WindowState
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2020, 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 { shortenName } from '../mixin'
|
||||
import { WindowToken } from "../common"
|
||||
import WindowContainer from "./WindowContainer"
|
||||
|
||||
WindowToken.fromProto = function (proto: any, isActivityInTree: Boolean): WindowToken {
|
||||
if (proto == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const windowContainer = WindowContainer.fromProto(
|
||||
/* proto */ proto.windowContainer,
|
||||
/* protoChildren */ proto.windowContainer?.children?.reverse() ?? [],
|
||||
/* isActivityInTree */ isActivityInTree,
|
||||
/* nameOverride */ null,
|
||||
/* identifierOverride */ null,
|
||||
/* tokenOverride */ proto.hashCode
|
||||
);
|
||||
const entry = new WindowToken(windowContainer);
|
||||
entry.kind = entry.constructor.name;
|
||||
entry.proto = proto;
|
||||
entry.shortName = shortenName(entry.name);
|
||||
return entry;
|
||||
}
|
||||
|
||||
export default WindowToken;
|
||||
136
tools/winscope-ng/src/common/trace/protolog.ts
Normal file
136
tools/winscope-ng/src/common/trace/protolog.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* 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 {StringUtils} from "common/utils/string_utils"
|
||||
import configJson from "../../../../../../frameworks/base/data/etc/services.core.protolog.json";
|
||||
|
||||
class LogMessage {
|
||||
text: string;
|
||||
time: string;
|
||||
tag: string;
|
||||
level: string;
|
||||
at: string;
|
||||
timestamp: number;
|
||||
|
||||
constructor(text: string, time: string, tag: string, level: string, at: string, timestamp: number) {
|
||||
this.text = text;
|
||||
this.time = time;
|
||||
this.tag = tag;
|
||||
this.level = level;
|
||||
this.at = at;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
class FormattedLogMessage extends LogMessage {
|
||||
constructor(proto: any) {
|
||||
const text = (
|
||||
proto.messageHash.toString() +
|
||||
' - [' + proto.strParams.toString() +
|
||||
'] [' + proto.sint64Params.toString() +
|
||||
'] [' + proto.doubleParams.toString() +
|
||||
'] [' + proto.booleanParams.toString() + ']'
|
||||
);
|
||||
super(
|
||||
text,
|
||||
StringUtils.nanosecondsToHuman(proto.elapsedRealtimeNanos),
|
||||
'INVALID',
|
||||
'invalid',
|
||||
'',
|
||||
Number(proto.elapsedRealtimeNanos));
|
||||
}
|
||||
}
|
||||
|
||||
class UnformattedLogMessage extends LogMessage {
|
||||
constructor(proto: any, message: any) {
|
||||
super(
|
||||
formatText(message.message, proto),
|
||||
StringUtils.nanosecondsToHuman(proto.elapsedRealtimeNanos),
|
||||
(<any>configJson).groups[message.group].tag,
|
||||
message.level,
|
||||
message.at,
|
||||
Number(proto.elapsedRealtimeNanos)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function formatText(messageFormat: any, data: any) {
|
||||
let out = '';
|
||||
|
||||
const strParams: string[] = data.strParams;
|
||||
let strParamsIdx = 0;
|
||||
const sint64Params: number[] = data.sint64Params;
|
||||
let sint64ParamsIdx = 0;
|
||||
const doubleParams: number[] = data.doubleParams;
|
||||
let doubleParamsIdx = 0;
|
||||
const booleanParams: number[] = data.booleanParams;
|
||||
let booleanParamsIdx = 0;
|
||||
|
||||
for (let i = 0; i < messageFormat.length;) {
|
||||
if (messageFormat[i] == '%') {
|
||||
if (i + 1 >= messageFormat.length) {
|
||||
// Should never happen - protologtool checks for that
|
||||
throw new Error('Invalid format string');
|
||||
}
|
||||
switch (messageFormat[i + 1]) {
|
||||
case '%':
|
||||
out += '%';
|
||||
break;
|
||||
case 'd':
|
||||
out += getParam(sint64Params, sint64ParamsIdx++).toString(10);
|
||||
break;
|
||||
case 'o':
|
||||
out += getParam(sint64Params, sint64ParamsIdx++).toString(8);
|
||||
break;
|
||||
case 'x':
|
||||
out += getParam(sint64Params, sint64ParamsIdx++).toString(16);
|
||||
break;
|
||||
case 'f':
|
||||
out += getParam(doubleParams, doubleParamsIdx++).toFixed(6);
|
||||
break;
|
||||
case 'e':
|
||||
out += getParam(doubleParams, doubleParamsIdx++).toExponential();
|
||||
break;
|
||||
case 'g':
|
||||
out += getParam(doubleParams, doubleParamsIdx++).toString();
|
||||
break;
|
||||
case 's':
|
||||
out += getParam(strParams, strParamsIdx++);
|
||||
break;
|
||||
case 'b':
|
||||
out += getParam(booleanParams, booleanParamsIdx++).toString();
|
||||
break;
|
||||
default:
|
||||
// Should never happen - protologtool checks for that
|
||||
throw new Error('Invalid format string conversion: ' +
|
||||
messageFormat[i + 1]);
|
||||
}
|
||||
i += 2;
|
||||
} else {
|
||||
out += messageFormat[i];
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function getParam<T>(arr: T[], idx: number): T {
|
||||
if (arr.length <= idx) {
|
||||
throw new Error('No param for format string conversion');
|
||||
}
|
||||
return arr[idx];
|
||||
}
|
||||
|
||||
export {FormattedLogMessage, LogMessage, UnformattedLogMessage};
|
||||
37
tools/winscope-ng/src/common/trace/type_id.ts
Normal file
37
tools/winscope-ng/src/common/trace/type_id.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
enum TraceTypeId {
|
||||
ACCESSIBILITY,
|
||||
WINDOW_MANAGER,
|
||||
SURFACE_FLINGER,
|
||||
WINDOW_MANAGER_DUMP,
|
||||
SURFACE_FLINGER_DUMP,
|
||||
SCREEN_RECORDING,
|
||||
TRANSACTIONS,
|
||||
TRANSACTIONS_LEGACY,
|
||||
WAYLAND,
|
||||
WAYLAND_DUMP,
|
||||
PROTO_LOG,
|
||||
SYSTEM_UI,
|
||||
LAUNCHER,
|
||||
INPUT_METHOD_CLIENTS,
|
||||
INPUT_METHOD_MANAGER_SERVICE,
|
||||
INPUT_METHOD_SERVICE,
|
||||
TAG,
|
||||
ERROR,
|
||||
};
|
||||
|
||||
export {TraceTypeId};
|
||||
62
tools/winscope-ng/src/common/utils/array_utils.spec.ts
Normal file
62
tools/winscope-ng/src/common/utils/array_utils.spec.ts
Normal file
@@ -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 {ArrayUtils} from './array_utils';
|
||||
|
||||
describe("ArrayUtils", () => {
|
||||
it("equal", () => {
|
||||
expect(ArrayUtils.equal([], [1])).toBeFalse();
|
||||
expect(ArrayUtils.equal([1], [])).toBeFalse();
|
||||
|
||||
expect(ArrayUtils.equal([], [])).toBeTrue();
|
||||
expect(ArrayUtils.equal([undefined], [undefined])).toBeTrue();
|
||||
expect(ArrayUtils.equal([1, 2, 3], [1, 2, 3])).toBeTrue();
|
||||
|
||||
expect(ArrayUtils.equal([], new Uint8Array(1))).toBeFalse();
|
||||
expect(ArrayUtils.equal([1], new Uint8Array(1))).toBeFalse();
|
||||
|
||||
expect(ArrayUtils.equal([], new Uint8Array())).toBeTrue();
|
||||
expect(ArrayUtils.equal([], new Uint8Array())).toBeTrue();
|
||||
expect(ArrayUtils.equal([1, 2, 3], new Uint8Array([1, 2, 3]))).toBeTrue();
|
||||
|
||||
expect(ArrayUtils.equal(new Uint8Array([]), new Uint8Array([1]))).toBeFalse();
|
||||
expect(ArrayUtils.equal(new Uint8Array([1]), new Uint8Array([]))).toBeFalse();
|
||||
|
||||
expect(ArrayUtils.equal(new Uint8Array([]), new Uint8Array([]))).toBeTrue();
|
||||
expect(ArrayUtils.equal(new Uint8Array([1, 2, 3]), new Uint8Array([1, 2, 3]))).toBeTrue();
|
||||
});
|
||||
|
||||
it("binarySearchLowerOrEqual", () => {
|
||||
// no match
|
||||
expect(ArrayUtils.binarySearchLowerOrEqual([], 5)).toBeUndefined();
|
||||
expect(ArrayUtils.binarySearchLowerOrEqual([6], 5)).toBeUndefined();
|
||||
expect(ArrayUtils.binarySearchLowerOrEqual([6, 7], 5)).toBeUndefined();
|
||||
expect(ArrayUtils.binarySearchLowerOrEqual([6, 7, 8], 5)).toBeUndefined();
|
||||
|
||||
// match (lower)
|
||||
expect(ArrayUtils.binarySearchLowerOrEqual([4], 5)).toEqual(0);
|
||||
expect(ArrayUtils.binarySearchLowerOrEqual([3, 4], 5)).toEqual(1);
|
||||
expect(ArrayUtils.binarySearchLowerOrEqual([2, 3, 4], 5)).toEqual(2);
|
||||
expect(ArrayUtils.binarySearchLowerOrEqual([2, 3, 4, 6], 5)).toEqual(2);
|
||||
expect(ArrayUtils.binarySearchLowerOrEqual([2, 3, 4, 6, 7], 5)).toEqual(2);
|
||||
|
||||
// match (equal)
|
||||
expect(ArrayUtils.binarySearchLowerOrEqual([5], 5)).toEqual(0);
|
||||
expect(ArrayUtils.binarySearchLowerOrEqual([4, 5], 5)).toEqual(1);
|
||||
expect(ArrayUtils.binarySearchLowerOrEqual([3, 4, 5], 5)).toEqual(2);
|
||||
expect(ArrayUtils.binarySearchLowerOrEqual([3, 4, 5, 6], 5)).toEqual(2);
|
||||
expect(ArrayUtils.binarySearchLowerOrEqual([3, 4, 5, 6, 7], 5)).toEqual(2);
|
||||
});
|
||||
});
|
||||
71
tools/winscope-ng/src/common/utils/array_utils.ts
Normal file
71
tools/winscope-ng/src/common/utils/array_utils.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
type TypedArray =
|
||||
| Int8Array
|
||||
| Uint8Array
|
||||
| Uint8ClampedArray
|
||||
| Int16Array
|
||||
| Uint16Array
|
||||
| Int32Array
|
||||
| Uint32Array
|
||||
| Float32Array
|
||||
| Float64Array;
|
||||
|
||||
class ArrayUtils {
|
||||
static equal<T>(a: T[] | TypedArray, b: T[] | TypedArray): boolean {
|
||||
if (a.length !== b.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
if (a[i] != b[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static binarySearchLowerOrEqual<T>(values: T[] | TypedArray, target: T): number|undefined {
|
||||
if (values.length == 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let low = 0;
|
||||
let high = values.length - 1;
|
||||
|
||||
let result: number|undefined = undefined;
|
||||
|
||||
while(low <= high) {
|
||||
const mid = (low + high) >> 1;
|
||||
|
||||
if (values[mid] < target) {
|
||||
result = mid;
|
||||
low = mid + 1;
|
||||
}
|
||||
else if (values[mid] > target) {
|
||||
high = mid - 1;
|
||||
}
|
||||
else {
|
||||
return mid;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
export {ArrayUtils};
|
||||
48
tools/winscope-ng/src/common/utils/string_utils.spec.ts
Normal file
48
tools/winscope-ng/src/common/utils/string_utils.spec.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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 {StringUtils} from './string_utils';
|
||||
|
||||
describe("StringUtils", () => {
|
||||
it("nanosecondsToHuman", () => {
|
||||
const MILLISECOND = 1000000;
|
||||
const SECOND = 1000000000;
|
||||
const MINUTE = 60 * SECOND;
|
||||
const HOUR = 60 * MINUTE;
|
||||
const DAY = 24 * HOUR;
|
||||
|
||||
expect(StringUtils.nanosecondsToHuman(0)) .toEqual("0ms");
|
||||
expect(StringUtils.nanosecondsToHuman(1000)) .toEqual("0ms");
|
||||
expect(StringUtils.nanosecondsToHuman(MILLISECOND-1)).toEqual("0ms");
|
||||
expect(StringUtils.nanosecondsToHuman(MILLISECOND)).toEqual("1ms");
|
||||
expect(StringUtils.nanosecondsToHuman(10 * MILLISECOND)).toEqual("10ms");
|
||||
|
||||
expect(StringUtils.nanosecondsToHuman(SECOND-1)).toEqual("999ms");
|
||||
expect(StringUtils.nanosecondsToHuman(SECOND)).toEqual("1s0ms");
|
||||
expect(StringUtils.nanosecondsToHuman(SECOND + MILLISECOND)).toEqual("1s1ms");
|
||||
|
||||
expect(StringUtils.nanosecondsToHuman(MINUTE-1)).toEqual("59s999ms");
|
||||
expect(StringUtils.nanosecondsToHuman(MINUTE)).toEqual("1m0s0ms");
|
||||
expect(StringUtils.nanosecondsToHuman(MINUTE + SECOND + MILLISECOND)).toEqual("1m1s1ms");
|
||||
|
||||
expect(StringUtils.nanosecondsToHuman(HOUR-1)).toEqual("59m59s999ms");
|
||||
expect(StringUtils.nanosecondsToHuman(HOUR)).toEqual("1h0m0s0ms");
|
||||
expect(StringUtils.nanosecondsToHuman(HOUR + MINUTE + SECOND + MILLISECOND)).toEqual("1h1m1s1ms");
|
||||
|
||||
expect(StringUtils.nanosecondsToHuman(DAY-1)).toEqual("23h59m59s999ms");
|
||||
expect(StringUtils.nanosecondsToHuman(DAY)).toEqual("1d0h0m0s0ms");
|
||||
expect(StringUtils.nanosecondsToHuman(DAY + HOUR + MINUTE + SECOND + MILLISECOND)).toEqual("1d1h1m1s1ms");
|
||||
});
|
||||
});
|
||||
43
tools/winscope-ng/src/common/utils/string_utils.ts
Normal file
43
tools/winscope-ng/src/common/utils/string_utils.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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 StringUtils {
|
||||
static nanosecondsToHuman(nanoseconds: number): string {
|
||||
const units: [number, string][] = [
|
||||
[1000, "ms"],
|
||||
[60, "s"],
|
||||
[60, "m"],
|
||||
[24, "h"],
|
||||
[Infinity, "d"],
|
||||
];
|
||||
|
||||
let remainder = Math.floor(nanoseconds / 1000000);
|
||||
const parts = [];
|
||||
|
||||
for(const [factor, unit] of units) {
|
||||
const part = (remainder % factor).toFixed();
|
||||
parts.push(part + unit);
|
||||
|
||||
remainder = Math.floor(remainder / factor);
|
||||
if (remainder == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return parts.reverse().join('');
|
||||
}
|
||||
}
|
||||
|
||||
export {StringUtils};
|
||||
BIN
tools/winscope-ng/src/favicon.ico
Normal file
BIN
tools/winscope-ng/src/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 948 B |
28
tools/winscope-ng/src/index.html
Normal file
28
tools/winscope-ng/src/index.html
Normal file
@@ -0,0 +1,28 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>WinscopeNg</title>
|
||||
<base href="/">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
</html>
|
||||
35
tools/winscope-ng/src/main.component.spec.ts
Normal file
35
tools/winscope-ng/src/main.component.spec.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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 'zone.js';
|
||||
import 'zone.js/testing';
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
import {BrowserDynamicTestingModule, platformBrowserDynamicTesting} from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: {
|
||||
context(path: string, deep?: boolean, filter?: RegExp): {
|
||||
<T>(id: string): T;
|
||||
keys(): string[];
|
||||
};
|
||||
};
|
||||
|
||||
TestBed.initTestEnvironment(
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting(),
|
||||
);
|
||||
|
||||
// load all tests of Angular components
|
||||
const context = require.context('./', true, /\.component\.spec\.ts$/);
|
||||
context.keys().forEach(context);
|
||||
35
tools/winscope-ng/src/main.ts
Normal file
35
tools/winscope-ng/src/main.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* For easier debugging in development mode, you can import the following file
|
||||
* to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
|
||||
*
|
||||
* This import should be commented out in production mode because it will have a negative impact
|
||||
* on performance if an error is thrown.
|
||||
*/
|
||||
// import 'zone.js/plugins/zone-error'; // Included with Angular CLI.
|
||||
|
||||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
|
||||
//TODO: implement production mode switch
|
||||
//enableProdMode();
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule)
|
||||
.catch(err => console.error(err));
|
||||
54
tools/winscope-ng/src/parsers/parser.ts
Normal file
54
tools/winscope-ng/src/parsers/parser.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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 {ArrayUtils} from '../common/utils/array_utils';
|
||||
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");
|
||||
}
|
||||
|
||||
this.traceEntriesProto = this.decodeProto(buffer);
|
||||
this.timestamps = this.traceEntriesProto.map((entryProto: any) => this.getTimestamp(entryProto));
|
||||
}
|
||||
|
||||
public abstract getTraceTypeId(): TraceTypeId;
|
||||
|
||||
public getTimestamps(): number[] {
|
||||
return this.timestamps;
|
||||
}
|
||||
|
||||
public getTraceEntry(timestamp: number): any|undefined {
|
||||
const index = ArrayUtils.binarySearchLowerOrEqual(this.getTimestamps(), timestamp);
|
||||
if (index === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
return this.processTraceEntryProto(this.traceEntriesProto[index]);
|
||||
}
|
||||
|
||||
protected abstract getMagicNumber(): number[];
|
||||
protected abstract decodeProto(buffer: Uint8Array): any[];
|
||||
protected abstract getTimestamp(entryProto: any): number;
|
||||
protected abstract processTraceEntryProto(entryProto: any): any;
|
||||
|
||||
private traceEntriesProto: any[];
|
||||
private timestamps: number[];
|
||||
}
|
||||
|
||||
export {Parser};
|
||||
44
tools/winscope-ng/src/parsers/parser_accessibility.spec.ts
Normal file
44
tools/winscope-ng/src/parsers/parser_accessibility.spec.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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 {ParserFactory} from './parser_factory';
|
||||
import {TestUtils} from "test/test_utils";
|
||||
|
||||
describe("ParserAccessibility", () => {
|
||||
let parser: Parser;
|
||||
|
||||
beforeAll(() => {
|
||||
const buffer = TestUtils.loadFixture("trace_Accessibility.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.ACCESSIBILITY);
|
||||
});
|
||||
|
||||
it("provides timestamps", () => {
|
||||
expect(parser.getTimestamps())
|
||||
.toEqual([850297444302, 850297882046, 850756176154, 850773581835]);
|
||||
});
|
||||
|
||||
it("retrieves trace entry", () => {
|
||||
expect(Number(parser.getTraceEntry(850297444302)!.elapsedRealtimeNanos))
|
||||
.toEqual(850297444302);
|
||||
});
|
||||
});
|
||||
48
tools/winscope-ng/src/parsers/parser_accessibility.ts
Normal file
48
tools/winscope-ng/src/parsers/parser_accessibility.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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 {AccessibilityTraceFileProto} from './proto_types';
|
||||
|
||||
class ParserAccessibility extends Parser {
|
||||
constructor(buffer: Uint8Array) {
|
||||
super(buffer);
|
||||
}
|
||||
|
||||
override getTraceTypeId(): TraceTypeId {
|
||||
return TraceTypeId.ACCESSIBILITY;
|
||||
}
|
||||
|
||||
override getMagicNumber(): number[] {
|
||||
return ParserAccessibility.MAGIC_NUMBER;
|
||||
}
|
||||
|
||||
override decodeProto(buffer: Uint8Array): any[] {
|
||||
return (<any>AccessibilityTraceFileProto.decode(buffer)).entry;
|
||||
}
|
||||
|
||||
override getTimestamp(entryProto: any): number {
|
||||
return Number(entryProto.elapsedRealtimeNanos);
|
||||
}
|
||||
|
||||
override processTraceEntryProto(entryProto: any): any {
|
||||
return entryProto;
|
||||
}
|
||||
|
||||
private static readonly MAGIC_NUMBER = [0x09, 0x41, 0x31, 0x31, 0x59, 0x54, 0x52, 0x41, 0x43]; // .A11YTRAC
|
||||
}
|
||||
|
||||
export {ParserAccessibility};
|
||||
60
tools/winscope-ng/src/parsers/parser_common.spec.ts
Normal file
60
tools/winscope-ng/src/parsers/parser_common.spec.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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 {ParserFactory} from "./parser_factory";
|
||||
import {Parser} from "./parser";
|
||||
import {TestUtils} from "test/test_utils";
|
||||
|
||||
describe("Parser", () => {
|
||||
let parser: Parser;
|
||||
|
||||
beforeAll(() => {
|
||||
const buffer = TestUtils.loadFixture("trace_WindowManager.pb");
|
||||
const parsers = new ParserFactory().createParsers([buffer]);
|
||||
expect(parsers.length).toEqual(1);
|
||||
parser = parsers[0];
|
||||
});
|
||||
|
||||
it("provides timestamps", () => {
|
||||
expect(parser.getTimestamps())
|
||||
.toEqual([850254319343, 850763506110, 850782750048]);
|
||||
});
|
||||
|
||||
it("retrieves trace entry (no timestamp matches)", () => {
|
||||
expect(parser.getTraceEntry(850254319342))
|
||||
.toEqual(undefined);
|
||||
});
|
||||
|
||||
it("retrieves trace entry (equal timestamp matches)", () => {
|
||||
expect(Number(parser.getTraceEntry(850254319343)!.timestampMs))
|
||||
.toEqual(850254319343);
|
||||
});
|
||||
|
||||
it("retrieves trace entry (equal timestamp matches)", () => {
|
||||
expect(Number(parser.getTraceEntry(850763506110)!.timestampMs))
|
||||
.toEqual(850763506110);
|
||||
});
|
||||
|
||||
it("retrieves trace entry (lower timestamp matches)", () => {
|
||||
expect(Number(parser.getTraceEntry(850254319344)!.timestampMs))
|
||||
.toEqual(850254319343);
|
||||
});
|
||||
|
||||
it("retrieves trace entry (equal timestamp matches)", () => {
|
||||
expect(Number(parser.getTraceEntry(850763506111)!.timestampMs))
|
||||
.toEqual(850763506110);
|
||||
});
|
||||
});
|
||||
56
tools/winscope-ng/src/parsers/parser_factory.ts
Normal file
56
tools/winscope-ng/src/parsers/parser_factory.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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 {Parser} from "./parser";
|
||||
import {ParserAccessibility} from "./parser_accessibility";
|
||||
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 {ParserSurfaceFlinger} from "./parser_surface_flinger"
|
||||
import {ParserTransactions} from "./parser_transactions";
|
||||
import {ParserWindowManager} from "./parser_window_manager"
|
||||
|
||||
class ParserFactory {
|
||||
static readonly PARSERS = [
|
||||
ParserAccessibility,
|
||||
ParserInputMethodClients,
|
||||
ParserInputMethodManagerService,
|
||||
ParserInputMethodService,
|
||||
ParserProtoLog,
|
||||
ParserSurfaceFlinger,
|
||||
ParserTransactions,
|
||||
ParserWindowManager,
|
||||
]
|
||||
|
||||
createParsers(buffers: Uint8Array[]): Parser[] {
|
||||
const parsers: Parser[] = [];
|
||||
|
||||
for (const buffer of buffers) {
|
||||
for (const ParserType of ParserFactory.PARSERS) {
|
||||
try {
|
||||
const parser = new ParserType(buffer);
|
||||
parsers.push(parser);
|
||||
break;
|
||||
} catch(error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return parsers;
|
||||
}
|
||||
}
|
||||
|
||||
export {ParserFactory};
|
||||
@@ -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 {TraceTypeId} from "common/trace/type_id";
|
||||
import {ParserFactory} from "./parser_factory";
|
||||
import {Parser} from "./parser";
|
||||
import {TestUtils} from "test/test_utils";
|
||||
|
||||
describe("ParserInputMethodlClients", () => {
|
||||
let parser: Parser;
|
||||
|
||||
beforeAll(() => {
|
||||
const buffer = TestUtils.loadFixture("trace_InputMethodClients.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.INPUT_METHOD_CLIENTS);
|
||||
});
|
||||
|
||||
it("provides timestamps", () => {
|
||||
expect(parser.getTimestamps().length)
|
||||
.toEqual(33);
|
||||
expect(parser.getTimestamps().slice(0, 3))
|
||||
.toEqual([1149083651642, 1149083950633, 1149127567251]);
|
||||
});
|
||||
|
||||
it("retrieves trace entry", () => {
|
||||
expect(Number(parser.getTraceEntry(1149083651642)!.elapsedRealtimeNanos))
|
||||
.toEqual(1149083651642);
|
||||
});
|
||||
});
|
||||
48
tools/winscope-ng/src/parsers/parser_input_method_clients.ts
Normal file
48
tools/winscope-ng/src/parsers/parser_input_method_clients.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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 {InputMethodClientsTraceFileProto} from './proto_types';
|
||||
|
||||
class ParserInputMethodClients extends Parser {
|
||||
constructor(buffer: Uint8Array) {
|
||||
super(buffer);
|
||||
}
|
||||
|
||||
getTraceTypeId(): TraceTypeId {
|
||||
return TraceTypeId.INPUT_METHOD_CLIENTS;
|
||||
}
|
||||
|
||||
override getMagicNumber(): number[] {
|
||||
return ParserInputMethodClients.MAGIC_NUMBER;
|
||||
}
|
||||
|
||||
override decodeProto(buffer: Uint8Array): any[] {
|
||||
return (<any>InputMethodClientsTraceFileProto.decode(buffer)).entry;
|
||||
}
|
||||
|
||||
override getTimestamp(entryProto: any): number {
|
||||
return Number(entryProto.elapsedRealtimeNanos);
|
||||
}
|
||||
|
||||
override processTraceEntryProto(entryProto: any): any {
|
||||
return entryProto;
|
||||
}
|
||||
|
||||
private static readonly MAGIC_NUMBER = [0x09, 0x49, 0x4d, 0x43, 0x54, 0x52, 0x41, 0x43, 0x45]; // .IMCTRACE
|
||||
}
|
||||
|
||||
export {ParserInputMethodClients};
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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 {ParserFactory} from "./parser_factory";
|
||||
import {Parser} from "./parser";
|
||||
import {TestUtils} from "test/test_utils";
|
||||
|
||||
describe("ParserInputMethodManagerService", () => {
|
||||
let parser: Parser;
|
||||
|
||||
beforeAll(() => {
|
||||
const buffer = TestUtils.loadFixture("trace_InputMethodManagerService.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.INPUT_METHOD_MANAGER_SERVICE);
|
||||
});
|
||||
|
||||
it("provides timestamps", () => {
|
||||
expect(parser.getTimestamps())
|
||||
.toEqual([1149226290110, 1149237707591, 1149238950389]);
|
||||
});
|
||||
|
||||
it("retrieves trace entry", () => {
|
||||
expect(Number(parser.getTraceEntry(1149226290110)!.elapsedRealtimeNanos))
|
||||
.toEqual(1149226290110);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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 {InputMethodManagerServiceTraceFileProto} from './proto_types';
|
||||
|
||||
class ParserInputMethodManagerService extends Parser {
|
||||
constructor(buffer: Uint8Array) {
|
||||
super(buffer);
|
||||
}
|
||||
|
||||
getTraceTypeId(): TraceTypeId {
|
||||
return TraceTypeId.INPUT_METHOD_MANAGER_SERVICE;
|
||||
}
|
||||
|
||||
override getMagicNumber(): number[] {
|
||||
return ParserInputMethodManagerService.MAGIC_NUMBER;
|
||||
}
|
||||
|
||||
override decodeProto(buffer: Uint8Array): any[] {
|
||||
return (<any>InputMethodManagerServiceTraceFileProto.decode(buffer)).entry;
|
||||
}
|
||||
|
||||
protected override getTimestamp(entryProto: any): number {
|
||||
return Number(entryProto.elapsedRealtimeNanos);
|
||||
}
|
||||
|
||||
protected override processTraceEntryProto(entryProto: any): any {
|
||||
return entryProto;
|
||||
}
|
||||
|
||||
private static readonly MAGIC_NUMBER = [0x09, 0x49, 0x4d, 0x4d, 0x54, 0x52, 0x41, 0x43, 0x45]; // .IMMTRACE
|
||||
}
|
||||
|
||||
export {ParserInputMethodManagerService};
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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 {ParserFactory} from "./parser_factory";
|
||||
import {Parser} from "./parser";
|
||||
import {TestUtils} from "test/test_utils";
|
||||
|
||||
describe("ParserInputMethodService", () => {
|
||||
let parser: Parser;
|
||||
|
||||
beforeAll(() => {
|
||||
const buffer = TestUtils.loadFixture("trace_InputMethodService.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.INPUT_METHOD_SERVICE);
|
||||
});
|
||||
|
||||
it("provides timestamps", () => {
|
||||
expect(parser.getTimestamps())
|
||||
.toEqual([1149230019887, 1149234359324, 1149241227244, 1149243083608, 1149249518016, 1149249784617, 1149272993520]);
|
||||
});
|
||||
|
||||
it("retrieves trace entry", () => {
|
||||
expect(Number(parser.getTraceEntry(1149230019887)!.elapsedRealtimeNanos))
|
||||
.toEqual(1149230019887);
|
||||
});
|
||||
});
|
||||
48
tools/winscope-ng/src/parsers/parser_input_method_service.ts
Normal file
48
tools/winscope-ng/src/parsers/parser_input_method_service.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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 {InputMethodServiceTraceFileProto} from './proto_types';
|
||||
|
||||
class ParserInputMethodService extends Parser {
|
||||
constructor(buffer: Uint8Array) {
|
||||
super(buffer);
|
||||
}
|
||||
|
||||
getTraceTypeId(): TraceTypeId {
|
||||
return TraceTypeId.INPUT_METHOD_SERVICE;
|
||||
}
|
||||
|
||||
override getMagicNumber(): number[] {
|
||||
return ParserInputMethodService.MAGIC_NUMBER;
|
||||
}
|
||||
|
||||
override decodeProto(buffer: Uint8Array): any[] {
|
||||
return (<any>InputMethodServiceTraceFileProto.decode(buffer)).entry;
|
||||
}
|
||||
|
||||
override getTimestamp(entryProto: any): number {
|
||||
return Number(entryProto.elapsedRealtimeNanos);
|
||||
}
|
||||
|
||||
override processTraceEntryProto(entryProto: any): any {
|
||||
return entryProto;
|
||||
}
|
||||
|
||||
private static readonly MAGIC_NUMBER = [0x09, 0x49, 0x4d, 0x53, 0x54, 0x52, 0x41, 0x43, 0x45]; // .IMSTRACE
|
||||
}
|
||||
|
||||
export {ParserInputMethodService};
|
||||
55
tools/winscope-ng/src/parsers/parser_protolog.spec.ts
Normal file
55
tools/winscope-ng/src/parsers/parser_protolog.spec.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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 {ParserFactory} from "./parser_factory";
|
||||
import {Parser} from "./parser";
|
||||
import {TestUtils} from "test/test_utils";
|
||||
|
||||
describe("ParserProtoLog", () => {
|
||||
let parser: Parser;
|
||||
|
||||
beforeAll(() => {
|
||||
const buffer = TestUtils.loadFixture("trace_ProtoLog.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.PROTO_LOG);
|
||||
});
|
||||
|
||||
it("provides timestamps", () => {
|
||||
const timestamps = parser.getTimestamps();
|
||||
expect(timestamps.length)
|
||||
.toEqual(50);
|
||||
expect(timestamps.slice(0, 3))
|
||||
.toEqual([850746266486, 850746336718, 850746350430]);
|
||||
});
|
||||
|
||||
it("reconstructs human-readable log message", () => {
|
||||
const actual = parser.getTraceEntry(850746266486)!;
|
||||
const expected = {
|
||||
text: "InsetsSource updateVisibility for ITYPE_IME, serverVisible: false clientVisible: false",
|
||||
time: "14m10s746ms",
|
||||
tag: "WindowManager",
|
||||
level: "DEBUG",
|
||||
at: "com/android/server/wm/InsetsSourceProvider.java",
|
||||
timestamp: Number(850746266486),
|
||||
};
|
||||
expect(Object.assign({}, actual)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
88
tools/winscope-ng/src/parsers/parser_protolog.ts
Normal file
88
tools/winscope-ng/src/parsers/parser_protolog.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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 {LogMessage, FormattedLogMessage, UnformattedLogMessage} from "common/trace/protolog";
|
||||
import {TraceTypeId} from "common/trace/type_id";
|
||||
import {Parser} from "./parser"
|
||||
import {ProtoLogFileProto} from "./proto_types";
|
||||
import configJson from "../../../../../frameworks/base/data/etc/services.core.protolog.json";
|
||||
|
||||
class ParserProtoLog extends Parser {
|
||||
constructor(buffer: Uint8Array) {
|
||||
super(buffer);
|
||||
}
|
||||
|
||||
override getTraceTypeId(): TraceTypeId {
|
||||
return TraceTypeId.PROTO_LOG;
|
||||
}
|
||||
|
||||
override getMagicNumber(): number[] {
|
||||
return ParserProtoLog.MAGIC_NUMBER;
|
||||
}
|
||||
|
||||
override decodeProto(buffer: Uint8Array): any[] {
|
||||
const fileProto: any = ProtoLogFileProto.decode(buffer);
|
||||
|
||||
if (fileProto.version !== ParserProtoLog.PROTOLOG_VERSION) {
|
||||
const message = "Unsupported ProtoLog trace version";
|
||||
console.log(message);
|
||||
throw new TypeError(message);
|
||||
}
|
||||
|
||||
if (configJson.version !== ParserProtoLog.PROTOLOG_VERSION) {
|
||||
const message = "Unsupported ProtoLog JSON config version";
|
||||
console.log(message);
|
||||
throw new TypeError(message);
|
||||
}
|
||||
|
||||
fileProto.log.sort((a: any, b: any) => {
|
||||
return Number(a.elapsedRealtimeNanos) - Number(b.elapsedRealtimeNanos);
|
||||
});
|
||||
|
||||
return fileProto.log;
|
||||
}
|
||||
|
||||
override getTimestamp(entryProto: any): number {
|
||||
return Number(entryProto.elapsedRealtimeNanos);
|
||||
}
|
||||
|
||||
override processTraceEntryProto(entryProto: any): LogMessage {
|
||||
const message = (<any>configJson).messages[entryProto.messageHash];
|
||||
if (!message) {
|
||||
return new FormattedLogMessage(entryProto);
|
||||
}
|
||||
|
||||
try {
|
||||
return new UnformattedLogMessage(entryProto, message);
|
||||
}
|
||||
catch (error) {
|
||||
if (error instanceof FormatStringMismatchError) {
|
||||
return new FormattedLogMessage(entryProto);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly MAGIC_NUMBER = [0x09, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x4c, 0x4f, 0x47]; // .PROTOLOG
|
||||
private static readonly PROTOLOG_VERSION = "1.0.0";
|
||||
}
|
||||
|
||||
class FormatStringMismatchError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
export {ParserProtoLog};
|
||||
46
tools/winscope-ng/src/parsers/parser_surface_flinger.spec.ts
Normal file
46
tools/winscope-ng/src/parsers/parser_surface_flinger.spec.ts
Normal file
@@ -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 {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("ParserSurfaceFlinger", () => {
|
||||
let parser: Parser;
|
||||
|
||||
beforeAll(() => {
|
||||
const buffer = TestUtils.loadFixture("trace_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 timestamps", () => {
|
||||
expect(parser.getTimestamps())
|
||||
.toEqual([850335483446, 850686322883, 850736507697]);
|
||||
});
|
||||
|
||||
it("retrieves trace entry", () => {
|
||||
const entry = parser.getTraceEntry(850335483446)!
|
||||
expect(entry).toBeInstanceOf(LayerTraceEntry);
|
||||
expect(Number(entry.timestampMs)).toEqual(850335483446);
|
||||
});
|
||||
});
|
||||
49
tools/winscope-ng/src/parsers/parser_surface_flinger.ts
Normal file
49
tools/winscope-ng/src/parsers/parser_surface_flinger.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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 {LayerTraceEntry} from 'common/trace/flickerlib/layers/LayerTraceEntry';
|
||||
import {TraceTypeId} from "common/trace/type_id";
|
||||
import {Parser} from './parser'
|
||||
import {LayersTraceFileProto} from './proto_types';
|
||||
|
||||
class ParserSurfaceFlinger extends Parser {
|
||||
constructor(buffer: Uint8Array) {
|
||||
super(buffer);
|
||||
}
|
||||
|
||||
override getTraceTypeId(): TraceTypeId {
|
||||
return TraceTypeId.SURFACE_FLINGER;
|
||||
}
|
||||
|
||||
override getMagicNumber(): number[] {
|
||||
return ParserSurfaceFlinger.MAGIC_NUMBER;
|
||||
}
|
||||
|
||||
override decodeProto(buffer: Uint8Array): any[] {
|
||||
return (<any>LayersTraceFileProto.decode(buffer)).entry;
|
||||
}
|
||||
|
||||
override getTimestamp(entryProto: any): number {
|
||||
return Number(entryProto.elapsedRealtimeNanos);
|
||||
}
|
||||
|
||||
override processTraceEntryProto(entryProto: any): any {
|
||||
return LayerTraceEntry.fromProto(entryProto.layers.layers, entryProto.displays, entryProto.elapsedRealtimeNanos, entryProto.hwcBlob);
|
||||
}
|
||||
|
||||
private static readonly MAGIC_NUMBER = [0x09, 0x4c, 0x59, 0x52, 0x54, 0x52, 0x41, 0x43, 0x45]; // .LYRTRACE
|
||||
}
|
||||
|
||||
export { ParserSurfaceFlinger };
|
||||
47
tools/winscope-ng/src/parsers/parser_transactions.spec.ts
Normal file
47
tools/winscope-ng/src/parsers/parser_transactions.spec.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 {ParserFactory} from './parser_factory';
|
||||
import {TestUtils} from "test/test_utils";
|
||||
|
||||
describe("ParserTransactions", () => {
|
||||
let parser: Parser;
|
||||
|
||||
beforeAll(() => {
|
||||
const buffer = TestUtils.loadFixture("trace_Transactions.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.TRANSACTIONS);
|
||||
});
|
||||
|
||||
it("provides timestamps", () => {
|
||||
const timestamps = parser.getTimestamps();
|
||||
expect(timestamps.length)
|
||||
.toEqual(4997);
|
||||
expect(timestamps.slice(0, 3))
|
||||
.toEqual([14862317023, 14873423549, 14884850511]);
|
||||
});
|
||||
|
||||
it("retrieves trace entry", () => {
|
||||
expect(Number(parser.getTraceEntry(14862317023)!.elapsedRealtimeNanos))
|
||||
.toEqual(14862317023);
|
||||
});
|
||||
});
|
||||
48
tools/winscope-ng/src/parsers/parser_transactions.ts
Normal file
48
tools/winscope-ng/src/parsers/parser_transactions.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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 {TransactionsTraceFileProto} from './proto_types';
|
||||
|
||||
class ParserTransactions extends Parser {
|
||||
constructor(buffer: Uint8Array) {
|
||||
super(buffer);
|
||||
}
|
||||
|
||||
override getTraceTypeId(): TraceTypeId {
|
||||
return TraceTypeId.TRANSACTIONS;
|
||||
}
|
||||
|
||||
override getMagicNumber(): number[] {
|
||||
return ParserTransactions.MAGIC_NUMBER;
|
||||
}
|
||||
|
||||
override decodeProto(buffer: Uint8Array): any[] {
|
||||
return (<any>TransactionsTraceFileProto.decode(buffer)).entry;
|
||||
}
|
||||
|
||||
override getTimestamp(entryProto: any): number {
|
||||
return Number(entryProto.elapsedRealtimeNanos);
|
||||
}
|
||||
|
||||
override processTraceEntryProto(entryProto: any): any {
|
||||
return entryProto;
|
||||
}
|
||||
|
||||
private static readonly MAGIC_NUMBER = [0x09, 0x54, 0x4e, 0x58, 0x54, 0x52, 0x41, 0x43, 0x45]; // .TNXTRACE
|
||||
}
|
||||
|
||||
export {ParserTransactions};
|
||||
46
tools/winscope-ng/src/parsers/parser_window_manager.spec.ts
Normal file
46
tools/winscope-ng/src/parsers/parser_window_manager.spec.ts
Normal file
@@ -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("ParserWindowManager", () => {
|
||||
let parser: Parser;
|
||||
|
||||
beforeAll(() => {
|
||||
const buffer = TestUtils.loadFixture("trace_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([850254319343, 850763506110, 850782750048]);
|
||||
});
|
||||
|
||||
it("retrieves trace entry", () => {
|
||||
const entry = parser.getTraceEntry(850254319343)!;
|
||||
expect(entry).toBeInstanceOf(WindowManagerState);
|
||||
expect(Number(entry.timestampMs)).toEqual(850254319343);
|
||||
});
|
||||
});
|
||||
49
tools/winscope-ng/src/parsers/parser_window_manager.ts
Normal file
49
tools/winscope-ng/src/parsers/parser_window_manager.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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 {WindowManagerTraceFileProto} from './proto_types';
|
||||
import {WindowManagerState} from 'common/trace/flickerlib/windows/WindowManagerState';
|
||||
|
||||
class ParserWindowManager extends Parser {
|
||||
constructor(buffer: Uint8Array) {
|
||||
super(buffer);
|
||||
}
|
||||
|
||||
override getTraceTypeId(): TraceTypeId {
|
||||
return TraceTypeId.WINDOW_MANAGER;
|
||||
}
|
||||
|
||||
override getMagicNumber(): number[] {
|
||||
return ParserWindowManager.MAGIC_NUMBER;
|
||||
}
|
||||
|
||||
override decodeProto(buffer: Uint8Array): any {
|
||||
return (<any>WindowManagerTraceFileProto.decode(buffer)).entry;
|
||||
}
|
||||
|
||||
override getTimestamp(entryProto: any): number {
|
||||
return Number(entryProto.elapsedRealtimeNanos);
|
||||
}
|
||||
|
||||
override processTraceEntryProto(entryProto: any): WindowManagerState {
|
||||
return WindowManagerState.fromProto(entryProto.windowManagerService, entryProto.elapsedRealtimeNanos, entryProto.where);
|
||||
}
|
||||
|
||||
private static readonly MAGIC_NUMBER = [0x09, 0x57, 0x49, 0x4e, 0x54, 0x52, 0x41, 0x43, 0x45]; // .WINTRACE
|
||||
}
|
||||
|
||||
export {ParserWindowManager};
|
||||
28
tools/winscope-ng/src/parsers/proto_types.js
Normal file
28
tools/winscope-ng/src/parsers/proto_types.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import * as protobuf from "protobufjs";
|
||||
|
||||
import accessibilityJson from "frameworks/base/core/proto/android/server/accessibilitytrace.proto";
|
||||
import inputMethodClientsJson from "frameworks/base/core/proto/android/view/inputmethod/inputmethodeditortrace.proto";
|
||||
import layersJson from "frameworks/native/services/surfaceflinger/layerproto/layerstrace.proto";
|
||||
import protoLogJson from "frameworks/base/core/proto/android/internal/protolog.proto";
|
||||
import transactionsJson from "frameworks/native/services/surfaceflinger/layerproto/transactions.proto";
|
||||
import windowManagerJson from "frameworks/base/core/proto/android/server/windowmanagertrace.proto";
|
||||
|
||||
const AccessibilityTraceFileProto = protobuf.Root.fromJSON(accessibilityJson).lookupType("com.android.server.accessibility.AccessibilityTraceFileProto");
|
||||
const InputMethodClientsTraceFileProto = protobuf.Root.fromJSON(inputMethodClientsJson).lookupType("android.view.inputmethod.InputMethodClientsTraceFileProto");
|
||||
const InputMethodManagerServiceTraceFileProto = protobuf.Root.fromJSON(inputMethodClientsJson).lookupType("android.view.inputmethod.InputMethodManagerServiceTraceFileProto");
|
||||
const InputMethodServiceTraceFileProto = protobuf.Root.fromJSON(inputMethodClientsJson).lookupType("android.view.inputmethod.InputMethodServiceTraceFileProto");
|
||||
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 WindowManagerTraceFileProto = protobuf.Root.fromJSON(windowManagerJson).lookupType("com.android.server.wm.WindowManagerTraceFileProto");
|
||||
|
||||
export {
|
||||
AccessibilityTraceFileProto,
|
||||
InputMethodClientsTraceFileProto,
|
||||
InputMethodManagerServiceTraceFileProto,
|
||||
InputMethodServiceTraceFileProto,
|
||||
LayersTraceFileProto,
|
||||
ProtoLogFileProto,
|
||||
TransactionsTraceFileProto,
|
||||
WindowManagerTraceFileProto
|
||||
};
|
||||
53
tools/winscope-ng/src/polyfills.ts
Normal file
53
tools/winscope-ng/src/polyfills.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* This file includes polyfills needed by Angular and is loaded before the app.
|
||||
* You can add your own extra polyfills to this file.
|
||||
*
|
||||
* This file is divided into 2 sections:
|
||||
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
|
||||
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
|
||||
* file.
|
||||
*
|
||||
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
|
||||
* automatically update themselves. This includes recent versions of Safari, Chrome (including
|
||||
* Opera), Edge on the desktop, and iOS and Chrome on mobile.
|
||||
*
|
||||
* Learn more in https://angular.io/guide/browser-support
|
||||
*/
|
||||
|
||||
/***************************************************************************************************
|
||||
* BROWSER POLYFILLS
|
||||
*/
|
||||
|
||||
/**
|
||||
* By default, zone.js will patch all possible macroTask and DomEvents
|
||||
* user can disable parts of macroTask/DomEvents patch by setting following flags
|
||||
* because those flags need to be set before `zone.js` being loaded, and webpack
|
||||
* will put import in the top of bundle, so user need to create a separate file
|
||||
* in this directory (for example: zone-flags.ts), and put the following flags
|
||||
* into that file, and then add the following code before importing zone.js.
|
||||
* import './zone-flags';
|
||||
*
|
||||
* The flags allowed in zone-flags.ts are listed here.
|
||||
*
|
||||
* The following flags will work for all browsers.
|
||||
*
|
||||
* (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
|
||||
* (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
|
||||
* (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
|
||||
*
|
||||
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
|
||||
* with the following flag, it will bypass `zone.js` patch for IE/Edge
|
||||
*
|
||||
* (window as any).__Zone_enable_cross_context_check = true;
|
||||
*
|
||||
*/
|
||||
|
||||
/***************************************************************************************************
|
||||
* Zone JS is required by default for Angular itself.
|
||||
*/
|
||||
import 'zone.js'; // Included with Angular CLI.
|
||||
|
||||
|
||||
/***************************************************************************************************
|
||||
* APPLICATION IMPORTS
|
||||
*/
|
||||
1
tools/winscope-ng/src/styles.css
Normal file
1
tools/winscope-ng/src/styles.css
Normal file
@@ -0,0 +1 @@
|
||||
/* You can add global styles to this file, and also import other style files */
|
||||
BIN
tools/winscope-ng/src/test/fixtures/trace_Accessibility.pb
vendored
Normal file
BIN
tools/winscope-ng/src/test/fixtures/trace_Accessibility.pb
vendored
Normal file
Binary file not shown.
BIN
tools/winscope-ng/src/test/fixtures/trace_InputMethodClients.pb
vendored
Normal file
BIN
tools/winscope-ng/src/test/fixtures/trace_InputMethodClients.pb
vendored
Normal file
Binary file not shown.
BIN
tools/winscope-ng/src/test/fixtures/trace_InputMethodManagerService.pb
vendored
Normal file
BIN
tools/winscope-ng/src/test/fixtures/trace_InputMethodManagerService.pb
vendored
Normal file
Binary file not shown.
BIN
tools/winscope-ng/src/test/fixtures/trace_InputMethodService.pb
vendored
Normal file
BIN
tools/winscope-ng/src/test/fixtures/trace_InputMethodService.pb
vendored
Normal file
Binary file not shown.
BIN
tools/winscope-ng/src/test/fixtures/trace_ProtoLog.pb
vendored
Normal file
BIN
tools/winscope-ng/src/test/fixtures/trace_ProtoLog.pb
vendored
Normal file
Binary file not shown.
BIN
tools/winscope-ng/src/test/fixtures/trace_SurfaceFlinger.pb
vendored
Normal file
BIN
tools/winscope-ng/src/test/fixtures/trace_SurfaceFlinger.pb
vendored
Normal file
Binary file not shown.
BIN
tools/winscope-ng/src/test/fixtures/trace_Transactions.pb
vendored
Normal file
BIN
tools/winscope-ng/src/test/fixtures/trace_Transactions.pb
vendored
Normal file
Binary file not shown.
BIN
tools/winscope-ng/src/test/fixtures/trace_WindowManager.pb
vendored
Normal file
BIN
tools/winscope-ng/src/test/fixtures/trace_WindowManager.pb
vendored
Normal file
Binary file not shown.
27
tools/winscope-ng/src/test/test_utils.ts
Normal file
27
tools/winscope-ng/src/test/test_utils.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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 fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
class TestUtils {
|
||||
static loadFixture(filename: string): Uint8Array {
|
||||
const fullPath = path.resolve(__dirname, path.join("../src/test/fixtures", filename));
|
||||
const data = fs.readFileSync(fullPath);
|
||||
return new Uint8Array(data);
|
||||
}
|
||||
};
|
||||
|
||||
export {TestUtils};
|
||||
24
tools/winscope-ng/src/viewers/viewer.ts
Normal file
24
tools/winscope-ng/src/viewers/viewer.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
interface Viewer {
|
||||
//TODO: add TraceEntry data type
|
||||
notifyCurrentTraceEntries(entries: Map<TraceTypeId, any>): void;
|
||||
getView(): HTMLElement;
|
||||
}
|
||||
|
||||
export { Viewer };
|
||||
42
tools/winscope-ng/src/viewers/viewer_factory.ts
Normal file
42
tools/winscope-ng/src/viewers/viewer_factory.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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 { Viewer } from './viewer';
|
||||
import { ViewerWindowManager } from './viewer_window_manager/viewer_window_manager';
|
||||
|
||||
class ViewerFactory {
|
||||
static readonly VIEWERS = [
|
||||
ViewerWindowManager,
|
||||
]
|
||||
|
||||
public createViewers(activeTraceTypes: Set<TraceTypeId>): Viewer[] {
|
||||
const viewers: Viewer[] = [];
|
||||
|
||||
for (const Viewer of ViewerFactory.VIEWERS) {
|
||||
const areViewerDepsSatisfied = Viewer.DEPENDENCIES.every((traceType: TraceTypeId) =>
|
||||
activeTraceTypes.has(traceType)
|
||||
);
|
||||
|
||||
if (areViewerDepsSatisfied) {
|
||||
viewers.push(new Viewer());
|
||||
}
|
||||
}
|
||||
|
||||
return viewers;
|
||||
}
|
||||
}
|
||||
|
||||
export { ViewerFactory };
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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 {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
import {ViewerWindowManagerComponent} from './viewer_window_manager.component';
|
||||
|
||||
describe("ViewerWindowManagerComponent", () => {
|
||||
let fixture: ComponentFixture<ViewerWindowManagerComponent>;
|
||||
let component: ViewerWindowManagerComponent;
|
||||
let htmlElement: HTMLElement;
|
||||
|
||||
beforeAll(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ViewerWindowManagerComponent],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ViewerWindowManagerComponent);
|
||||
component = fixture.componentInstance;
|
||||
htmlElement = fixture.nativeElement;
|
||||
});
|
||||
|
||||
it("can be created", () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it("renders the title", () => {
|
||||
const divTitle = htmlElement.querySelector(".viewer-window-manager div.title");
|
||||
expect(divTitle?.innerHTML).toContain("Window Manager");
|
||||
});
|
||||
|
||||
it("renders the input value", async () => {
|
||||
component.inputValue = new Date("2012-12-12");
|
||||
fixture.detectChanges();
|
||||
|
||||
const divInputValue = htmlElement.querySelector(".viewer-window-manager div.input-value");
|
||||
expect(divInputValue?.innerHTML).toContain("Wed Dec 12 2012 00:00:00 GMT+0000 (Coordinated Universal Time)");
|
||||
});
|
||||
|
||||
});
|
||||
@@ -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 {
|
||||
Component,
|
||||
EventEmitter,
|
||||
Input,
|
||||
Output
|
||||
} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<div class="viewer-window-manager">
|
||||
<div class="title">Window Manager</div>
|
||||
<div class="input-value">Input value: {{inputValue}}</div>
|
||||
<div class="button"><button mat-icon-button (click)="generateOutputEvent($event)">Output event!</button></div>
|
||||
</div>
|
||||
`
|
||||
})
|
||||
export class ViewerWindowManagerComponent {
|
||||
@Input()
|
||||
inputValue?: Date;
|
||||
|
||||
@Output()
|
||||
outputEvent = new EventEmitter<DummyEvent>(); // or EventEmitter<void>()
|
||||
|
||||
public generateOutputEvent(event: MouseEvent) {
|
||||
this.outputEvent.emit(new DummyEvent())
|
||||
}
|
||||
}
|
||||
|
||||
export class DummyEvent {
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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 {Viewer} from 'viewers/viewer';
|
||||
|
||||
class ViewerWindowManager implements Viewer {
|
||||
public static readonly DEPENDENCIES: TraceTypeId[] = [TraceTypeId.WINDOW_MANAGER];
|
||||
private view: HTMLElement;
|
||||
|
||||
constructor() {
|
||||
this.view = document.createElement("viewer-window-manager");
|
||||
|
||||
//this.view.setAttribute("input-value", new Date() as unknown as string)
|
||||
(this.view as any).inputValue = new Date();
|
||||
|
||||
this.view.addEventListener("outputEvent", () => console.log("Viewer component generated event!"));
|
||||
}
|
||||
|
||||
public notifyCurrentTraceEntries(entries: Map<TraceTypeId, any>): void {
|
||||
}
|
||||
|
||||
public getView(): HTMLElement {
|
||||
return this.view;
|
||||
}
|
||||
}
|
||||
|
||||
export {ViewerWindowManager};
|
||||
36
tools/winscope-ng/tsconfig.json
Normal file
36
tools/winscope-ng/tsconfig.json
Normal file
@@ -0,0 +1,36 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"compileOnSave": false,
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./src",
|
||||
"outDir": "./dist/out-tsc",
|
||||
"allowJs": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"noImplicitOverride": true,
|
||||
"noPropertyAccessFromIndexSignature": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"sourceMap": true,
|
||||
"declaration": false,
|
||||
"downlevelIteration": true,
|
||||
"experimentalDecorators": true,
|
||||
"moduleResolution": "node",
|
||||
"importHelpers": true,
|
||||
"target": "es2020",
|
||||
"module": "es2020",
|
||||
"lib": [
|
||||
"es2020",
|
||||
"dom"
|
||||
],
|
||||
"resolveJsonModule": true,
|
||||
},
|
||||
"include": ["src"],
|
||||
"angularCompilerOptions": {
|
||||
"enableI18nLegacyMessageIdFormat": false,
|
||||
"strictInjectionParameters": true,
|
||||
"strictInputAccessModifiers": true,
|
||||
"strictTemplates": true
|
||||
}
|
||||
}
|
||||
71
tools/winscope-ng/webpack.config.common.js
Normal file
71
tools/winscope-ng/webpack.config.common.js
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
const path = require('path');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
|
||||
module.exports = {
|
||||
entry: {
|
||||
polyfills: "./src/polyfills.ts",
|
||||
app: "./src/main.ts"
|
||||
},
|
||||
|
||||
resolve: {
|
||||
extensions: [".ts", ".js"],
|
||||
modules: [
|
||||
"node_modules",
|
||||
"src",
|
||||
"kotlin_build",
|
||||
path.resolve(__dirname, '../../..'),
|
||||
]
|
||||
},
|
||||
|
||||
resolveLoader: {
|
||||
modules: ['node_modules', path.resolve(__dirname, 'loaders')],
|
||||
},
|
||||
|
||||
module: {
|
||||
rules:[
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: ["style-loader", "css-loader"]
|
||||
},
|
||||
{
|
||||
test: /\.html$/,
|
||||
use: ["html-loader"]
|
||||
},
|
||||
{
|
||||
test: /\.proto$/,
|
||||
loader: 'proto-loader',
|
||||
options: {
|
||||
paths: [
|
||||
path.resolve(__dirname, '../../..'),
|
||||
path.resolve(__dirname, '../../../external/protobuf/src'),
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.ts$/,
|
||||
use: ["ts-loader", "angular2-template-loader"]
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
plugins: [
|
||||
new HtmlWebpackPlugin({
|
||||
template: 'src/index.html'
|
||||
})
|
||||
]
|
||||
}
|
||||
24
tools/winscope-ng/webpack.config.dev.js
Normal file
24
tools/winscope-ng/webpack.config.dev.js
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
const {merge} = require('webpack-merge');
|
||||
const configCommon = require('./webpack.config.common');
|
||||
|
||||
const configDev = {
|
||||
mode: 'development',
|
||||
devtool: "source-map",
|
||||
};
|
||||
|
||||
module.exports = merge(configCommon, configDev);
|
||||
22
tools/winscope-ng/webpack.config.js
Normal file
22
tools/winscope-ng/webpack.config.js
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
const environment = (process.env.NODE_ENV || 'development').trim();
|
||||
|
||||
if (environment === 'development') {
|
||||
module.exports = require('./webpack.config.dev');
|
||||
} else {
|
||||
module.exports = require('./webpack.config.prod');
|
||||
}
|
||||
54
tools/winscope-ng/webpack.config.prod.js
Normal file
54
tools/winscope-ng/webpack.config.prod.js
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
const {merge} = require('webpack-merge');
|
||||
const configCommon = require('./webpack.config.common');
|
||||
const path = require('path');
|
||||
|
||||
const configProd = {
|
||||
mode: 'production',
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
publicPath: '/',
|
||||
filename: 'js/[name].[hash].js',
|
||||
chunkFilename: 'js/[name].[id].[hash].chunk.js',
|
||||
},
|
||||
optimization: {
|
||||
runtimeChunk: 'single',
|
||||
splitChunks: {
|
||||
chunks: 'all',
|
||||
maxInitialRequests: Infinity,
|
||||
minSize: 0,
|
||||
cacheGroups: {
|
||||
vendor: {
|
||||
test: /[\\/]node_modules[\\/]/,
|
||||
name(module) {
|
||||
const packageName = module.context
|
||||
.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];
|
||||
return `npm.${packageName.replace('@', '')}`;
|
||||
},
|
||||
},
|
||||
styles: {
|
||||
test: /\.css$/,
|
||||
name: 'styles',
|
||||
chunks: 'all',
|
||||
enforce: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = merge(configCommon, configProd);
|
||||
40
tools/winscope-ng/webpack.config.spec.js
Normal file
40
tools/winscope-ng/webpack.config.spec.js
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
const path = require('path');
|
||||
const glob = require('glob');
|
||||
|
||||
let config = require('./webpack.config.common');
|
||||
|
||||
const allTestFiles = [
|
||||
...glob.sync('./src/**/*.spec.js'),
|
||||
...glob.sync('./src/**/*.spec.ts')
|
||||
]
|
||||
const unitTestFiles = allTestFiles.filter(file => !file.match(".*component\.spec\.(js|ts)$"))
|
||||
config["entry"] = {
|
||||
tests: unitTestFiles,
|
||||
};
|
||||
|
||||
config["output"] = {
|
||||
path: path.resolve(__dirname, './dist'),
|
||||
filename: 'bundle.spec.js',
|
||||
};
|
||||
|
||||
config["target"] = "node";
|
||||
config["node"] = {
|
||||
__dirname: false
|
||||
}
|
||||
|
||||
module.exports = config;
|
||||
Reference in New Issue
Block a user