1#!/usr/bin/env python3 2 3# Copyright (C) 2022 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17import os 18import glob 19import argparse 20import pathlib 21import shutil 22import subprocess 23import re 24 25 26def sed(pattern, replacement, file): 27 """ Performs an in-place string replacement of pattern in a target file 28 29 Args: 30 pattern: pattern to replace 31 replacement: replacement for the pattern matches 32 file: target file 33 34 Returns: 35 Nothing 36 """ 37 38 with open(file) as reader: 39 file_contents = reader.read() 40 new_file_contents = re.sub(pattern, replacement, file_contents) 41 with open(file, "w") as writer: 42 writer.write(new_file_contents) 43 44 45def single(items): 46 """ Returns the only item from a list of just one item 47 48 Raises a ValueError if the list does not contain exactly one element 49 50 Args: 51 items: a list of one item 52 53 Returns: 54 The only item from a single-item-list 55 """ 56 57 if len(items) != 1: 58 raise ValueError('Expected a list of size 1. Found: %s' % items) 59 return items[0] 60 61 62def update_tracing_perfetto(old_version, new_version, core_path, force_unstripped_binaries=False): 63 """Updates tracing-perfetto version and artifacts (including building new binaries) 64 65 Args: 66 old_version: old version of the existing library 67 new_version: new version of the library; defaults to incrementing the old_version 68 core_path: path to frameworks/support directory 69 force_unstripped_binaries: flag allowing to force unstripped variant of binaries 70 Returns: 71 Nothing 72 """ 73 74 print("Updating tracing-perfetto, this can take a while...") 75 76 # update version in code 77 sed('tracingPerfettoVersion = "%s"' % old_version, 78 'tracingPerfettoVersion = "%s"' % new_version, 79 os.path.join(core_path, 'benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/' 80 'macro/perfetto/PerfettoSdkHandshakeTest.kt')) 81 sed('TRACING_PERFETTO = "%s"' % old_version, 82 'TRACING_PERFETTO = "%s"' % new_version, 83 os.path.join(core_path, 'libraryversions.toml')) 84 sed('#define VERSION "%s"' % old_version, 85 '#define VERSION "%s"' % new_version, 86 os.path.join(core_path, 'tracing/tracing-perfetto-binary/src/main/cpp/tracing_perfetto.cc')) 87 sed('const val libraryVersion = "%s"' % old_version, 88 'const val libraryVersion = "%s"' % new_version, 89 os.path.join(core_path, 'tracing/tracing-perfetto/src/androidTest/java/androidx/tracing/' 90 'perfetto/jni/test/PerfettoNativeTest.kt')) 91 sed('const val version = "%s"' % old_version, 92 'const val version = "%s"' % new_version, 93 os.path.join(core_path, 'tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/' 94 'jni/PerfettoNative.kt')) 95 96 # build new binaries 97 subprocess.check_call(["./gradlew", 98 ":tracing:tracing-perfetto-binary:createProjectZip", 99 "-Pandroidx.constraints=true", 100 "-DTRACING_PERFETTO_REUSE_PREBUILTS_AAR=false"], 101 cwd=core_path) 102 103 # copy binaries to prebuilts 104 project_zip_dir = os.path.join(core_path, '../../out/dist/per-project-zips') 105 project_zip_file = os.path.join( 106 project_zip_dir, 107 single(glob.glob('%s/*tracing*perfetto*binary*%s*.zip' % (project_zip_dir, new_version)))) 108 dst_dir = pathlib.Path(os.path.join( 109 core_path, 110 "../../prebuilts/androidx/internal/androidx/tracing/tracing-perfetto-binary", 111 new_version)) 112 if dst_dir.exists(): 113 shutil.rmtree(dst_dir) 114 dst_dir.mkdir() 115 subprocess.check_call( 116 ["unzip", "-xjqq", project_zip_file, '**/%s/**' % new_version, "-d", dst_dir]) 117 118 # force unstripped binaries if the flag is enabled 119 if force_unstripped_binaries: 120 # locate unstripped binaries 121 out_dir = pathlib.Path(core_path, "../../out") 122 arm64_lib_file = out_dir.joinpath(single(subprocess.check_output( 123 'find . -type f -name "libtracing_perfetto.so"' 124 ' -and -path "*RelWithDebInfo/*/obj/arm64*"' 125 ' -exec stat -c "%Y %n" {} \\; |' 126 ' sort | tail -1 | cut -d " " -f2-', 127 cwd=out_dir, 128 shell=True).splitlines()).decode()) 129 base_dir = arm64_lib_file.parent.parent.parent 130 obj_dir = base_dir.joinpath('obj') 131 if not obj_dir.exists(): 132 raise RuntimeError('Expected path %s to exist' % repr(obj_dir)) 133 jni_dir = base_dir.joinpath('jni') 134 135 # prepare a jni folder to inject into the destination aar 136 if jni_dir.exists(): 137 shutil.rmtree(jni_dir) 138 shutil.copytree(obj_dir, jni_dir) 139 140 # inject the jni folder into the aar 141 dst_aar = os.path.join(dst_dir, 'tracing-perfetto-binary-%s.aar' % new_version) 142 subprocess.check_call(['zip', '-r', dst_aar, 'jni'], cwd=base_dir) 143 144 # clean up 145 if jni_dir.exists(): 146 shutil.rmtree(jni_dir) 147 148 # update SHA 149 for arch in ['armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64']: 150 checksum = subprocess.check_output( 151 'unzip -cxqq "*tracing*binary*%s*.aar" "**/%s/libtracing_perfetto.so" | shasum -a256 |' 152 ' awk \'{print $1}\' | tr -d "\n"' % (new_version, arch), 153 cwd=dst_dir, 154 shell=True 155 ).decode() 156 if not re.fullmatch('^[0-9a-z]{64}$', checksum): 157 raise ValueError('Expecting a sha256 sum. Got: %s' % checksum) 158 sed( 159 '"%s" to "[0-9a-z]{64}"' % arch, 160 '"%s" to "%s"' % (arch, checksum), 161 os.path.join(core_path, 'tracing/tracing-perfetto/src/main/java/androidx/tracing/' 162 'perfetto/jni/PerfettoNative.kt')) 163 164 print("Updated tracing-perfetto.") 165 166 167if __name__ == '__main__': 168 parser = argparse.ArgumentParser( 169 description='Updates tracing-perfetto in the source code, which involves:' 170 ' 1) updating hardcoded version references in code' 171 ' 2) building binaries and updating them in the prebuilts folder' 172 ' 3) updating SHA checksums hardcoded in code.') 173 parser.add_argument('-f', '--frameworks-support-dir', 174 required=True, 175 help='Path to frameworks/support directory') 176 parser.add_argument('-c', '--current-version', 177 required=True, 178 help='Current version, e.g. 1.0.0-alpha07') 179 parser.add_argument('-t', '--target-version', 180 required=True, 181 help='Target version, e.g. 1.0.0-alpha08') 182 parser.add_argument('-k', '--keep-binary-debug-symbols', 183 required=False, 184 default=False, 185 action='store_true', 186 help='Keeps debug symbols in the built binaries. Useful when profiling ' 187 'performance of the library. ') 188 args = parser.parse_args() 189 core_path_abs = pathlib.Path(args.frameworks_support_dir).resolve() 190 update_tracing_perfetto(args.current_version, args.target_version, core_path_abs, 191 args.keep_binary_debug_symbols) 192