From 8d82d19787222e112ae49265714ac8ada87e3ad5 Mon Sep 17 00:00:00 2001 From: Priyanka Date: Tue, 27 Jul 2021 16:15:47 +0000 Subject: [PATCH] Add typescript classes and code to read proto files. New typescript classes added for Error, Tag, ErrorState, TagState, ErrorTrace, TagTrace. Decoding functions and file getters added. Bug: b/195496092 Test: Upload the winscope zip file, the trace file and the error file from the bug. Check they upload correctly and then submit the files to make sure the timeline is not affected by the additional files. Change-Id: I0d12ed3f55474ea5ff712a4ac0561ff354d97884 --- tools/winscope/src/Overlay.vue | 3 + tools/winscope/src/decode.js | 57 +++++++++++++++++++ tools/winscope/src/flickerlib/ErrorTrace.ts | 33 +++++++++++ tools/winscope/src/flickerlib/TagTrace.ts | 33 +++++++++++ tools/winscope/src/flickerlib/common.js | 18 ++++++ tools/winscope/src/flickerlib/errors/Error.ts | 31 ++++++++++ .../src/flickerlib/errors/ErrorState.ts | 26 +++++++++ tools/winscope/src/flickerlib/index.js | 4 +- tools/winscope/src/flickerlib/tags/Tag.ts | 32 +++++++++++ .../winscope/src/flickerlib/tags/TagState.ts | 26 +++++++++ tools/winscope/src/main.js | 10 ++++ tools/winscope/src/traces/TraceError.ts | 37 ++++++++++++ tools/winscope/src/traces/TraceTag.ts | 37 ++++++++++++ 13 files changed, 346 insertions(+), 1 deletion(-) create mode 100644 tools/winscope/src/flickerlib/ErrorTrace.ts create mode 100644 tools/winscope/src/flickerlib/TagTrace.ts create mode 100644 tools/winscope/src/flickerlib/errors/Error.ts create mode 100644 tools/winscope/src/flickerlib/errors/ErrorState.ts create mode 100644 tools/winscope/src/flickerlib/tags/Tag.ts create mode 100644 tools/winscope/src/flickerlib/tags/TagState.ts create mode 100644 tools/winscope/src/traces/TraceError.ts create mode 100644 tools/winscope/src/traces/TraceTag.ts diff --git a/tools/winscope/src/Overlay.vue b/tools/winscope/src/Overlay.vue index e123d7c23..2bfb8cae7 100644 --- a/tools/winscope/src/Overlay.vue +++ b/tools/winscope/src/Overlay.vue @@ -344,6 +344,9 @@ export default { timelineFiles() { return this.$store.getters.timelineFiles; }, + tagFiles() { + return this.$store.getters.tagFiles; + }, focusedFile() { return this.$store.state.focusedFile; }, diff --git a/tools/winscope/src/decode.js b/tools/winscope/src/decode.js index 953971478..a665fe168 100644 --- a/tools/winscope/src/decode.js +++ b/tools/winscope/src/decode.js @@ -26,6 +26,8 @@ import jsonProtoDefsWl from 'WaylandSafePath/waylandtrace.proto'; import jsonProtoDefsSysUi from 'frameworks/base/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto'; import jsonProtoDefsLauncher from 'packages/apps/Launcher3/protos/launcher_trace_file.proto'; import jsonProtoDefsIme from 'frameworks/base/core/proto/android/view/inputmethod/inputmethodeditortrace.proto'; +import jsonProtoDefsTags from 'platform_testing/libraries/flicker/src/com/android/server/wm/proto/tags.proto'; +import jsonProtoDefsErrors from 'platform_testing/libraries/flicker/src/com/android/server/wm/proto/errors.proto'; import protobuf from 'protobufjs'; import {transform_accessibility_trace} from './transform_accessibility.js'; import {transform_transaction_trace} from './transform_transaction.js'; @@ -53,6 +55,9 @@ import SurfaceFlingerDump from '@/dumps/SurfaceFlinger.ts'; import WindowManagerDump from '@/dumps/WindowManager.ts'; import WaylandDump from '@/dumps/Wayland.ts'; +import TagTrace from '@/traces/TraceTag.ts'; +import ErrorTrace from '@/traces/TraceError.ts'; + const AccessibilityTraceMessage = lookup_type(jsonProtoDefsAccessibility, 'com.android.server.accessibility.AccessibilityTraceFileProto'); const WmTraceMessage = lookup_type(jsonProtoDefsWm, 'com.android.server.wm.WindowManagerTraceFileProto'); const WmDumpMessage = lookup_type(jsonProtoDefsWm, 'com.android.server.wm.WindowManagerServiceDumpProto'); @@ -67,6 +72,8 @@ const LauncherTraceMessage = lookup_type(jsonProtoDefsLauncher, 'com.android.lau const InputMethodClientsTraceMessage = lookup_type(jsonProtoDefsIme, 'android.view.inputmethod.InputMethodClientsTraceFileProto'); const InputMethodServiceTraceMessage = lookup_type(jsonProtoDefsIme, 'android.view.inputmethod.InputMethodServiceTraceFileProto'); const InputMethodManagerServiceTraceMessage = lookup_type(jsonProtoDefsIme, 'android.view.inputmethod.InputMethodManagerServiceTraceFileProto'); +const TagTraceMessage = lookup_type(jsonProtoDefsTags, 'com.android.server.wm.flicker.FlickerTagTraceProto'); +const ErrorTraceMessage = lookup_type(jsonProtoDefsErrors, 'com.android.server.wm.flicker.FlickerErrorTraceProto'); const ACCESSIBILITY_MAGIC_NUMBER = [0x09, 0x41, 0x31, 0x31, 0x59, 0x54, 0x52, 0x41, 0x43]; // .A11YTRAC const LAYER_TRACE_MAGIC_NUMBER = [0x09, 0x4c, 0x59, 0x52, 0x54, 0x52, 0x41, 0x43, 0x45]; // .LYRTRACE @@ -79,6 +86,8 @@ const LAUNCHER_MAGIC_NUMBER = [0x09, 0x4C, 0x4E, 0x43, 0x48, 0x52, 0x54, 0x52, 0 const IMC_TRACE_MAGIC_NUMBER = [0x09, 0x49, 0x4d, 0x43, 0x54, 0x52, 0x41, 0x43, 0x45]; // .IMCTRACE const IMS_TRACE_MAGIC_NUMBER = [0x09, 0x49, 0x4d, 0x53, 0x54, 0x52, 0x41, 0x43, 0x45]; // .IMSTRACE const IMM_TRACE_MAGIC_NUMBER = [0x09, 0x49, 0x4d, 0x4d, 0x54, 0x52, 0x41, 0x43, 0x45]; // .IMMTRACE +const TAG_TRACE_MAGIC_NUMBER = [0x09, 0x54, 0x41, 0x47, 0x54, 0x52, 0x41, 0x43, 0x45]; //.TAGTRACE +const ERROR_TRACE_MAGIC_NUMBER = [0x09, 0x45, 0x52, 0x52, 0x54, 0x52, 0x41, 0x43, 0x45]; //.ERRORTRACE const FILE_TYPES = Object.freeze({ ACCESSIBILITY_TRACE: 'AccessibilityTrace', @@ -96,6 +105,8 @@ const FILE_TYPES = Object.freeze({ IME_TRACE_CLIENTS: 'ImeTraceClients', IME_TRACE_SERVICE: 'ImeTrace InputMethodService', IME_TRACE_MANAGERSERVICE: 'ImeTrace InputMethodManagerService', + TAG_TRACE: 'TagTrace', + ERROR_TRACE: 'ErrorTrace', }); const WINDOW_MANAGER_ICON = 'view_compact'; @@ -108,6 +119,8 @@ const SYSTEM_UI_ICON = 'filter_none'; const LAUNCHER_ICON = 'filter_none'; const IME_ICON = 'keyboard'; const ACCESSIBILITY_ICON = 'filter_none'; +const TAG_ICON = 'details'; +const TRACE_ERROR_ICON = 'warning'; const FILE_ICONS = { [FILE_TYPES.ACCESSIBILITY_TRACE]: ACCESSIBILITY_ICON, @@ -125,6 +138,8 @@ const FILE_ICONS = { [FILE_TYPES.IME_TRACE_CLIENTS]: IME_ICON, [FILE_TYPES.IME_TRACE_SERVICE]: IME_ICON, [FILE_TYPES.IME_TRACE_MANAGERSERVICE]: IME_ICON, + [FILE_TYPES.TAG_TRACE]: TAG_ICON, + [FILE_TYPES.ERROR_TRACE]: TRACE_ERROR_ICON, }; function oneOf(dataType) { @@ -144,6 +159,8 @@ const TRACE_TYPES = Object.freeze({ IME_CLIENTS: 'ImeTrace Clients', IME_SERVICE: 'ImeTrace InputMethodService', IME_MANAGERSERVICE: 'ImeTrace InputMethodManagerService', + TAG: 'TagTrace', + ERROR: 'ErrorTrace', }); const TRACE_INFO = { @@ -221,6 +238,18 @@ const TRACE_INFO = { files: [oneOf(FILE_TYPES.IME_TRACE_MANAGERSERVICE)], constructor: ImeTraceManagerService, }, + [TRACE_TYPES.TAG]: { + name: 'Tag', + icon: TAG_ICON, + files: [oneOf(FILE_TYPES.TAG_TRACE)], + constructor: TagTrace, + }, + [TRACE_TYPES.ERROR]: { + name: 'Error', + icon: TRACE_ERROR_ICON, + files: [oneOf(FILE_TYPES.ERROR_TRACE)], + constructor: ErrorTrace, + }, }; const DUMP_TYPES = Object.freeze({ @@ -262,6 +291,8 @@ export const TRACE_ICONS = { [TRACE_TYPES.IME_CLIENTS]: IME_ICON, [TRACE_TYPES.IME_SERVICE]: IME_ICON, [TRACE_TYPES.IME_MANAGERSERVICE]: IME_ICON, + [TRACE_TYPES.TAG_TRACE]: TAG_ICON, + [TRACE_TYPES.ERROR_TRACE]: TRACE_ERROR_ICON, [DUMP_TYPES.WINDOW_MANAGER]: WINDOW_MANAGER_ICON, [DUMP_TYPES.SURFACE_FLINGER]: SURFACE_FLINGER_ICON, @@ -431,6 +462,26 @@ const FILE_DECODERS = { timeline: true, }, }, + [FILE_TYPES.TAG_TRACE]: { + name: 'Tag trace', + decoder: protoDecoder, + decoderParams: { + type: FILE_TYPES.TAG_TRACE, + protoType: TagTraceMessage, + transform: TagTrace.fromProto, + timeline: true, + }, + }, + [FILE_TYPES.ERROR_TRACE]: { + name: 'Error trace', + decoder: protoDecoder, + decoderParams: { + type: FILE_TYPES.ERROR_TRACE, + protoType: ErrorTraceMessage, + transform: ErrorTrace.fromProto, + timeline: true, + }, + }, }; function lookup_type(protoPath, type) { @@ -568,6 +619,12 @@ function detectAndDecode(buffer, fileName, store) { if (arrayStartsWith(buffer, IMM_TRACE_MAGIC_NUMBER)) { return decodedFile(FILE_TYPES.IME_TRACE_MANAGERSERVICE, buffer, fileName, store); } + if (arrayStartsWith(buffer, TAG_TRACE_MAGIC_NUMBER)) { + return decodedFile(FILE_TYPES.TAG_TRACE, buffer, fileName, store); + } + if (arrayStartsWith(buffer, ERROR_TRACE_MAGIC_NUMBER)) { + return decodedFile(FILE_TYPES.ERROR_TRACE, buffer, fileName, store); + } // TODO(b/169305853): Add magic number at beginning of file for better auto detection for (const [filetype, condition] of [ diff --git a/tools/winscope/src/flickerlib/ErrorTrace.ts b/tools/winscope/src/flickerlib/ErrorTrace.ts new file mode 100644 index 000000000..36b830794 --- /dev/null +++ b/tools/winscope/src/flickerlib/ErrorTrace.ts @@ -0,0 +1,33 @@ +/* + * 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 { ErrorTrace } from "./common" +import ErrorState from "./errors/ErrorState" + +ErrorTrace.fromProto = function (proto: any) { + const states = []; + for (const stateProto of proto.states) { + const transformedState = ErrorState.fromProto( + stateProto.errors, + stateProto.timestamp); + + states.push(transformedState); + } + const source = null; + return new ErrorTrace(states, source); +} + +export default ErrorTrace; diff --git a/tools/winscope/src/flickerlib/TagTrace.ts b/tools/winscope/src/flickerlib/TagTrace.ts new file mode 100644 index 000000000..862e51fb9 --- /dev/null +++ b/tools/winscope/src/flickerlib/TagTrace.ts @@ -0,0 +1,33 @@ +/* + * 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 { TagTrace } from "./common" +import TagState from "./tags/TagState" + +TagTrace.fromProto = function (proto: any): TagTrace { + const states = []; + for (const stateProto of proto.states) { + const transformedState = TagState.fromProto( + stateProto.timestamp, + stateProto.tags); + + states.push(transformedState); + } + const source = null; + return new TagTrace(states, source); +} + +export default TagTrace; diff --git a/tools/winscope/src/flickerlib/common.js b/tools/winscope/src/flickerlib/common.js index 2df565963..db16f9de3 100644 --- a/tools/winscope/src/flickerlib/common.js +++ b/tools/winscope/src/flickerlib/common.js @@ -76,6 +76,16 @@ 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; +//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; + const EMPTY_BUFFER = new Buffer(0, 0, 0, 0); const EMPTY_COLOR = new Color(-1, -1, -1, 0); const EMPTY_RECT = new Rect(0, 0, 0, 0); @@ -226,6 +236,14 @@ export { LayersTrace, Transform, Matrix, + // Tags + Tag, + TagState, + TagTrace, + // Errors + Error, + ErrorState, + ErrorTrace, // Common Size, Buffer, diff --git a/tools/winscope/src/flickerlib/errors/Error.ts b/tools/winscope/src/flickerlib/errors/Error.ts new file mode 100644 index 000000000..4c08a7dfb --- /dev/null +++ b/tools/winscope/src/flickerlib/errors/Error.ts @@ -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. + */ + + +import { Error } from "../common" + +Error.fromProto = function (proto: any): Error { + const error = new Error( + proto.stacktrace, + proto.message, + proto.layerId, + proto.windowToken, + proto.taskId + ); + return error; +} + +export default Error; diff --git a/tools/winscope/src/flickerlib/errors/ErrorState.ts b/tools/winscope/src/flickerlib/errors/ErrorState.ts new file mode 100644 index 000000000..78364c626 --- /dev/null +++ b/tools/winscope/src/flickerlib/errors/ErrorState.ts @@ -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; diff --git a/tools/winscope/src/flickerlib/index.js b/tools/winscope/src/flickerlib/index.js index 1c564a08e..216d621cb 100644 --- a/tools/winscope/src/flickerlib/index.js +++ b/tools/winscope/src/flickerlib/index.js @@ -18,9 +18,11 @@ import LayersTrace from './LayersTrace'; import WindowManagerState from './WindowManagerState'; import WindowManagerTrace from './WindowManagerTrace'; import ObjectFormatter from './ObjectFormatter'; +import TagTrace from './TagTrace'; +import ErrorTrace from './ErrorTrace'; /** * Entry point into the flickerlib for Winscope. * Expose everything we want Winscope to have access to here. */ -export {ObjectFormatter, LayersTrace, WindowManagerState, WindowManagerTrace}; +export {ObjectFormatter, LayersTrace, WindowManagerState, WindowManagerTrace, TagTrace, ErrorTrace}; diff --git a/tools/winscope/src/flickerlib/tags/Tag.ts b/tools/winscope/src/flickerlib/tags/Tag.ts new file mode 100644 index 000000000..283105d5e --- /dev/null +++ b/tools/winscope/src/flickerlib/tags/Tag.ts @@ -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 { Tag } from "../common" + +Tag.fromProto = function (proto: any): Tag { + const tag = new Tag( + proto.id, + proto.transition, + proto.isStartTag, + proto.layerId, + proto.windowToken, + proto.taskId + ); + return tag +} + +export default Tag; diff --git a/tools/winscope/src/flickerlib/tags/TagState.ts b/tools/winscope/src/flickerlib/tags/TagState.ts new file mode 100644 index 000000000..d127a2d37 --- /dev/null +++ b/tools/winscope/src/flickerlib/tags/TagState.ts @@ -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; diff --git a/tools/winscope/src/main.js b/tools/winscope/src/main.js index 907e7de0e..26a0f8ee9 100644 --- a/tools/winscope/src/main.js +++ b/tools/winscope/src/main.js @@ -66,6 +66,8 @@ const store = new Vuex.Store({ dumps: {}, excludeFromTimeline: [ TRACE_TYPES.PROTO_LOG, + TRACE_TYPES.TAG, + TRACE_TYPES.ERROR ], activeFile: null, focusedFile: null, @@ -93,6 +95,14 @@ const store = new Vuex.Store({ return Object.values(state.traces) .filter(file => !state.excludeFromTimeline.includes(file.type)); }, + tagFiles(state, getters) { + return Object.values(state.traces) + .filter(file => file.type === TRACE_TYPES.TAG); + }, + errorFiles(state, getters) { + return Object.values(state.traces) + .filter(file => file.type === TRACE_TYPES.ERROR); + }, sortedTimelineFiles(state, getters) { return sortFiles(getters.timelineFiles); }, diff --git a/tools/winscope/src/traces/TraceError.ts b/tools/winscope/src/traces/TraceError.ts new file mode 100644 index 000000000..3c9daa75b --- /dev/null +++ b/tools/winscope/src/traces/TraceError.ts @@ -0,0 +1,37 @@ +/* + * 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 { FILE_TYPES, TRACE_TYPES } from '@/decode.js'; +import TraceBase from './TraceBase'; +import { ErrorTrace } from '@/flickerlib'; + +export default class TraceError extends TraceBase { + errorTraceFile: Object; + + constructor(files) { + const errorTraceFile = files[FILE_TYPES.ERROR_TRACE]; + super(errorTraceFile.data, errorTraceFile.timeline, files); + this.errorTraceFile = errorTraceFile; + } + + get type() { + return TRACE_TYPES.ERROR; + } + + static fromProto(proto: any): ErrorTrace { + return ErrorTrace.fromProto(proto); + } +} diff --git a/tools/winscope/src/traces/TraceTag.ts b/tools/winscope/src/traces/TraceTag.ts new file mode 100644 index 000000000..401a18578 --- /dev/null +++ b/tools/winscope/src/traces/TraceTag.ts @@ -0,0 +1,37 @@ +/* + * 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 { FILE_TYPES, TRACE_TYPES } from '@/decode.js'; +import TraceBase from './TraceBase'; +import { TagTrace } from '@/flickerlib'; + +export default class TraceTag extends TraceBase { + tagTraceFile: Object; + + constructor(files) { + const tagTraceFile = files[FILE_TYPES.TAG_TRACE]; + super(tagTraceFile.data, tagTraceFile.timeline, files); + this.tagTraceFile = tagTraceFile; + } + + get type() { + return TRACE_TYPES.TAG; + } + + static fromProto(proto: any): TagTrace { + return TagTrace.fromProto(proto); + } +} \ No newline at end of file