def GenerateBuildInfo(args): build_info = apex_build_info_pb2.ApexBuildInfo() if (args.include_cmd_line_in_build_info): build_info.apexer_command_line = str(sys.argv) with open(args.file_contexts) as f: build_info.file_contexts = f.read() with open(args.canned_fs_config) as f: build_info.canned_fs_config = f.read() with open(args.android_manifest) as f: build_info.android_manifest = f.read() if args.target_sdk_version: build_info.target_sdk_version = args.target_sdk_version if args.min_sdk_version: build_info.min_sdk_version = args.min_sdk_version if args.no_hashtree: build_info.no_hashtree = True if args.override_apk_package_name: build_info.override_apk_package_name = args.override_apk_package_name if args.logging_parent: build_info.logging_parent = args.logging_parent if args.payload_type == 'image': build_info.payload_fs_type = args.payload_fs_type return build_info
def ValidateArgs(args): build_info = None if args.build_info is not None: if not os.path.exists(args.build_info): print("Build info file '" + args.build_info + "' does not exist") return False with open(args.build_info) as buildInfoFile: build_info = apex_build_info_pb2.ApexBuildInfo() build_info.ParseFromString(buildInfoFile.read()) if not os.path.exists(args.manifest): print("Manifest file '" + args.manifest + "' does not exist") return False if not os.path.isfile(args.manifest): print("Manifest file '" + args.manifest + "' is not a file") return False if args.android_manifest is not None: if not os.path.exists(args.android_manifest): print("Android Manifest file '" + args.android_manifest + "' does not exist") return False if not os.path.isfile(args.android_manifest): print("Android Manifest file '" + args.android_manifest + "' is not a file") return False elif build_info is not None: with tempfile.NamedTemporaryFile(delete=False) as temp: temp.write(build_info.android_manifest) args.android_manifest = temp.name if not os.path.exists(args.input_dir): print("Input directory '" + args.input_dir + "' does not exist") return False if not os.path.isdir(args.input_dir): print("Input directory '" + args.input_dir + "' is not a directory") return False if not args.force and os.path.exists(args.output): print(args.output + ' already exists. Use --force to overwrite.') return False if args.unsigned_payload_only: args.payload_only = True args.unsigned_payload = True if args.payload_type == 'image': if not args.key and not args.unsigned_payload: print('Missing --key {keyfile} argument!') return False if not args.file_contexts: if build_info is not None: with tempfile.NamedTemporaryFile(delete=False) as temp: temp.write(build_info.file_contexts) args.file_contexts = temp.name else: print( 'Missing --file_contexts {contexts} argument, or a --build_info argument!' ) return False if not args.canned_fs_config: if not args.canned_fs_config: if build_info is not None: with tempfile.NamedTemporaryFile(delete=False) as temp: temp.write(build_info.canned_fs_config) args.canned_fs_config = temp.name else: print( 'Missing ----canned_fs_config {config} argument, or a --build_info argument!' ) return False if not args.target_sdk_version: if build_info is not None: if build_info.target_sdk_version: args.target_sdk_version = build_info.target_sdk_version if not args.no_hashtree: if build_info is not None: if build_info.no_hashtree: args.no_hashtree = True if not args.min_sdk_version: if build_info is not None: if build_info.min_sdk_version: args.min_sdk_version = build_info.min_sdk_version if not args.override_apk_package_name: if build_info is not None: if build_info.override_apk_package_name: args.override_apk_package_name = build_info.override_apk_package_name if not args.logging_parent: if build_info is not None: if build_info.logging_parent: args.logging_parent = build_info.logging_parent return True
def main(argv): args = parse_args(argv) apex_file_path = args.input container_files = get_container_files(apex_file_path, args.tmpdir) payload_dir = extract_payload_from_img(container_files['apex_payload.img'], args.tmpdir) libs = args.libs assert len(libs) > 0 lib_paths = [ os.path.join(payload_dir, lib_dir, lib) for lib_dir in ['lib', 'lib64'] for lib in libs if os.path.exists(os.path.join(payload_dir, lib_dir, lib)) ] assert len(lib_paths) > 0 lib_paths_hashes = [(lib, compute_sha512(lib)) for lib in lib_paths] if args.mode == 'strip': # Stripping mode. Add a reference to the version of libc++.so to the # requireSharedApexLibs entry in the manifest, and remove lib64/libc++.so # from the payload. pb = apex_manifest_pb2.ApexManifest() with open(container_files['apex_manifest.pb'], 'rb') as f: pb.ParseFromString(f.read()) for lib_path_hash in lib_paths_hashes: basename = os.path.basename(lib_path_hash[0]) libpath = _extract_lib_or_lib64(payload_dir, lib_path_hash[0]) assert libpath in ('lib', 'lib64') pb.requireSharedApexLibs.append( os.path.join(libpath, basename) + ':' + lib_path_hash[1]) # Replace existing library with symlink symlink_dst = os.path.join('/', 'apex', 'sharedlibs', libpath, basename, lib_path_hash[1], basename) os.remove(lib_path_hash[0]) os.system('ln -s {0} {1}'.format(symlink_dst, lib_path_hash[0])) # # Example of resulting manifest: # --- # name: "com.android.apex.test.foo" # version: 1 # requireNativeLibs: "libc.so" # requireNativeLibs: "libdl.so" # requireNativeLibs: "libm.so" # requireSharedApexLibs: "lib/libc++.so:23c5dd..." # requireSharedApexLibs: "lib/libsharedlibtest.so:870f38..." # requireSharedApexLibs: "lib64/libc++.so:72a584..." # requireSharedApexLibs: "lib64/libsharedlibtest.so:109015..." # -- # To print uncomment the following: # from google.protobuf import text_format # print(text_format.MessageToString(pb)) with open(container_files['apex_manifest.pb'], 'wb') as f: f.write(pb.SerializeToString()) if args.mode == 'sharedlibs': # Sharedlibs mode. Mark in the APEX manifest that this package contains # shared libraries. pb = apex_manifest_pb2.ApexManifest() with open(container_files['apex_manifest.pb'], 'rb') as f: pb.ParseFromString(f.read()) del pb.requireNativeLibs[:] pb.provideSharedApexLibs = True with open(container_files['apex_manifest.pb'], 'wb') as f: f.write(pb.SerializeToString()) pb = apex_build_info_pb2.ApexBuildInfo() with open(container_files['apex_build_info.pb'], 'rb') as f: pb.ParseFromString(f.read()) canned_fs_config = parse_fs_config(pb.canned_fs_config.decode('utf-8')) # Remove the bin directory from payload dir and from the canned_fs_config. shutil.rmtree(os.path.join(payload_dir, 'bin')) canned_fs_config = [ config for config in canned_fs_config if not config[0].startswith('/bin') ] # Remove from the canned_fs_config the entries we are about to relocate in # different dirs. source_lib_paths = [ os.path.join('/', libpath, lib) for libpath in ['lib', 'lib64'] for lib in libs ] # We backup the fs config lines for the libraries we are going to relocate, # so we can set the same permissions later. canned_fs_config_original_lib = { config[0]: config for config in canned_fs_config if config[0] in source_lib_paths } canned_fs_config = [ config for config in canned_fs_config if config[0] not in source_lib_paths ] # We move any targeted library in lib64/ or lib/ to a directory named # /lib64/libNAME.so/${SHA512_OF_LIBCPP}/ or # /lib/libNAME.so/${SHA512_OF_LIBCPP}/ # for lib_path_hash in lib_paths_hashes: basename = os.path.basename(lib_path_hash[0]) libpath = _extract_lib_or_lib64(payload_dir, lib_path_hash[0]) tmp_lib = os.path.join(payload_dir, libpath, basename + '.bak') shutil.move(lib_path_hash[0], tmp_lib) destdir = os.path.join(payload_dir, libpath, basename, lib_path_hash[1]) os.makedirs(destdir) shutil.move(tmp_lib, os.path.join(destdir, basename)) canned_fs_config.append( ['/' + libpath + '/' + basename, '0', '2000', '0755']) canned_fs_config.append([ '/' + libpath + '/' + basename + '/' + lib_path_hash[1], '0', '2000', '0755' ]) if os.path.join('/', libpath, basename) in canned_fs_config_original_lib: config = canned_fs_config_original_lib[os.path.join( '/', libpath, basename)] canned_fs_config.append([ os.path.join('/', libpath, basename, lib_path_hash[1], basename), config[1], config[2], config[3] ]) else: canned_fs_config.append([ os.path.join('/', libpath, basename, lib_path_hash[1], basename), '1000', '1000', '0644' ]) pb.canned_fs_config = config_to_str(canned_fs_config).encode('utf-8') with open(container_files['apex_build_info.pb'], 'wb') as f: f.write(pb.SerializeToString()) try: for lib in lib_paths: os.rmdir(os.path.dirname(lib)) except OSError: # Directory not empty, that's OK. pass repack_apex_file_path = run_apexer(container_files, payload_dir, args.key, args.pubkey, args.tmpdir) resigned_apex_file_path = sign_apk_container(repack_apex_file_path, args.x509key, args.pk8key, args.tmpdir) shutil.copyfile(resigned_apex_file_path, args.output)