blob: 974d277845c05b2d8ff47b6b0346509f9f747cda [file] [log] [blame]
// 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 {TraceConfig} from '../protos';
// TargetFactory connects, disconnects and keeps track of targets.
// There is one factory for AndroidWebusb, AndroidWebsocket, Chrome etc.
// For instance, the AndroidWebusb factory returns a RecordingTargetV2 for each
// device.
export interface TargetFactory {
// Store the kind explicitly as a string as opposed to using class.kind in
// case we ever minify our code.
readonly kind: string;
// Setter for OnTargetChange, which is executed when a target is
// added/removed or when its information is updated.
setOnTargetChange(onTargetChange: OnTargetChangeCallback): void;
getName(): string;
listTargets(): RecordingTargetV2[];
// Returns recording problems that we encounter when not directly using the
// target. For instance we connect webusb devices when Perfetto is loaded. If
// there is an issue with connecting a webusb device, we do not want to crash
// all of Perfetto, as the user may not want to use the recording
// functionality at all.
listRecordingProblems(): string[];
connectNewTarget(): Promise<RecordingTargetV2>;
}
export interface DataSource {
name: string;
// Contains information that is opaque to the recording code. The caller can
// use the DataSource name to type cast the DataSource descriptor.
// For targets calling QueryServiceState, 'descriptor' will hold the
// datasource descriptor:
// https://source.corp.google.com/android/external/perfetto/protos/perfetto/
// common/data_source_descriptor.proto;l=28-60
// For Chrome, 'descriptor' will contain the answer received from
// 'GetCategories':
// https://source.corp.google.com/android/external/perfetto/ui/src/
// chrome_extension/chrome_tracing_controller.ts;l=220
descriptor: unknown;
}
// Common fields for all types of targetInfo: Chrome, Android, Linux etc.
interface TargetInfoBase {
name: string;
// The dataSources exposed by a target. They are fetched from the target
// (ex: using QSS for Android or GetCategories for Chrome).
dataSources: DataSource[];
}
export interface AndroidTargetInfo extends TargetInfoBase {
targetType: 'ANDROID';
// This is the Android API level. For instance, it can be 32, 31, 30 etc.
// It is the "API level" column here:
// https://source.android.com/setup/start/build-numbers
androidApiLevel?: number;
}
export interface ChromeTargetInfo extends TargetInfoBase {
targetType: 'CHROME'|'CHROME_OS';
}
export interface HostOsTargetInfo extends TargetInfoBase {
targetType: 'LINUX'|'MACOS';
}
// Holds information about a target. It's used by the UI and the logic which
// generates a config.
export type TargetInfo = AndroidTargetInfo|ChromeTargetInfo|HostOsTargetInfo;
// RecordingTargetV2 is subclassed by Android devices and the Chrome browser/OS.
// It creates tracing sessions which are used by the UI. For Android, it manages
// the connection with the device.
export interface RecordingTargetV2 {
// Allows targets to surface target specific information such as
// well known key/value pairs: OS, targetType('ANDROID', 'CHROME', etc.)
getInfo(): TargetInfo;
// Disconnects the target.
disconnect(disconnectMessage?: string): Promise<void>;
// Returns true if we are able to connect to the target without interfering
// with other processes. For example, for adb devices connected over WebUSB,
// this will be false when we can not claim the interface (Which most likely
// means that 'adb server' is running locally.). After querrying this method,
// the caller can decide if they want to connect to the target and as a side
// effect take the connection away from other processes.
canConnectWithoutContention(): Promise<boolean>;
// Whether the recording target can be used in a tracing session. For example,
// virtual targets do not support a tracing session.
canCreateTracingSession(recordingMode?: string): boolean;
// Some target information can only be obtained after connecting to the
// target. This will establish a connection and retrieve data such as
// dataSources and apiLevel for Android.
fetchTargetInfo(tracingSessionListener: TracingSessionListener):
Promise<void>;
createTracingSession(tracingSessionListener: TracingSessionListener):
Promise<TracingSession>;
}
// TracingSession is used by the UI to record a trace. Depending on user
// actions, the UI can start/stop/cancel a session. During the recording, it
// provides updates about buffer usage. It is subclassed by
// TracedTracingSession, which manages the communication with traced and has
// logic for encoding/decoding Perfetto client requests/replies.
export interface TracingSession {
// Starts the tracing session.
start(config: TraceConfig): void;
// Will stop the tracing session and NOT return any trace.
cancel(): void;
// Will stop the tracing session. The implementing class may also return
// the trace using a callback.
stop(): void;
// Returns the percentage of the trace buffer that is currently being
// occupied.
getTraceBufferUsage(): Promise<number>;
}
// Connection with an Adb device. Implementations will have logic specific to
// the connection protocol used(Ex: WebSocket, WebUsb).
export interface AdbConnection {
// Will push a binary to a given path.
push(binary: ArrayBuffer, path: string): Promise<void>;
// Will issue a shell command to the device.
shell(cmd: string): Promise<ByteStream>;
// Will establish a connection(a ByteStream) with the device.
connectSocket(path: string): Promise<ByteStream>;
// Returns true if we are able to connect without interfering
// with other processes. For example, for adb devices connected over WebUSB,
// this will be false when we can not claim the interface (Which most likely
// means that 'adb server' is running locally.).
canConnectWithoutContention(): Promise<boolean>;
// Ends the connection.
disconnect(disconnectMessage?: string): Promise<void>;
}
// A stream for a connection between a target and a tracing session.
export interface ByteStream {
// The caller can add callbacks, to be executed when the stream receives new
// data or when it finished closing itself.
addOnStreamDataCallback(onStreamData: OnStreamDataCallback): void;
addOnStreamCloseCallback(onStreamClose: OnStreamCloseCallback): void;
isConnected(): boolean;
write(data: string|Uint8Array): void;
close(): void;
closeAndWaitForTeardown(): Promise<void>;
}
// Handles binary messages received over the ByteStream.
export interface OnStreamDataCallback {
(data: Uint8Array): void;
}
// Called when the ByteStream is closed.
export interface OnStreamCloseCallback {
(): void;
}
// OnTraceDataCallback will return the entire trace when it has been fully
// assembled. This will be changed in the following CL aosp/2057640.
export interface OnTraceDataCallback {
(trace: Uint8Array): void;
}
// Handles messages that are useful in the UI and that occur at any layer of the
// recording (trace, connection). The messages includes both status messages and
// error messages.
export interface OnMessageCallback {
(message: string): void;
}
// Handles the loss of the connection at the connection layer (used by the
// AdbConnection).
export interface OnDisconnectCallback {
(errorMessage?: string): void;
}
// Called when there is a change of targets or within a target.
// For instance, it's used when an Adb device becomes connected/disconnected.
// It's also executed by a target when the information it stores gets updated.
export interface OnTargetChangeCallback {
(): void;
}
// A collection of callbacks that is passed to RecordingTargetV2 and
// subsequently to TracingSession. The callbacks are decided by the UI, so the
// recording code is not coupled with the rendering logic.
export interface TracingSessionListener {
onTraceData: OnTraceDataCallback;
onStatus: OnMessageCallback;
onDisconnect: OnDisconnectCallback;
onError: OnMessageCallback;
}