1*6dbdd20aSAndroid Build Coastguard Worker#!/usr/bin/env python3 2*6dbdd20aSAndroid Build Coastguard Worker# Copyright (C) 2022 The Android Open Source Project 3*6dbdd20aSAndroid Build Coastguard Worker# 4*6dbdd20aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 5*6dbdd20aSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 6*6dbdd20aSAndroid Build Coastguard Worker# You may obtain a copy of the License at 7*6dbdd20aSAndroid Build Coastguard Worker# 8*6dbdd20aSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 9*6dbdd20aSAndroid Build Coastguard Worker# 10*6dbdd20aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 11*6dbdd20aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 12*6dbdd20aSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*6dbdd20aSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 14*6dbdd20aSAndroid Build Coastguard Worker# limitations under the License. 15*6dbdd20aSAndroid Build Coastguard Worker 16*6dbdd20aSAndroid Build Coastguard Workerimport os 17*6dbdd20aSAndroid Build Coastguard Workerimport sys 18*6dbdd20aSAndroid Build Coastguard Workerimport re 19*6dbdd20aSAndroid Build Coastguard Workerimport subprocess 20*6dbdd20aSAndroid Build Coastguard Workerimport pathlib 21*6dbdd20aSAndroid Build Coastguard Workerimport tempfile 22*6dbdd20aSAndroid Build Coastguard Workerimport contextlib 23*6dbdd20aSAndroid Build Coastguard Workerimport argparse 24*6dbdd20aSAndroid Build Coastguard Workerimport itertools 25*6dbdd20aSAndroid Build Coastguard Worker 26*6dbdd20aSAndroid Build Coastguard WorkerROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 27*6dbdd20aSAndroid Build Coastguard WorkerTOOLS_DIR = os.path.join(ROOT_DIR, "tools") 28*6dbdd20aSAndroid Build Coastguard WorkerOUT_DIR = os.path.join(ROOT_DIR, "out", "tools") 29*6dbdd20aSAndroid Build Coastguard WorkerNINJA = os.path.join(TOOLS_DIR, "ninja") 30*6dbdd20aSAndroid Build Coastguard WorkerGN = os.path.join(TOOLS_DIR, "gn") 31*6dbdd20aSAndroid Build Coastguard WorkerPROTOC_PATH = os.path.join(OUT_DIR, "protoc") 32*6dbdd20aSAndroid Build Coastguard WorkerDESCRIPTOR_PATH = os.path.join(ROOT_DIR, "src", "trace_processor", "importers", 33*6dbdd20aSAndroid Build Coastguard Worker "proto", "atoms.descriptor") 34*6dbdd20aSAndroid Build Coastguard WorkerPROTOBUF_BUILTINS_DIR = os.path.join(ROOT_DIR, "buildtools", "protobuf", "src") 35*6dbdd20aSAndroid Build Coastguard WorkerPROTO_LOGGING_URL = "https://android.googlesource.com/platform/frameworks/proto_logging.git" 36*6dbdd20aSAndroid Build Coastguard WorkerATOM_RE = r" message_type {\n. name: \"Atom\"(\n .+)+(\n })" 37*6dbdd20aSAndroid Build Coastguard WorkerFIELD_RE = r" field {\n name: \"([^\"]+)\"\n number: ([0-9]+)" 38*6dbdd20aSAndroid Build Coastguard WorkerEXTENSIONS_RE = r" extension {\n name: \"([^\"]+)\"\n extendee: \".android.os.statsd.Atom\"\n number: ([0-9]+)(\n .+)+(\n })" 39*6dbdd20aSAndroid Build Coastguard WorkerATOM_IDS_PATH = os.path.join(ROOT_DIR, "protos", "perfetto", "config", "statsd", 40*6dbdd20aSAndroid Build Coastguard Worker "atom_ids.proto") 41*6dbdd20aSAndroid Build Coastguard Worker 42*6dbdd20aSAndroid Build Coastguard WorkerATOM_IDS_TEMPLATE = """/* 43*6dbdd20aSAndroid Build Coastguard Worker * Copyright (C) 2022 The Android Open Source Project 44*6dbdd20aSAndroid Build Coastguard Worker * 45*6dbdd20aSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 46*6dbdd20aSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 47*6dbdd20aSAndroid Build Coastguard Worker * You may obtain a copy of the License at 48*6dbdd20aSAndroid Build Coastguard Worker * 49*6dbdd20aSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 50*6dbdd20aSAndroid Build Coastguard Worker * 51*6dbdd20aSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 52*6dbdd20aSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 53*6dbdd20aSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 54*6dbdd20aSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 55*6dbdd20aSAndroid Build Coastguard Worker * limitations under the License. 56*6dbdd20aSAndroid Build Coastguard Worker */ 57*6dbdd20aSAndroid Build Coastguard Workersyntax = "proto2"; 58*6dbdd20aSAndroid Build Coastguard Worker 59*6dbdd20aSAndroid Build Coastguard Workerpackage perfetto.protos; 60*6dbdd20aSAndroid Build Coastguard Worker 61*6dbdd20aSAndroid Build Coastguard Worker// This enum is obtained by post-processing 62*6dbdd20aSAndroid Build Coastguard Worker// AOSP/frameworks/proto_logging/stats/atoms.proto through 63*6dbdd20aSAndroid Build Coastguard Worker// AOSP/external/perfetto/tools/update-statsd-descriptor, which extracts one 64*6dbdd20aSAndroid Build Coastguard Worker// enum value for each proto field defined in the upstream atoms.proto. 65*6dbdd20aSAndroid Build Coastguard Workerenum AtomId {{ 66*6dbdd20aSAndroid Build Coastguard Worker ATOM_UNSPECIFIED = 0; 67*6dbdd20aSAndroid Build Coastguard Worker{atoms} 68*6dbdd20aSAndroid Build Coastguard Worker}}""" 69*6dbdd20aSAndroid Build Coastguard Worker 70*6dbdd20aSAndroid Build Coastguard Worker 71*6dbdd20aSAndroid Build Coastguard Workerdef call(*cmd, stdin=None): 72*6dbdd20aSAndroid Build Coastguard Worker try: 73*6dbdd20aSAndroid Build Coastguard Worker return subprocess.check_output(cmd, stdin=stdin) 74*6dbdd20aSAndroid Build Coastguard Worker except subprocess.CalledProcessError as e: 75*6dbdd20aSAndroid Build Coastguard Worker print("Error running the command:") 76*6dbdd20aSAndroid Build Coastguard Worker print(" ".join(cmd)) 77*6dbdd20aSAndroid Build Coastguard Worker print(e) 78*6dbdd20aSAndroid Build Coastguard Worker exit(1) 79*6dbdd20aSAndroid Build Coastguard Worker 80*6dbdd20aSAndroid Build Coastguard Worker 81*6dbdd20aSAndroid Build Coastguard Worker# Extract core atoms. To do this we regex the pbtext 82*6dbdd20aSAndroid Build Coastguard Worker# of the descriptor. This is hopefully: 83*6dbdd20aSAndroid Build Coastguard Worker# - more stable than regexing atom.proto directly 84*6dbdd20aSAndroid Build Coastguard Worker# - less complicated than parsing finding, importing, and using the 85*6dbdd20aSAndroid Build Coastguard Worker# Python protobuf library. 86*6dbdd20aSAndroid Build Coastguard Workerdef atoms_from_descriptor(): 87*6dbdd20aSAndroid Build Coastguard Worker with contextlib.ExitStack() as stack: 88*6dbdd20aSAndroid Build Coastguard Worker descriptor_in = stack.enter_context(open(DESCRIPTOR_PATH)) 89*6dbdd20aSAndroid Build Coastguard Worker pbtext = call( 90*6dbdd20aSAndroid Build Coastguard Worker PROTOC_PATH, 91*6dbdd20aSAndroid Build Coastguard Worker f"--proto_path={PROTOBUF_BUILTINS_DIR}", 92*6dbdd20aSAndroid Build Coastguard Worker f"{PROTOBUF_BUILTINS_DIR}/google/protobuf/descriptor.proto", 93*6dbdd20aSAndroid Build Coastguard Worker "--decode=google.protobuf.FileDescriptorSet", 94*6dbdd20aSAndroid Build Coastguard Worker stdin=descriptor_in).decode("utf8") 95*6dbdd20aSAndroid Build Coastguard Worker 96*6dbdd20aSAndroid Build Coastguard Worker # Core atoms: 97*6dbdd20aSAndroid Build Coastguard Worker atom_pbtext = re.search(ATOM_RE, pbtext, re.MULTILINE)[0] 98*6dbdd20aSAndroid Build Coastguard Worker for m in re.finditer(FIELD_RE, atom_pbtext): 99*6dbdd20aSAndroid Build Coastguard Worker yield m[1], m[2] 100*6dbdd20aSAndroid Build Coastguard Worker 101*6dbdd20aSAndroid Build Coastguard Worker # Extensions 102*6dbdd20aSAndroid Build Coastguard Worker for m in re.finditer(EXTENSIONS_RE, pbtext): 103*6dbdd20aSAndroid Build Coastguard Worker yield m[1], m[2] 104*6dbdd20aSAndroid Build Coastguard Worker 105*6dbdd20aSAndroid Build Coastguard Worker 106*6dbdd20aSAndroid Build Coastguard Workerdef main(): 107*6dbdd20aSAndroid Build Coastguard Worker parser = argparse.ArgumentParser() 108*6dbdd20aSAndroid Build Coastguard Worker parser.add_argument("--atoms-checkout") 109*6dbdd20aSAndroid Build Coastguard Worker args = parser.parse_args() 110*6dbdd20aSAndroid Build Coastguard Worker 111*6dbdd20aSAndroid Build Coastguard Worker call(GN, "gen", OUT_DIR, "--args=is_debug=false") 112*6dbdd20aSAndroid Build Coastguard Worker call(NINJA, "-C", OUT_DIR, "protoc") 113*6dbdd20aSAndroid Build Coastguard Worker 114*6dbdd20aSAndroid Build Coastguard Worker with contextlib.ExitStack() as stack: 115*6dbdd20aSAndroid Build Coastguard Worker 116*6dbdd20aSAndroid Build Coastguard Worker # Write the descriptor. 117*6dbdd20aSAndroid Build Coastguard Worker if args.atoms_checkout: 118*6dbdd20aSAndroid Build Coastguard Worker atoms_root = args.atoms_checkout 119*6dbdd20aSAndroid Build Coastguard Worker proto_logging_dir = os.path.join(atoms_root, "frameworks", 120*6dbdd20aSAndroid Build Coastguard Worker "proto_logging") 121*6dbdd20aSAndroid Build Coastguard Worker else: 122*6dbdd20aSAndroid Build Coastguard Worker atoms_root = stack.enter_context(tempfile.TemporaryDirectory()) 123*6dbdd20aSAndroid Build Coastguard Worker proto_logging_dir = os.path.join(atoms_root, "frameworks", 124*6dbdd20aSAndroid Build Coastguard Worker "proto_logging") 125*6dbdd20aSAndroid Build Coastguard Worker pathlib.Path(proto_logging_dir).mkdir(parents=True, exist_ok=True) 126*6dbdd20aSAndroid Build Coastguard Worker call("git", "clone", PROTO_LOGGING_URL, proto_logging_dir) 127*6dbdd20aSAndroid Build Coastguard Worker 128*6dbdd20aSAndroid Build Coastguard Worker 129*6dbdd20aSAndroid Build Coastguard Worker extensions_path = os.path.join(proto_logging_dir, "stats", "atoms") 130*6dbdd20aSAndroid Build Coastguard Worker extensions = [] 131*6dbdd20aSAndroid Build Coastguard Worker if os.path.isdir(extensions_path): 132*6dbdd20aSAndroid Build Coastguard Worker for dirpath, dirnames, filenames in os.walk(extensions_path): 133*6dbdd20aSAndroid Build Coastguard Worker for name in filenames: 134*6dbdd20aSAndroid Build Coastguard Worker if name.endswith(".proto"): 135*6dbdd20aSAndroid Build Coastguard Worker path = os.path.join(dirpath, name) 136*6dbdd20aSAndroid Build Coastguard Worker extensions.append(path) 137*6dbdd20aSAndroid Build Coastguard Worker 138*6dbdd20aSAndroid Build Coastguard Worker cmd = [ 139*6dbdd20aSAndroid Build Coastguard Worker f"--proto_path={PROTOBUF_BUILTINS_DIR}", 140*6dbdd20aSAndroid Build Coastguard Worker f"--proto_path={atoms_root}", 141*6dbdd20aSAndroid Build Coastguard Worker f"--descriptor_set_out={DESCRIPTOR_PATH}", 142*6dbdd20aSAndroid Build Coastguard Worker "--include_imports", 143*6dbdd20aSAndroid Build Coastguard Worker ] + extensions + [ 144*6dbdd20aSAndroid Build Coastguard Worker os.path.join(proto_logging_dir, "stats", "atoms.proto") 145*6dbdd20aSAndroid Build Coastguard Worker ] 146*6dbdd20aSAndroid Build Coastguard Worker call(PROTOC_PATH, *cmd) 147*6dbdd20aSAndroid Build Coastguard Worker 148*6dbdd20aSAndroid Build Coastguard Worker lines = [] 149*6dbdd20aSAndroid Build Coastguard Worker for name, field in atoms_from_descriptor(): 150*6dbdd20aSAndroid Build Coastguard Worker name = "ATOM_" + name.upper() 151*6dbdd20aSAndroid Build Coastguard Worker lines.append(f" {name} = {field};".format(name=name, field=field)) 152*6dbdd20aSAndroid Build Coastguard Worker atom_ids_out = stack.enter_context(open(ATOM_IDS_PATH, "w")) 153*6dbdd20aSAndroid Build Coastguard Worker atom_ids_out.write(ATOM_IDS_TEMPLATE.format(atoms="\n".join(lines))) 154*6dbdd20aSAndroid Build Coastguard Worker 155*6dbdd20aSAndroid Build Coastguard Worker 156*6dbdd20aSAndroid Build Coastguard Workerif __name__ == "__main__": 157*6dbdd20aSAndroid Build Coastguard Worker sys.exit(main()) 158