1#!/usr/bin/env python3 2 3"""This is a wrapper function of apexer. It provides opportunity to do 4some artifact preprocessing before calling into apexer. Some of these 5artifact preprocessing are difficult or impossible to do in soong or 6bazel such as trimming the apex native shared libs. It is better to do 7these in a binary so that the preprocessing logic can be reused regardless 8of the build system 9""" 10 11import argparse 12from glob import glob 13import os 14import re 15import shutil 16import sys 17import tempfile 18 19import apex_manifest_pb2 20import apexer_wrapper_utils 21 22def ParseArgs(argv): 23 parser = argparse.ArgumentParser( 24 description='wrapper to run apexer with native shared lib trimming') 25 parser.add_argument( 26 '--apexer', 27 help='path to apexer binary') 28 parser.add_argument( 29 '--canned_fs_config', 30 help='path to canned_fs_config file') 31 parser.add_argument( 32 '--manifest', 33 help='path to apex_manifest.pb file') 34 parser.add_argument( 35 '--libs_to_trim', 36 help='native shared libraries to trim') 37 parser.add_argument( 38 'input_dir', 39 metavar='INPUT_DIR', 40 help='the directory having files to be packaged') 41 parser.add_argument( 42 'output', 43 metavar='OUTPUT', 44 help='name of the APEX file') 45 parser.add_argument( 46 'rest_args', 47 nargs='*', 48 help='remaining flags that will be passed as-is to apexer') 49 return parser.parse_args(argv) 50 51def TrimNativeSharedLibs(image_dir: str, canned_fs_config: str, 52 manifest: str, libs_to_trim: list[str]): 53 """Place native shared libs for trimmed variant in a special way. 54 55 Traditional apex has native shared libs placed under /lib(64)? inside 56 the apex. However, for trimmed variant, for the libs to trim, they will 57 be replaced with a sym link to 58 59 /apex/sharedlibs/lib(64)?/foo.so/[sha512 foo.so]/foo.so 60 """ 61 62 libs_trimmed = set() 63 with open(canned_fs_config, 'r') as f: 64 lines = f.readlines() 65 for line in lines: 66 segs = line.split(' ') 67 if segs[0].endswith('.so'): 68 if any(segs[0].endswith(v) for v in libs_to_trim): 69 lib_relative_path = segs[0][1:] 70 lib_absolute_path = os.path.join(image_dir, lib_relative_path) 71 lib_name = os.path.basename(lib_relative_path) 72 libs_trimmed.add(lib_name) 73 digest = apexer_wrapper_utils.GetDigest(lib_absolute_path) 74 os.remove(lib_absolute_path) 75 link = os.path.join('/apex/sharedlibs', lib_relative_path, digest, lib_name) 76 os.symlink(link, lib_absolute_path) 77 78 manifest_pb = apex_manifest_pb2.ApexManifest() 79 with open(manifest, 'rb') as f: 80 manifest_pb.ParseFromString(f.read()) 81 82 # bump version code 83 # google mainline module logic, for trimmed variant, the variant digit is 2 84 manifest_pb.version = 10*(manifest_pb.version // 10) + 2 85 86 # setting requireSharedApexLibs 87 del manifest_pb.requireSharedApexLibs[:] 88 manifest_pb.requireSharedApexLibs.extend( 89 sorted(re.sub(r':.{128}$', ':sha-512', lib) 90 for lib in libs_trimmed)) 91 92 # write back to root apex_manifest.pb 93 with open(manifest, 'wb') as f: 94 f.write(manifest_pb.SerializeToString()) 95 96def main(argv): 97 args = ParseArgs(argv) 98 segs = args.libs_to_trim.split(',') 99 libs_to_trim = [v+'.so' for v in args.libs_to_trim.split(',')] 100 TrimNativeSharedLibs(args.input_dir, args.canned_fs_config, args.manifest, 101 libs_to_trim) 102 cmd = [args.apexer, '--canned_fs_config', args.canned_fs_config] 103 cmd.extend(['--manifest', args.manifest]) 104 cmd.extend(args.rest_args) 105 cmd.extend([args.input_dir, args.output]) 106 107 apexer_wrapper_utils.RunCommand(cmd) 108 109if __name__ == "__main__": 110 main(sys.argv[1:]) 111