• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (C) 2022 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15import {RecordingError} from '../recording_error_handling';
16import {
17  OnTargetChangeCallback,
18  RecordingTargetV2,
19  TargetFactory,
20} from '../recording_interfaces_v2';
21import {
22  EXTENSION_ID,
23  EXTENSION_NOT_INSTALLED,
24  isCrOS,
25} from '../recording_utils';
26import {targetFactoryRegistry} from '../target_factory_registry';
27import {ChromeTarget} from '../targets/chrome_target';
28
29export const CHROME_TARGET_FACTORY = 'ChromeTargetFactory';
30
31export class ChromeTargetFactory implements TargetFactory {
32  readonly kind = CHROME_TARGET_FACTORY;
33  // We only check the connection once at the beginning to:
34  // a) Avoid creating a 'Port' object every time 'getInfo' is called.
35  // b) When a new Port is created, the extension starts communicating with it
36  // and leaves aside the old Port objects, so creating a new Port would break
37  // any ongoing tracing session.
38  isExtensionInstalled: boolean = false;
39  private targets: ChromeTarget[] = [];
40
41  constructor() {
42    this.init();
43  }
44
45  init() {
46    const testPort = chrome.runtime.connect(EXTENSION_ID);
47    this.isExtensionInstalled = !!testPort;
48    testPort.disconnect();
49
50    if (!this.isExtensionInstalled) {
51      return;
52    }
53    this.targets.push(new ChromeTarget('Chrome', 'CHROME'));
54    if (isCrOS(navigator.userAgent)) {
55      this.targets.push(new ChromeTarget('ChromeOS', 'CHROME_OS'));
56    }
57  }
58
59  connectNewTarget(): Promise<RecordingTargetV2> {
60    throw new RecordingError(
61        'Can not create a new Chrome target.' +
62        'All Chrome targets are created at factory initialisation.');
63  }
64
65  getName(): string {
66    return 'Chrome';
67  }
68
69  listRecordingProblems(): string[] {
70    const recordingProblems = [];
71    if (!this.isExtensionInstalled) {
72      recordingProblems.push(EXTENSION_NOT_INSTALLED);
73    }
74    return recordingProblems;
75  }
76
77  listTargets(): RecordingTargetV2[] {
78    return this.targets;
79  }
80
81  setOnTargetChange(onTargetChange: OnTargetChangeCallback): void {
82    for (const target of this.targets) {
83      target.onTargetChange = onTargetChange;
84    }
85  }
86}
87
88// We only instantiate the factory if Perfetto UI is open in the Chrome browser.
89if (window.chrome && chrome.runtime) {
90  targetFactoryRegistry.register(new ChromeTargetFactory());
91}
92