1*90c8c64dSAndroid Build Coastguard Worker#!/usr/bin/env python3 2*90c8c64dSAndroid Build Coastguard Worker 3*90c8c64dSAndroid Build Coastguard Workerimport argparse 4*90c8c64dSAndroid Build Coastguard Workerimport csv 5*90c8c64dSAndroid Build Coastguard Workerimport glob 6*90c8c64dSAndroid Build Coastguard Workerimport json 7*90c8c64dSAndroid Build Coastguard Workerimport os 8*90c8c64dSAndroid Build Coastguard Workerimport sys 9*90c8c64dSAndroid Build Coastguard Worker 10*90c8c64dSAndroid Build Coastguard WorkerHELP_MSG = ''' 11*90c8c64dSAndroid Build Coastguard WorkerThis script computes the differences between two system images (system1 - 12*90c8c64dSAndroid Build Coastguard Workersystem2), and lists the files grouped by package. The difference is just based 13*90c8c64dSAndroid Build Coastguard Workeron the existence of the file, not on its contents. 14*90c8c64dSAndroid Build Coastguard Worker''' 15*90c8c64dSAndroid Build Coastguard Worker 16*90c8c64dSAndroid Build Coastguard WorkerVENDOR_PATH_MAP = { 17*90c8c64dSAndroid Build Coastguard Worker 'vendor/google' : 'Google', 18*90c8c64dSAndroid Build Coastguard Worker 'vendor/unbundled_google': 'Google', 19*90c8c64dSAndroid Build Coastguard Worker 'vendor/verizon' : 'Verizon', 20*90c8c64dSAndroid Build Coastguard Worker 'vendor/qcom' : 'Qualcomm', 21*90c8c64dSAndroid Build Coastguard Worker 'vendor/tmobile' : 'TMobile', 22*90c8c64dSAndroid Build Coastguard Worker 'vendor/mediatek' : 'Mediatek', 23*90c8c64dSAndroid Build Coastguard Worker 'vendor/htc' : 'HTC', 24*90c8c64dSAndroid Build Coastguard Worker 'vendor/realtek' : 'Realtek' 25*90c8c64dSAndroid Build Coastguard Worker} 26*90c8c64dSAndroid Build Coastguard Worker 27*90c8c64dSAndroid Build Coastguard Workerdef _get_relative_out_path_from_root(out_path): 28*90c8c64dSAndroid Build Coastguard Worker """Given a path to a target out directory, get the relative path from the 29*90c8c64dSAndroid Build Coastguard Worker Android root. 30*90c8c64dSAndroid Build Coastguard Worker 31*90c8c64dSAndroid Build Coastguard Worker The module-info.json file paths are relative to the root source folder 32*90c8c64dSAndroid Build Coastguard Worker ie. one directory before out.""" 33*90c8c64dSAndroid Build Coastguard Worker system_path = os.path.normpath(os.path.join(out_path, 'system')) 34*90c8c64dSAndroid Build Coastguard Worker system_path_dirs = system_path.split(os.sep) 35*90c8c64dSAndroid Build Coastguard Worker out_index = system_path_dirs.index("out") 36*90c8c64dSAndroid Build Coastguard Worker return os.path.join(*system_path_dirs[out_index:]) 37*90c8c64dSAndroid Build Coastguard Worker 38*90c8c64dSAndroid Build Coastguard Workerdef system_files(path): 39*90c8c64dSAndroid Build Coastguard Worker """Returns an array of the files under /system, recursively, and ignoring 40*90c8c64dSAndroid Build Coastguard Worker symbolic-links""" 41*90c8c64dSAndroid Build Coastguard Worker system_files = [] 42*90c8c64dSAndroid Build Coastguard Worker system_prefix = os.path.join(path, 'system') 43*90c8c64dSAndroid Build Coastguard Worker # Skip trailing '/' 44*90c8c64dSAndroid Build Coastguard Worker system_prefix_len = len(system_prefix) + 1 45*90c8c64dSAndroid Build Coastguard Worker 46*90c8c64dSAndroid Build Coastguard Worker for root, dirs, files in os.walk(system_prefix, topdown=True): 47*90c8c64dSAndroid Build Coastguard Worker for file in files: 48*90c8c64dSAndroid Build Coastguard Worker # Ignore symbolic links. 49*90c8c64dSAndroid Build Coastguard Worker if not os.path.islink(os.path.join(root, file)): 50*90c8c64dSAndroid Build Coastguard Worker system_files.append(os.path.join(root[system_prefix_len:], file)) 51*90c8c64dSAndroid Build Coastguard Worker 52*90c8c64dSAndroid Build Coastguard Worker return system_files 53*90c8c64dSAndroid Build Coastguard Worker 54*90c8c64dSAndroid Build Coastguard Workerdef system_files_to_package_map(path): 55*90c8c64dSAndroid Build Coastguard Worker """Returns a dictionary mapping from each file in the /system partition to its 56*90c8c64dSAndroid Build Coastguard Worker package, according to modules-info.json.""" 57*90c8c64dSAndroid Build Coastguard Worker system_files_to_package_map = {} 58*90c8c64dSAndroid Build Coastguard Worker system_prefix = _get_relative_out_path_from_root(path) 59*90c8c64dSAndroid Build Coastguard Worker # Skip trailing '/' 60*90c8c64dSAndroid Build Coastguard Worker system_prefix_len = len(system_prefix) + 1 61*90c8c64dSAndroid Build Coastguard Worker 62*90c8c64dSAndroid Build Coastguard Worker with open(os.path.join(path, 'module-info.json')) as module_info_json: 63*90c8c64dSAndroid Build Coastguard Worker module_info = json.load(module_info_json) 64*90c8c64dSAndroid Build Coastguard Worker for module in module_info: 65*90c8c64dSAndroid Build Coastguard Worker installs = module_info[module]['installed'] 66*90c8c64dSAndroid Build Coastguard Worker for install in installs: 67*90c8c64dSAndroid Build Coastguard Worker if install.startswith(system_prefix): 68*90c8c64dSAndroid Build Coastguard Worker system_file = install[system_prefix_len:] 69*90c8c64dSAndroid Build Coastguard Worker # Not clear if collisions can ever happen in modules-info.json (e.g. 70*90c8c64dSAndroid Build Coastguard Worker # the same file installed by multiple packages), but it doesn't hurt 71*90c8c64dSAndroid Build Coastguard Worker # to check. 72*90c8c64dSAndroid Build Coastguard Worker if system_file in system_files_to_package_map: 73*90c8c64dSAndroid Build Coastguard Worker system_files_to_package_map[system_file] = "--multiple--" 74*90c8c64dSAndroid Build Coastguard Worker else: 75*90c8c64dSAndroid Build Coastguard Worker system_files_to_package_map[system_file] = module 76*90c8c64dSAndroid Build Coastguard Worker 77*90c8c64dSAndroid Build Coastguard Worker return system_files_to_package_map 78*90c8c64dSAndroid Build Coastguard Worker 79*90c8c64dSAndroid Build Coastguard Workerdef package_to_vendor_map(path): 80*90c8c64dSAndroid Build Coastguard Worker """Returns a dictionary mapping from each package in modules-info.json to its 81*90c8c64dSAndroid Build Coastguard Worker vendor. If a vendor cannot be found, it maps to "--unknown--". Those cases 82*90c8c64dSAndroid Build Coastguard Worker are: 83*90c8c64dSAndroid Build Coastguard Worker 84*90c8c64dSAndroid Build Coastguard Worker 1. The package maps to multiple modules (e.g., one in APPS and one in 85*90c8c64dSAndroid Build Coastguard Worker SHARED_LIBRARIES. 86*90c8c64dSAndroid Build Coastguard Worker 2. The path to the module is not one of the recognized vendor paths in 87*90c8c64dSAndroid Build Coastguard Worker VENDOR_PATH_MAP.""" 88*90c8c64dSAndroid Build Coastguard Worker package_vendor_map = {} 89*90c8c64dSAndroid Build Coastguard Worker system_prefix = os.path.join(path, 'system') 90*90c8c64dSAndroid Build Coastguard Worker # Skip trailing '/' 91*90c8c64dSAndroid Build Coastguard Worker system_prefix_len = len(system_prefix) + 1 92*90c8c64dSAndroid Build Coastguard Worker vendor_prefixes = VENDOR_PATH_MAP.keys() 93*90c8c64dSAndroid Build Coastguard Worker 94*90c8c64dSAndroid Build Coastguard Worker with open(os.path.join(path, 'module-info.json')) as module_info_json: 95*90c8c64dSAndroid Build Coastguard Worker module_info = json.load(module_info_json) 96*90c8c64dSAndroid Build Coastguard Worker for module in module_info: 97*90c8c64dSAndroid Build Coastguard Worker paths = module_info[module]['path'] 98*90c8c64dSAndroid Build Coastguard Worker vendor = "" 99*90c8c64dSAndroid Build Coastguard Worker if len(paths) == 1: 100*90c8c64dSAndroid Build Coastguard Worker path = paths[0] 101*90c8c64dSAndroid Build Coastguard Worker for prefix in vendor_prefixes: 102*90c8c64dSAndroid Build Coastguard Worker if path.startswith(prefix): 103*90c8c64dSAndroid Build Coastguard Worker vendor = VENDOR_PATH_MAP[prefix] 104*90c8c64dSAndroid Build Coastguard Worker break 105*90c8c64dSAndroid Build Coastguard Worker if vendor == "": 106*90c8c64dSAndroid Build Coastguard Worker vendor = "--unknown--" 107*90c8c64dSAndroid Build Coastguard Worker else: 108*90c8c64dSAndroid Build Coastguard Worker vendor = "--multiple--" 109*90c8c64dSAndroid Build Coastguard Worker package_vendor_map[module] = vendor 110*90c8c64dSAndroid Build Coastguard Worker 111*90c8c64dSAndroid Build Coastguard Worker return package_vendor_map 112*90c8c64dSAndroid Build Coastguard Worker 113*90c8c64dSAndroid Build Coastguard Workerdef main(): 114*90c8c64dSAndroid Build Coastguard Worker parser = argparse.ArgumentParser(description=HELP_MSG) 115*90c8c64dSAndroid Build Coastguard Worker parser.add_argument("out1", help="First $OUT directory") 116*90c8c64dSAndroid Build Coastguard Worker parser.add_argument("out2", help="Second $OUT directory") 117*90c8c64dSAndroid Build Coastguard Worker args = parser.parse_args() 118*90c8c64dSAndroid Build Coastguard Worker 119*90c8c64dSAndroid Build Coastguard Worker system_files1 = system_files(args.out1) 120*90c8c64dSAndroid Build Coastguard Worker system_files2 = system_files(args.out2) 121*90c8c64dSAndroid Build Coastguard Worker system_files_diff = set(system_files1) - set(system_files2) 122*90c8c64dSAndroid Build Coastguard Worker 123*90c8c64dSAndroid Build Coastguard Worker system_files_map = system_files_to_package_map(args.out1) 124*90c8c64dSAndroid Build Coastguard Worker package_vendor_map = package_to_vendor_map(args.out1) 125*90c8c64dSAndroid Build Coastguard Worker packages = {} 126*90c8c64dSAndroid Build Coastguard Worker 127*90c8c64dSAndroid Build Coastguard Worker for file in system_files_diff: 128*90c8c64dSAndroid Build Coastguard Worker if file in system_files_map: 129*90c8c64dSAndroid Build Coastguard Worker package = system_files_map[file] 130*90c8c64dSAndroid Build Coastguard Worker else: 131*90c8c64dSAndroid Build Coastguard Worker package = "--unknown--" 132*90c8c64dSAndroid Build Coastguard Worker 133*90c8c64dSAndroid Build Coastguard Worker if package in packages: 134*90c8c64dSAndroid Build Coastguard Worker packages[package].append(file) 135*90c8c64dSAndroid Build Coastguard Worker else: 136*90c8c64dSAndroid Build Coastguard Worker packages[package] = [file] 137*90c8c64dSAndroid Build Coastguard Worker 138*90c8c64dSAndroid Build Coastguard Worker with open(os.path.join(args.out1, 'module-info.json')) as module_info_json: 139*90c8c64dSAndroid Build Coastguard Worker module_info = json.load(module_info_json) 140*90c8c64dSAndroid Build Coastguard Worker 141*90c8c64dSAndroid Build Coastguard Worker writer = csv.writer(sys.stdout, quoting = csv.QUOTE_NONNUMERIC, 142*90c8c64dSAndroid Build Coastguard Worker delimiter = ',', lineterminator = '\n') 143*90c8c64dSAndroid Build Coastguard Worker for package, files in packages.iteritems(): 144*90c8c64dSAndroid Build Coastguard Worker for file in files: 145*90c8c64dSAndroid Build Coastguard Worker # Group sources of the deltas. 146*90c8c64dSAndroid Build Coastguard Worker if package in package_vendor_map: 147*90c8c64dSAndroid Build Coastguard Worker vendor = package_vendor_map[package] 148*90c8c64dSAndroid Build Coastguard Worker else: 149*90c8c64dSAndroid Build Coastguard Worker vendor = "--unknown--" 150*90c8c64dSAndroid Build Coastguard Worker # Get file size. 151*90c8c64dSAndroid Build Coastguard Worker full_path = os.path.join(args.out1, 'system', file) 152*90c8c64dSAndroid Build Coastguard Worker size = os.stat(full_path).st_size 153*90c8c64dSAndroid Build Coastguard Worker if package in module_info.keys(): 154*90c8c64dSAndroid Build Coastguard Worker module_path = module_info[package]['path'] 155*90c8c64dSAndroid Build Coastguard Worker else: 156*90c8c64dSAndroid Build Coastguard Worker module_path = '' 157*90c8c64dSAndroid Build Coastguard Worker writer.writerow([ 158*90c8c64dSAndroid Build Coastguard Worker # File that exists in out1 but not out2. 159*90c8c64dSAndroid Build Coastguard Worker file, 160*90c8c64dSAndroid Build Coastguard Worker # Module name that the file came from. 161*90c8c64dSAndroid Build Coastguard Worker package, 162*90c8c64dSAndroid Build Coastguard Worker # Path to the module. 163*90c8c64dSAndroid Build Coastguard Worker module_path, 164*90c8c64dSAndroid Build Coastguard Worker # File size. 165*90c8c64dSAndroid Build Coastguard Worker size, 166*90c8c64dSAndroid Build Coastguard Worker # Vendor owner. 167*90c8c64dSAndroid Build Coastguard Worker vendor]) 168*90c8c64dSAndroid Build Coastguard Worker 169*90c8c64dSAndroid Build Coastguard Workerif __name__ == '__main__': 170*90c8c64dSAndroid Build Coastguard Worker main() 171