• 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 m from 'mithril';
16import {
17  RecordingPageController,
18} from '../../common/recordingV2/recording_page_controller';
19import {EXTENSION_URL} from '../../common/recordingV2/recording_utils';
20import {
21  CHROME_TARGET_FACTORY,
22  ChromeTargetFactory,
23} from '../../common/recordingV2/target_factories/chrome_target_factory';
24import {
25  targetFactoryRegistry,
26} from '../../common/recordingV2/target_factory_registry';
27import {
28  WebsocketMenuController,
29} from '../../common/recordingV2/websocket_menu_controller';
30import {fullscreenModalContainer, ModalDefinition} from '../modal';
31import {CodeSnippet} from '../record_widgets';
32
33import {RecordingMultipleChoice} from './recording_multiple_choice';
34
35const RUN_WEBSOCKET_CMD = '# Get tracebox\n' +
36    'curl -LO https://get.perfetto.dev/tracebox\n' +
37    'chmod +x ./tracebox\n' +
38    '# Option A - trace android devices\n' +
39    'adb start-server\n' +
40    '# Option B - trace the host OS\n' +
41    './tracebox traced --background\n' +
42    './tracebox traced_probes --background\n' +
43    '# Start the websocket server\n' +
44    './tracebox websocket_bridge\n';
45
46export function addNewTarget(recordingPageController: RecordingPageController):
47    ModalDefinition {
48  const components = [];
49  components.push(m('text', 'Select platform:'));
50
51  components.push(assembleWebusbSection(recordingPageController));
52
53  components.push(m('.line'));
54  components.push(assembleWebsocketSection(recordingPageController));
55
56  components.push(m('.line'));
57  components.push(assembleChromeSection(recordingPageController));
58
59  return {
60    title: 'Add new recording target',
61    content: m('.record-modal', components),
62  };
63}
64
65function assembleWebusbSection(
66    recordingPageController: RecordingPageController): m.Vnode {
67  return m(
68      '.record-modal-section',
69      m('.logo-wrapping', m('i.material-icons', 'usb')),
70      m('.record-modal-description',
71        m('h3', 'Android device over WebUSB'),
72        m('text',
73          'Android developers: this option cannot co-operate ' +
74              'with the adb host on your machine. Only one entity between ' +
75              'the browser and adb can control the USB endpoint. If adb is ' +
76              'running, you will be prompted to re-assign the device to the ' +
77              'browser. Use the websocket option below to use both ' +
78              'simultaneously.'),
79        m('.record-modal-button',
80          {
81            onclick: () => {
82              fullscreenModalContainer.close();
83              recordingPageController.addAndroidDevice();
84            },
85          },
86          'Connect new WebUSB driver')));
87}
88
89function assembleWebsocketSection(
90    recordingPageController: RecordingPageController): m.Vnode {
91  const websocketComponents = [];
92  websocketComponents.push(
93      m('h3', 'Android / Linux / MacOS device via Websocket'));
94  websocketComponents.push(
95      m('text',
96        'This option assumes that the adb server is already ' +
97            'running on your machine.'),
98      m('.record-modal-command', m(CodeSnippet, {
99          text: RUN_WEBSOCKET_CMD,
100        })));
101
102  websocketComponents.push(m(
103      '.record-modal-command',
104      m('text', 'Websocket bridge address: '),
105      m('input[type=text]', {
106        value: websocketMenuController.getPath(),
107        oninput() {
108          websocketMenuController.setPath(this.value);
109        },
110      }),
111      m('.record-modal-logo-button',
112        {
113          onclick: () => websocketMenuController.onPathChange(),
114        },
115        m('i.material-icons', 'refresh')),
116      ));
117
118  websocketComponents.push(m(RecordingMultipleChoice, {
119    controller: recordingPageController,
120    targetFactories: websocketMenuController.getTargetFactories(),
121  }));
122
123  return m(
124      '.record-modal-section',
125      m('.logo-wrapping', m('i.material-icons', 'settings_ethernet')),
126      m('.record-modal-description', ...websocketComponents));
127}
128
129function assembleChromeSection(
130    recordingPageController: RecordingPageController): m.Vnode|undefined {
131  if (!targetFactoryRegistry.has(CHROME_TARGET_FACTORY)) {
132    return undefined;
133  }
134
135  const chromeComponents = [];
136  chromeComponents.push(m('h3', 'Chrome Browser instance or ChromeOS device'));
137
138  const chromeFactory: ChromeTargetFactory =
139      targetFactoryRegistry.get(CHROME_TARGET_FACTORY) as ChromeTargetFactory;
140
141  if (!chromeFactory.isExtensionInstalled) {
142    chromeComponents.push(
143        m('text',
144          'Install the extension ',
145          m('a', {href: EXTENSION_URL, target: '_blank'}, 'from this link '),
146          'and refresh the page.'));
147  } else {
148    chromeComponents.push(m(RecordingMultipleChoice, {
149      controller: recordingPageController,
150      targetFactories: [chromeFactory],
151    }));
152  }
153
154  return m(
155      '.record-modal-section',
156      m('.logo-wrapping', m('i.material-icons', 'web')),
157      m('.record-modal-description', ...chromeComponents));
158}
159
160const websocketMenuController = new WebsocketMenuController();
161