From 23e5188422fdeb42a708756d59d0979d6ac89ced Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Tue, 15 Jan 2019 08:32:18 -0500 Subject: [PATCH] Update scripts 1. Update build.py to use f-strings 2. Directly append busybox binaries to update-binary 3. Remove b64xz --- build.py | 109 ++++++++++++++++++--------------------- native/jni/Android.mk | 13 ----- native/jni/misc/b64xz.c | 78 ---------------------------- scripts/update_binary.sh | 39 +++++++------- 4 files changed, 72 insertions(+), 167 deletions(-) delete mode 100644 native/jni/misc/b64xz.c diff --git a/build.py b/build.py index b49be3409..879927339 100755 --- a/build.py +++ b/build.py @@ -60,7 +60,7 @@ def mv(source, target): def cp(source, target): try: shutil.copyfile(source, target) - vprint('cp: {} -> {}'.format(source, target)) + vprint(f'cp: {source} -> {target}') except: pass @@ -82,9 +82,9 @@ def mkdir_p(path, mode=0o777): def zip_with_msg(zipfile, source, target): if not os.path.exists(source): - error('{} does not exist! Try build \'binary\' and \'apk\' before zipping!'.format(source)) + error(f'{source} does not exist! Try build \'binary\' and \'apk\' before zipping!') zipfile.write(source, target) - vprint('zip: {} -> {}'.format(source, target)) + vprint(f'zip: {source} -> {target}') def collect_binary(): for arch in archs: @@ -111,7 +111,7 @@ def sign_zip(unsigned, output, release): header('* Building ' + signer_name) proc = execv([gradlew, 'utils:shadowJar']) if proc.returncode != 0: - error('Build {} failed!'.format(signer_name)) + error(f'Build {signer_name} failed!') header('* Signing Zip') @@ -124,41 +124,38 @@ def sign_zip(unsigned, output, release): error('Signing zip failed!') def binary_dump(src, out, var_name): - out.write('const static unsigned char {}[] = {{'.format(var_name)) + out.write(f'const static unsigned char {var_name}[] = {{') for i, c in enumerate(xz(src.read())): if i % 16 == 0: out.write('\n') - out.write('0x{:02X},'.format(c)) + out.write(f'0x{c:02X},') out.write('\n};\n') out.flush() def gen_update_binary(): - update_bin = [] - binary = os.path.join('native', 'out', 'armeabi-v7a', 'b64xz') - if not os.path.exists(binary): - error('Please build \'binary\' before zipping!') - with open(binary, 'rb') as b64xz: - update_bin.append('#! /sbin/sh\nEX_ARM=\'') - update_bin.append(''.join("\\x{:02X}".format(c) for c in b64xz.read())) - binary = os.path.join('native', 'out', 'x86', 'b64xz') - with open(binary, 'rb') as b64xz: - update_bin.append('\'\nEX_X86=\'') - update_bin.append(''.join("\\x{:02X}".format(c) for c in b64xz.read())) - binary = os.path.join('native', 'out', 'armeabi-v7a', 'busybox') - with open(binary, 'rb') as busybox: - update_bin.append('\'\nBB_ARM=') - update_bin.append(base64.b64encode(xz(busybox.read())).decode('ascii')) - binary = os.path.join('native', 'out', 'x86', 'busybox') - with open(binary, 'rb') as busybox: - update_bin.append('\nBB_X86=') - update_bin.append(base64.b64encode(xz(busybox.read())).decode('ascii')) - update_bin.append('\n') - with open(os.path.join('scripts', 'update_binary.sh'), 'r') as script: - update_bin.append(script.read()) - return ''.join(update_bin) + bs = 1024 + update_bin = bytearray(bs) + file = os.path.join('native', 'out', 'x86', 'busybox') + with open(file, 'rb') as f: + x86_bb = f.read() + file = os.path.join('native', 'out', 'armeabi-v7a', 'busybox') + with open(file, 'rb') as f: + arm_bb = f.read() + file = os.path.join('scripts', 'update_binary.sh') + with open(file, 'rb') as f: + script = f.read() + # Align x86 busybox to bs + blkCnt = (len(x86_bb) - 1) // bs + 1 + script = script.replace(b'__X86_CNT__', b'%d' % blkCnt) + update_bin[:len(script)] = script + update_bin.extend(x86_bb) + # Padding for alignment + update_bin.extend(b'\0' * (blkCnt * bs - len(x86_bb))) + update_bin.extend(arm_bb) + return update_bin def build_binary(args): - support_targets = {'magisk', 'magiskinit', 'magiskboot', 'busybox', 'b64xz'} + support_targets = {'magisk', 'magiskinit', 'magiskboot', 'busybox'} if len(args.target) == 0: # If nothing specified, build everything args.target = support_targets @@ -173,13 +170,13 @@ def build_binary(args): os.utime(os.path.join('native', 'jni', 'include', 'flags.h')) # Basic flags - base_flags = 'MAGISK_VERSION=\"{}\" MAGISK_VER_CODE={}'.format(config['version'], config['versionCode']) + base_flags = f'MAGISK_VERSION="{config["version"]}" MAGISK_VER_CODE={config["versionCode"]}' if not args.release: base_flags += ' MAGISK_DEBUG=1' + # Magisk is special case as it is a dependency of magiskinit if 'magisk' in args.target: - # Magisk is special case as it is a dependency of magiskinit - proc = system('{} -C native {} B_MAGISK=1 -j{}'.format(ndk_build, base_flags, cpu_count)) + proc = system(f'{ndk_build} -C native {base_flags} B_MAGISK=1 -j{cpu_count}') if proc.returncode != 0: error('Build Magisk binary failed!') collect_binary() @@ -190,12 +187,15 @@ def build_binary(args): with open(bin_file, 'rb') as src: binary_dump(src, out, 'magisk_xz') - old_plat = False - flags = base_flags + # BusyBox is special case as it needs special flags to build + if 'busybox' in args.target: + proc = system(f'{ndk_build} -C native {base_flags} B_BB=1 -j{cpu_count}') + if proc.returncode != 0: + error('Build binaries failed!') + collect_binary() - if 'b64xz' in args.target: - flags += ' B_BXZ=1' - old_plat = True + build = False + flags = base_flags if 'magiskinit' in args.target: if not os.path.exists(os.path.join('native', 'out', 'x86', 'binaries_arch.h')): @@ -203,20 +203,14 @@ def build_binary(args): if not os.path.exists(os.path.join('native', 'out', 'binaries.h')): error('Build stub APK before building "magiskinit"') flags += ' B_INIT=1' - old_plat = True + build = True if 'magiskboot' in args.target: flags += ' B_BOOT=1' - old_plat = True + build = True - if old_plat: - proc = system('{} -C native {} -j{}'.format(ndk_build, flags, cpu_count)) - if proc.returncode != 0: - error('Build binaries failed!') - collect_binary() - - if 'busybox' in args.target: - proc = system('{} -C native {} B_BB=1 -j{}'.format(ndk_build, base_flags, cpu_count)) + if build: + proc = system(f'{ndk_build} -C native {flags} -j{cpu_count}') if proc.returncode != 0: error('Build binaries failed!') collect_binary() @@ -226,13 +220,13 @@ def build_apk(args, flavor): buildType = 'Release' if args.release else 'Debug' - proc = execv([gradlew, 'app:assemble' + flavor + buildType, '-PconfigPath=' + os.path.abspath(args.config)]) + proc = execv([gradlew, f'app:assemble{flavor}{buildType}', '-PconfigPath=' + os.path.abspath(args.config)]) if proc.returncode != 0: error('Build Magisk Manager failed!') flavor = flavor.lower() buildType = buildType.lower() - apk = 'app-{}-{}.apk'.format(flavor, buildType) + apk = f'app-{flavor}-{buildType}.apk' source = os.path.join('app', 'build', 'outputs', 'apk', flavor, buildType, apk) target = os.path.join(config['outdir'], apk) @@ -306,9 +300,9 @@ def zip_main(args): with open(source, 'r') as script: # Add version info util_functions.sh util_func = script.read().replace('#MAGISK_VERSION_STUB', - 'MAGISK_VER="{}"\nMAGISK_VER_CODE={}'.format(config['version'], config['versionCode'])) + f'MAGISK_VER="{config["version"]}"\nMAGISK_VER_CODE={config["versionCode"]}') target = os.path.join('common', 'util_functions.sh') - vprint('zip: ' + source + ' -> ' + target) + vprint(f'zip: {source} -> {target}') zipf.writestr(target, util_func) # addon.d.sh source = os.path.join('scripts', 'addon.d.sh') @@ -322,7 +316,7 @@ def zip_main(args): # End of zipping - output = os.path.join(config['outdir'], 'Magisk-v{}.zip'.format(config['version']) if config['prettyName'] else + output = os.path.join(config['outdir'], f'Magisk-v{config["version"]}.zip' if config['prettyName'] else 'magisk-release.zip' if args.release else 'magisk-debug.zip') sign_zip(unsigned, output, args.release) header('Output: ' + output) @@ -354,9 +348,8 @@ def zip_uninstaller(args): # util_functions.sh source = os.path.join('scripts', 'util_functions.sh') with open(source, 'r') as script: - # Remove the stub target = os.path.join('util_functions.sh') - vprint('zip: ' + source + ' -> ' + target) + vprint(f'zip: {source} -> {target}') zipf.writestr(target, script.read()) # Prebuilts @@ -366,7 +359,7 @@ def zip_uninstaller(args): # End of zipping - output = os.path.join(config['outdir'], 'Magisk-uninstaller-{}.zip'.format(datetime.datetime.now().strftime('%Y%m%d')) + output = os.path.join(config['outdir'], f'Magisk-uninstaller-{datetime.datetime.now().strftime("%Y%m%d")}.zip' if config['prettyName'] else 'magisk-uninstaller.zip') sign_zip(unsigned, output, args.release) header('Output: ' + output) @@ -407,7 +400,7 @@ all_parser = subparsers.add_parser('all', help='build everything (binaries/apks/ all_parser.set_defaults(func=build_all) binary_parser = subparsers.add_parser('binary', help='build binaries') -binary_parser.add_argument('target', nargs='*', help='Support: magisk, magiskinit, magiskboot, busybox, b64xz. Leave empty to build all.') +binary_parser.add_argument('target', nargs='*', help='Support: magisk, magiskinit, magiskboot, busybox. Leave empty to build all.') binary_parser.set_defaults(func=build_binary) apk_parser = subparsers.add_parser('apk', help='build Magisk Manager APK') @@ -459,6 +452,6 @@ config['prettyName'] = config['prettyName'].lower() == 'true' mkdir_p(config['outdir']) if args.release and not os.path.exists(keystore): - error('Please generate a java keystore and place it in \'{}\''.format(keystore)) + error(f'Please generate a java keystore and place it in "{keystore}"') STDOUT = None if args.verbose else subprocess.DEVNULL args.func(args) diff --git a/native/jni/Android.mk b/native/jni/Android.mk index 9b9ac07ce..2a7d1984c 100644 --- a/native/jni/Android.mk +++ b/native/jni/Android.mk @@ -115,19 +115,6 @@ include $(BUILD_EXECUTABLE) endif -ifdef B_BXZ - -# b64xz -include $(CLEAR_VARS) -LOCAL_MODULE := b64xz -LOCAL_STATIC_LIBRARIES := libxz -LOCAL_C_INCLUDES := $(EXT_PATH)/include -LOCAL_SRC_FILES := misc/b64xz.c -LOCAL_LDFLAGS := -static -include $(BUILD_EXECUTABLE) - -endif - ifdef B_BB # Busybox diff --git a/native/jni/misc/b64xz.c b/native/jni/misc/b64xz.c deleted file mode 100644 index 4cd758410..000000000 --- a/native/jni/misc/b64xz.c +++ /dev/null @@ -1,78 +0,0 @@ -/* b64xz.c - Base64-XZ Extractor - * - * This program converts data from stdin to stdout. - * The input should be compressed with xz (integrity check only support CRC32 or none) and then - * encoded into base64 format. What b64xz does is basically the reverse of the - * mentioned process: decode base64 to bytes, decompress xz, then dump to stdout - * - * The compiled binary will be hex-dumped into update-binary - * Busybox will be xz-compressed, base64 encoded and dumped into update-binary - * This program is to recover busybox for Magisk installation environment - */ - -#include -#include - -static const char trans_tbl[] = - "|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq"; - -static void decodeblock(uint8_t* in, uint8_t* out) { - out[0] = (uint8_t)(in[0] << 2 | in[1] >> 4); - out[1] = (uint8_t)(in[1] << 4 | in[2] >> 2); - out[2] = (uint8_t)(((in[2] << 6) & 0xc0) | in[3]); -} - -static int unxz(struct xz_dec *dec, const void *buf, unsigned size) { - uint8_t out[8192]; - struct xz_buf b = { - .in = buf, - .in_pos = 0, - .in_size = size, - .out = out, - .out_pos = 0, - .out_size = sizeof(out) - }; - enum xz_ret ret; - do { - ret = xz_dec_run(dec, &b); - if (ret != XZ_OK && ret != XZ_STREAM_END) - return 1; - write(STDOUT_FILENO, out, b.out_pos); - b.out_pos = 0; - } while (b.in_pos != size); - return 0; -} - -int main(int argc, char const* argv[]) { - if (argc > 1) - return 0; - - uint8_t in[4], buf[6144]; - unsigned len = 0, pos = 0; - int8_t c; - - xz_crc32_init(); - struct xz_dec *dec = xz_dec_init(XZ_DYNALLOC, 1 << 26); - if (dec == NULL) - return 1; - - while (read(STDIN_FILENO, &c, sizeof(c)) == 1) { - c = ((c < 43 || c > 122) ? -1 : (trans_tbl[c - 43] == '$' ? -1 : trans_tbl[c - 43] - 62)); - if (c >= 0) - in[len++] = c; - if (len < 4) - continue; - len = 0; - decodeblock(in, buf + pos); - pos += 3; - if (pos == sizeof(buf)) { - if (unxz(dec, buf, pos)) - return 1; - pos = 0; - } - } - if (pos && unxz(dec, buf, pos)) - return 1; - xz_dec_end(dec); - return 0; -} diff --git a/scripts/update_binary.sh b/scripts/update_binary.sh index 2488a7218..8b2bda69d 100644 --- a/scripts/update_binary.sh +++ b/scripts/update_binary.sh @@ -1,34 +1,37 @@ -# EX_ARM, EX_X86, BB_ARM, and BB_X86 should be generated in build.py +#!/sbin/sh +X86_CNT=__X86_CNT__ extract_bb() { - EXBIN=$BBDIR/b64xz; BBBIN=$BBDIR/busybox - touch $EXBIN; touch $BBBIN; chmod 755 $EXBIN $BBBIN - echo -ne $EX_ARM > $EXBIN - if $EXBIN --test 2>/dev/null; then - echo $BB_ARM | $EXBIN > $BBBIN - else - echo -ne $EX_X86 > $EXBIN - echo $BB_X86 | $EXBIN > $BBBIN - fi - rm $EXBIN + case `uname -m` in + x*) dd if="$0" of="$BBBIN" bs=1024 skip=1 count=$X86_CNT ;; + *) dd if="$0" of="$BBBIN" bs=1024 skip=$(($X86_CNT + 1));; + esac + chmod 755 "$BBBIN" } setup_bb() { - BBDIR=$TMPDIR/bin; mkdir -p $BBDIR 2>/dev/null + BBDIR=$TMPDIR/bin + BBBIN=$BBDIR/busybox + mkdir -p $BBDIR 2>/dev/null extract_bb $BBBIN --install -s $BBDIR export PATH=$BBDIR:$PATH } case "$1" in - "extract") - [ -z "$2" ] && BBDIR=. || BBDIR="$2" + "extract"|"-x") + [ -z "$2" ] && BBBIN=./busybox || BBBIN="$2" extract_bb ;; - "indep") - TMPDIR=.; setup_bb; shift + "indep"|"sh") + TMPDIR=.;setup_bb;shift exec /system/bin/sh "$@" ;; *) - export TMPDIR=/dev/tmp; rm -rf $TMPDIR 2>/dev/null; setup_bb - export INSTALLER=$TMPDIR/install; mkdir -p $INSTALLER; unzip -o "$3" -d $INSTALLER >&2 + export TMPDIR=/dev/tmp + rm -rf $TMPDIR 2>/dev/null + setup_bb + export INSTALLER=$TMPDIR/install + mkdir -p $INSTALLER + unzip -o "$3" -d $INSTALLER >&2 exec sh $INSTALLER/META-INF/com/google/android/updater-script "$@" ;; esac +exit