1/*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16const {exec} = require('child_process');
17
18const ANDROID_BUILD_TOP = __dirname + '/../../../../';
19const WINSCOPE_TOP = __dirname + '/..';
20const PERFETTO_TOP = ANDROID_BUILD_TOP + '/external/perfetto';
21const OUT_TOP = __dirname + '/../deps_build/protos';
22
23build();
24
25async function build() {
26    await runCommand(`rm -rf ${OUT_TOP}`);
27
28    const promises = [
29        // IME
30        buildProtos([
31            '../../../../frameworks/base/core/proto/android/view/inputmethod/inputmethodeditortrace.proto'
32        ], 'ime/udc'),
33        buildProtos([
34            'ime/latest/wrapper.proto',
35        ], 'ime/latest'),
36
37        // ProtoLog
38        buildProtos([
39            'protolog/udc/protolog.proto'
40        ], 'protolog/udc'),
41        buildProtos([
42            '../../../../external/perfetto/protos/perfetto/trace/android/protolog.proto'
43        ], 'protolog/latest'),
44
45        // SurfaceFlinger
46        buildProtos([
47            'surfaceflinger/udc/layerstrace.proto',
48        ], 'surfaceflinger/udc'),
49        buildProtos([
50            '../../../../external/perfetto/protos/perfetto/trace/android/surfaceflinger_layers.proto',
51        ], 'surfaceflinger/latest'),
52
53        // Transactions
54        buildProtos([
55            'surfaceflinger/udc/transactions.proto',
56        ], 'transactions/udc'),
57        buildProtos([
58            '../../../../external/perfetto/protos/perfetto/trace/android/surfaceflinger_transactions.proto',
59        ], 'transactions/latest'),
60
61        // Transitions
62        buildProtos([
63            'transitions/udc/windowmanagertransitiontrace.proto',
64            'transitions/udc/wm_shell_transition_trace.proto'
65        ], 'transitions/udc'),
66        buildProtos([
67            '../../../../external/perfetto/protos/perfetto/trace/android/shell_transition.proto',
68        ], 'transitions/latest'),
69
70        // ViewCapture
71        buildProtos([
72            '../../../../frameworks/libs/systemui/viewcapturelib/src/com/android/app/viewcapture/proto/view_capture.proto'
73        ], 'viewcapture/udc'),
74        buildProtos([
75            'viewcapture/latest/wrapper.proto',
76        ], 'viewcapture/latest'),
77
78        // WindowManager
79        buildProtos([
80            '../../../../frameworks/base/core/proto/android/server/windowmanagertrace.proto',
81        ], 'windowmanager/latest'),
82
83        // Input
84        buildProtos([
85            '../../../../external/perfetto/protos/perfetto/trace/android/android_input_event.proto',
86            'input/latest/input_event_wrapper.proto',
87        ], 'input/latest'),
88
89        // Test proto fields
90        buildProtos([
91            'test/fake_proto_test.proto',
92        ], 'test/fake_proto'),
93
94        // Test intdef translation
95        buildProtos([
96            'test/intdef_translation_test.proto',
97        ], 'test/intdef_translation'),
98    ];
99
100    await Promise.all(promises);
101}
102
103async function buildProtos(protoPaths, outSubdir) {
104    const outDir = OUT_TOP + '/' + outSubdir;
105    const protoFullPaths = protoPaths.map((path) => __dirname + '/' + path);
106    const rootName = outSubdir.replaceAll('/', '_');
107
108    const commandBuildJson = [
109        'npx',
110        'pbjs',
111        //TODO(b/318480413): for perfetto traces use '--force-bigint' as soon as available,
112        // i.e. when this PR is merged https://github.com/protobufjs/protobuf.js/pull/1557
113        '--force-long',
114        '--target json-module',
115        '--wrap es6',
116        `--out ${outDir}/json.js`,
117        `--root ${rootName}`,
118        `--path ${PERFETTO_TOP}`,
119        `--path ${WINSCOPE_TOP}`,
120        `--path ${ANDROID_BUILD_TOP}`,
121        protoFullPaths.join(' ')
122    ].join(' ');
123
124    const commandBuildJs = [
125        'npx',
126        'pbjs',
127        '--force-long',
128        '--target static-module',
129        `--root ${outSubdir.replace('/', '')}`,
130        `--out ${outDir}/static.js`,
131        `--path ${PERFETTO_TOP}`,
132        `--path ${WINSCOPE_TOP}`,
133        `--path ${ANDROID_BUILD_TOP}`,
134        protoFullPaths.join(' '),
135    ].join(' ');
136
137    const commandBuildTs = [
138        'npx',
139        'pbts',
140        `--out ${outDir}/static.d.ts`,
141        `${outDir}/static.js`
142    ].join(' ');
143
144    await runCommand(`mkdir -p ${outDir}`)
145    await runCommand(commandBuildJson);
146    await runCommand(commandBuildJs);
147    await runCommand(commandBuildTs);
148}
149
150function runCommand(command) {
151    return new Promise((resolve, reject) => {
152        exec(command, (err, stdout, stderr) => {
153            if (err) {
154                const errorMessage =
155                    "Failed to execute command" +
156                    `\n\ncommand: ${command}` +
157                    `\n\nstdout: ${stdout}` +
158                    `\n\nstderr: ${stderr}`;
159                reject(errorMessage);
160            }
161            resolve();
162        });
163    });
164}
165