diff --git a/README b/README new file mode 100644 index 0000000..f938081 --- /dev/null +++ b/README @@ -0,0 +1 @@ +This is a place holder, please fill in real text when you add stuff. diff --git a/aapt b/aapt new file mode 100755 index 0000000..5d1fbb5 Binary files /dev/null and b/aapt differ diff --git a/aapt.exe b/aapt.exe index 54718d6..1f51b87 100755 Binary files a/aapt.exe and b/aapt.exe differ diff --git a/add_miui_methods_and_variables.sh b/add_miui_methods_and_variables.sh deleted file mode 100755 index 341e45c..0000000 --- a/add_miui_methods_and_variables.sh +++ /dev/null @@ -1,74 +0,0 @@ -#!/bin/bash -# -# Copyright 2016 Miui Patchrom -# - -BASE_DIR=$1 -MOD_DIR=$2 -TARGET_DIR=$3 - -IFS=$'\x0A' - -tmp_fifo_file="/tmp/$$.fifo" -mkfifo $tmp_fifo_file -exec 9<>$tmp_fifo_file - -# 8 threads -for((i=0;i<8;i++)) -do - echo "" -done >&9 - - -for modSmaliFile in $(find $MOD_DIR -name "*.smali" ! -name "*\$[0-9]*.smali" ! -name "R\$*.smali") -do - baseSmaliFile=${modSmaliFile/$MOD_DIR/$BASE_DIR} - targetSmaliFile=${modSmaliFile/$MOD_DIR/$TARGET_DIR} - read -u9 - { - if [ -f $baseSmaliFile ];then - if [ "$(diff $baseSmaliFile $modSmaliFile)" == "" ];then - echo "" >&9 - continue - fi - methodBeginLines=($(grep -n "^.method " $modSmaliFile)) - methodEndLines=($(grep -n "^.end method" $modSmaliFile)) - for((i=0;i<${#methodBeginLines[@]};i++)) - do - if [ "$(echo ${methodBeginLines[$i]} | grep -E 'static synthetic|clinit')" == "" ];then - grepPattern="[^->]$(echo ${methodBeginLines[$i]##* } | sed 's/\[/\\\[/g')" - if [ "$(grep $grepPattern $baseSmaliFile)" == "" ];then - beginLineNum=$(echo ${methodBeginLines[$i]} | cut -d ':' -f1) - endLineNum=$(echo ${methodEndLines[$i]} | cut -d ':' -f1) - echo "Add method ${methodBeginLines[$i]##* } into $targetSmaliFile" - sed -n ${beginLineNum},${endLineNum}p $modSmaliFile >> $targetSmaliFile - fi - fi - done - - fieldLines=($(grep -En "^.field |^.end field" $modSmaliFile)) - linesCount=${#fieldLines[@]} - for ((i=0;i<$linesCount;i++)) - do - beginLine=${fieldLines[$i]%% =*} - grepPattern="[^->]$(echo ${beginLine##* } | sed 's/\[/\\\[/g')" - if [ "$(grep $grepPattern $baseSmaliFile)" == "" ];then - echo "Add field ${beginLine##* } into $targetSmaliFile" - beginLineNum=$(echo $beginLine | cut -d ":" -f1) - if [ $(($linesCount-$i)) -ne 1 -a "$(echo ${fieldLines[$i+1]} | grep ".end field")" != "" ];then - endLineNum=$(echo ${fieldLines[$i+1]} | cut -d ":" -f1) - sed -n ${beginLineNum},${endLineNum}p $modSmaliFile >> $targetSmaliFile - i=$(($i+1)) - else - sed -n ${beginLineNum}p $modSmaliFile >> $targetSmaliFile - fi - fi - done - fi - echo "" >&9 - }& -done -wait -exec 9>&- - -exit 0 diff --git a/add_miui_smail.sh b/add_miui_smail.sh index 2e4cc54..9b2e751 100755 --- a/add_miui_smail.sh +++ b/add_miui_smail.sh @@ -1,49 +1,19 @@ #!/bin/bash # -# Add miui smali files +# $1: dir for miui +# $2: dir for original # -# $1: android original src dir -# $2: miui src dir -# $3: target src dir - -BASE_DIR=$1 -MIUI_DIR=$2 -TARGET_DIR=$3 -OVERLAY_DIR=$PORT_ROOT/android/overlay -OVERLAY_CLASSES=$OVERLAY_DIR/OVERLAY_CLASSES - -$PORT_ROOT/tools/add_miui_methods_and_variables.sh $BASE_DIR $MIUI_DIR $TARGET_DIR - - -for class in `cat $OVERLAY_CLASSES | grep -Ev "^$|^#.*$"` -do - target_smali=$TARGET_DIR/smali/$class.smali - target_classes=$TARGET_DIR/smali/$class* - if [ -f "$target_smali" ];then - rm -f $target_classes - fi -done - - -for overlay_smali in `find $OVERLAY_DIR -name "*.smali" | sed 's/\$.*/.smali/' | uniq` -do - target_smali=${overlay_smali/$OVERLAY_DIR/$TARGET_DIR} - if [ -f "$target_smali" ];then - cp -f ${overlay_smali/.smali/}*.smali `dirname $target_smali` - fi -done - - -for file in `find $MIUI_DIR -name "*.smali"` +for file in `find $1 -name "*.smali"` do - newfile=${file/$MIUI_DIR/$TARGET_DIR} + newfile=${file/$1/$2} if [ ! -f "$newfile" ] then mkdir -p `dirname $newfile` + echo "add smali from miui: $file" cp $file $newfile fi done if [ -f "customize_framework.sh" ]; then - bash ./customize_framework.sh $2 $3 + ./customize_framework.sh $1 $2 fi diff --git a/apkcerts.py b/apkcerts.py index 62f5c6f..b5dcaeb 100755 --- a/apkcerts.py +++ b/apkcerts.py @@ -1,23 +1,18 @@ #!/usr/bin/env python -import os import sys import string import xml import xml.dom from xml.dom import minidom -def getName(pkg, updatedPackages): - codePath = pkg.attributes["codePath"].value - if codePath.startswith("/data/app"): - codePath = "" - pkgName = pkg.attributes["name"].value - for updatedPkg in updatedPackages: - updatedPkgName = updatedPkg.attributes["name"].value - if updatedPkgName == pkgName: - codePath=updatedPkg.attributes["codePath"].value - break - return os.path.basename(codePath) +def getName(codePath): + if codePath.startswith("/system/app"): + return codePath.replace("/system/app/", "") + if codePath.startswith("/system/priv-app"): + return codePath.replace("/system/priv-app/", "") + else : + return "" def usage(): print "Usage: python ./apkcerts.py path-to-packages.xml path-to-apkcerts.txt" @@ -33,11 +28,10 @@ def main(): print "Error: %s doesn't exist or isn't a vaild xml file" %(sys.argv[1]) sys.exit(1) - updatedPackages = xmldoc.getElementsByTagName("updated-package") packages = xmldoc.getElementsByTagName("package") sigpkgs = {} for pkg in packages: - name = getName(pkg, updatedPackages) + name = getName(pkg.attributes["codePath"].value) cert= pkg.getElementsByTagName("cert") if not cert or not name: continue index = cert[0].getAttribute("index") @@ -62,9 +56,9 @@ def main(): sig = sigmap.get(keyindex, None) for pkgname in pkgnames: if sig: - line = 'name="{0}.apk" certificate="build/target/product/security/{1}.x509.pem" private_key="build/target/product/security/{1}.pk8"\n'.format(pkgname, sig) + line = 'name="{0}" certificate="build/target/product/security/{1}.x509.pem" private_key="build/target/product/security/{1}.pk8"\n'.format(pkgname, sig) else: - line = 'name="{0}.apk" certificate="PRESIGNED" private_key=""\n'.format(pkgname) + line = 'name="{0}" certificate="PRESIGNED" private_key=""\n'.format(pkgname) f.write(line) if "__main__" == __name__: diff --git a/apktool b/apktool index 0c887be..b439eff 100755 --- a/apktool +++ b/apktool @@ -56,7 +56,7 @@ javaOpts="" # line and adjust the value accordingly. Use "java -X" for a list of options # you can pass here. # -javaOpts="-Xmx1024M" +javaOpts="-Xmx256M" # Alternatively, this will extract any parameter "-Jxxx" from the command line # and pass them to Java (instead of to dx). This makes it possible for you to diff --git a/apktool.jar b/apktool.jar index 58dd293..3d5fc2a 100644 Binary files a/apktool.jar and b/apktool.jar differ diff --git a/build_target_files.sh b/build_target_files.sh index 4106282..eed0c6e 100755 --- a/build_target_files.sh +++ b/build_target_files.sh @@ -10,16 +10,6 @@ OTA_FROM_TARGET_FILES=$TOOL_DIR/releasetools/ota_from_target_files SIGN_TARGET_FILES_APKS=$TOOL_DIR/releasetools/sign_target_files_apks OUT_ZIP_FILE= NO_SIGN=false -CERTIFICATE_DIR=$PORT_ROOT/build/security - -APKCERT=$PORT_ROOT/miui/metadata/apkcert.txt -if [ "$USE_ANDROID_OUT" == "true" ];then - APKCERT=$ANDROID_OUT/obj/PACKAGING/apkcerts_intermediates/*.txt -fi -FILESYSTEM_CONFIG=$PORT_ROOT/miui/metadata/filesystem_config.txt -if [ "$USE_ANDROID_OUT" == "true" ];then - FILESYSTEM_CONFIG=$(find $ANDROID_OUT/obj/PACKAGING/target_files_intermediates/ -name filesystem_config.txt) -fi # copy the whole target_files_template dir function copy_target_files_template { @@ -35,7 +25,7 @@ function copy_bootimage { do if [ -f $ZIP_DIR/$file ] then - cp $ZIP_DIR/$file $TARGET_FILES_DIR/BOOTABLE_IMAGES/ + cp $ZIP_DIR/$file $TARGET_FILES_DIR/BOOTABLE_IMAGES/boot.img return fi done @@ -70,19 +60,12 @@ function recover_link { function process_metadata { echo "Process metadata" - cp -f $TARGET_FILES_TEMPLATE_DIR/META/filesystem_config.txt $TARGET_FILES_DIR/META - python $TOOL_DIR/uniq_first.py $METADATA_DIR/filesystem_config.txt $TARGET_FILES_DIR/META/filesystem_config.txt - python $TOOL_DIR/uniq_first.py $FILESYSTEM_CONFIG $TARGET_FILES_DIR/META/filesystem_config.txt - cat $TARGET_FILES_DIR/META/filesystem_config.txt | sort > $TARGET_FILES_DIR/META/temp.txt - mv $TARGET_FILES_DIR/META/temp.txt $TARGET_FILES_DIR/META/filesystem_config.txt - + cp -f $METADATA_DIR/filesystem_config.txt $TARGET_FILES_DIR/META + cat $TOOL_DIR/target_files_template/META/filesystem_config.txt >> $TARGET_FILES_DIR/META/filesystem_config.txt cp -f $METADATA_DIR/recovery.fstab $TARGET_FILES_DIR/RECOVERY/RAMDISK/etc - - cp -rf $APKCERT $TARGET_FILES_DIR/META/apkcerts.txt - python $TOOL_DIR/uniq_first.py $METADATA_DIR/apkcerts.txt $TARGET_FILES_DIR/META/apkcerts.txt - python $TOOL_DIR/uniq_first.py $TARGET_FILES_TEMPLATE_DIR/META/apkcerts.txt $TARGET_FILES_DIR/META/apkcerts.txt - cat $TARGET_FILES_DIR/META/apkcerts.txt | sort > $TARGET_FILES_DIR/META/temp.txt - mv $TARGET_FILES_DIR/META/temp.txt $TARGET_FILES_DIR/META/apkcerts.txt + python $TOOL_DIR/uniq_first.py $METADATA_DIR/apkcerts.txt $TARGET_FILES_DIR/META/apkcerts.txt $PRJ_DIR + cat $TARGET_FILES_DIR/META/apkcerts.txt | sort > $TARGET_FILES_DIR/temp.txt + mv $TARGET_FILES_DIR/temp.txt $TARGET_FILES_DIR/META/apkcerts.txt recover_link } @@ -98,39 +81,20 @@ function zip_target_files { function sign_target_files { echo "Sign target files" - $SIGN_TARGET_FILES_APKS -d $CERTIFICATE_DIR $TARGET_FILES_ZIP temp.zip + $SIGN_TARGET_FILES_APKS -d $PORT_ROOT/build/security $TARGET_FILES_ZIP temp.zip mv temp.zip $TARGET_FILES_ZIP } # build a new full ota package function build_ota_package { echo "Build full ota package: $OUT_DIR/$OUT_ZIP_FILE" - $OTA_FROM_TARGET_FILES -n -k $CERTIFICATE_DIR/testkey $TARGET_FILES_ZIP $OUT_DIR/$OUT_ZIP_FILE + $OTA_FROM_TARGET_FILES -n -k $PORT_ROOT/build/security/testkey $TARGET_FILES_ZIP $OUT_DIR/$OUT_ZIP_FILE } -function adjust_replace_key_script { - if [ "$CERTIFICATE_DIR" != "$PORT_ROOT/build/security" -a -f "$CERTIFICATE_DIR/platform.x509.pem" \ - -a -f "$CERTIFICATE_DIR/shared.x509.pem" -a -f "$CERTIFICATE_DIR/media.x509.pem" -a -f "$CERTIFICATE_DIR/shared.x509.pem" ];then - platform_cert=$(cat $CERTIFICATE_DIR/platform.x509.pem | sed 's/-----/#/g' | cut -d'#' -f1 | tr -d ["\n"] | base64 --decode | hexdump -v -e '/1 "%02x"') - sed -i "s/@user_platform/$platform_cert/g" out/target_files/OTA/bin/replace_key - shared_cert=$(cat $CERTIFICATE_DIR/shared.x509.pem | sed 's/-----/#/g' | cut -d'#' -f1 | tr -d ["\n"] | base64 --decode | hexdump -v -e '/1 "%02x"') - sed -i "s/@user_shared/$shared_cert/g" out/target_files/OTA/bin/replace_key - media_cert=$(cat $CERTIFICATE_DIR/media.x509.pem | sed 's/-----/#/g' | cut -d'#' -f1 | tr -d ["\n"] | base64 --decode | hexdump -v -e '/1 "%02x"') - sed -i "s/@user_media/$media_cert/g" out/target_files/OTA/bin/replace_key - testkey_cert=$(cat $CERTIFICATE_DIR/shared.x509.pem | sed 's/-----/#/g' | cut -d'#' -f1 | tr -d ["\n"] | base64 --decode | hexdump -v -e '/1 "%02x"') - sed -i "s/@user_testkey/$testkey_cert/g" out/target_files/OTA/bin/replace_key - else - rm -rf out/target_files/OTA/bin/replace_key - fi -} if [ $# -eq 3 ];then + NO_SIGN=true OUT_ZIP_FILE=$3 - if [ "$2" == "-n" ];then - NO_SIGN=true - elif [ -n "$2" ];then - CERTIFICATE_DIR=$2 - fi INCLUDE_THIRDPART_APP=$1 elif [ $# -eq 2 ];then OUT_ZIP_FILE=$2 @@ -139,13 +103,7 @@ elif [ $# -eq 1 ];then INCLUDE_THIRDPART_APP=$1 fi -#Set certificate pass word -if [ -f "$CERTIFICATE_DIR/passwd" ];then - export ANDROID_PW_FILE=$CERTIFICATE_DIR/passwd -fi - copy_target_files_template -adjust_replace_key_script copy_bootimage copy_system_dir copy_data_dir diff --git a/darwin-x86/aapt b/darwin-x86/aapt deleted file mode 100755 index 2a0db5d..0000000 Binary files a/darwin-x86/aapt and /dev/null differ diff --git a/darwin-x86/bsdiff b/darwin-x86/bsdiff deleted file mode 100755 index 0f5cd34..0000000 Binary files a/darwin-x86/bsdiff and /dev/null differ diff --git a/darwin-x86/imgdiff b/darwin-x86/imgdiff deleted file mode 100755 index d9eba10..0000000 Binary files a/darwin-x86/imgdiff and /dev/null differ diff --git a/darwin-x86/lib64/libcutils.dylib b/darwin-x86/lib64/libcutils.dylib deleted file mode 100755 index 18d64f0..0000000 Binary files a/darwin-x86/lib64/libcutils.dylib and /dev/null differ diff --git a/darwin-x86/lib64/liblog.dylib b/darwin-x86/lib64/liblog.dylib deleted file mode 100755 index 412814f..0000000 Binary files a/darwin-x86/lib64/liblog.dylib and /dev/null differ diff --git a/darwin-x86/mkbootfs b/darwin-x86/mkbootfs deleted file mode 100755 index f190aee..0000000 Binary files a/darwin-x86/mkbootfs and /dev/null differ diff --git a/darwin-x86/mkbootimg b/darwin-x86/mkbootimg deleted file mode 100755 index f3f1d16..0000000 Binary files a/darwin-x86/mkbootimg and /dev/null differ diff --git a/darwin-x86/unpackbootimg b/darwin-x86/unpackbootimg deleted file mode 100755 index 5c97816..0000000 Binary files a/darwin-x86/unpackbootimg and /dev/null differ diff --git a/darwin-x86/zipalign b/darwin-x86/zipalign deleted file mode 100755 index 0e3827d..0000000 Binary files a/darwin-x86/zipalign and /dev/null differ diff --git a/deoat.sh b/deoat.sh deleted file mode 100755 index 97f9206..0000000 --- a/deoat.sh +++ /dev/null @@ -1,88 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 2016, Miui Patchrom -# - -TARGET_DIR=$1 - -function removeDuplicateFiles() { - local bootOat64Path=$(find $TARGET_DIR -name "boot.oat" | grep "64\/") - if [ -n $bootOat64Path ];then - rm -rf ${bootOat64Path/64\///} - rm -rf ${bootOat64Path/64\/boot.oat//boot.art} - fi - local odex - for odex in $(find $TARGET_DIR -name "*.odex" | grep "64\/") - do - echo "rm -rf ${odex/64\///}" - rm -rf ${odex/64\///} - done -} - -function zipDex() { - local zipDir=$1 - local dexPath=$2 - local suffix=$3 - local dexName=$(basename $dexPath .dex) - local zipName=${dexName%%-classes*} - if [ $dexName = $zipName ];then - local zipDexName=classes.dex - else - local zipDexName=classes${dexName##*-classes}.dex - fi - mv $dexPath $zipDexName - if [ -f $zipDir/$zipName.$suffix ];then - zip -m $zipDir/$zipName.$suffix $zipDexName > /dev/null - fi -} - -function decodeBootOat() { - BOOTOAT_PATH=$(find $TARGET_DIR -name "boot.oat") - if [ -z $BOOTOAT_PATH ];then - return - fi - BOOTOAT_DIR=$(dirname $BOOTOAT_PATH) - echo "Decoding $BOOTOAT_PATH" - oat2dex boot $BOOTOAT_PATH > /dev/null - local bootDex - for bootDex in $(find $BOOTOAT_DIR/dex -name "*.dex") - do - zipDex $(dirname $BOOTOAT_DIR) $bootDex jar - done -} - -function decodeOdex() { - local suffix=$1 - local zipPath - for zipPath in $(find $TARGET_DIR -name "*.$suffix") - do - local zipDir=$(dirname $zipPath) - local zipName=$(basename $zipPath) - local odexPath=$(find $zipDir -name ${zipName/.$suffix/.odex}) - if [ -z $odexPath ];then - continue - fi - echo "Decoding $odexPath" - local bootClassPath=$BOOTOAT_DIR/odex - if [ "$suffix" = "apk" ];then - bootClassPath=$(dirname $BOOTOAT_DIR) - fi - local ret=$(oat2dex -o $zipDir $odexPath $bootClassPath) - if [ -n "$(echo $ret | grep -i "failed")" -a -f $PORT_ROOT/tools/oat2dex-0.86.jar ];then - echo "Decoding $odexPath failed, try to use old version oat2dex" - java -jar $PORT_ROOT/tools/oat2dex-0.86.jar -o $zipDir $odexPath $bootClassPath > /dev/null - fi - rm -rf $odexPath - local dexPath - for dexPath in $(find $zipDir -maxdepth 1 -name "*.dex") - do - zipDex $zipDir $dexPath $suffix - done - done -} - -removeDuplicateFiles -decodeBootOat -decodeOdex jar -decodeOdex apk -rm -rf $BOOTOAT_DIR/boot.oat $BOOTOAT_DIR/boot.art $BOOTOAT_DIR/odex $BOOTOAT_DIR/dex diff --git a/get_apk_cert.py b/get_apk_cert.py deleted file mode 100755 index 7797e05..0000000 --- a/get_apk_cert.py +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (C) 2016 The Miui Patchrom -# - -import os -import sys -import re - -# Values for "certificate" in apkcerts that mean special things. -SPECIAL_CERT_STRINGS = ("PRESIGNED", "EXTERNAL") -PUBLIC_KEY_SUFFIX = ".x509.pem" -PRIVATE_KEY_SUFFIX = ".pk8" - - -def ReadApkCerts(apkcerts): - """parse the apkcerts.txt file and return a {package: cert} dict.""" - certmap = {} - with open(apkcerts, 'r') as certs: - for line in certs.readlines(): - m = re.match(r'^name="(.*)"\s+certificate="(.*)"\s+' - r'private_key="(.*)"$', line) - if m: - name, cert, privkey = m.groups() - public_key_suffix_len = len(PUBLIC_KEY_SUFFIX) - private_key_suffix_len = len(PRIVATE_KEY_SUFFIX) - if cert in SPECIAL_CERT_STRINGS and not privkey: - certmap[name] = cert - elif (cert.endswith(PUBLIC_KEY_SUFFIX) and - privkey.endswith(PRIVATE_KEY_SUFFIX) and - cert[:-public_key_suffix_len] == privkey[:-private_key_suffix_len]): - certmap[name] = cert[:-public_key_suffix_len] - else: - raise ValueError("failed to parse line from apkcerts.txt:\n" + line) - return certmap - -if __name__ == '__main__': - apkPath = sys.argv[1] - apkCerts = sys.argv[2] - certmap = ReadApkCerts(apkCerts) - cert = os.path.basename(certmap[os.path.basename(apkPath)]) - print cert diff --git a/get_filesystem_config b/get_filesystem_config deleted file mode 100755 index ddbdf8f..0000000 --- a/get_filesystem_config +++ /dev/null @@ -1,86 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 2016, Miui Patchrom -# - -ACTION=$1 -LINE_TERMINATION=$'\r\n' -OLD_IFS=$IFS -IFS=$'\n' -BUSYBOX="$2" -if [ -n "$(adb shell id | grep "uid=0")" ];then - root='true' -elif [ -z "$(adb shell su -c "id" | grep "uid=0")" ];then - echo "Please root your device, and try again." - exit 1 -fi - -if [ -n $root ];then - fileSystemInfo=$(adb shell ls -aRZ /system) -else - fileSystemInfo=$(adb shell su -c "ls -aRZ /system") -fi - -if [ "$ACTION" = '--info' ];then - for line in $fileSystemInfo - do - if [ $line == $LINE_TERMINATION -o ${line:0:1} == 'd' ];then - continue - fi - # lrwxrwxrwx root root u:object_r:system_file:s0 chmod -> toybox - # cut line before the string " ->" - line=${line%% ->*} - if [ $(echo $line | cut -d ':' -f2) == $LINE_TERMINATION ];then - dir=$(echo $line | cut -d ':' -f1) - path=$dir - if [ -n $root ];then - line=$(adb shell ls -dZ $path) - else - line=$(adb shell su -c "ls -dZ $path") - fi - else - path=$dir/$(echo ${line##*:s0} | tr -d $LINE_TERMINATION | sed 's/^[ ]*//') - fi - selabel="u:${line##*u:}" - selabel=${selabel%% *} - if [ -n $root ];then - uid=$(adb shell $BUSYBOX stat -c %u $path | tr -d $LINE_TERMINATION) - gid=$(adb shell $BUSYBOX stat -c %g $path | tr -d $LINE_TERMINATION) - perm=$(adb shell $BUSYBOX stat -c %a $path | tr -d $LINE_TERMINATION) - else - uid=$(adb shell su -c "$BUSYBOX stat -c %u $path" | tr -d $LINE_TERMINATION) - gid=$(adb shell su -c "$BUSYBOX stat -c %g $path" | tr -d $LINE_TERMINATION) - perm=$(adb shell su -c "$BUSYBOX stat -c %a $path" | tr -d $LINE_TERMINATION) - fi - #Remove blank in filename, it cause ota_from_target_files failed. - path=$(echo $path | sed 's/ //g') - echo "${path#\/} $uid $gid $perm selabel=$selabel capabilities=0x0" - done -elif [ "$ACTION" = '--link' ];then - for line in $fileSystemInfo - do - if [ $line == $LINE_TERMINATION];then - continue - fi - line=${line%% ->*} - if [ $(echo $line | cut -d ':' -f2) == $LINE_TERMINATION ];then - dir=$(echo $line | cut -d ':' -f1) - path=$dir - if [ -n $root ];then - line=$(adb shell ls -dZ $path) - else - line=$(adb shell su -c "ls -dZ $path") - fi - fi - - if [ ${line:0:1} == 'l' ];then - path=$dir/$(echo ${line##*:s0} | tr -d $LINE_TERMINATION | sed 's/^[ ]*//') - if [ -n $root ];then - link=$(adb shell $BUSYBOX readlink $path | tr -d $LINE_TERMINATION) - else - link=$(adb shell su -c "$BUSYBOX readlink $path" | tr -d $LINE_TERMINATION) - fi - echo "${path#\/}|$link" - fi - done -fi diff --git a/hex_replace.py b/hex_replace.py deleted file mode 100644 index 818c1ec..0000000 --- a/hex_replace.py +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env pyhon - -from sys import argv -import struct - -def usage(): - print "Usage: %s orignal target file" % argv[0] - - -def do_replace(inFile, outFile, oldHex, newHex): - inFp = open(inFile, 'rb') - outFp = open(outFile, 'wb') - oldstr = struct.pack('LH', 4611950241719001088, 18288) - newstr = struct.pack('LH', 5147649559655096320, 18112) - while 1: - s = inFp.read(10) - if s: - print struct.unpack('LH', s) - if s == oldstr: - print "replace" - outFp.write(newstr) - else: - outFp.write(s) - else: - break - - inFp.close() - outFp.close() - - - -if __name__ == "__main__": - #if len(argv) < 4: - # exit(usage()) - - do_replace(argv[1], argv[2], 0, 0) - - diff --git a/insertkeys.py b/insertkeys.py deleted file mode 100755 index ca1e432..0000000 --- a/insertkeys.py +++ /dev/null @@ -1,267 +0,0 @@ -#!/usr/bin/env python - -from xml.sax import saxutils, handler, make_parser -from optparse import OptionParser -import ConfigParser -import logging -import base64 -import sys -import os - -__VERSION = (0, 1) - -''' -This tool reads a mac_permissions.xml and replaces keywords in the signature -clause with keys provided by pem files. -''' - -class GenerateKeys(object): - def __init__(self, path): - ''' - Generates an object with Base16 and Base64 encoded versions of the keys - found in the supplied pem file argument. PEM files can contain multiple - certs, however this seems to be unused in Android as pkg manager grabs - the first cert in the APK. This will however support multiple certs in - the resulting generation with index[0] being the first cert in the pem - file. - ''' - - self._base64Key = list() - self._base16Key = list() - - if not os.path.isfile(path): - sys.exit("Path " + path + " does not exist or is not a file!") - - pkFile = open(path, 'rb').readlines() - base64Key = "" - lineNo = 1 - certNo = 1 - inCert = False - for line in pkFile: - line = line.strip() - # Are we starting the certificate? - if line == "-----BEGIN CERTIFICATE-----": - if inCert: - sys.exit("Encountered another BEGIN CERTIFICATE without END CERTIFICATE on " + - "line: " + str(lineNo)) - - inCert = True - - # Are we ending the ceritifcate? - elif line == "-----END CERTIFICATE-----": - if not inCert: - sys.exit("Encountered END CERTIFICATE before BEGIN CERTIFICATE on line: " - + str(lineNo)) - - # If we ended the certificate trip the flag - inCert = False - - # Sanity check the input - if len(base64Key) == 0: - sys.exit("Empty certficate , certificate "+ str(certNo) + " found in file: " - + path) - - # ... and append the certificate to the list - # Base 64 includes uppercase. DO NOT tolower() - self._base64Key.append(base64Key) - try: - # Pkgmanager and setool see hex strings with lowercase, lets be consistent - self._base16Key.append(base64.b16encode(base64.b64decode(base64Key)).lower()) - except TypeError: - sys.exit("Invalid certificate, certificate "+ str(certNo) + " found in file: " - + path) - - # After adding the key, reset the accumulator as pem files may have subsequent keys - base64Key="" - - # And increment your cert number - certNo = certNo + 1 - - # If we haven't started the certificate, then we should not encounter any data - elif not inCert: - if line is not "": - sys.exit("Detected erroneous line \""+ line + "\" on " + str(lineNo) - + " in pem file: " + path) - - # else we have started the certicate and need to append the data - elif inCert: - base64Key += line - - else: - # We should never hit this assert, if we do then an unaccounted for state - # was entered that was NOT addressed by the if/elif statements above - assert(False == True) - - # The last thing to do before looping up is to increment line number - lineNo = lineNo + 1 - - def __len__(self): - return len(self._base16Key) - - def __str__(self): - return str(self.getBase16Keys()) - - def getBase16Keys(self): - return self._base16Key - - def getBase64Keys(self): - return self._base64Key - -class ParseConfig(ConfigParser.ConfigParser): - - # This must be lowercase - OPTION_WILDCARD_TAG = "all" - - def generateKeyMap(self, target_build_variant, key_directory): - - keyMap = dict() - - for tag in self.sections(): - - options = self.options(tag) - - for option in options: - - # Only generate the key map for debug or release, - # not both! - if option != target_build_variant and \ - option != ParseConfig.OPTION_WILDCARD_TAG: - logging.info("Skipping " + tag + " : " + option + - " because target build variant is set to " + - str(target_build_variant)) - continue - - if tag in keyMap: - sys.exit("Duplicate tag detected " + tag) - - tag_path = os.path.expandvars(self.get(tag, option)) - path = os.path.join(key_directory, tag_path) - - keyMap[tag] = GenerateKeys(path) - - # Multiple certificates may exist in - # the pem file. GenerateKeys supports - # this however, the mac_permissions.xml - # as well as PMS do not. - assert len(keyMap[tag]) == 1 - - return keyMap - -class ReplaceTags(handler.ContentHandler): - - DEFAULT_TAG = "default" - PACKAGE_TAG = "package" - POLICY_TAG = "policy" - SIGNER_TAG = "signer" - SIGNATURE_TAG = "signature" - - TAGS_WITH_CHILDREN = [ DEFAULT_TAG, PACKAGE_TAG, POLICY_TAG, SIGNER_TAG ] - - XML_ENCODING_TAG = '' - - def __init__(self, keyMap, out=sys.stdout): - - handler.ContentHandler.__init__(self) - self._keyMap = keyMap - self._out = out - self._out.write(ReplaceTags.XML_ENCODING_TAG) - self._out.write("") - self._out.write("") - - def __del__(self): - self._out.write("") - - def startElement(self, tag, attrs): - if tag == ReplaceTags.POLICY_TAG: - return - - self._out.write('<' + tag) - - for (name, value) in attrs.items(): - - if name == ReplaceTags.SIGNATURE_TAG and value in self._keyMap: - for key in self._keyMap[value].getBase16Keys(): - logging.info("Replacing " + name + " " + value + " with " + key) - self._out.write(' %s="%s"' % (name, saxutils.escape(key))) - else: - self._out.write(' %s="%s"' % (name, saxutils.escape(value))) - - if tag in ReplaceTags.TAGS_WITH_CHILDREN: - self._out.write('>') - else: - self._out.write('/>') - - def endElement(self, tag): - if tag == ReplaceTags.POLICY_TAG: - return - - if tag in ReplaceTags.TAGS_WITH_CHILDREN: - self._out.write('' % tag) - - def characters(self, content): - if not content.isspace(): - self._out.write(saxutils.escape(content)) - - def ignorableWhitespace(self, content): - pass - - def processingInstruction(self, target, data): - self._out.write('' % (target, data)) - -if __name__ == "__main__": - - # Intentional double space to line up equls signs and opening " for - # readability. - usage = "usage: %prog [options] CONFIG_FILE MAC_PERMISSIONS_FILE [MAC_PERMISSIONS_FILE...]\n" - usage += "This tool allows one to configure an automatic inclusion\n" - usage += "of signing keys into the mac_permision.xml file(s) from the\n" - usage += "pem files. If mulitple mac_permision.xml files are included\n" - usage += "then they are unioned to produce a final version." - - version = "%prog " + str(__VERSION) - - parser = OptionParser(usage=usage, version=version) - - parser.add_option("-v", "--verbose", - action="store_true", dest="verbose", default=False, - help="Print internal operations to stdout") - - parser.add_option("-o", "--output", default="stdout", dest="output_file", - metavar="FILE", help="Specify an output file, default is stdout") - - parser.add_option("-c", "--cwd", default=os.getcwd(), dest="root", - metavar="DIR", help="Specify a root (CWD) directory to run this from, it" \ - "chdirs' AFTER loading the config file") - - parser.add_option("-t", "--target-build-variant", default="eng", dest="target_build_variant", - help="Specify the TARGET_BUILD_VARIANT, defaults to eng") - - parser.add_option("-d", "--key-directory", default="", dest="key_directory", - help="Specify a parent directory for keys") - - (options, args) = parser.parse_args() - - if len(args) < 2: - parser.error("Must specify a config file (keys.conf) AND mac_permissions.xml file(s)!") - - logging.basicConfig(level=logging.INFO if options.verbose == True else logging.WARN) - - # Read the config file - config = ParseConfig() - config.read(args[0]) - - os.chdir(options.root) - - output_file = sys.stdout if options.output_file == "stdout" else open(options.output_file, "w") - logging.info("Setting output file to: " + options.output_file) - - # Generate the key list - key_map = config.generateKeyMap(options.target_build_variant.lower(), options.key_directory) - logging.info("Generate key map:") - for k in key_map: - logging.info(k + " : " + str(key_map[k])) - # Generate the XML file with markup replaced with keys - parser = make_parser() - parser.setContentHandler(ReplaceTags(key_map, output_file)) - for f in args[1:]: - parser.parse(f) diff --git a/keys.conf b/keys.conf deleted file mode 100644 index 7a307b5..0000000 --- a/keys.conf +++ /dev/null @@ -1,25 +0,0 @@ -# -# Maps an arbitrary tag [TAGNAME] with the string contents found in -# TARGET_BUILD_VARIANT. Common convention is to start TAGNAME with an @ and -# name it after the base file name of the pem file. -# -# Each tag (section) then allows one to specify any string found in -# TARGET_BUILD_VARIANT. Typcially this is user, eng, and userdebug. Another -# option is to use ALL which will match ANY TARGET_BUILD_VARIANT string. -# - -[@PLATFORM] -ALL : $DEFAULT_SYSTEM_DEV_CERTIFICATE/platform.x509.pem - -[@MEDIA] -ALL : $DEFAULT_SYSTEM_DEV_CERTIFICATE/media.x509.pem - -[@SHARED] -ALL : $DEFAULT_SYSTEM_DEV_CERTIFICATE/shared.x509.pem - -# Example of ALL TARGET_BUILD_VARIANTS -[@RELEASE] -ENG : $DEFAULT_SYSTEM_DEV_CERTIFICATE/testkey.x509.pem -USER : $DEFAULT_SYSTEM_DEV_CERTIFICATE/testkey.x509.pem -USERDEBUG : $DEFAULT_SYSTEM_DEV_CERTIFICATE/testkey.x509.pem - diff --git a/linux-x86/aapt b/linux-x86/aapt deleted file mode 100755 index 9a119c4..0000000 Binary files a/linux-x86/aapt and /dev/null differ diff --git a/linux-x86/lib/libc++.so b/linux-x86/lib/libc++.so deleted file mode 100755 index 0101d43..0000000 Binary files a/linux-x86/lib/libc++.so and /dev/null differ diff --git a/linux-x86/mkbootimg b/linux-x86/mkbootimg deleted file mode 100755 index 8b3b315..0000000 Binary files a/linux-x86/mkbootimg and /dev/null differ diff --git a/linux-x86/unpackbootimg b/linux-x86/unpackbootimg deleted file mode 100755 index 1c4eac2..0000000 Binary files a/linux-x86/unpackbootimg and /dev/null differ diff --git a/linux-x86/zipalign b/linux-x86/zipalign deleted file mode 100755 index 8186151..0000000 Binary files a/linux-x86/zipalign and /dev/null differ diff --git a/make_key b/make_key deleted file mode 100755 index 03ed880..0000000 --- a/make_key +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 2009 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Generates a public/private key pair suitable for use in signing -# android .apks and OTA update packages. - -if [ "$#" -lt 2 -o "$#" -gt 3 ]; then - cat < [] - -Creates .pk8 key and .x509.pem cert. Cert contains the -given . A keytype of "rsa" or "ec" is accepted. -EOF - exit 2 -fi - -if [[ -e $1.pk8 || -e $1.x509.pem ]]; then - echo "$1.pk8 and/or $1.x509.pem already exist; please delete them first" - echo "if you want to replace them." - exit 1 -fi - -# Use named pipes to connect get the raw RSA private key to the cert- -# and .pk8-creating programs, to avoid having the private key ever -# touch the disk. - -tmpdir=$(mktemp -d) -trap 'rm -rf ${tmpdir}; echo; exit 1' EXIT INT QUIT - -one=${tmpdir}/one -two=${tmpdir}/two -mknod ${one} p -mknod ${two} p -chmod 0600 ${one} ${two} - -read -p "Enter password for '$1' (blank for none; password will be visible): " \ - password - -export RANDFILE=".rnd" - -if [ "${3}" = "rsa" -o "$#" -eq 2 ]; then - ( openssl genrsa -f4 2048 | tee ${one} > ${two} ) & - hash="-sha1" -elif [ "${3}" = "ec" ]; then - ( openssl ecparam -name prime256v1 -genkey -noout | tee ${one} > ${two} ) & - hash="-sha256" -else - echo "Only accepts RSA or EC keytypes." - exit 1 -fi - -openssl req -new -x509 ${hash} -key ${two} -out $1.x509.pem \ - -days 10000 -subj "$2" & - -if [ "${password}" == "" ]; then - echo "creating ${1}.pk8 with no password" - openssl pkcs8 -in ${one} -topk8 -outform DER -out $1.pk8 -nocrypt -else - echo "creating ${1}.pk8 with password [${password}]" - export password - openssl pkcs8 -in ${one} -topk8 -outform DER -out $1.pk8 \ - -passout env:password - unset password -fi - -wait -wait diff --git a/linux-x86/mkbootfs b/mkbootfs similarity index 100% rename from linux-x86/mkbootfs rename to mkbootfs diff --git a/mkbootimg b/mkbootimg new file mode 100755 index 0000000..6ff4b84 Binary files /dev/null and b/mkbootimg differ diff --git a/oat2dex b/oat2dex deleted file mode 100755 index f91a83f..0000000 --- a/oat2dex +++ /dev/null @@ -1,83 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 2007 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# As per the Apache license requirements, this file has been modified -# from its original state. -# -# Such modifications are Copyright (C) 2016 Miui Patchrom Project, and -# are released under the original license - -# This script is a wrapper around oat2dex.jar, so you can simply call -# "oat2dex", instead of java -jar oat2dex.jar. It is heavily based on -# the "dx" script from the Android SDK - -# Set up prog to be the path of this script, including following symlinks, -# and set up progdir to be the fully-qualified pathname of its directory. -prog="$0" -while [ -h "${prog}" ]; do - newProg=`/bin/ls -ld "${prog}"` - echo ${newProg} - - - newProg=`expr "${newProg}" : ".* -> \(.*\)$"` - if expr "x${newProg}" : 'x/' >/dev/null; then - prog="${newProg}" - else - progdir=`dirname "${prog}"` - prog="${progdir}/${newProg}" - fi -done -oldwd=`pwd` -progdir=`dirname "${prog}"` -cd "${progdir}" -progdir=`pwd` -prog="${progdir}"/`basename "${prog}"` -cd "${oldwd}" - - -jarfile=oat2dex.jar -libdir="$progdir" -if [ ! -r "$libdir/$jarfile" ] -then - echo `basename "$prog"`": can't find $jarfile" - exit 1 -fi - -javaOpts="" - -# If you want DX to have more memory when executing, uncomment the following -# line and adjust the value accordingly. Use "java -X" for a list of options -# you can pass here. -# -javaOpts="-Xmx1024M" - -# Alternatively, this will extract any parameter "-Jxxx" from the command line -# and pass them to Java (instead of to dx). This makes it possible for you to -# add a command-line parameter such as "-JXmx256M" in your ant scripts, for -# example. -while expr "x$1" : 'x-J' >/dev/null; do - opt=`expr "$1" : '-J\(.*\)'` - javaOpts="${javaOpts} -${opt}" - shift -done - -if [ "$OSTYPE" = "cygwin" ] ; then - jarpath=`cygpath -w "$libdir/$jarfile"` -else - jarpath="$libdir/$jarfile" -fi - -exec java $javaOpts -jar "$jarpath" "$@" diff --git a/oat2dex-0.86.jar b/oat2dex-0.86.jar deleted file mode 100644 index 8f1a611..0000000 Binary files a/oat2dex-0.86.jar and /dev/null differ diff --git a/oat2dex-0.87.jar b/oat2dex-0.87.jar deleted file mode 100644 index bf0eab8..0000000 Binary files a/oat2dex-0.87.jar and /dev/null differ diff --git a/oat2dex.jar b/oat2dex.jar deleted file mode 120000 index 696f33d..0000000 --- a/oat2dex.jar +++ /dev/null @@ -1 +0,0 @@ -oat2dex-0.87.jar \ No newline at end of file diff --git a/overlay_smali.sh b/overlay_smali.sh new file mode 100755 index 0000000..f9262a2 --- /dev/null +++ b/overlay_smali.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +TARGET_DIR=$1 +OVERLAY_DIR=$2 + +for overlay_smali in `find $OVERLAY_DIR -name "*.smali" | sed 's/\$.*/.smali/' | uniq` +do + target_smali=${overlay_smali/$OVERLAY_DIR/$TARGET_DIR} + if [ -f "$target_smali" ];then + cp -f ${overlay_smali/.smali/}*.smali `dirname $target_smali` + fi +done diff --git a/patch_bootimg.sh b/patch_bootimg.sh deleted file mode 100755 index 17f0775..0000000 --- a/patch_bootimg.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/bash - -if [ -f "./patch_bootimg.sh" ];then - bash ./patch_bootimg.sh $1 - exit $? -fi - -BOOTIMG=$1 - -# Unpack bootimg -rm -rf $TARGET_BOOT_DIR -mkdir -p $TARGET_BOOT_DIR -$UNPACKBOOTIMG -i $BOOTIMG -o $TARGET_BOOT_DIR > /dev/null - -# Unpack ramdisk -gunzip $TARGET_BOOT_DIR/boot.img-ramdisk.gz -mkdir -p $TARGET_BOOT_DIR/ramdisk -cd $TARGET_BOOT_DIR/ramdisk -cpio -i < ../boot.img-ramdisk -cd - > /dev/null - -# Change init -if [ ! -f $TARGET_BOOT_DIR/ramdisk/init_vendor ];then -mv $TARGET_BOOT_DIR/ramdisk/init $TARGET_BOOT_DIR/ramdisk/init_vendor -fi -cp -f $PREBUILT_BOOT_DIR/$TARGET_BIT/init $TARGET_BOOT_DIR/ramdisk/init - -# Pack ramdisk -$MKBOOTFS $TARGET_BOOT_DIR/ramdisk | gzip > $TARGET_BOOT_DIR/ramdisk.gz - - -# Disable selinux -OLDCMDLINE=$(cat $TARGET_BOOT_DIR/boot.img-cmdline) -NEWCMDLINE="androidboot.selinux=disabled" -for prop in $OLDCMDLINE -do - echo $prop | grep "androidboot.selinux=" > /dev/null - if [ $? -eq 0 ];then - continue - fi - NEWCMDLINE="$NEWCMDLINE $prop" -done - -echo "NEWCMDLINE: $NEWCMDLINE" - -BASEADDR=$(cat $TARGET_BOOT_DIR/boot.img-base) -PAGESIZE=$(cat $TARGET_BOOT_DIR/boot.img-pagesize) -RAMDISKOFFSET=$(cat $TARGET_BOOT_DIR/boot.img-ramdisk_offset) -TAGSOFFSET=$(cat $TARGET_BOOT_DIR/boot.img-tags_offset) - -# Pack bootimg -$MKBOOTIMG --kernel $TARGET_BOOT_DIR/boot.img-zImage --ramdisk $TARGET_BOOT_DIR/ramdisk.gz --dt $TARGET_BOOT_DIR/boot.img-dt --base "$BASEADDR" --pagesize "$PAGESIZE" --ramdisk_offset "$RAMDISKOFFSET" --tags_offset "$TAGSOFFSET" --cmdline "$NEWCMDLINE" -o $BOOTIMG diff --git a/patch_miui_app.sh b/patch_miui_app.sh index 8cc67ae..bb4d001 100755 --- a/patch_miui_app.sh +++ b/patch_miui_app.sh @@ -10,18 +10,16 @@ if [ -f "customize_miui_app.sh" ]; then fi fi -if [ -f $1 ];then - if [ $1 = "MiuiHome" ];then - if [ -f $1/res/xml/default_workspace.xml.part ]; then - $PORT_ROOT/tools/gen_desklayout.pl $1/res/xml/default_workspace.xml.part $2/res/xml - for file in $2/res/xml/default_workspace*.xml; do - mv $file.new $file - done - fi - fi - - # patch *.smali.method under $1 - for file in `find $1 -name "*.smali.method"`; do - $PORT_ROOT/tools/replace_smali_method.sh apply $file - done +if [ $1 = "MiuiHome" ];then + if [ -f $1/res/xml/default_workspace.xml.part ]; then + $PORT_ROOT/tools/gen_desklayout.pl $1/res/xml/default_workspace.xml.part $2/res/xml + for file in $2/res/xml/default_workspace*.xml; do + mv $file.new $file + done + fi fi + +# patch *.smali.method under $1 +for file in `find $1 -name "*.smali.method"`; do + $PORT_ROOT/tools/replace_smali_method.sh apply $file +done diff --git a/patch_miui_framework.sh b/patch_miui_framework.sh index 7ef2f65..96ce5be 100755 --- a/patch_miui_framework.sh +++ b/patch_miui_framework.sh @@ -80,10 +80,10 @@ function apply_miui_patch() { rm -rf $dst_code_orig } -jar_outs=`find $new_smali_dir -name "*.jar.out"` +jar_outs=`grep -rn "JAR_OUTS" $new_smali_dir/README | cut -d'=' -f2` for out in $jar_outs do - apply_miui_patch $(basename $out) + apply_miui_patch $out done echo diff --git a/post_process_props.py b/post_process_props.py deleted file mode 100755 index 0387d6e..0000000 --- a/post_process_props.py +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (C) 2009 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import sys - -# Put the modifications that you need to make into the /system/build.prop into this -# function. The prop object has get(name) and put(name,value) methods. -def mangle_build_prop(prop, overlaylines): - for i in range(0,len(overlaylines)): - pair = overlaylines[i].split('=') - if len(pair) == 2: - name = pair[0].strip() - value = pair[1].strip() - if not name.startswith("#"): - prop.put(name,value) - pass - -class PropFile: - def __init__(self, lines): - self.lines = [s[:-1] for s in lines] - - def get(self, name): - key = name + "=" - for line in self.lines: - if line.startswith(key): - return line[len(key):] - return "" - - def put(self, name, value): - key = name + "=" - for i in range(0,len(self.lines)): - if self.lines[i].startswith(key): - self.lines[i] = key + value - return - self.lines.append(key + value) - - def delete(self, name): - key = name + "=" - i = 0 - while i < len(self.lines): - if self.lines[i].startswith(key): - del self.lines[i] - else: - i += 1 - - def write(self, f): - f.write("\n".join(self.lines)) - f.write("\n") - -def main(argv): - srcfilename = argv[1] - overlayfilename = argv[2] - fs = open(srcfilename) - srclines = fs.readlines() - fs.close() - - fo = open(overlayfilename) - overlaylines = fo.readlines() - fo.close() - - properties = PropFile(srclines) - if srcfilename.endswith("/build.prop"): - mangle_build_prop(properties, overlaylines) - else: - sys.stderr.write("bad command line: " + str(argv) + "\n") - sys.exit(1) - - fs = open(srcfilename, 'w+') - properties.write(fs) - fs.close() - -if __name__ == "__main__": - main(sys.argv) diff --git a/releasetools/blockimgdiff.py b/releasetools/blockimgdiff.py deleted file mode 100644 index 6ed9ca2..0000000 --- a/releasetools/blockimgdiff.py +++ /dev/null @@ -1,910 +0,0 @@ -# Copyright (C) 2014 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import print_function - -from collections import deque, OrderedDict -from hashlib import sha1 -import heapq -import itertools -import multiprocessing -import os -import re -import subprocess -import threading -import tempfile - -from rangelib import RangeSet - - -__all__ = ["EmptyImage", "DataImage", "BlockImageDiff"] - - -def compute_patch(src, tgt, imgdiff=False): - srcfd, srcfile = tempfile.mkstemp(prefix="src-") - tgtfd, tgtfile = tempfile.mkstemp(prefix="tgt-") - patchfd, patchfile = tempfile.mkstemp(prefix="patch-") - os.close(patchfd) - - try: - with os.fdopen(srcfd, "wb") as f_src: - for p in src: - f_src.write(p) - - with os.fdopen(tgtfd, "wb") as f_tgt: - for p in tgt: - f_tgt.write(p) - try: - os.unlink(patchfile) - except OSError: - pass - if imgdiff: - p = subprocess.call(["imgdiff", "-z", srcfile, tgtfile, patchfile], - stdout=open("/dev/null", "a"), - stderr=subprocess.STDOUT) - else: - p = subprocess.call(["bsdiff", srcfile, tgtfile, patchfile]) - - if p: - raise ValueError("diff failed: " + str(p)) - - with open(patchfile, "rb") as f: - return f.read() - finally: - try: - os.unlink(srcfile) - os.unlink(tgtfile) - os.unlink(patchfile) - except OSError: - pass - - -class Image(object): - def ReadRangeSet(self, ranges): - raise NotImplementedError - - def TotalSha1(self, include_clobbered_blocks=False): - raise NotImplementedError - - -class EmptyImage(Image): - """A zero-length image.""" - blocksize = 4096 - care_map = RangeSet() - clobbered_blocks = RangeSet() - extended = RangeSet() - total_blocks = 0 - file_map = {} - def ReadRangeSet(self, ranges): - return () - def TotalSha1(self, include_clobbered_blocks=False): - # EmptyImage always carries empty clobbered_blocks, so - # include_clobbered_blocks can be ignored. - assert self.clobbered_blocks.size() == 0 - return sha1().hexdigest() - - -class DataImage(Image): - """An image wrapped around a single string of data.""" - - def __init__(self, data, trim=False, pad=False): - self.data = data - self.blocksize = 4096 - - assert not (trim and pad) - - partial = len(self.data) % self.blocksize - if partial > 0: - if trim: - self.data = self.data[:-partial] - elif pad: - self.data += '\0' * (self.blocksize - partial) - else: - raise ValueError(("data for DataImage must be multiple of %d bytes " - "unless trim or pad is specified") % - (self.blocksize,)) - - assert len(self.data) % self.blocksize == 0 - - self.total_blocks = len(self.data) / self.blocksize - self.care_map = RangeSet(data=(0, self.total_blocks)) - self.clobbered_blocks = RangeSet() - self.extended = RangeSet() - - zero_blocks = [] - nonzero_blocks = [] - reference = '\0' * self.blocksize - - for i in range(self.total_blocks): - d = self.data[i*self.blocksize : (i+1)*self.blocksize] - if d == reference: - zero_blocks.append(i) - zero_blocks.append(i+1) - else: - nonzero_blocks.append(i) - nonzero_blocks.append(i+1) - - self.file_map = {"__ZERO": RangeSet(zero_blocks), - "__NONZERO": RangeSet(nonzero_blocks)} - - def ReadRangeSet(self, ranges): - return [self.data[s*self.blocksize:e*self.blocksize] for (s, e) in ranges] - - def TotalSha1(self, include_clobbered_blocks=False): - # DataImage always carries empty clobbered_blocks, so - # include_clobbered_blocks can be ignored. - assert self.clobbered_blocks.size() == 0 - return sha1(self.data).hexdigest() - - -class Transfer(object): - def __init__(self, tgt_name, src_name, tgt_ranges, src_ranges, style, by_id): - self.tgt_name = tgt_name - self.src_name = src_name - self.tgt_ranges = tgt_ranges - self.src_ranges = src_ranges - self.style = style - self.intact = (getattr(tgt_ranges, "monotonic", False) and - getattr(src_ranges, "monotonic", False)) - - # We use OrderedDict rather than dict so that the output is repeatable; - # otherwise it would depend on the hash values of the Transfer objects. - self.goes_before = OrderedDict() - self.goes_after = OrderedDict() - - self.stash_before = [] - self.use_stash = [] - - self.id = len(by_id) - by_id.append(self) - - def NetStashChange(self): - return (sum(sr.size() for (_, sr) in self.stash_before) - - sum(sr.size() for (_, sr) in self.use_stash)) - - def __str__(self): - return (str(self.id) + ": <" + str(self.src_ranges) + " " + self.style + - " to " + str(self.tgt_ranges) + ">") - - -# BlockImageDiff works on two image objects. An image object is -# anything that provides the following attributes: -# -# blocksize: the size in bytes of a block, currently must be 4096. -# -# total_blocks: the total size of the partition/image, in blocks. -# -# care_map: a RangeSet containing which blocks (in the range [0, -# total_blocks) we actually care about; i.e. which blocks contain -# data. -# -# file_map: a dict that partitions the blocks contained in care_map -# into smaller domains that are useful for doing diffs on. -# (Typically a domain is a file, and the key in file_map is the -# pathname.) -# -# clobbered_blocks: a RangeSet containing which blocks contain data -# but may be altered by the FS. They need to be excluded when -# verifying the partition integrity. -# -# ReadRangeSet(): a function that takes a RangeSet and returns the -# data contained in the image blocks of that RangeSet. The data -# is returned as a list or tuple of strings; concatenating the -# elements together should produce the requested data. -# Implementations are free to break up the data into list/tuple -# elements in any way that is convenient. -# -# TotalSha1(): a function that returns (as a hex string) the SHA-1 -# hash of all the data in the image (ie, all the blocks in the -# care_map minus clobbered_blocks, or including the clobbered -# blocks if include_clobbered_blocks is True). -# -# When creating a BlockImageDiff, the src image may be None, in which -# case the list of transfers produced will never read from the -# original image. - -class BlockImageDiff(object): - def __init__(self, tgt, src=None, threads=None, version=3): - if threads is None: - threads = multiprocessing.cpu_count() // 2 - if threads == 0: - threads = 1 - self.threads = threads - self.version = version - self.transfers = [] - self.src_basenames = {} - self.src_numpatterns = {} - - assert version in (1, 2, 3) - - self.tgt = tgt - if src is None: - src = EmptyImage() - self.src = src - - # The updater code that installs the patch always uses 4k blocks. - assert tgt.blocksize == 4096 - assert src.blocksize == 4096 - - # The range sets in each filemap should comprise a partition of - # the care map. - self.AssertPartition(src.care_map, src.file_map.values()) - self.AssertPartition(tgt.care_map, tgt.file_map.values()) - - def Compute(self, prefix): - # When looking for a source file to use as the diff input for a - # target file, we try: - # 1) an exact path match if available, otherwise - # 2) a exact basename match if available, otherwise - # 3) a basename match after all runs of digits are replaced by - # "#" if available, otherwise - # 4) we have no source for this target. - self.AbbreviateSourceNames() - self.FindTransfers() - - # Find the ordering dependencies among transfers (this is O(n^2) - # in the number of transfers). - self.GenerateDigraph() - # Find a sequence of transfers that satisfies as many ordering - # dependencies as possible (heuristically). - self.FindVertexSequence() - # Fix up the ordering dependencies that the sequence didn't - # satisfy. - if self.version == 1: - self.RemoveBackwardEdges() - else: - self.ReverseBackwardEdges() - self.ImproveVertexSequence() - - # Double-check our work. - self.AssertSequenceGood() - - self.ComputePatches(prefix) - self.WriteTransfers(prefix) - - def HashBlocks(self, source, ranges): # pylint: disable=no-self-use - data = source.ReadRangeSet(ranges) - ctx = sha1() - - for p in data: - ctx.update(p) - - return ctx.hexdigest() - - def WriteTransfers(self, prefix): - out = [] - - total = 0 - performs_read = False - - stashes = {} - stashed_blocks = 0 - max_stashed_blocks = 0 - - free_stash_ids = [] - next_stash_id = 0 - - for xf in self.transfers: - - if self.version < 2: - assert not xf.stash_before - assert not xf.use_stash - - for s, sr in xf.stash_before: - assert s not in stashes - if free_stash_ids: - sid = heapq.heappop(free_stash_ids) - else: - sid = next_stash_id - next_stash_id += 1 - stashes[s] = sid - stashed_blocks += sr.size() - if self.version == 2: - out.append("stash %d %s\n" % (sid, sr.to_string_raw())) - else: - sh = self.HashBlocks(self.src, sr) - if sh in stashes: - stashes[sh] += 1 - else: - stashes[sh] = 1 - out.append("stash %s %s\n" % (sh, sr.to_string_raw())) - - if stashed_blocks > max_stashed_blocks: - max_stashed_blocks = stashed_blocks - - free_string = [] - - if self.version == 1: - src_str = xf.src_ranges.to_string_raw() - elif self.version >= 2: - - # <# blocks> - # OR - # <# blocks> - # OR - # <# blocks> - - - size = xf.src_ranges.size() - src_str = [str(size)] - - unstashed_src_ranges = xf.src_ranges - mapped_stashes = [] - for s, sr in xf.use_stash: - sid = stashes.pop(s) - stashed_blocks -= sr.size() - unstashed_src_ranges = unstashed_src_ranges.subtract(sr) - sh = self.HashBlocks(self.src, sr) - sr = xf.src_ranges.map_within(sr) - mapped_stashes.append(sr) - if self.version == 2: - src_str.append("%d:%s" % (sid, sr.to_string_raw())) - else: - assert sh in stashes - src_str.append("%s:%s" % (sh, sr.to_string_raw())) - stashes[sh] -= 1 - if stashes[sh] == 0: - free_string.append("free %s\n" % (sh)) - stashes.pop(sh) - heapq.heappush(free_stash_ids, sid) - - if unstashed_src_ranges: - src_str.insert(1, unstashed_src_ranges.to_string_raw()) - if xf.use_stash: - mapped_unstashed = xf.src_ranges.map_within(unstashed_src_ranges) - src_str.insert(2, mapped_unstashed.to_string_raw()) - mapped_stashes.append(mapped_unstashed) - self.AssertPartition(RangeSet(data=(0, size)), mapped_stashes) - else: - src_str.insert(1, "-") - self.AssertPartition(RangeSet(data=(0, size)), mapped_stashes) - - src_str = " ".join(src_str) - - # all versions: - # zero - # new - # erase - # - # version 1: - # bsdiff patchstart patchlen - # imgdiff patchstart patchlen - # move - # - # version 2: - # bsdiff patchstart patchlen - # imgdiff patchstart patchlen - # move - # - # version 3: - # bsdiff patchstart patchlen srchash tgthash - # imgdiff patchstart patchlen srchash tgthash - # move hash - - tgt_size = xf.tgt_ranges.size() - - if xf.style == "new": - assert xf.tgt_ranges - out.append("%s %s\n" % (xf.style, xf.tgt_ranges.to_string_raw())) - total += tgt_size - elif xf.style == "move": - performs_read = True - assert xf.tgt_ranges - assert xf.src_ranges.size() == tgt_size - if xf.src_ranges != xf.tgt_ranges: - if self.version == 1: - out.append("%s %s %s\n" % ( - xf.style, - xf.src_ranges.to_string_raw(), xf.tgt_ranges.to_string_raw())) - elif self.version == 2: - out.append("%s %s %s\n" % ( - xf.style, - xf.tgt_ranges.to_string_raw(), src_str)) - elif self.version >= 3: - # take into account automatic stashing of overlapping blocks - if xf.src_ranges.overlaps(xf.tgt_ranges): - temp_stash_usage = stashed_blocks + xf.src_ranges.size() - if temp_stash_usage > max_stashed_blocks: - max_stashed_blocks = temp_stash_usage - - out.append("%s %s %s %s\n" % ( - xf.style, - self.HashBlocks(self.tgt, xf.tgt_ranges), - xf.tgt_ranges.to_string_raw(), src_str)) - total += tgt_size - elif xf.style in ("bsdiff", "imgdiff"): - performs_read = True - assert xf.tgt_ranges - assert xf.src_ranges - if self.version == 1: - out.append("%s %d %d %s %s\n" % ( - xf.style, xf.patch_start, xf.patch_len, - xf.src_ranges.to_string_raw(), xf.tgt_ranges.to_string_raw())) - elif self.version == 2: - out.append("%s %d %d %s %s\n" % ( - xf.style, xf.patch_start, xf.patch_len, - xf.tgt_ranges.to_string_raw(), src_str)) - elif self.version >= 3: - # take into account automatic stashing of overlapping blocks - if xf.src_ranges.overlaps(xf.tgt_ranges): - temp_stash_usage = stashed_blocks + xf.src_ranges.size() - if temp_stash_usage > max_stashed_blocks: - max_stashed_blocks = temp_stash_usage - - out.append("%s %d %d %s %s %s %s\n" % ( - xf.style, - xf.patch_start, xf.patch_len, - self.HashBlocks(self.src, xf.src_ranges), - self.HashBlocks(self.tgt, xf.tgt_ranges), - xf.tgt_ranges.to_string_raw(), src_str)) - total += tgt_size - elif xf.style == "zero": - assert xf.tgt_ranges - to_zero = xf.tgt_ranges.subtract(xf.src_ranges) - if to_zero: - out.append("%s %s\n" % (xf.style, to_zero.to_string_raw())) - total += to_zero.size() - else: - raise ValueError("unknown transfer style '%s'\n" % xf.style) - - if free_string: - out.append("".join(free_string)) - - # sanity check: abort if we're going to need more than 512 MB if - # stash space - assert max_stashed_blocks * self.tgt.blocksize < (512 << 20) - - # Zero out extended blocks as a workaround for bug 20881595. - if self.tgt.extended: - out.append("zero %s\n" % (self.tgt.extended.to_string_raw(),)) - - # We erase all the blocks on the partition that a) don't contain useful - # data in the new image and b) will not be touched by dm-verity. - all_tgt = RangeSet(data=(0, self.tgt.total_blocks)) - all_tgt_minus_extended = all_tgt.subtract(self.tgt.extended) - new_dontcare = all_tgt_minus_extended.subtract(self.tgt.care_map) - if new_dontcare: - out.append("erase %s\n" % (new_dontcare.to_string_raw(),)) - - out.insert(0, "%d\n" % (self.version,)) # format version number - out.insert(1, str(total) + "\n") - if self.version >= 2: - # version 2 only: after the total block count, we give the number - # of stash slots needed, and the maximum size needed (in blocks) - out.insert(2, str(next_stash_id) + "\n") - out.insert(3, str(max_stashed_blocks) + "\n") - - with open(prefix + ".transfer.list", "wb") as f: - for i in out: - f.write(i) - - if self.version >= 2: - print("max stashed blocks: %d (%d bytes)\n" % ( - max_stashed_blocks, max_stashed_blocks * self.tgt.blocksize)) - - def ComputePatches(self, prefix): - print("Reticulating splines...") - diff_q = [] - patch_num = 0 - with open(prefix + ".new.dat", "wb") as new_f: - for xf in self.transfers: - if xf.style == "zero": - pass - elif xf.style == "new": - for piece in self.tgt.ReadRangeSet(xf.tgt_ranges): - new_f.write(piece) - elif xf.style == "diff": - src = self.src.ReadRangeSet(xf.src_ranges) - tgt = self.tgt.ReadRangeSet(xf.tgt_ranges) - - # We can't compare src and tgt directly because they may have - # the same content but be broken up into blocks differently, eg: - # - # ["he", "llo"] vs ["h", "ello"] - # - # We want those to compare equal, ideally without having to - # actually concatenate the strings (these may be tens of - # megabytes). - - src_sha1 = sha1() - for p in src: - src_sha1.update(p) - tgt_sha1 = sha1() - tgt_size = 0 - for p in tgt: - tgt_sha1.update(p) - tgt_size += len(p) - - if src_sha1.digest() == tgt_sha1.digest(): - # These are identical; we don't need to generate a patch, - # just issue copy commands on the device. - xf.style = "move" - else: - # For files in zip format (eg, APKs, JARs, etc.) we would - # like to use imgdiff -z if possible (because it usually - # produces significantly smaller patches than bsdiff). - # This is permissible if: - # - # - the source and target files are monotonic (ie, the - # data is stored with blocks in increasing order), and - # - we haven't removed any blocks from the source set. - # - # If these conditions are satisfied then appending all the - # blocks in the set together in order will produce a valid - # zip file (plus possibly extra zeros in the last block), - # which is what imgdiff needs to operate. (imgdiff is - # fine with extra zeros at the end of the file.) - imgdiff = (xf.intact and - xf.tgt_name.split(".")[-1].lower() - in ("apk", "jar", "zip")) - xf.style = "imgdiff" if imgdiff else "bsdiff" - diff_q.append((tgt_size, src, tgt, xf, patch_num)) - patch_num += 1 - - else: - assert False, "unknown style " + xf.style - - if diff_q: - if self.threads > 1: - print("Computing patches (using %d threads)..." % (self.threads,)) - else: - print("Computing patches...") - diff_q.sort() - - patches = [None] * patch_num - - # TODO: Rewrite with multiprocessing.ThreadPool? - lock = threading.Lock() - def diff_worker(): - while True: - with lock: - if not diff_q: - return - tgt_size, src, tgt, xf, patchnum = diff_q.pop() - patch = compute_patch(src, tgt, imgdiff=(xf.style == "imgdiff")) - size = len(patch) - with lock: - patches[patchnum] = (patch, xf) - print("%10d %10d (%6.2f%%) %7s %s" % ( - size, tgt_size, size * 100.0 / tgt_size, xf.style, - xf.tgt_name if xf.tgt_name == xf.src_name else ( - xf.tgt_name + " (from " + xf.src_name + ")"))) - - threads = [threading.Thread(target=diff_worker) - for _ in range(self.threads)] - for th in threads: - th.start() - while threads: - threads.pop().join() - else: - patches = [] - - p = 0 - with open(prefix + ".patch.dat", "wb") as patch_f: - for patch, xf in patches: - xf.patch_start = p - xf.patch_len = len(patch) - patch_f.write(patch) - p += len(patch) - - def AssertSequenceGood(self): - # Simulate the sequences of transfers we will output, and check that: - # - we never read a block after writing it, and - # - we write every block we care about exactly once. - - # Start with no blocks having been touched yet. - touched = RangeSet() - - # Imagine processing the transfers in order. - for xf in self.transfers: - # Check that the input blocks for this transfer haven't yet been touched. - - x = xf.src_ranges - if self.version >= 2: - for _, sr in xf.use_stash: - x = x.subtract(sr) - - assert not touched.overlaps(x) - # Check that the output blocks for this transfer haven't yet been touched. - assert not touched.overlaps(xf.tgt_ranges) - # Touch all the blocks written by this transfer. - touched = touched.union(xf.tgt_ranges) - - # Check that we've written every target block. - assert touched == self.tgt.care_map - - def ImproveVertexSequence(self): - print("Improving vertex order...") - - # At this point our digraph is acyclic; we reversed any edges that - # were backwards in the heuristically-generated sequence. The - # previously-generated order is still acceptable, but we hope to - # find a better order that needs less memory for stashed data. - # Now we do a topological sort to generate a new vertex order, - # using a greedy algorithm to choose which vertex goes next - # whenever we have a choice. - - # Make a copy of the edge set; this copy will get destroyed by the - # algorithm. - for xf in self.transfers: - xf.incoming = xf.goes_after.copy() - xf.outgoing = xf.goes_before.copy() - - L = [] # the new vertex order - - # S is the set of sources in the remaining graph; we always choose - # the one that leaves the least amount of stashed data after it's - # executed. - S = [(u.NetStashChange(), u.order, u) for u in self.transfers - if not u.incoming] - heapq.heapify(S) - - while S: - _, _, xf = heapq.heappop(S) - L.append(xf) - for u in xf.outgoing: - del u.incoming[xf] - if not u.incoming: - heapq.heappush(S, (u.NetStashChange(), u.order, u)) - - # if this fails then our graph had a cycle. - assert len(L) == len(self.transfers) - - self.transfers = L - for i, xf in enumerate(L): - xf.order = i - - def RemoveBackwardEdges(self): - print("Removing backward edges...") - in_order = 0 - out_of_order = 0 - lost_source = 0 - - for xf in self.transfers: - lost = 0 - size = xf.src_ranges.size() - for u in xf.goes_before: - # xf should go before u - if xf.order < u.order: - # it does, hurray! - in_order += 1 - else: - # it doesn't, boo. trim the blocks that u writes from xf's - # source, so that xf can go after u. - out_of_order += 1 - assert xf.src_ranges.overlaps(u.tgt_ranges) - xf.src_ranges = xf.src_ranges.subtract(u.tgt_ranges) - xf.intact = False - - if xf.style == "diff" and not xf.src_ranges: - # nothing left to diff from; treat as new data - xf.style = "new" - - lost = size - xf.src_ranges.size() - lost_source += lost - - print((" %d/%d dependencies (%.2f%%) were violated; " - "%d source blocks removed.") % - (out_of_order, in_order + out_of_order, - (out_of_order * 100.0 / (in_order + out_of_order)) - if (in_order + out_of_order) else 0.0, - lost_source)) - - def ReverseBackwardEdges(self): - print("Reversing backward edges...") - in_order = 0 - out_of_order = 0 - stashes = 0 - stash_size = 0 - - for xf in self.transfers: - for u in xf.goes_before.copy(): - # xf should go before u - if xf.order < u.order: - # it does, hurray! - in_order += 1 - else: - # it doesn't, boo. modify u to stash the blocks that it - # writes that xf wants to read, and then require u to go - # before xf. - out_of_order += 1 - - overlap = xf.src_ranges.intersect(u.tgt_ranges) - assert overlap - - u.stash_before.append((stashes, overlap)) - xf.use_stash.append((stashes, overlap)) - stashes += 1 - stash_size += overlap.size() - - # reverse the edge direction; now xf must go after u - del xf.goes_before[u] - del u.goes_after[xf] - xf.goes_after[u] = None # value doesn't matter - u.goes_before[xf] = None - - print((" %d/%d dependencies (%.2f%%) were violated; " - "%d source blocks stashed.") % - (out_of_order, in_order + out_of_order, - (out_of_order * 100.0 / (in_order + out_of_order)) - if (in_order + out_of_order) else 0.0, - stash_size)) - - def FindVertexSequence(self): - print("Finding vertex sequence...") - - # This is based on "A Fast & Effective Heuristic for the Feedback - # Arc Set Problem" by P. Eades, X. Lin, and W.F. Smyth. Think of - # it as starting with the digraph G and moving all the vertices to - # be on a horizontal line in some order, trying to minimize the - # number of edges that end up pointing to the left. Left-pointing - # edges will get removed to turn the digraph into a DAG. In this - # case each edge has a weight which is the number of source blocks - # we'll lose if that edge is removed; we try to minimize the total - # weight rather than just the number of edges. - - # Make a copy of the edge set; this copy will get destroyed by the - # algorithm. - for xf in self.transfers: - xf.incoming = xf.goes_after.copy() - xf.outgoing = xf.goes_before.copy() - - # We use an OrderedDict instead of just a set so that the output - # is repeatable; otherwise it would depend on the hash values of - # the transfer objects. - G = OrderedDict() - for xf in self.transfers: - G[xf] = None - s1 = deque() # the left side of the sequence, built from left to right - s2 = deque() # the right side of the sequence, built from right to left - - while G: - - # Put all sinks at the end of the sequence. - while True: - sinks = [u for u in G if not u.outgoing] - if not sinks: - break - for u in sinks: - s2.appendleft(u) - del G[u] - for iu in u.incoming: - del iu.outgoing[u] - - # Put all the sources at the beginning of the sequence. - while True: - sources = [u for u in G if not u.incoming] - if not sources: - break - for u in sources: - s1.append(u) - del G[u] - for iu in u.outgoing: - del iu.incoming[u] - - if not G: - break - - # Find the "best" vertex to put next. "Best" is the one that - # maximizes the net difference in source blocks saved we get by - # pretending it's a source rather than a sink. - - max_d = None - best_u = None - for u in G: - d = sum(u.outgoing.values()) - sum(u.incoming.values()) - if best_u is None or d > max_d: - max_d = d - best_u = u - - u = best_u - s1.append(u) - del G[u] - for iu in u.outgoing: - del iu.incoming[u] - for iu in u.incoming: - del iu.outgoing[u] - - # Now record the sequence in the 'order' field of each transfer, - # and by rearranging self.transfers to be in the chosen sequence. - - new_transfers = [] - for x in itertools.chain(s1, s2): - x.order = len(new_transfers) - new_transfers.append(x) - del x.incoming - del x.outgoing - - self.transfers = new_transfers - - def GenerateDigraph(self): - print("Generating digraph...") - for a in self.transfers: - for b in self.transfers: - if a is b: - continue - - # If the blocks written by A are read by B, then B needs to go before A. - i = a.tgt_ranges.intersect(b.src_ranges) - if i: - if b.src_name == "__ZERO": - # the cost of removing source blocks for the __ZERO domain - # is (nearly) zero. - size = 0 - else: - size = i.size() - b.goes_before[a] = size - a.goes_after[b] = size - - def FindTransfers(self): - empty = RangeSet() - for tgt_fn, tgt_ranges in self.tgt.file_map.items(): - if tgt_fn == "__ZERO": - # the special "__ZERO" domain is all the blocks not contained - # in any file and that are filled with zeros. We have a - # special transfer style for zero blocks. - src_ranges = self.src.file_map.get("__ZERO", empty) - Transfer(tgt_fn, "__ZERO", tgt_ranges, src_ranges, - "zero", self.transfers) - continue - - elif tgt_fn == "__COPY": - # "__COPY" domain includes all the blocks not contained in any - # file and that need to be copied unconditionally to the target. - Transfer(tgt_fn, None, tgt_ranges, empty, "new", self.transfers) - continue - - elif tgt_fn in self.src.file_map: - # Look for an exact pathname match in the source. - Transfer(tgt_fn, tgt_fn, tgt_ranges, self.src.file_map[tgt_fn], - "diff", self.transfers) - continue - - b = os.path.basename(tgt_fn) - if b in self.src_basenames: - # Look for an exact basename match in the source. - src_fn = self.src_basenames[b] - Transfer(tgt_fn, src_fn, tgt_ranges, self.src.file_map[src_fn], - "diff", self.transfers) - continue - - b = re.sub("[0-9]+", "#", b) - if b in self.src_numpatterns: - # Look for a 'number pattern' match (a basename match after - # all runs of digits are replaced by "#"). (This is useful - # for .so files that contain version numbers in the filename - # that get bumped.) - src_fn = self.src_numpatterns[b] - Transfer(tgt_fn, src_fn, tgt_ranges, self.src.file_map[src_fn], - "diff", self.transfers) - continue - - Transfer(tgt_fn, None, tgt_ranges, empty, "new", self.transfers) - - def AbbreviateSourceNames(self): - for k in self.src.file_map.keys(): - b = os.path.basename(k) - self.src_basenames[b] = k - b = re.sub("[0-9]+", "#", b) - self.src_numpatterns[b] = k - - @staticmethod - def AssertPartition(total, seq): - """Assert that all the RangeSets in 'seq' form a partition of the - 'total' RangeSet (ie, they are nonintersecting and their union - equals 'total').""" - so_far = RangeSet() - for i in seq: - assert not so_far.overlaps(i) - so_far = so_far.union(i) - assert so_far == total diff --git a/linux-x86/bsdiff b/releasetools/bsdiff similarity index 100% rename from linux-x86/bsdiff rename to releasetools/bsdiff diff --git a/releasetools/common.py b/releasetools/common.py index f6eae50..2fb3aa5 100644 --- a/releasetools/common.py +++ b/releasetools/common.py @@ -20,7 +20,6 @@ import os import platform import re -import shlex import shutil import subprocess import sys @@ -29,43 +28,30 @@ import time import zipfile -import blockimgdiff -import rangelib - -from hashlib import sha1 as sha1 - - -class Options(object): - def __init__(self): - self.search_path = os.path.join(os.environ["PORT_ROOT"], "tools"); - self.signapk_path = "signapk.jar" # Relative to search_path - self.extra_signapk_args = [] - self.java_path = "java" # Use the one on the path by default. - self.java_args = "-Xmx2048m" # JVM Args - self.public_key_suffix = ".x509.pem" - self.private_key_suffix = ".pk8" - # use otatools built boot_signer by default - self.boot_signer_path = "boot_signer" - self.boot_signer_args = [] - self.verity_signer_path = None - self.verity_signer_args = [] - self.verbose = False - self.tempfiles = [] - self.device_specific = None - self.extras = {} - self.info_dict = None - self.worker_threads = None +try: + from hashlib import sha1 as sha1 +except ImportError: + from sha import sha as sha1 +# missing in Python 2.4 and before +if not hasattr(os, "SEEK_SET"): + os.SEEK_SET = 0 +class Options(object): pass OPTIONS = Options() +OPTIONS.search_path = os.path.join(os.environ["PORT_ROOT"], "tools"); +OPTIONS.verbose = False +OPTIONS.tempfiles = [] +OPTIONS.device_specific = None +OPTIONS.extras = {} +OPTIONS.info_dict = None # Values for "certificate" in apkcerts that mean special things. SPECIAL_CERT_STRINGS = ("PRESIGNED", "EXTERNAL") -class ExternalError(RuntimeError): - pass +class ExternalError(RuntimeError): pass def Run(args, **kwargs): @@ -92,24 +78,17 @@ def CloseInheritedPipes(): pass -def LoadInfoDict(input_file): +def LoadInfoDict(zip): """Read and parse the META/misc_info.txt key/value pairs from the input target files and return a dict.""" - def read_helper(fn): - if isinstance(input_file, zipfile.ZipFile): - return input_file.read(fn) - else: - path = os.path.join(input_file, *fn.split("/")) - try: - with open(path) as f: - return f.read() - except IOError as e: - if e.errno == errno.ENOENT: - raise KeyError(fn) d = {} try: - d = LoadDictionaryFromLines(read_helper("META/misc_info.txt").split("\n")) + for line in zip.read("META/misc_info.txt").split("\n"): + line = line.strip() + if not line or line.startswith("#"): continue + k, v = line.split("=", 1) + d[k] = v except KeyError: # ok if misc_info.txt doesn't exist pass @@ -120,37 +99,30 @@ def read_helper(fn): if "mkyaffs2_extra_flags" not in d: try: - d["mkyaffs2_extra_flags"] = read_helper( - "META/mkyaffs2-extra-flags.txt").strip() + d["mkyaffs2_extra_flags"] = zip.read("META/mkyaffs2-extra-flags.txt").strip() except KeyError: # ok if flags don't exist pass if "recovery_api_version" not in d: try: - d["recovery_api_version"] = read_helper( - "META/recovery-api-version.txt").strip() + d["recovery_api_version"] = zip.read("META/recovery-api-version.txt").strip() except KeyError: raise ValueError("can't find recovery API version in input target-files") if "tool_extensions" not in d: try: - d["tool_extensions"] = read_helper("META/tool-extensions.txt").strip() + d["tool_extensions"] = zip.read("META/tool-extensions.txt").strip() except KeyError: # ok if extensions don't exist pass - if "fstab_version" not in d: - d["fstab_version"] = "1" - try: - data = read_helper("META/imagesizes.txt") + data = zip.read("META/imagesizes.txt") for line in data.split("\n"): - if not line: - continue + if not line: continue name, value = line.split(" ", 1) - if not value: - continue + if not value: continue if name == "blocksize": d[name] = value else: @@ -165,129 +137,57 @@ def makeint(key): makeint("recovery_api_version") makeint("blocksize") makeint("system_size") - makeint("vendor_size") makeint("userdata_size") - makeint("cache_size") - makeint("cust_size") makeint("recovery_size") makeint("boot_size") - makeint("fstab_version") - d["fstab"] = LoadRecoveryFSTab(read_helper, d["fstab_version"]) - d["build.prop"] = LoadBuildProp(read_helper) + d["fstab"] = LoadRecoveryFSTab(zip) return d -def LoadBuildProp(read_helper): - try: - data = read_helper("SYSTEM/build.prop") - except KeyError: - print "Warning: could not find SYSTEM/build.prop in %s" % zip - data = "" - return LoadDictionaryFromLines(data.split("\n")) - -def LoadDictionaryFromLines(lines): - d = {} - for line in lines: - line = line.strip() - if not line or line.startswith("#"): - continue - if "=" in line: - name, value = line.split("=", 1) - d[name] = value - return d - -def LoadRecoveryFSTab(read_helper, fstab_version): +def LoadRecoveryFSTab(zip): class Partition(object): - def __init__(self, mount_point, fs_type, device, length, device2, context): - self.mount_point = mount_point - self.fs_type = fs_type - self.device = device - self.length = length - self.device2 = device2 - self.context = context + pass try: - data = read_helper("RECOVERY/RAMDISK/etc/recovery.fstab") + data = zip.read("RECOVERY/RAMDISK/etc/recovery.fstab") except KeyError: - print "Warning: could not find RECOVERY/RAMDISK/etc/recovery.fstab" + print "Warning: could not find RECOVERY/RAMDISK/etc/recovery.fstab in %s." % zip data = "" - if fstab_version == 1: - d = {} - for line in data.split("\n"): - line = line.strip() - if not line or line.startswith("#"): - continue - pieces = line.split() - if not 3 <= len(pieces) <= 4: - raise ValueError("malformed recovery.fstab line: \"%s\"" % (line,)) - options = None - if len(pieces) >= 4: - if pieces[3].startswith("/"): - device2 = pieces[3] - if len(pieces) >= 5: - options = pieces[4] - else: - device2 = None - options = pieces[3] + d = {} + for line in data.split("\n"): + line = line.strip() + if not line or line.startswith("#"): continue + pieces = line.split() + if not (3 <= len(pieces) <= 4): + raise ValueError("malformed recovery.fstab line: \"%s\"" % (line,)) + + p = Partition() + p.mount_point = pieces[0] + p.fs_type = pieces[1] + p.device = pieces[2] + p.length = 0 + options = None + if len(pieces) >= 4: + if pieces[3].startswith("/"): + p.device2 = pieces[3] + if len(pieces) >= 5: + options = pieces[4] else: - device2 = None - - mount_point = pieces[0] - length = 0 - if options: - options = options.split(",") - for i in options: - if i.startswith("length="): - length = int(i[7:]) - else: - print "%s: unknown option \"%s\"" % (mount_point, i) - - d[mount_point] = Partition(mount_point=mount_point, fs_type=pieces[1], - device=pieces[2], length=length, - device2=device2, context=None) - - elif fstab_version == 2: - d = {} - for line in data.split("\n"): - line = line.strip() - if not line or line.startswith("#"): - continue - # - pieces = line.split() - if len(pieces) != 5: - raise ValueError("malformed recovery.fstab line: \"%s\"" % (line,)) - - # Ignore entries that are managed by vold - options = pieces[4] - if "voldmanaged=" in options: - continue - - # It's a good line, parse it - length = 0 + p.device2 = None + options = pieces[3] + else: + p.device2 = None + + if options: options = options.split(",") for i in options: if i.startswith("length="): - length = int(i[7:]) + p.length = int(i[7:]) else: - # Ignore all unknown options in the unified fstab - continue - - mount_flags = pieces[3] - # Honor the SELinux context if present. - context = None - for i in mount_flags.split(","): - if i.startswith("context="): - context = i - - mount_point = pieces[1] - d[mount_point] = Partition(mount_point=mount_point, fs_type=pieces[2], - device=pieces[0], length=length, - device2=None, context=context) - - else: - raise ValueError("Unknown fstab_version: \"%d\"" % (fstab_version,)) + print "%s: unknown option \"%s\"" % (p.mount_point, i) + d[p.mount_point] = p return d @@ -295,8 +195,7 @@ def DumpInfoDict(d): for k, v in sorted(d.items()): print "%-25s = (%s) %s" % (k, type(v).__name__, v) - -def BuildBootableImage(sourcedir, fs_config_file, info_dict=None): +def BuildBootableImage(sourcedir): """Take a kernel, cmdline, and ramdisk directory from the input (in 'sourcedir'), and turn them into a boot image. Return the image data, or None if sourcedir does not appear to contains files for @@ -306,34 +205,20 @@ def BuildBootableImage(sourcedir, fs_config_file, info_dict=None): not os.access(os.path.join(sourcedir, "kernel"), os.F_OK)): return None - if info_dict is None: - info_dict = OPTIONS.info_dict - ramdisk_img = tempfile.NamedTemporaryFile() img = tempfile.NamedTemporaryFile() - if os.access(fs_config_file, os.F_OK): - cmd = ["mkbootfs", "-f", fs_config_file, os.path.join(sourcedir, "RAMDISK")] - else: - cmd = ["mkbootfs", os.path.join(sourcedir, "RAMDISK")] - p1 = Run(cmd, stdout=subprocess.PIPE) + p1 = Run(["mkbootfs", os.path.join(sourcedir, "RAMDISK")], + stdout=subprocess.PIPE) p2 = Run(["minigzip"], stdin=p1.stdout, stdout=ramdisk_img.file.fileno()) p2.wait() p1.wait() - assert p1.returncode == 0, "mkbootfs of %s ramdisk failed" % (sourcedir,) - assert p2.returncode == 0, "minigzip of %s ramdisk failed" % (sourcedir,) - - # use MKBOOTIMG from environ, or "mkbootimg" if empty or not set - mkbootimg = os.getenv('MKBOOTIMG') or "mkbootimg" + assert p1.returncode == 0, "mkbootfs of %s ramdisk failed" % (targetname,) + assert p2.returncode == 0, "minigzip of %s ramdisk failed" % (targetname,) - cmd = [mkbootimg, "--kernel", os.path.join(sourcedir, "kernel")] - - fn = os.path.join(sourcedir, "second") - if os.access(fn, os.F_OK): - cmd.append("--second") - cmd.append(fn) + cmd = ["mkbootimg", "--kernel", os.path.join(sourcedir, "kernel")] fn = os.path.join(sourcedir, "cmdline") if os.access(fn, os.F_OK): @@ -350,52 +235,14 @@ def BuildBootableImage(sourcedir, fs_config_file, info_dict=None): cmd.append("--pagesize") cmd.append(open(fn).read().rstrip("\n")) - args = info_dict.get("mkbootimg_args", None) - if args and args.strip(): - cmd.extend(shlex.split(args)) - - img_unsigned = None - if info_dict.get("vboot", None): - img_unsigned = tempfile.NamedTemporaryFile() - cmd.extend(["--ramdisk", ramdisk_img.name, - "--output", img_unsigned.name]) - else: - cmd.extend(["--ramdisk", ramdisk_img.name, - "--output", img.name]) + cmd.extend(["--ramdisk", ramdisk_img.name, + "--output", img.name]) p = Run(cmd, stdout=subprocess.PIPE) p.communicate() assert p.returncode == 0, "mkbootimg of %s image failed" % ( os.path.basename(sourcedir),) - if (info_dict.get("boot_signer", None) == "true" and - info_dict.get("verity_key", None)): - path = "/" + os.path.basename(sourcedir).lower() - cmd = [OPTIONS.boot_signer_path] - cmd.extend(OPTIONS.boot_signer_args) - cmd.extend([path, img.name, - info_dict["verity_key"] + ".pk8", - info_dict["verity_key"] + ".x509.pem", img.name]) - p = Run(cmd, stdout=subprocess.PIPE) - p.communicate() - assert p.returncode == 0, "boot_signer of %s image failed" % path - - # Sign the image if vboot is non-empty. - elif info_dict.get("vboot", None): - path = "/" + os.path.basename(sourcedir).lower() - img_keyblock = tempfile.NamedTemporaryFile() - cmd = [info_dict["vboot_signer_cmd"], info_dict["futility"], - img_unsigned.name, info_dict["vboot_key"] + ".vbpubk", - info_dict["vboot_key"] + ".vbprivk", img_keyblock.name, - img.name] - p = Run(cmd, stdout=subprocess.PIPE) - p.communicate() - assert p.returncode == 0, "vboot_signer of %s image failed" % path - - # Clean up the temp files. - img_unsigned.close() - img_keyblock.close() - img.seek(os.SEEK_SET, 0) data = img.read() @@ -405,32 +252,20 @@ def BuildBootableImage(sourcedir, fs_config_file, info_dict=None): return data -def GetBootableImage(name, prebuilt_name, unpack_dir, tree_subdir, - info_dict=None): +def GetBootableImage(name, prebuilt_name, unpack_dir, tree_subdir): """Return a File object (with name 'name') with the desired bootable image. Look for it in 'unpack_dir'/BOOTABLE_IMAGES under the name - 'prebuilt_name', otherwise look for it under 'unpack_dir'/IMAGES, - otherwise construct it from the source files in + 'prebuilt_name', otherwise construct it from the source files in 'unpack_dir'/'tree_subdir'.""" prebuilt_path = os.path.join(unpack_dir, "BOOTABLE_IMAGES", prebuilt_name) if os.path.exists(prebuilt_path): - print "using prebuilt %s from BOOTABLE_IMAGES..." % (prebuilt_name,) + print "using prebuilt %s..." % (prebuilt_name,) return File.FromLocalFile(name, prebuilt_path) - - prebuilt_path = os.path.join(unpack_dir, "IMAGES", prebuilt_name) - if os.path.exists(prebuilt_path): - print "using prebuilt %s from IMAGES..." % (prebuilt_name,) - return File.FromLocalFile(name, prebuilt_path) - - print "building image from target_files %s..." % (tree_subdir,) - fs_config = "META/" + tree_subdir.lower() + "_filesystem_config.txt" - data = BuildBootableImage(os.path.join(unpack_dir, tree_subdir), - os.path.join(unpack_dir, fs_config), - info_dict) - if data: - return File(name, data) - return None + else: + return None + #print "building image from target_files %s..." % (tree_subdir,) + #return File(name, BuildBootableImage(os.path.join(unpack_dir, tree_subdir))) def UnzipTemp(filename, pattern=None): @@ -474,7 +309,6 @@ def GetKeyPasswords(keylist): no_passwords = [] need_passwords = [] - key_passwords = {} devnull = open("/dev/null", "w+b") for k in sorted(keylist): # We don't need a password for things that aren't really keys. @@ -482,36 +316,19 @@ def GetKeyPasswords(keylist): no_passwords.append(k) continue - p = Run(["openssl", "pkcs8", "-in", k+OPTIONS.private_key_suffix, + p = Run(["openssl", "pkcs8", "-in", k+".pk8", "-inform", "DER", "-nocrypt"], stdin=devnull.fileno(), stdout=devnull.fileno(), stderr=subprocess.STDOUT) p.communicate() if p.returncode == 0: - # Definitely an unencrypted key. no_passwords.append(k) else: - p = Run(["openssl", "pkcs8", "-in", k+OPTIONS.private_key_suffix, - "-inform", "DER", "-passin", "pass:"], - stdin=devnull.fileno(), - stdout=devnull.fileno(), - stderr=subprocess.PIPE) - _, stderr = p.communicate() - if p.returncode == 0: - # Encrypted key with empty string as password. - key_passwords[k] = '' - elif stderr.startswith('Error decrypting key'): - # Definitely encrypted key. - # It would have said "Error reading key" if it didn't parse correctly. - need_passwords.append(k) - else: - # Potentially, a type of key that openssl doesn't understand. - # We'll let the routines in signapk.jar handle it. - no_passwords.append(k) + need_passwords.append(k) devnull.close() - key_passwords.update(PasswordManager().GetPasswords(need_passwords)) + key_passwords = PasswordManager().GetPasswords(need_passwords) key_passwords.update(dict.fromkeys(no_passwords, None)) return key_passwords @@ -539,13 +356,11 @@ def SignFile(input_name, output_name, key, password, align=None, else: sign_name = output_name - cmd = [OPTIONS.java_path, OPTIONS.java_args, "-jar", - os.path.join(OPTIONS.search_path, OPTIONS.signapk_path)] - cmd.extend(OPTIONS.extra_signapk_args) + cmd = ["java", "-Xmx4096m", "-jar", + os.path.join(OPTIONS.search_path, "signapk.jar")] if whole_file: cmd.append("-w") - cmd.extend([key + OPTIONS.public_key_suffix, - key + OPTIONS.private_key_suffix, + cmd.extend([key + ".x509.pem", key + ".pk8", input_name, sign_name]) p = Run(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE) @@ -556,7 +371,7 @@ def SignFile(input_name, output_name, key, password, align=None, raise ExternalError("signapk.jar failed: return code %s" % (p.returncode,)) if align: - p = Run(["zipalign", "-f", "-p", str(align), sign_name, output_name]) + p = Run(["zipalign", "-f", str(align), sign_name, output_name]) p.communicate() if p.returncode != 0: raise ExternalError("zipalign failed: return code %s" % (p.returncode,)) @@ -568,39 +383,31 @@ def CheckSize(data, target, info_dict): any, for the given target. Raise exception if the data is too big. Print a warning if the data is nearing the maximum size.""" - if target.endswith(".img"): - target = target[:-4] + if target.endswith(".img"): target = target[:-4] mount_point = "/" + target - fs_type = None - limit = None if info_dict["fstab"]: - if mount_point == "/userdata": - mount_point = "/data" + if mount_point == "/userdata": mount_point = "/data" p = info_dict["fstab"][mount_point] fs_type = p.fs_type - device = p.device - if "/" in device: - device = device[device.rfind("/")+1:] - limit = info_dict.get(device + "_size", None) - if not fs_type or not limit: - return + limit = info_dict.get(p.device + "_size", None) + if not fs_type or not limit: return if fs_type == "yaffs2": # image size should be increased by 1/64th to account for the # spare area (64 bytes per 2k page) limit = limit / 2048 * (2048+64) - size = len(data) - pct = float(size) * 100.0 / limit - msg = "%s size (%d) is %.2f%% of limit (%d)" % (target, size, pct, limit) - if pct >= 99.0: - raise ExternalError(msg) - elif pct >= 95.0: - print - print " WARNING: ", msg - print - elif OPTIONS.verbose: - print " ", msg + size = len(data) + pct = float(size) * 100.0 / limit + msg = "%s size (%d) is %.2f%% of limit (%d)" % (target, size, pct, limit) + if pct >= 99.0: + raise ExternalError(msg) + elif pct >= 95.0: + print + print " WARNING: ", msg + print + elif OPTIONS.verbose: + print " ", msg def ReadApkCerts(tf_zip): @@ -609,20 +416,17 @@ def ReadApkCerts(tf_zip): certmap = {} for line in tf_zip.read("META/apkcerts.txt").split("\n"): line = line.strip() - if not line: - continue + if not line: continue m = re.match(r'^name="(.*)"\s+certificate="(.*)"\s+' r'private_key="(.*)"$', line) if m: name, cert, privkey = m.groups() - public_key_suffix_len = len(OPTIONS.public_key_suffix) - private_key_suffix_len = len(OPTIONS.private_key_suffix) if cert in SPECIAL_CERT_STRINGS and not privkey: certmap[name] = cert - elif (cert.endswith(OPTIONS.public_key_suffix) and - privkey.endswith(OPTIONS.private_key_suffix) and - cert[:-public_key_suffix_len] == privkey[:-private_key_suffix_len]): - certmap[name] = cert[:-public_key_suffix_len] + elif (cert.endswith(".x509.pem") and + privkey.endswith(".pk8") and + cert[:-9] == privkey[:-4]): + certmap[name] = cert[:-9] else: raise ValueError("failed to parse line from apkcerts.txt:\n" + line) return certmap @@ -666,17 +470,15 @@ def ParseOptions(argv, try: opts, args = getopt.getopt( argv, "hvp:s:x:" + extra_opts, - ["help", "verbose", "path=", "signapk_path=", "extra_signapk_args=", - "java_path=", "java_args=", "public_key_suffix=", - "private_key_suffix=", "boot_signer_path=", "boot_signer_args=", - "verity_signer_path=", "verity_signer_args=", "device_specific=", - "extra="] + - list(extra_long_opts)) - except getopt.GetoptError as err: + ["help", "verbose", "path=", "device_specific=", "extra="] + + list(extra_long_opts)) + except getopt.GetoptError, err: Usage(docstring) print "**", str(err), "**" sys.exit(2) + path_specified = False + for o, a in opts: if o in ("-h", "--help"): Usage(docstring) @@ -685,26 +487,6 @@ def ParseOptions(argv, OPTIONS.verbose = True elif o in ("-p", "--path"): OPTIONS.search_path = a - elif o in ("--signapk_path",): - OPTIONS.signapk_path = a - elif o in ("--extra_signapk_args",): - OPTIONS.extra_signapk_args = shlex.split(a) - elif o in ("--java_path",): - OPTIONS.java_path = a - elif o in ("--java_args",): - OPTIONS.java_args = a - elif o in ("--public_key_suffix",): - OPTIONS.public_key_suffix = a - elif o in ("--private_key_suffix",): - OPTIONS.private_key_suffix = a - elif o in ("--boot_signer_path",): - OPTIONS.boot_signer_path = a - elif o in ("--boot_signer_args",): - OPTIONS.boot_signer_args = shlex.split(a) - elif o in ("--verity_signer_path",): - OPTIONS.verity_signer_path = a - elif o in ("--verity_signer_args",): - OPTIONS.verity_signer_args = shlex.split(a) elif o in ("-s", "--device_specific"): OPTIONS.device_specific = a elif o in ("-x", "--extra"): @@ -714,22 +496,12 @@ def ParseOptions(argv, if extra_option_handler is None or not extra_option_handler(o, a): assert False, "unknown option \"%s\"" % (o,) - if OPTIONS.search_path: - os.environ["PATH"] = (os.path.join(OPTIONS.search_path, "bin") + - os.pathsep + os.environ["PATH"]) + os.environ["PATH"] = (os.path.join(OPTIONS.search_path, "bin") + + os.pathsep + os.environ["PATH"]) return args -def MakeTempFile(prefix=None, suffix=None): - """Make a temp file and add it to the list of things to be deleted - when Cleanup() is called. Return the filename.""" - fd, fn = tempfile.mkstemp(prefix=prefix, suffix=suffix) - os.close(fd) - OPTIONS.tempfiles.append(fn) - return fn - - def Cleanup(): for i in OPTIONS.tempfiles: if os.path.isdir(i): @@ -763,8 +535,7 @@ def GetPasswords(self, items): if i not in current or not current[i]: missing.append(i) # Are all the passwords already in the file? - if not missing: - return current + if not missing: return current for i in missing: current[i] = "" @@ -778,7 +549,7 @@ def GetPasswords(self, items): current = self.UpdateAndReadFile(current) - def PromptResult(self, current): # pylint: disable=no-self-use + def PromptResult(self, current): """Prompt the user to enter a value (password) for each key in 'current' whose value is fales. Returns a new dict with all the values. @@ -789,10 +560,9 @@ def PromptResult(self, current): # pylint: disable=no-self-use result[k] = v else: while True: - result[k] = getpass.getpass( - "Enter password for %s key> " % k).strip() - if result[k]: - break + result[k] = getpass.getpass("Enter password for %s key> " + % (k,)).strip() + if result[k]: break return result def UpdateAndReadFile(self, current): @@ -800,13 +570,14 @@ def UpdateAndReadFile(self, current): return self.PromptResult(current) f = open(self.pwfile, "w") - os.chmod(self.pwfile, 0o600) + os.chmod(self.pwfile, 0600) f.write("# Enter key passwords between the [[[ ]]] brackets.\n") f.write("# (Additional spaces are harmless.)\n\n") first_line = None - sorted_list = sorted([(not v, k, v) for (k, v) in current.iteritems()]) - for i, (_, k, v) in enumerate(sorted_list): + sorted = [(not v, k, v) for (k, v) in current.iteritems()] + sorted.sort() + for i, (_, k, v) in enumerate(sorted): f.write("[[[ %s ]]] %s\n" % (v, k)) if not v and first_line is None: # position cursor on first line with no password. @@ -820,115 +591,31 @@ def UpdateAndReadFile(self, current): def ReadFile(self): result = {} - if self.pwfile is None: - return result + if self.pwfile is None: return result try: f = open(self.pwfile, "r") for line in f: line = line.strip() - if not line or line[0] == '#': - continue + if not line or line[0] == '#': continue m = re.match(r"^\[\[\[\s*(.*?)\s*\]\]\]\s*(\S+)$", line) if not m: print "failed to parse password file: ", line else: result[m.group(2)] = m.group(1) f.close() - except IOError as e: + except IOError, e: if e.errno != errno.ENOENT: print "error reading password file: ", str(e) return result -def ZipWrite(zip_file, filename, arcname=None, perms=0o644, - compress_type=None): - import datetime - - # http://b/18015246 - # Python 2.7's zipfile implementation wrongly thinks that zip64 is required - # for files larger than 2GiB. We can work around this by adjusting their - # limit. Note that `zipfile.writestr()` will not work for strings larger than - # 2GiB. The Python interpreter sometimes rejects strings that large (though - # it isn't clear to me exactly what circumstances cause this). - # `zipfile.write()` must be used directly to work around this. - # - # This mess can be avoided if we port to python3. - saved_zip64_limit = zipfile.ZIP64_LIMIT - zipfile.ZIP64_LIMIT = (1 << 32) - 1 - - if compress_type is None: - compress_type = zip_file.compression - if arcname is None: - arcname = filename - - saved_stat = os.stat(filename) - - try: - # `zipfile.write()` doesn't allow us to pass ZipInfo, so just modify the - # file to be zipped and reset it when we're done. - os.chmod(filename, perms) - - # Use a fixed timestamp so the output is repeatable. - epoch = datetime.datetime.fromtimestamp(0) - timestamp = (datetime.datetime(2009, 1, 1) - epoch).total_seconds() - os.utime(filename, (timestamp, timestamp)) - - zip_file.write(filename, arcname=arcname, compress_type=compress_type) - finally: - os.chmod(filename, saved_stat.st_mode) - os.utime(filename, (saved_stat.st_atime, saved_stat.st_mtime)) - zipfile.ZIP64_LIMIT = saved_zip64_limit - - -def ZipWriteStr(zip_file, zinfo_or_arcname, data, perms=None, - compress_type=None): - """Wrap zipfile.writestr() function to work around the zip64 limit. - - Even with the ZIP64_LIMIT workaround, it won't allow writing a string - longer than 2GiB. It gives 'OverflowError: size does not fit in an int' - when calling crc32(bytes). - - But it still works fine to write a shorter string into a large zip file. - We should use ZipWrite() whenever possible, and only use ZipWriteStr() - when we know the string won't be too long. - """ - - saved_zip64_limit = zipfile.ZIP64_LIMIT - zipfile.ZIP64_LIMIT = (1 << 32) - 1 - - if not isinstance(zinfo_or_arcname, zipfile.ZipInfo): - zinfo = zipfile.ZipInfo(filename=zinfo_or_arcname) - zinfo.compress_type = zip_file.compression - if perms is None: - perms = 0o644 - else: - zinfo = zinfo_or_arcname - - # If compress_type is given, it overrides the value in zinfo. - if compress_type is not None: - zinfo.compress_type = compress_type - - # If perms is given, it has a priority. - if perms is not None: - zinfo.external_attr = perms << 16 - - # Use a fixed timestamp so the output is repeatable. - zinfo.date_time = (2009, 1, 1, 0, 0, 0) - - zip_file.writestr(zinfo, data) - zipfile.ZIP64_LIMIT = saved_zip64_limit - - -def ZipClose(zip_file): - # http://b/18015246 - # zipfile also refers to ZIP64_LIMIT during close() when it writes out the - # central directory. - saved_zip64_limit = zipfile.ZIP64_LIMIT - zipfile.ZIP64_LIMIT = (1 << 32) - 1 - - zip_file.close() - - zipfile.ZIP64_LIMIT = saved_zip64_limit +def ZipWriteStr(zip, filename, data, perms=0644): + # use a fixed timestamp so the output is repeatable. + zinfo = zipfile.ZipInfo(filename=filename, + date_time=(2009, 1, 1, 0, 0, 0)) + zinfo.compress_type = zip.compression + zinfo.external_attr = perms << 16 + zip.writestr(zinfo, data) class DeviceSpecificParams(object): @@ -948,8 +635,7 @@ def __init__(self, **kwargs): if self.module is None: path = OPTIONS.device_specific - if not path: - return + if not path: return try: if os.path.isdir(path): info = imp.find_module("releasetools", [path]) @@ -959,7 +645,6 @@ def __init__(self, **kwargs): if x == ".py": f = b info = imp.find_module(f, [d]) - print "loaded device-specific extensions from", path self.module = imp.load_module("device_specific", *info) except ImportError: print "unable to load device-specific module; assuming none" @@ -993,7 +678,7 @@ def _DoCall(self, function_name, *args, **kwargs): if self.miui_module is not None and hasattr(self.miui_module, function_name): getattr(self.miui_module, function_name)(*((self,) + args), **kwargs) if run_default: - return kwargs.get("default", None) + return kwargs.get("default", None) else: return ret #END @@ -1004,10 +689,6 @@ def FullOTA_Assertions(self): assertions they like.""" return self._DoCall("FullOTA_Assertions") - def FullOTA_InstallBegin(self): - """Called at the start of full OTA installation.""" - return self._DoCall("FullOTA_InstallBegin") - def FullOTA_InstallEnd(self): """Called at the end of full OTA installation; typically this is used to install the image for the device's baseband processor.""" @@ -1019,29 +700,21 @@ def IncrementalOTA_Assertions(self): additional assertions they like.""" return self._DoCall("IncrementalOTA_Assertions") - def IncrementalOTA_VerifyBegin(self): - """Called at the start of the verification phase of incremental - OTA installation; additional checks can be placed here to abort - the script before any changes are made.""" - return self._DoCall("IncrementalOTA_VerifyBegin") - def IncrementalOTA_VerifyEnd(self): """Called at the end of the verification phase of incremental OTA installation; additional checks can be placed here to abort the script before any changes are made.""" return self._DoCall("IncrementalOTA_VerifyEnd") - def IncrementalOTA_InstallBegin(self): - """Called at the start of incremental OTA installation (after - verification is complete).""" - return self._DoCall("IncrementalOTA_InstallBegin") - def IncrementalOTA_InstallEnd(self): """Called at the end of incremental OTA installation; typically this is used to install the image for the device's baseband processor.""" return self._DoCall("IncrementalOTA_InstallEnd") + def WriteRawImage(self, *args): + return self._DoCall("WriteRawImage") + class File(object): def __init__(self, name, data): self.name = name @@ -1062,8 +735,8 @@ def WriteToTemp(self): t.flush() return t - def AddToZip(self, z, compression=None): - ZipWriteStr(z, self.name, self.data, compress_type=compression) + def AddToZip(self, z): + ZipWriteStr(z, self.name, self.data) DIFF_PROGRAM_BY_EXT = { ".gz" : "imgdiff", @@ -1074,11 +747,10 @@ def AddToZip(self, z, compression=None): } class Difference(object): - def __init__(self, tf, sf, diff_program=None): + def __init__(self, tf, sf): self.tf = tf self.sf = sf self.patch = None - self.diff_program = diff_program def ComputePatch(self): """Compute the patch (as a string of data) needed to turn sf into @@ -1087,11 +759,11 @@ def ComputePatch(self): tf = self.tf sf = self.sf - if self.diff_program: - diff_program = self.diff_program - else: - ext = os.path.splitext(tf.name)[1] - diff_program = DIFF_PROGRAM_BY_EXT.get(ext, "bsdiff") + if tf.name.startswith("data/preinstall_apps"): + return self.tf, self.sf, self.patch + + ext = os.path.splitext(tf.name)[1] + diff_program = DIFF_PROGRAM_BY_EXT.get(ext, "bsdiff") ttemp = tf.WriteToTemp() stemp = sf.WriteToTemp() @@ -1101,36 +773,19 @@ def ComputePatch(self): try: ptemp = tempfile.NamedTemporaryFile() if isinstance(diff_program, list): + diff_program[0] = os.path.join(OPTIONS.search_path, "releasetools", diff_program[0]) cmd = copy.copy(diff_program) else: + diff_program = os.path.join(OPTIONS.search_path, "releasetools", diff_program) cmd = [diff_program] cmd.append(stemp.name) cmd.append(ttemp.name) cmd.append(ptemp.name) p = Run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - err = [] - def run(): - _, e = p.communicate() - if e: - err.append(e) - th = threading.Thread(target=run) - th.start() - # MIUI MOD : START - #th.join(timeout=300) # 5 mins - th.join(timeout=1200) # 20 mins - if th.is_alive(): - print "WARNING: diff command timed out" - p.terminate() - th.join(5) - if th.is_alive(): - p.kill() - th.join() - + _, err = p.communicate() if err or p.returncode != 0: - print "WARNING: failure running %s:\n%s\n" % ( - diff_program, "".join(err)) - self.patch = None - return None, None, None + print "WARNING: failure running %s:\n%s\n" % (diff_program, err) + return None diff = ptemp.read() finally: ptemp.close() @@ -1181,7 +836,7 @@ def worker(): print "%8.2f sec %8d / %8d bytes (%6.2f%%) %s" % ( dur, len(patch), tf.size, 100.0 * len(patch) / tf.size, name) lock.release() - except Exception as e: + except Exception, e: print e raise @@ -1194,264 +849,14 @@ def worker(): threads.pop().join() -class BlockDifference(object): - def __init__(self, partition, tgt, src=None, check_first_block=False, - version=None): - self.tgt = tgt - self.src = src - self.partition = partition - self.check_first_block = check_first_block - - # Due to http://b/20939131, check_first_block is disabled temporarily. - assert not self.check_first_block - - if version is None: - version = 1 - if OPTIONS.info_dict: - version = max( - int(i) for i in - OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(",")) - self.version = version - - b = blockimgdiff.BlockImageDiff(tgt, src, threads=OPTIONS.worker_threads, - version=self.version) - tmpdir = tempfile.mkdtemp() - OPTIONS.tempfiles.append(tmpdir) - self.path = os.path.join(tmpdir, partition) - b.Compute(self.path) - - _, self.device = GetTypeAndDevice("/" + partition, OPTIONS.info_dict) - - def WriteScript(self, script, output_zip, progress=None): - if not self.src: - # write the output unconditionally - script.Print("Patching %s image unconditionally..." % (self.partition,)) - else: - script.Print("Patching %s image after verification." % (self.partition,)) - - if progress: - script.ShowProgress(progress, 0) - self._WriteUpdate(script, output_zip) - self._WritePostInstallVerifyScript(script) - - def WriteVerifyScript(self, script): - partition = self.partition - if not self.src: - script.Print("Image %s will be patched unconditionally." % (partition,)) - else: - ranges = self.src.care_map.subtract(self.src.clobbered_blocks) - ranges_str = ranges.to_string_raw() - if self.version >= 3: - script.AppendExtra(('if (range_sha1("%s", "%s") == "%s" || ' - 'block_image_verify("%s", ' - 'package_extract_file("%s.transfer.list"), ' - '"%s.new.dat", "%s.patch.dat")) then') % ( - self.device, ranges_str, self.src.TotalSha1(), - self.device, partition, partition, partition)) - else: - script.AppendExtra('if range_sha1("%s", "%s") == "%s" then' % ( - self.device, ranges_str, self.src.TotalSha1())) - script.Print('Verified %s image...' % (partition,)) - script.AppendExtra('else') - - # When generating incrementals for the system and vendor partitions, - # explicitly check the first block (which contains the superblock) of - # the partition to see if it's what we expect. If this check fails, - # give an explicit log message about the partition having been - # remounted R/W (the most likely explanation) and the need to flash to - # get OTAs working again. - if self.check_first_block: - self._CheckFirstBlock(script) - - # Abort the OTA update. Note that the incremental OTA cannot be applied - # even if it may match the checksum of the target partition. - # a) If version < 3, operations like move and erase will make changes - # unconditionally and damage the partition. - # b) If version >= 3, it won't even reach here. - script.AppendExtra(('abort("%s partition has unexpected contents");\n' - 'endif;') % (partition,)) - - def _WritePostInstallVerifyScript(self, script): - partition = self.partition - script.Print('Verifying the updated %s image...' % (partition,)) - # Unlike pre-install verification, clobbered_blocks should not be ignored. - ranges = self.tgt.care_map - ranges_str = ranges.to_string_raw() - script.AppendExtra('if range_sha1("%s", "%s") == "%s" then' % ( - self.device, ranges_str, - self.tgt.TotalSha1(include_clobbered_blocks=True))) - - # Bug: 20881595 - # Verify that extended blocks are really zeroed out. - if self.tgt.extended: - ranges_str = self.tgt.extended.to_string_raw() - script.AppendExtra('if range_sha1("%s", "%s") == "%s" then' % ( - self.device, ranges_str, - self._HashZeroBlocks(self.tgt.extended.size()))) - script.Print('Verified the updated %s image.' % (partition,)) - script.AppendExtra( - 'else\n' - ' abort("%s partition has unexpected non-zero contents after OTA ' - 'update");\n' - 'endif;' % (partition,)) - else: - script.Print('Verified the updated %s image.' % (partition,)) - - script.AppendExtra( - 'else\n' - ' abort("%s partition has unexpected contents after OTA update");\n' - 'endif;' % (partition,)) - - def _WriteUpdate(self, script, output_zip): - ZipWrite(output_zip, - '{}.transfer.list'.format(self.path), - '{}.transfer.list'.format(self.partition)) - ZipWrite(output_zip, - '{}.new.dat'.format(self.path), - '{}.new.dat'.format(self.partition)) - ZipWrite(output_zip, - '{}.patch.dat'.format(self.path), - '{}.patch.dat'.format(self.partition), - compress_type=zipfile.ZIP_STORED) - - call = ('block_image_update("{device}", ' - 'package_extract_file("{partition}.transfer.list"), ' - '"{partition}.new.dat", "{partition}.patch.dat");\n'.format( - device=self.device, partition=self.partition)) - script.AppendExtra(script.WordWrap(call)) - - def _HashBlocks(self, source, ranges): # pylint: disable=no-self-use - data = source.ReadRangeSet(ranges) - ctx = sha1() - - for p in data: - ctx.update(p) - - return ctx.hexdigest() - - def _HashZeroBlocks(self, num_blocks): # pylint: disable=no-self-use - """Return the hash value for all zero blocks.""" - zero_block = '\x00' * 4096 - ctx = sha1() - for _ in range(num_blocks): - ctx.update(zero_block) - - return ctx.hexdigest() - - # TODO(tbao): Due to http://b/20939131, block 0 may be changed without - # remounting R/W. Will change the checking to a finer-grained way to - # mask off those bits. - def _CheckFirstBlock(self, script): - r = rangelib.RangeSet((0, 1)) - srchash = self._HashBlocks(self.src, r) - - script.AppendExtra(('(range_sha1("%s", "%s") == "%s") || ' - 'abort("%s has been remounted R/W; ' - 'reflash device to reenable OTA updates");') - % (self.device, r.to_string_raw(), srchash, - self.device)) - -DataImage = blockimgdiff.DataImage - - # map recovery.fstab's fs_types to mount/format "partition types" -PARTITION_TYPES = { - "yaffs2": "MTD", - "mtd": "MTD", - "ext4": "EMMC", - "emmc": "EMMC", - "f2fs": "EMMC", - "squashfs": "EMMC" -} +PARTITION_TYPES = { "yaffs2": "MTD", "mtd": "MTD", "ext3": "EMMC", + "ext4": "EMMC", "emmc": "EMMC", "vfat": "EMMC", + "auto": "EMMC"} def GetTypeAndDevice(mount_point, info): fstab = info["fstab"] if fstab: - return (PARTITION_TYPES[fstab[mount_point].fs_type], - fstab[mount_point].device) - else: - raise KeyError - - -def ParseCertificate(data): - """Parse a PEM-format certificate.""" - cert = [] - save = False - for line in data.split("\n"): - if "--END CERTIFICATE--" in line: - break - if save: - cert.append(line) - if "--BEGIN CERTIFICATE--" in line: - save = True - cert = "".join(cert).decode('base64') - return cert - -def MakeRecoveryPatch(input_dir, output_sink, recovery_img, boot_img, - info_dict=None): - """Generate a binary patch that creates the recovery image starting - with the boot image. (Most of the space in these images is just the - kernel, which is identical for the two, so the resulting patch - should be efficient.) Add it to the output zip, along with a shell - script that is run from init.rc on first boot to actually do the - patching and install the new recovery image. - - recovery_img and boot_img should be File objects for the - corresponding images. info should be the dictionary returned by - common.LoadInfoDict() on the input target_files. - """ - - if info_dict is None: - info_dict = OPTIONS.info_dict - - diff_program = ["imgdiff"] - path = os.path.join(input_dir, "SYSTEM", "etc", "recovery-resource.dat") - if os.path.exists(path): - diff_program.append("-b") - diff_program.append(path) - bonus_args = "-b /system/etc/recovery-resource.dat" + return PARTITION_TYPES[fstab[mount_point].fs_type], fstab[mount_point].device else: - bonus_args = "" - - d = Difference(recovery_img, boot_img, diff_program=diff_program) - _, _, patch = d.ComputePatch() - output_sink("recovery-from-boot.p", patch) - - try: - boot_type, boot_device = GetTypeAndDevice("/boot", info_dict) - recovery_type, recovery_device = GetTypeAndDevice("/recovery", info_dict) - except KeyError: - return - - sh = """#!/system/bin/sh -if ! applypatch -c %(recovery_type)s:%(recovery_device)s:%(recovery_size)d:%(recovery_sha1)s; then - applypatch %(bonus_args)s %(boot_type)s:%(boot_device)s:%(boot_size)d:%(boot_sha1)s %(recovery_type)s:%(recovery_device)s %(recovery_sha1)s %(recovery_size)d %(boot_sha1)s:/system/recovery-from-boot.p && log -t recovery "Installing new recovery image: succeeded" || log -t recovery "Installing new recovery image: failed" -else - log -t recovery "Recovery image already installed" -fi -""" % {'boot_size': boot_img.size, - 'boot_sha1': boot_img.sha1, - 'recovery_size': recovery_img.size, - 'recovery_sha1': recovery_img.sha1, - 'boot_type': boot_type, - 'boot_device': boot_device, - 'recovery_type': recovery_type, - 'recovery_device': recovery_device, - 'bonus_args': bonus_args} - - # The install script location moved from /system/etc to /system/bin - # in the L release. Parse the init.rc file to find out where the - # target-files expects it to be, and put it there. - sh_location = "etc/install-recovery.sh" - try: - with open(os.path.join(input_dir, "BOOT", "RAMDISK", "init.rc")) as f: - for line in f: - m = re.match(r"^service flash_recovery /system/(\S+)\s*$", line) - if m: - sh_location = m.group(1) - print "putting script in", sh_location - break - except (OSError, IOError) as e: - print "failed to read init.rc: %s" % (e,) - - output_sink(sh_location, sh) + return None diff --git a/releasetools/edify_generator.py b/releasetools/edify_generator.py index 77e0e04..537af1c 100644 --- a/releasetools/edify_generator.py +++ b/releasetools/edify_generator.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import os import re import common @@ -20,15 +21,11 @@ class EdifyGenerator(object): """Class to generate scripts in the 'edify' recovery script language used from donut onwards.""" - def __init__(self, version, info, fstab=None): + def __init__(self, version, info): self.script = [] self.mounts = set() self.version = version self.info = info - if fstab is None: - self.fstab = self.info.get("fstab", None) - else: - self.fstab = fstab def MakeTemporary(self): """Make a temporary script object whose commands can latter be @@ -39,7 +36,7 @@ def MakeTemporary(self): return x @staticmethod - def WordWrap(cmd, linelen=80): + def _WordWrap(cmd, linelen=80): """'cmd' should be a function call with null characters after each parameter (eg, "somefun(foo,\0bar,\0baz)"). This function wraps cmd to a given line length, replacing nulls with spaces and/or newlines @@ -71,56 +68,29 @@ def AppendScript(self, other): with temporary=True) to this one.""" self.script.extend(other.script) - def AssertOemProperty(self, name, value): - """Assert that a property on the OEM paritition matches a value.""" - if not name: - raise ValueError("must specify an OEM property") - if not value: - raise ValueError("must specify the OEM value") - cmd = ('file_getprop("/oem/oem.prop", "{name}") == "{value}" || ' - 'abort("This package expects the value \\"{value}\\" for ' - '\\"{name}\\" on the OEM partition; this has value \\"" + ' - 'file_getprop("/oem/oem.prop", "{name}") + "\\".");').format( - name=name, value=value) - self.script.append(cmd) - def AssertSomeFingerprint(self, *fp): """Assert that the current system build fingerprint is one of *fp.""" if not fp: raise ValueError("must specify some fingerprints") - cmd = (' ||\n '.join([('file_getprop("/system/build.prop", "ro.build.fingerprint") == "%s"') % i - for i in fp]) + - ' ||\n abort("Package expects build fingerprint of %s; this ' - 'device has " + getprop("ro.build.fingerprint") + ".");') % ( - " or ".join(fp)) - self.script.append(cmd) - - def AssertSomeThumbprint(self, *fp): - """Assert that the current system build thumbprint is one of *fp.""" - if not fp: - raise ValueError("must specify some thumbprints") - cmd = (' ||\n '.join([('file_getprop("/system/build.prop", "ro.build.thumbprint") == "%s"') % i - for i in fp]) + - ' ||\n abort("Package expects build thumbprint of %s; this ' - 'device has " + getprop("ro.build.thumbprint") + ".");') % ( - " or ".join(fp)) - self.script.append(cmd) - - def AssertOlderBuild(self, timestamp, timestamp_text): + cmd = ('assert(' + + ' ||\0'.join([('file_getprop("/system/build.prop", ' + '"ro.build.fingerprint") == "%s"') + % i for i in fp]) + + ');') + self.script.append(self._WordWrap(cmd)) + + def AssertOlderBuild(self, timestamp): """Assert that the build on the device is older (or the same as) the given timestamp.""" - self.script.append( - ('(!less_than_int(%s, getprop("ro.build.date.utc"))) || ' - 'abort("Can\'t install this package (%s) over newer ' - 'build (" + getprop("ro.build.date") + ").");') % (timestamp, - timestamp_text)) + self.script.append(('assert(!less_than_int(%s, ' + 'getprop("ro.build.date.utc")));') % (timestamp,)) def AssertDevice(self, device): """Assert that the device identifier is the given string.""" cmd = ('getprop("ro.product.device") == "%s" || ' 'abort("This package is for \\"%s\\" devices; ' - 'this is a \\"" + getprop("ro.product.device") + "\\".");') % ( - device, device) + 'this is a \\"" + getprop("ro.product.device") + "\\".");' + ) % (device, device) self.script.append(cmd) def AssertSomeBootloader(self, *bootloaders): @@ -129,7 +99,7 @@ def AssertSomeBootloader(self, *bootloaders): " ||\0".join(['getprop("ro.bootloader") == "%s"' % (b,) for b in bootloaders]) + ");") - self.script.append(self.WordWrap(cmd)) + self.script.append(self._WordWrap(cmd)) def ShowProgress(self, frac, dur): """Update the progress bar, advancing it over 'frac' over the next @@ -147,10 +117,9 @@ def PatchCheck(self, filename, *sha1): """Check that the given file (or MTD reference) has one of the given *sha1 hashes, checking the version saved in cache if the file does not match.""" - self.script.append( - 'apply_patch_check("%s"' % (filename,) + - "".join([', "%s"' % (i,) for i in sha1]) + - ') || abort("\\"%s\\" has unexpected contents.");' % (filename,)) + self.script.append('assert(apply_patch_check("%s"' % (filename,) + + "".join([', "%s"' % (i,) for i in sha1]) + + '));') def FileCheck(self, filename, *sha1): """Check that the given file (or MTD reference) has one of the @@ -162,42 +131,25 @@ def FileCheck(self, filename, *sha1): def CacheFreeSpaceCheck(self, amount): """Check that there's at least 'amount' space that can be made available on /cache.""" - self.script.append(('apply_patch_space(%d) || abort("Not enough free space ' - 'on /system to apply patches.");') % (amount,)) - - def Mount(self, mount_point, mount_options_by_format=""): - """Mount the partition with the given mount_point. - mount_options_by_format: - [fs_type=option[,option]...[|fs_type=option[,option]...]...] - where option is optname[=optvalue] - E.g. ext4=barrier=1,nodelalloc,errors=panic|f2fs=errors=recover - """ - fstab = self.fstab + self.script.append("assert(apply_patch_space(%d));" % (amount,)) + + def Mount(self, mount_point): + """Mount the partition with the given mount_point.""" + fstab = self.info.get("fstab", None) if fstab: p = fstab[mount_point] - mount_dict = {} - if mount_options_by_format is not None: - for option in mount_options_by_format.split("|"): - if "=" in option: - key, value = option.split("=", 1) - mount_dict[key] = value - mount_flags = mount_dict.get(p.fs_type, "") - if p.context is not None: - mount_flags = p.context + ("," + mount_flags if mount_flags else "") - self.script.append('mount("%s", "%s", "%s", "%s", "%s");' % ( - p.fs_type, common.PARTITION_TYPES[p.fs_type], p.device, - p.mount_point, mount_flags)) + self.script.append('mount("%s", "%s", "%s", "%s");' % + (p.fs_type, common.PARTITION_TYPES[p.fs_type], + p.device, p.mount_point)) self.mounts.add(p.mount_point) + def Unmount(self, mount_point): + self.script.append('unmount("%s");' % mount_point) + def UnpackPackageDir(self, src, dst): """Unpack a given directory from the OTA package into the given destination directory.""" - # MIUI MOD:START - # self.script.append('package_extract_dir("%s", "%s");' % (src, dst)) - self.script.append( - 'package_extract_dir("%s", "%s") || abort("Failed to extract dir from \\"%s\\" to \\"%s\\".");' % - (src, dst, src, dst)) - # END + self.script.append('package_extract_dir("%s", "%s");' % (src, dst)) def Comment(self, comment): """Write a comment into the update script.""" @@ -210,66 +162,23 @@ def Print(self, message): """Log a message to the screen (if the logs are visible).""" self.script.append('ui_print("%s");' % (message,)) - def TunePartition(self, partition, *options): - fstab = self.fstab - if fstab: - p = fstab[partition] - if p.fs_type not in ("ext2", "ext3", "ext4"): - raise ValueError("Partition %s cannot be tuned\n" % (partition,)) - self.script.append( - 'tune2fs(' + "".join(['"%s", ' % (i,) for i in options]) + - '"%s") || abort("Failed to tune partition %s");' % ( - p.device, partition)) - def FormatPartition(self, partition): """Format the given partition, specified by its mount point (eg, "/system").""" - fstab = self.fstab + reserve_size = 0 + fstab = self.info.get("fstab", None) if fstab: p = fstab[partition] self.script.append('format("%s", "%s", "%s", "%s", "%s");' % (p.fs_type, common.PARTITION_TYPES[p.fs_type], p.device, p.length, p.mount_point)) - def WipeBlockDevice(self, partition): - if partition not in ("/system", "/vendor"): - raise ValueError(("WipeBlockDevice doesn't work on %s\n") % (partition,)) - fstab = self.fstab - size = self.info.get(partition.lstrip("/") + "_size", None) - device = fstab[partition].device - - self.script.append('wipe_block_device("%s", %s);' % (device, size)) - def DeleteFiles(self, file_list): """Delete all files in file_list.""" - if not file_list: - return + if not file_list: return cmd = "delete(" + ",\0".join(['"%s"' % (i,) for i in file_list]) + ");" - self.script.append(self.WordWrap(cmd)) - - def DeleteFilesIfNotMatching(self, file_list): - """Delete the file in file_list if not matching the checksum.""" - if not file_list: - return - for name, sha1 in file_list: - cmd = ('sha1_check(read_file("{name}"), "{sha1}") || ' - 'delete("{name}");'.format(name=name, sha1=sha1)) - self.script.append(self.WordWrap(cmd)) - - def RenameFile(self, srcfile, tgtfile): - """Moves a file from one location to another.""" - if self.info.get("update_rename_support", False): - self.script.append('rename("%s", "%s");' % (srcfile, tgtfile)) - else: - raise ValueError("Rename not supported by update binary") - - def SkipNextActionIfTargetExists(self, tgtfile, tgtsha1): - """Prepend an action with an apply_patch_check in order to - skip the action if the file exists. Used when a patch - is later renamed.""" - cmd = ('sha1_check(read_file("%s"), %s) ||' % (tgtfile, tgtsha1)) - self.script.append(self.WordWrap(cmd)) + self.script.append(self._WordWrap(cmd)) def ApplyPatch(self, srcfile, tgtfile, tgtsize, tgtsha1, *patchpairs): """Apply binary patches (in *patchpairs) to the given srcfile to @@ -279,24 +188,17 @@ def ApplyPatch(self, srcfile, tgtfile, tgtsize, tgtsha1, *patchpairs): raise ValueError("bad patches given to ApplyPatch") cmd = ['apply_patch("%s",\0"%s",\0%s,\0%d' % (srcfile, tgtfile, tgtsha1, tgtsize)] - # MIUI MOD:START - # for i in range(0, len(patchpairs), 2): - # cmd.append(',\0%s, package_extract_file("%s")' % patchpairs[i:i+2]) - # cmd.append(');') - patchfiles = "" for i in range(0, len(patchpairs), 2): cmd.append(',\0%s, package_extract_file("%s")' % patchpairs[i:i+2]) - patchfiles = patchfiles.join('%s ' % patchpairs[i+1]) - cmd.append(') || abort("Failed to apply patch \\"%s\\".");' % (patchfiles,)) - # END + cmd.append(');') cmd = "".join(cmd) - self.script.append(self.WordWrap(cmd)) + self.script.append(self._WordWrap(cmd)) - def WriteRawImage(self, mount_point, fn, mapfn=None): + def WriteRawImage(self, mount_point, fn): """Write the given package file into the partition for the given mount point.""" - fstab = self.fstab + fstab = self.info["fstab"] if fstab: p = fstab[mount_point] partition_type = common.PARTITION_TYPES[p.fs_type] @@ -306,44 +208,36 @@ def WriteRawImage(self, mount_point, fn, mapfn=None): 'write_raw_image(package_extract_file("%(fn)s"), "%(device)s");' % args) elif partition_type == "EMMC": - if mapfn: - args["map"] = mapfn - self.script.append( - 'package_extract_file("%(fn)s", "%(device)s", "%(map)s");' % args) - else: - self.script.append( - 'package_extract_file("%(fn)s", "%(device)s");' % args) + self.script.append( + 'package_extract_file("%(fn)s", "%(device)s");' % args) else: - raise ValueError( - "don't know how to write \"%s\" partitions" % p.fs_type) + raise ValueError("don't know how to write \"%s\" partitions" % (p.fs_type,)) - def SetPermissions(self, fn, uid, gid, mode, selabel, capabilities): + def SetPermissions(self, fn, uid, gid, mode, selabel=None, capabilities=None): """Set file ownership and permissions.""" if not self.info.get("use_set_metadata", False): self.script.append('set_perm(%d, %d, 0%o, "%s");' % (uid, gid, mode, fn)) else: - cmd = 'set_metadata("%s", "uid", %d, "gid", %d, "mode", 0%o' % (fn, uid, gid, mode) - if capabilities is not None: - cmd += ', "capabilities", "%s"' % capabilities + if capabilities is None: capabilities = "0x0" + cmd = 'set_metadata("%s", "uid", %d, "gid", %d, "mode", 0%o, ' \ + '"capabilities", %s' % (fn, uid, gid, mode, capabilities) if selabel is not None: - cmd += ', "selabel", "%s"' % selabel + cmd += ', "selabel", "%s"' % ( selabel ) cmd += ');' self.script.append(cmd) - def SetPermissionsRecursive(self, fn, uid, gid, dmode, fmode, selabel, - capabilities): + def SetPermissionsRecursive(self, fn, uid, gid, dmode, fmode, selabel=None, capabilities=None): """Recursively set path ownership and permissions.""" if not self.info.get("use_set_metadata", False): self.script.append('set_perm_recursive(%d, %d, 0%o, 0%o, "%s");' % (uid, gid, dmode, fmode, fn)) else: - if capabilities is None: - capabilities = "0x0" + if capabilities is None: capabilities = "0x0" cmd = 'set_metadata_recursive("%s", "uid", %d, "gid", %d, ' \ '"dmode", 0%o, "fmode", 0%o, "capabilities", %s' \ % (fn, uid, gid, dmode, fmode, capabilities) if selabel is not None: - cmd += ', "selabel", "%s"' % selabel + cmd += ', "selabel", "%s"' % ( selabel ) cmd += ');' self.script.append(cmd) @@ -356,16 +250,26 @@ def MakeSymlinks(self, symlink_list): for dest, links in sorted(by_dest.iteritems()): cmd = ('symlink("%s", ' % (dest,) + ",\0".join(['"' + i + '"' for i in sorted(links)]) + ");") - self.script.append(self.WordWrap(cmd)) + self.script.append(self._WordWrap(cmd)) + + def RetouchBinaries(self, file_list): + """Execute the retouch instructions in files listed.""" + cmd = ('retouch_binaries(' + + ', '.join(['"' + i[0] + '", "' + i[1] + '"' for i in file_list]) + + ');') + self.script.append(self._WordWrap(cmd)) + + def UndoRetouchBinaries(self, file_list): + """Undo the retouching (retouch to zero offset).""" + cmd = ('undo_retouch_binaries(' + + ', '.join(['"' + i[0] + '", "' + i[1] + '"' for i in file_list]) + + ');') + self.script.append(self._WordWrap(cmd)) def AppendExtra(self, extra): """Append text verbatim to the output script.""" self.script.append(extra) - def Unmount(self, mount_point): - self.script.append('unmount("%s");' % mount_point) - self.mounts.remove(mount_point) - def UnmountAll(self): for p in sorted(self.mounts): self.script.append('unmount("%s");' % (p,)) @@ -385,6 +289,6 @@ def AddToZip(self, input_zip, output_zip, input_path=None): if input_path is None: data = input_zip.read("OTA/bin/updater") else: - data = open(input_path, "rb").read() + data = open(os.path.join(input_path, "updater")).read() common.ZipWriteStr(output_zip, "META-INF/com/google/android/update-binary", - data, perms=0o755) + data, perms=0755) diff --git a/linux-x86/imgdiff b/releasetools/imgdiff similarity index 100% rename from linux-x86/imgdiff rename to releasetools/imgdiff diff --git a/releasetools/miui_releasetools.py b/releasetools/miui_releasetools.py index 73d563b..f82ce63 100644 --- a/releasetools/miui_releasetools.py +++ b/releasetools/miui_releasetools.py @@ -1,7 +1,6 @@ import common import copy -import edify_generator def FullOTA_Assertions(info): info.script.Mount("/data") @@ -9,60 +8,37 @@ def FullOTA_Assertions(info): def IncrementalOTA_Assertions(info): info.script.Mount("/data") -def PushBusybox(input_zip, output_zip, script): - try: - data = input_zip.read("OTA/bin/busybox") - common.ZipWriteStr(output_zip, "META-INF/com/miui/busybox", data) - script.AppendExtra("package_extract_file(\"META-INF/com/miui/busybox\", \"/tmp/busybox\");") - script.SetPermissions("/tmp/busybox", 0, 0, 0555, None, None) - except KeyError: - print 'Ignore replace cert' - -def RemoveUseslessFiles(script): - script.DeleteFiles(["/tmp/busybox"]) - -def ProcessSystemFormat(info): - edify = info.script - script_temp = edify_generator.EdifyGenerator(3, info.script.info) - PushBusybox(info.input_zip, info.output_zip, script_temp) - script_temp.AppendExtra("run_program(\"/tmp/busybox\", \"rm\", \"-rf\", \"/system\");") - script_temp_str = "".join(script_temp.script).replace(";", ";\n").strip() - format_system_line = 0 - mount_system_line = 0 - for i in xrange(len(edify.script)): - if format_system_line > 0 and mount_system_line > 0: - break - if ");" in edify.script[i] and "format" in edify.script[i] and "/system" in edify.script[i]: - format_system_line = i - continue - elif ");" in edify.script[i] and "mount" in edify.script[i] and "/system" in edify.script[i]: - mount_system_line = i - continue - if mount_system_line > format_system_line > 0: - edify.script[format_system_line] = edify.script[format_system_line].replace(edify.script[format_system_line], edify.script[mount_system_line]) - edify.script[mount_system_line] = edify.script[mount_system_line].replace(edify.script[mount_system_line] , script_temp_str) - elif format_system_line > mount_system_line > 0: - edify.script[format_system_line] = edify.script[format_system_line].replace(edify.script[format_system_line], "") - edify.script[mount_system_line] = edify.script[mount_system_line].replace(";", ";\n" + script_temp_str) - else: - PushBusybox(info.input_zip, info.output_zip, info.script) - def FullOTA_InstallEnd(info): UnpackData(info.script) CopyDataFiles(info.input_zip, info.output_zip, info.script) - ProcessSystemFormat(info) - Replace_Cert(info.input_zip, info.output_zip, info.script) - RemoveUseslessFiles(info.script) + Relink(info.input_zip, info.output_zip, info.script) SetPermissions(info.script) RemoveAbandonedPreinstall(info.script) def IncrementalOTA_InstallEnd(info): UnpackData(info.script) - Replace_Cert(info.target_zip, info.output_zip, info.script) + Relink(info.target_zip, info.output_zip, info.script) SetPermissions(info.script) RemoveAbandonedPreinstall(info.script) + + +def Relink(input_zip, output_zip, script): + """relink tool to rebuilding cust variant file and cust link +for backward compatibility that update with ota""" + + print "[MIUI CUST] OTA: handle relink" + # copy relink + data = input_zip.read("OTA/bin/relink") + common.ZipWriteStr(output_zip, "META-INF/com/miui/relink", data) + # add to script + script.AppendExtra("package_extract_file(\"META-INF/com/miui/relink\", \"/tmp/relink\");") + script.AppendExtra("set_perm(0, 0, 0555, \"/tmp/relink\");") + script.AppendExtra("run_program(\"/tmp/relink\");") + script.AppendExtra("delete(\"/tmp/relink\");") + + def CopyDataFiles(input_zip, output_zip, script): """Copies files underneath data/miui in the input zip to the output zip.""" @@ -74,6 +50,8 @@ def CopyDataFiles(input_zip, output_zip, script): info2.filename = "data/" + basefilename data = input_zip.read(info.filename) output_zip.writestr(info2, data) + common.ZipWriteStr(output_zip, "data/miui/reinstall_apps", "reinstall_apps") + script.AppendExtra("set_perm(1000, 1000, 0666, \"/data/miui/reinstall_apps\");") def UnpackData(script): @@ -83,6 +61,7 @@ def UnpackData(script): def SetPermissions(script): print "[MIUI CUST] OTA: SetPermissions" SetPermissionsRecursive(script, "/data/miui", 1000, 1000, 0755, 0644) + SetPermissionsRecursive(script, "/data/miui/cust", 1000, 1000, 0755, 0644) def SetPermissionsRecursive(script, d, gid, uid, dmod, fmod): @@ -96,14 +75,3 @@ def RemoveAbandonedPreinstall(script): script.AppendExtra("delete_recursive(\"/data/miui/preinstall_apps\");") script.AppendExtra("delete_recursive(\"/data/miui/cust/preinstall_apps\");") -def Replace_Cert(input_zip, output_zip, script): - try: - data = input_zip.read("OTA/bin/replace_key") - common.ZipWriteStr(output_zip, "META-INF/com/miui/replace_key", data) - script.AppendExtra("package_extract_file(\"META-INF/com/miui/replace_key\", \"/tmp/replace_key\");") - script.SetPermissions("/tmp/replace_key", 0, 0, 0555, None, None) - script.AppendExtra("run_program(\"/sbin/sh\", \"/tmp/replace_key\");") - script.DeleteFiles(["/tmp/replace_key"]) - except KeyError: - print 'Ignore replace cert' - diff --git a/releasetools/ota_from_target_files b/releasetools/ota_from_target_files index 00e2a46..23b87ee 100755 --- a/releasetools/ota_from_target_files +++ b/releasetools/ota_from_target_files @@ -21,7 +21,7 @@ a full OTA is produced. Usage: ota_from_target_files [flags] input_target_files output_ota_package - --board_config + -b (--board_config) Deprecated. -k (--package_key) Key to use to sign the package (default is @@ -37,19 +37,6 @@ Usage: ota_from_target_files [flags] input_target_files output_ota_package Generate an incremental OTA using the given target-files zip as the starting build. - --full_radio - When generating an incremental OTA, always include a full copy of - radio image. This option is only meaningful when -i is specified, - because a full radio is always included in a full OTA if applicable. - - -v (--verify) - Remount and verify the checksums of the files written to the - system and vendor (if used) partitions. Incremental builds only. - - -o (--oem_settings) - Use the file to specify the expected OEM-specific properties - on the OEM partition of the intended device. - -w (--wipe_user_data) Generate an OTA package that will wipe the user data partition when installed. @@ -64,47 +51,34 @@ Usage: ota_from_target_files [flags] input_target_files output_ota_package -a (--aslr_mode) Specify whether to turn on ASLR for the package (on by default). - - -2 (--two_step) - Generate a 'two-step' OTA package, where recovery is updated - first, so that any changes made to the system partition are done - using the new recovery (new kernel, etc.). - - --block - Generate a block-based OTA if possible. Will fall back to a - file-based OTA if the target_files is older and doesn't support - block-based OTAs. - - -b (--binary) - Use the given binary as the update-binary in the output package, - instead of the binary in the build's target_files. Use for - development only. - - -t (--worker_threads) - Specifies the number of worker-threads that will be used when - generating patches for incremental updates (defaults to 3). - """ import sys -if sys.hexversion < 0x02070000: - print >> sys.stderr, "Python 2.7 or newer is required." +if sys.hexversion < 0x02040000: + print >> sys.stderr, "Python 2.4 or newer is required." sys.exit(1) -import multiprocessing +import copy +import errno import os +import re +import subprocess import tempfile +import time import zipfile +try: + from hashlib import sha1 as sha1 +except ImportError: + from sha import sha as sha1 + import common import edify_generator -import sparse_img OPTIONS = common.OPTIONS OPTIONS.package_key = None OPTIONS.incremental_source = None -OPTIONS.verify = False OPTIONS.require_verbatim = set() OPTIONS.prohibit_verbatim = set(("system/build.prop",)) OPTIONS.patch_threshold = 0.95 @@ -112,23 +86,13 @@ OPTIONS.wipe_user_data = False OPTIONS.omit_prereq = False OPTIONS.extra_script = None OPTIONS.aslr_mode = True -OPTIONS.worker_threads = multiprocessing.cpu_count() // 2 -if OPTIONS.worker_threads == 0: - OPTIONS.worker_threads = 1 -OPTIONS.two_step = False -OPTIONS.no_signing = False -OPTIONS.block_based = False -OPTIONS.updater_binary = None -OPTIONS.oem_source = None -OPTIONS.fallback_to_full = True -OPTIONS.full_radio = False +OPTIONS.worker_threads = 3 def MostPopularKey(d, default): """Given a dict, return the key corresponding to the largest value. Returns 'default' if the dict is empty.""" x = [(v, k) for (k, v) in d.iteritems()] - if not x: - return default + if not x: return default x.sort() return x[-1][1] @@ -136,152 +100,113 @@ def MostPopularKey(d, default): def IsSymlink(info): """Return true if the zipfile.ZipInfo object passed in represents a symlink.""" - return (info.external_attr >> 28) == 0o12 + return (info.external_attr >> 16) == 0120777 def IsRegular(info): """Return true if the zipfile.ZipInfo object passed in represents a symlink.""" - return (info.external_attr >> 28) == 0o10 - -def ClosestFileMatch(src, tgtfiles, existing): - """Returns the closest file match between a source file and list - of potential matches. The exact filename match is preferred, - then the sha1 is searched for, and finally a file with the same - basename is evaluated. Rename support in the updater-binary is - required for the latter checks to be used.""" - - result = tgtfiles.get("path:" + src.name) - if result is not None: - return result - - # MIUI ADD: - # disable rename support - return None - - if not OPTIONS.target_info_dict.get("update_rename_support", False): - return None - - if src.size < 1000: - return None - - result = tgtfiles.get("sha1:" + src.sha1) - if result is not None and existing.get(result.name) is None: - return result - result = tgtfiles.get("file:" + src.name.split("/")[-1]) - if result is not None and existing.get(result.name) is None: - return result - return None - -class ItemSet(object): - def __init__(self, partition, fs_config): - self.partition = partition - self.fs_config = fs_config - self.ITEMS = {} - - def Get(self, name, is_dir=False): - if name not in self.ITEMS: - self.ITEMS[name] = Item(self, name, is_dir=is_dir) - return self.ITEMS[name] - - def GetMetadata(self, input_zip): - # The target_files contains a record of what the uid, - # gid, and mode are supposed to be. - output = input_zip.read(self.fs_config) + return (info.external_attr >> 28) == 010 - for line in output.split("\n"): - if not line: - continue - columns = line.split() - name, uid, gid, mode = columns[:4] - selabel = None - capabilities = None - - # After the first 4 columns, there are a series of key=value - # pairs. Extract out the fields we care about. - for element in columns[4:]: - key, value = element.split("=") - if key == "selabel": - selabel = value - if key == "capabilities": - capabilities = value - - i = self.ITEMS.get(name, None) - if i is not None: - i.uid = int(uid) - i.gid = int(gid) - i.mode = int(mode, 8) - i.selabel = selabel - i.capabilities = capabilities - if i.is_dir: - i.children.sort(key=lambda i: i.name) - - # set metadata for the files generated by this script. - # MIUI MOD: - if self.partition == "system": - i = self.ITEMS.get("system/recovery-from-boot.p", None) - if i: - i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o644, None, None - i = self.ITEMS.get("system/etc/install-recovery.sh", None) - if i: - i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o544, None, None - - -class Item(object): +class Item: """Items represent the metadata (user, group, mode) of files and directories in the system image.""" - def __init__(self, itemset, name, is_dir=False): - self.itemset = itemset + ITEMS = {} + def __init__(self, name, dir=False): self.name = name self.uid = 0 self.gid = 0 - self.mode = 0o644 + self.mode = 0644 + if dir: + self.mode = 0755 self.selabel = None + if OPTIONS.info_dict.get("use_set_metadata", False): + if name.find("system/") == 0: + self.selabel = 'u:object_r:system_file:s0' self.capabilities = None - self.is_dir = is_dir - self.descendants = None - self.best_subtree = None + self.dir = dir if name: - self.parent = itemset.Get(os.path.dirname(name), is_dir=True) + self.parent = Item.Get(os.path.dirname(name), dir=True) self.parent.children.append(self) else: self.parent = None - if self.is_dir: + if dir: self.children = [] def Dump(self, indent=0): if self.uid is not None: - print "%s%s %d %d %o" % ( - " " * indent, self.name, self.uid, self.gid, self.mode) + print "%s%s %d %d %o" % (" "*indent, self.name, self.uid, self.gid, self.mode) else: - print "%s%s %s %s %s" % ( - " " * indent, self.name, self.uid, self.gid, self.mode) - if self.is_dir: + print "%s%s %s %s %s" % (" "*indent, self.name, self.uid, self.gid, self.mode) + if self.dir: print "%s%s" % (" "*indent, self.descendants) print "%s%s" % (" "*indent, self.best_subtree) for i in self.children: i.Dump(indent=indent+1) + @classmethod + def Get(cls, name, dir=False): + if name not in cls.ITEMS: + cls.ITEMS[name] = Item(name, dir=dir) + return cls.ITEMS[name] + + @classmethod + def GetMetadata(cls, input_zip): + + # The target_files contains a record of what the uid, + # gid, and mode are supposed to be. + output = input_zip.read("META/filesystem_config.txt") + + for line in output.split("\n"): + if not line: continue + columns = line.split() + name, uid, gid, mode = columns[:4] + selabel = None + capabilities = None + + # After the first 4 columns, there are a series of key=value + # pairs. Extract out the fields we care about. + if OPTIONS.info_dict.get("use_set_metadata", False): + for element in columns[4:]: + key, value = element.split("=") + if key == "selabel": + selabel = value + if key == "capabilities": + capabilities = value + + i = cls.ITEMS.get(name, None) + if i is not None: + i.uid = int(uid) + i.gid = int(gid) + i.mode = int(mode, 8) + i.selabel = selabel + i.capabilities = capabilities + if i.dir: + i.children.sort(key=lambda i: i.name) + + # set metadata for the files generated by this script. + i = cls.ITEMS.get("system/recovery-from-boot.p", None) + if i: i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0644, None, None + i = cls.ITEMS.get("system/etc/install-recovery.sh", None) + if i: i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0544, None, None + def CountChildMetadata(self): """Count up the (uid, gid, mode, selabel, capabilities) tuples for - all children and determine the best strategy for using set_perm_recursive - and set_perm to correctly chown/chmod all the files to their desired + all children and determine the best strategy for using set_perm_recursive and + set_perm to correctly chown/chmod all the files to their desired values. Recursively calls itself for all descendants. - Returns a dict of {(uid, gid, dmode, fmode, selabel, capabilities): count} - counting up all descendants of this node. (dmode or fmode may be None.) - Also sets the best_subtree of each directory Item to the (uid, gid, dmode, - fmode, selabel, capabilities) tuple that will match the most descendants of - that Item. + Returns a dict of {(uid, gid, dmode, fmode, selabel, capabilities): count} counting up + all descendants of this node. (dmode or fmode may be None.) Also + sets the best_subtree of each directory Item to the (uid, gid, + dmode, fmode, selabel, capabilities) tuple that will match the most + descendants of that Item. """ - assert self.is_dir - key = (self.uid, self.gid, self.mode, None, self.selabel, - self.capabilities) - self.descendants = {key: 1} - d = self.descendants + assert self.dir + d = self.descendants = {(self.uid, self.gid, self.mode, None, self.selabel, self.capabilities): 1} for i in self.children: - if i.is_dir: + if i.dir: for k, v in i.CountChildMetadata().iteritems(): d[k] = d.get(k, 0) + v else: @@ -300,23 +225,17 @@ class Item(object): # Now find the dmode, fmode, selabel, and capabilities that match # the most descendants with that (uid, gid), and choose those. - best_dmode = (0, 0o755) - best_fmode = (0, 0o644) + best_dmode = (0, 0755) + best_fmode = (0, 0644) best_selabel = (0, None) best_capabilities = (0, None) for k, count in d.iteritems(): - if k[:2] != ug: - continue - if k[2] is not None and count >= best_dmode[0]: - best_dmode = (count, k[2]) - if k[3] is not None and count >= best_fmode[0]: - best_fmode = (count, k[3]) - if k[4] is not None and count >= best_selabel[0]: - best_selabel = (count, k[4]) - if k[5] is not None and count >= best_capabilities[0]: - best_capabilities = (count, k[5]) - self.best_subtree = ug + ( - best_dmode[1], best_fmode[1], best_selabel[1], best_capabilities[1]) + if k[:2] != ug: continue + if k[2] is not None and count >= best_dmode[0]: best_dmode = (count, k[2]) + if k[3] is not None and count >= best_fmode[0]: best_fmode = (count, k[3]) + if k[4] is not None and count >= best_selabel[0]: best_selabel = (count, k[4]) + if k[5] is not None and count >= best_capabilities[0]: best_capabilities = (count, k[5]) + self.best_subtree = ug + (best_dmode[1], best_fmode[1], best_selabel[1], best_capabilities[1]) return d @@ -328,11 +247,11 @@ class Item(object): self.CountChildMetadata() def recurse(item, current): - # current is the (uid, gid, dmode, fmode, selabel, capabilities) tuple - # that the current item (and all its children) have already been set to. - # We only need to issue set_perm/set_perm_recursive commands if we're + # current is the (uid, gid, dmode, fmode, selabel, capabilities) tuple that the current + # item (and all its children) have already been set to. We only + # need to issue set_perm/set_perm_recursive commands if we're # supposed to be something different. - if item.is_dir: + if item.dir: if current != item.best_subtree: script.SetPermissionsRecursive("/"+item.name, *item.best_subtree) current = item.best_subtree @@ -355,30 +274,29 @@ class Item(object): recurse(self, (-1, -1, -1, -1, None, None)) -def CopyPartitionFiles(itemset, input_zip, output_zip=None, substitute=None): - """Copies files for the partition in the input zip to the output +def CopySystemFiles(input_zip, output_zip=None, + substitute=None): + """Copies files underneath system/ in the input zip to the output zip. Populates the Item class with their metadata, and returns a - list of symlinks. output_zip may be None, in which case the copy is - skipped (but the other side effects still happen). substitute is an - optional dict of {output filename: contents} to be output instead of - certain input files. + list of symlinks as well as a list of files that will be retouched. + output_zip may be None, in which case the copy is skipped (but the + other side effects still happen). substitute is an optional dict + of {output filename: contents} to be output instead of certain input + files. """ symlinks = [] - - partition = itemset.partition + retouch_files = [] for info in input_zip.infolist(): - prefix = partition.upper() + "/" - if info.filename.startswith(prefix): - basefilename = info.filename[len(prefix):] + if info.filename.startswith("SYSTEM/"): + basefilename = info.filename[7:] if IsSymlink(info): symlinks.append((input_zip.read(info.filename), - "/" + partition + "/" + basefilename)) + "/system/" + basefilename)) else: - import copy info2 = copy.copy(info) - fn = info2.filename = partition + "/" + basefilename + fn = info2.filename = "system/" + basefilename if substitute and fn in substitute and substitute[fn] is None: continue if output_zip is not None: @@ -386,15 +304,17 @@ def CopyPartitionFiles(itemset, input_zip, output_zip=None, substitute=None): data = substitute[fn] else: data = input_zip.read(info.filename) - common.ZipWriteStr(output_zip, info2, data) + if info.filename.startswith("SYSTEM/lib/") and IsRegular(info): + retouch_files.append(("/system/" + basefilename, + common.sha1(data).hexdigest())) + output_zip.writestr(info2, data) if fn.endswith("/"): - itemset.Get(fn[:-1], is_dir=True) + Item.Get(fn[:-1], dir=True) else: - itemset.Get(fn) + Item.Get(fn, dir=False) symlinks.sort() - return symlinks - + return (symlinks, retouch_files) def SignOutput(temp_zip_name, output_zip_name): key_passwords = common.GetKeyPasswords([OPTIONS.package_key]) @@ -404,124 +324,65 @@ def SignOutput(temp_zip_name, output_zip_name): whole_file=True) -def AppendAssertions(script, info_dict, oem_dict=None): - oem_props = info_dict.get("oem_fingerprint_properties") - if oem_props is None or len(oem_props) == 0: - device = GetBuildProp("ro.product.device", info_dict) - script.AssertDevice(device) - else: - if oem_dict is None: - raise common.ExternalError( - "No OEM file provided to answer expected assertions") - for prop in oem_props.split(): - if oem_dict.get(prop) is None: - raise common.ExternalError( - "The OEM file is missing the property %s" % prop) - script.AssertOemProperty(prop, oem_dict.get(prop)) - - -def HasRecoveryPatch(target_files_zip): - try: - target_files_zip.getinfo("SYSTEM/recovery-from-boot.p") - return True - except KeyError: - return False - -def HasVendorPartition(target_files_zip): - try: - target_files_zip.getinfo("VENDOR/") - return True - except KeyError: - return False - -# MIUI ADD -def HasCustPartition(target_files_zip): - try: - target_files_zip.getinfo("CUST/") - return True - except KeyError: - return False - -def GetOemProperty(name, oem_props, oem_dict, info_dict): - if oem_props is not None and name in oem_props: - return oem_dict[name] - return GetBuildProp(name, info_dict) - - -def CalculateFingerprint(oem_props, oem_dict, info_dict): - if oem_props is None: - return GetBuildProp("ro.build.fingerprint", info_dict) - return "%s/%s/%s:%s" % ( - GetOemProperty("ro.product.brand", oem_props, oem_dict, info_dict), - GetOemProperty("ro.product.name", oem_props, oem_dict, info_dict), - GetOemProperty("ro.product.device", oem_props, oem_dict, info_dict), - GetBuildProp("ro.build.thumbprint", info_dict)) - +def AppendAssertions(script, input_zip): + device = GetBuildProp("ro.product.device", input_zip) + script.AssertDevice(device) -def GetImage(which, tmpdir, info_dict): - # Return an image object (suitable for passing to BlockImageDiff) - # for the 'which' partition (most be "system" or "vendor"). If a - # prebuilt image and file map are found in tmpdir they are used, - # otherwise they are reconstructed from the individual files. - assert which in ("system", "vendor") +def MakeRecoveryPatch(output_zip, recovery_img, boot_img): + """Generate a binary patch that creates the recovery image starting + with the boot image. (Most of the space in these images is just the + kernel, which is identical for the two, so the resulting patch + should be efficient.) Add it to the output zip, along with a shell + script that is run from init.rc on first boot to actually do the + patching and install the new recovery image. - path = os.path.join(tmpdir, "IMAGES", which + ".img") - mappath = os.path.join(tmpdir, "IMAGES", which + ".map") - if os.path.exists(path) and os.path.exists(mappath): - print "using %s.img from target-files" % (which,) - # This is a 'new' target-files, which already has the image in it. + recovery_img and boot_img should be File objects for the + corresponding images. info should be the dictionary returned by + common.LoadInfoDict() on the input target_files. - else: - print "building %s.img from target-files" % (which,) - - # This is an 'old' target-files, which does not contain images - # already built. Build them. - - mappath = tempfile.mkstemp()[1] - OPTIONS.tempfiles.append(mappath) + Returns an Item for the shell script, which must be made + executable. + """ - import add_img_to_target_files - if which == "system": - path = add_img_to_target_files.BuildSystem( - tmpdir, info_dict, block_list=mappath) - elif which == "vendor": - path = add_img_to_target_files.BuildVendor( - tmpdir, info_dict, block_list=mappath) + d = common.Difference(recovery_img, boot_img) + _, _, patch = d.ComputePatch() + common.ZipWriteStr(output_zip, "recovery/recovery-from-boot.p", patch) + Item.Get("system/recovery-from-boot.p", dir=False) - # Bug: http://b/20939131 - # In ext4 filesystems, block 0 might be changed even being mounted - # R/O. We add it to clobbered_blocks so that it will be written to the - # target unconditionally. Note that they are still part of care_map. - clobbered_blocks = "0" + boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict) + recovery_type, recovery_device = common.GetTypeAndDevice("/recovery", OPTIONS.info_dict) - return sparse_img.SparseImage(path, mappath, clobbered_blocks) + sh = """#!/system/bin/sh +if ! applypatch -c %(recovery_type)s:%(recovery_device)s:%(recovery_size)d:%(recovery_sha1)s; then + log -t recovery "Installing new recovery image" + applypatch %(boot_type)s:%(boot_device)s:%(boot_size)d:%(boot_sha1)s %(recovery_type)s:%(recovery_device)s %(recovery_sha1)s %(recovery_size)d %(boot_sha1)s:/system/recovery-from-boot.p +else + log -t recovery "Recovery image already installed" +fi +""" % { 'boot_size': boot_img.size, + 'boot_sha1': boot_img.sha1, + 'recovery_size': recovery_img.size, + 'recovery_sha1': recovery_img.sha1, + 'boot_type': boot_type, + 'boot_device': boot_device, + 'recovery_type': recovery_type, + 'recovery_device': recovery_device, + } + common.ZipWriteStr(output_zip, "recovery/etc/install-recovery.sh", sh) + return Item.Get("system/etc/install-recovery.sh", dir=False) def WriteFullOTAPackage(input_zip, output_zip): # TODO: how to determine this? We don't know what version it will - # be installed on top of. For now, we expect the API just won't - # change very often. Similarly for fstab, it might have changed - # in the target build. + # be installed on top of. For now, we expect the API just won't + # change very often. script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict) - oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties") - recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options") - oem_dict = None - if oem_props is not None and len(oem_props) > 0: - if OPTIONS.oem_source is None: - raise common.ExternalError("OEM source required for this build") - script.Mount("/oem", recovery_mount_options) - oem_dict = common.LoadDictionaryFromLines( - open(OPTIONS.oem_source).readlines()) - - metadata = { - "post-build": CalculateFingerprint(oem_props, oem_dict, - OPTIONS.info_dict), - "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict, - OPTIONS.info_dict), - "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict), - } + metadata = {"post-build": GetBuildProp("ro.build.fingerprint", input_zip), + "pre-device": GetBuildProp("ro.product.device", input_zip), + "post-timestamp": GetBuildProp("ro.build.date.utc", input_zip), + } device_specific = common.DeviceSpecificParams( input_zip=input_zip, @@ -532,239 +393,123 @@ def WriteFullOTAPackage(input_zip, output_zip): metadata=metadata, info_dict=OPTIONS.info_dict) - has_recovery_patch = HasRecoveryPatch(input_zip) - block_based = OPTIONS.block_based and has_recovery_patch - if not OPTIONS.omit_prereq: - ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict) - ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict) - script.AssertOlderBuild(ts, ts_text) + ts = GetBuildProp("ro.build.date.utc", input_zip) + script.AssertOlderBuild(ts) - AppendAssertions(script, OPTIONS.info_dict, oem_dict) + AppendAssertions(script, input_zip) device_specific.FullOTA_Assertions() - # Two-step package strategy (in chronological order, which is *not* - # the order in which the generated script has things): - # - # if stage is not "2/3" or "3/3": - # write recovery image to boot partition - # set stage to "2/3" - # reboot to boot partition and restart recovery - # else if stage is "2/3": - # write recovery image to recovery partition - # set stage to "3/3" - # reboot to recovery partition and restart recovery - # else: - # (stage must be "3/3") - # set stage to "" - # do normal full package installation: - # wipe and install system, boot image, etc. - # set up system to update recovery partition on first boot - # complete script normally - # (allow recovery to mark itself finished and reboot) - - #recovery_img = common.GetBootableImage("recovery.img", "recovery.img", - # OPTIONS.input_tmp, "RECOVERY") - #if OPTIONS.two_step: - # if not OPTIONS.info_dict.get("multistage_support", None): - # assert False, "two-step packages not supported by this build" - # fs = OPTIONS.info_dict["fstab"]["/misc"] - # assert fs.fs_type.upper() == "EMMC", \ - # "two-step packages only supported on devices with EMMC /misc partitions" - # bcb_dev = {"bcb_dev": fs.device} - # common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data) - # script.AppendExtra(""" -#if get_stage("%(bcb_dev)s") == "2/3" then -#""" % bcb_dev) -# script.WriteRawImage("/recovery", "recovery.img") -# script.AppendExtra(""" -#set_stage("%(bcb_dev)s", "3/3"); -#reboot_now("%(bcb_dev)s", "recovery"); -#else if get_stage("%(bcb_dev)s") == "3/3" then -#""" % bcb_dev) - - # Dump fingerprints - script.Print("Target: %s" % CalculateFingerprint( - oem_props, oem_dict, OPTIONS.info_dict)) - - device_specific.FullOTA_InstallBegin() - - system_progress = 0.75 + script.ShowProgress(0.5, 0) if OPTIONS.wipe_user_data: - system_progress -= 0.1 - if HasVendorPartition(input_zip): - system_progress -= 0.1 - # MIUI ADD: - if HasCustPartition(input_zip): - system_progress -= 0.1 - - if "selinux_fc" in OPTIONS.info_dict: - WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip) - - recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options") - - system_items = ItemSet("system", "META/filesystem_config.txt") - script.ShowProgress(system_progress, 0) - - if block_based: - # Full OTA is done as an "incremental" against an empty source - # image. This has the effect of writing new data from the package - # to the entire partition, but lets us reuse the updater code that - # writes incrementals to do it. - system_tgt = GetImage("system", OPTIONS.input_tmp, OPTIONS.info_dict) - system_tgt.ResetFileMap() - system_diff = common.BlockDifference("system", system_tgt, src=None) - system_diff.WriteScript(script, output_zip) - else: - script.FormatPartition("/system") - script.Mount("/system", recovery_mount_options) - if not has_recovery_patch: - script.UnpackPackageDir("recovery", "/system") - script.UnpackPackageDir("system", "/system") - - symlinks = CopyPartitionFiles(system_items, input_zip, output_zip) - script.MakeSymlinks(symlinks) - - boot_img = common.GetBootableImage("boot.img", "boot.img", - OPTIONS.input_tmp, "BOOT") - - if not block_based: - def output_sink(fn, data): - common.ZipWriteStr(output_zip, "recovery/" + fn, data) - system_items.Get("system/" + fn) - - #common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink, - # recovery_img, boot_img) - - system_items.GetMetadata(input_zip) - system_items.Get("system").SetPermissions(script) - - if HasVendorPartition(input_zip): - vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt") - script.ShowProgress(0.1, 0) + script.FormatPartition("/data") - if block_based: - vendor_tgt = GetImage("vendor", OPTIONS.input_tmp, OPTIONS.info_dict) - vendor_tgt.ResetFileMap() - vendor_diff = common.BlockDifference("vendor", vendor_tgt) - vendor_diff.WriteScript(script, output_zip) - else: - script.FormatPartition("/vendor") - script.Mount("/vendor", recovery_mount_options) - script.UnpackPackageDir("vendor", "/vendor") + script.Print("Formatting system...") + script.Unmount("/system") + script.FormatPartition("/system") - symlinks = CopyPartitionFiles(vendor_items, input_zip, output_zip) - script.MakeSymlinks(symlinks) + script.Print("Installing system files...") + script.Mount("/system") + #script.UnpackPackageDir("recovery", "/system") + script.UnpackPackageDir("system", "/system") - vendor_items.GetMetadata(input_zip) - vendor_items.Get("vendor").SetPermissions(script) + script.Print("Creating system links...") + (symlinks, retouch_files) = CopySystemFiles(input_zip, output_zip) + script.MakeSymlinks(symlinks) + # if OPTIONS.aslr_mode: + # script.RetouchBinaries(retouch_files) + # else: + # script.UndoRetouchBinaries(retouch_files) - if HasCustPartition(input_zip): - cust_items = ItemSet("cust", "META/cust_filesystem_config.txt") - script.ShowProgress(0.1, 0) - script.Mount("/cust", recovery_mount_options) - script.UnpackPackageDir("cust", "/cust") - symlinks = CopyPartitionFiles(cust_items, input_zip, output_zip) - script.MakeSymlinks(symlinks) - cust_items.GetMetadata(input_zip) - cust_items.Get("cust").SetPermissions(script) + boot_img = common.GetBootableImage("boot.img", "boot.img", + OPTIONS.input_tmp, "BOOT") + # recovery_img = common.GetBootableImage("recovery.img", "recovery.img", + # OPTIONS.input_tmp, "RECOVERY") + # MakeRecoveryPatch(output_zip, recovery_img, boot_img) - #common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict) - common.ZipWriteStr(output_zip, "boot.img", boot_img.data) + script.Print("Set permission...") + Item.GetMetadata(input_zip) + Item.Get("system").SetPermissions(script) - script.ShowProgress(0.05, 5) - script.WriteRawImage("/boot", "boot.img") + script.Print("Update Boot image...") + if boot_img: + common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict) + common.ZipWriteStr(output_zip, "boot.img", boot_img.data) + script.ShowProgress(0.2, 0) script.ShowProgress(0.2, 10) + if boot_img and not device_specific.WriteRawImage("/boot", "boot.img"): + script.WriteRawImage("/boot", "boot.img") + + script.ShowProgress(0.1, 0) device_specific.FullOTA_InstallEnd() if OPTIONS.extra_script is not None: script.AppendExtra(OPTIONS.extra_script) script.UnmountAll() - - if OPTIONS.wipe_user_data: - script.ShowProgress(0.1, 10) - script.FormatPartition("/data") - - if OPTIONS.two_step: - script.AppendExtra(""" -set_stage("%(bcb_dev)s", ""); -""" % bcb_dev) - script.AppendExtra("else\n") - script.WriteRawImage("/boot", "recovery.img") - script.AppendExtra(""" -set_stage("%(bcb_dev)s", "2/3"); -reboot_now("%(bcb_dev)s", ""); -endif; -endif; -""" % bcb_dev) - script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary) + script.AddToZip(input_zip, output_zip) WriteMetadata(metadata, output_zip) -def WritePolicyConfig(file_name, output_zip): - common.ZipWrite(output_zip, file_name, os.path.basename(file_name)) - - def WriteMetadata(metadata, output_zip): common.ZipWriteStr(output_zip, "META-INF/com/android/metadata", "".join(["%s=%s\n" % kv for kv in sorted(metadata.iteritems())])) -def LoadPartitionFiles(z, partition): - """Load all the files from the given partition in a given target-files + + +def LoadSystemFiles(z): + """Load all the files from SYSTEM/... in a given target-files ZipFile, and return a dict of {filename: File object}.""" out = {} - prefix = partition.upper() + "/" + retouch_files = [] for info in z.infolist(): - if info.filename.startswith(prefix) and not IsSymlink(info): - basefilename = info.filename[len(prefix):] - fn = partition + "/" + basefilename + if info.filename.startswith("SYSTEM/") and not IsSymlink(info): + basefilename = info.filename[7:] + fn = "system/" + basefilename data = z.read(info.filename) out[fn] = common.File(fn, data) - return out - - -def GetBuildProp(prop, info_dict): - """Return the fingerprint of the build of a given target-files info_dict.""" - try: - return info_dict.get("build.prop", {})[prop] - except KeyError: - raise common.ExternalError("couldn't find %s in build.prop" % (prop,)) + if info.filename.startswith("SYSTEM/lib/") and IsRegular(info): + retouch_files.append(("/system/" + basefilename, + out[fn].sha1)) + # MIUI ADDD: + # load /data/miui files + elif info.filename.startswith("DATA/miui/") and not IsSymlink(info): + + basefilename = info.filename[5:] + fn = "data/" + basefilename + data = z.read(info.filename) + out[fn] = common.File(fn, data) + return (out, retouch_files) -def AddToKnownPaths(filename, known_paths): - if filename[-1] == "/": - return - dirs = filename.split("/")[:-1] - while len(dirs) > 0: - path = "/".join(dirs) - if path in known_paths: - break - known_paths.add(path) - dirs.pop() +def GetBuildProp(property, z): + """Return the fingerprint of the build of a given target-files + ZipFile object.""" + bp = z.read("SYSTEM/build.prop") + if not property: + return bp + m = re.search(re.escape(property) + r"=(.*)\n", bp) + if not m: + raise common.ExternalError("couldn't find %s in build.prop" % (property,)) + return m.group(1).strip() -def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip): +def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip): source_version = OPTIONS.source_info_dict["recovery_api_version"] target_version = OPTIONS.target_info_dict["recovery_api_version"] if source_version == 0: print ("WARNING: generating edify script for a source that " "can't install it.") - script = edify_generator.EdifyGenerator( - source_version, OPTIONS.target_info_dict, - fstab=OPTIONS.source_info_dict["fstab"]) + script = edify_generator.EdifyGenerator(source_version, OPTIONS.target_info_dict) - metadata = { - "pre-device": GetBuildProp("ro.product.device", - OPTIONS.source_info_dict), - "post-timestamp": GetBuildProp("ro.build.date.utc", - OPTIONS.target_info_dict), - } + metadata = {"pre-device": GetBuildProp("ro.product.device", source_zip), + "post-timestamp": GetBuildProp("ro.build.date.utc", target_zip), + } device_specific = common.DeviceSpecificParams( source_zip=source_zip, @@ -776,575 +521,94 @@ def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip): metadata=metadata, info_dict=OPTIONS.info_dict) - # MIUI ADD: START - if "selinux_fc" in OPTIONS.info_dict: - WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip) - # END - - # TODO: Currently this works differently from WriteIncrementalOTAPackage(). - # This function doesn't consider thumbprints when writing - # metadata["pre/post-build"]. One possible reason is that the current - # devices with thumbprints are all using file-based OTAs. Long term we - # should factor out the common parts into a shared one to avoid further - # divergence. - source_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.source_info_dict) - target_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.target_info_dict) - metadata["pre-build"] = source_fp - metadata["post-build"] = target_fp - - source_boot = common.GetBootableImage( - "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT", - OPTIONS.source_info_dict) - target_boot = common.GetBootableImage( - "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT") - updating_boot = (not OPTIONS.two_step and - (source_boot.data != target_boot.data)) - - target_recovery = common.GetBootableImage( - "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY") - - system_src = GetImage("system", OPTIONS.source_tmp, OPTIONS.source_info_dict) - system_tgt = GetImage("system", OPTIONS.target_tmp, OPTIONS.target_info_dict) - - blockimgdiff_version = 1 - if OPTIONS.info_dict: - blockimgdiff_version = max( - int(i) for i in - OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(",")) - - system_diff = common.BlockDifference("system", system_tgt, system_src, - version=blockimgdiff_version) - - if HasVendorPartition(target_zip): - if not HasVendorPartition(source_zip): - raise RuntimeError("can't generate incremental that adds /vendor") - vendor_src = GetImage("vendor", OPTIONS.source_tmp, - OPTIONS.source_info_dict) - vendor_tgt = GetImage("vendor", OPTIONS.target_tmp, - OPTIONS.target_info_dict) - vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src, - version=blockimgdiff_version) - else: - vendor_diff = None - - oem_props = OPTIONS.target_info_dict.get("oem_fingerprint_properties") - recovery_mount_options = OPTIONS.source_info_dict.get( - "recovery_mount_options") - oem_dict = None - if oem_props is not None and len(oem_props) > 0: - if OPTIONS.oem_source is None: - raise common.ExternalError("OEM source required for this build") - script.Mount("/oem", recovery_mount_options) - oem_dict = common.LoadDictionaryFromLines( - open(OPTIONS.oem_source).readlines()) - - AppendAssertions(script, OPTIONS.target_info_dict, oem_dict) - device_specific.IncrementalOTA_Assertions() - - # MIUI ADD: support cust - cust_diff = None - if HasCustPartition(target_zip): - if not HasCustPartition(source_zip): - cust_items = ItemSet("cust", "META/cust_filesystem_config.txt") - - script.FormatPartition("/cust") - script.Mount("/cust", recovery_mount_options) - script.UnpackPackageDir("cust", "/cust") - - symlinks = CopyPartitionFiles(cust_items, target_zip, output_zip) - script.MakeSymlinks(symlinks) - - cust_items.GetMetadata(target_zip) - cust_items.Get("cust").SetPermissions(script) + print "Loading target..." + (target_data, target_retouch_files) = LoadSystemFiles(target_zip) + print "Loading source..." + (source_data, source_retouch_files) = LoadSystemFiles(source_zip) + + verbatim_targets = [] + patch_list = [] + diffs = [] + largest_source_size = 0 + for fn in sorted(target_data.keys()): + tf = target_data[fn] + assert fn == tf.name + sf = source_data.get(fn, None) + + if sf is None or fn in OPTIONS.require_verbatim: + # This file should be included verbatim + if fn in OPTIONS.prohibit_verbatim: + raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,)) + print "send", fn, "verbatim" + tf.AddToZip(output_zip) + verbatim_targets.append((fn, tf.size)) + elif tf.sha1 != sf.sha1: + # File is different; consider sending as a patch + diffs.append(common.Difference(tf, sf)) else: - # cust_diff = FileDifference("cust", source_zip, target_zip, output_zip) - # script.Mount("/cust", recovery_mount_options) - cust_items = ItemSet("cust", "META/cust_filesystem_config.txt") - - script.Mount("/cust", recovery_mount_options) - script.UnpackPackageDir("cust", "/cust") - - symlinks = CopyPartitionFiles(cust_items, target_zip, output_zip) - script.MakeSymlinks(symlinks) - - cust_items.GetMetadata(target_zip) - cust_items.Get("cust").SetPermissions(script) - - # Two-step incremental package strategy (in chronological order, - # which is *not* the order in which the generated script has - # things): - # - # if stage is not "2/3" or "3/3": - # do verification on current system - # write recovery image to boot partition - # set stage to "2/3" - # reboot to boot partition and restart recovery - # else if stage is "2/3": - # write recovery image to recovery partition - # set stage to "3/3" - # reboot to recovery partition and restart recovery - # else: - # (stage must be "3/3") - # perform update: - # patch system files, etc. - # force full install of new boot image - # set up system to update recovery partition on first boot - # complete script normally - # (allow recovery to mark itself finished and reboot) - - if OPTIONS.two_step: - if not OPTIONS.source_info_dict.get("multistage_support", None): - assert False, "two-step packages not supported by this build" - fs = OPTIONS.source_info_dict["fstab"]["/misc"] - assert fs.fs_type.upper() == "EMMC", \ - "two-step packages only supported on devices with EMMC /misc partitions" - bcb_dev = {"bcb_dev": fs.device} - common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data) - script.AppendExtra(""" -if get_stage("%(bcb_dev)s") == "2/3" then -""" % bcb_dev) - script.AppendExtra("sleep(20);\n") - script.WriteRawImage("/recovery", "recovery.img") - script.AppendExtra(""" -set_stage("%(bcb_dev)s", "3/3"); -reboot_now("%(bcb_dev)s", "recovery"); -else if get_stage("%(bcb_dev)s") != "3/3" then -""" % bcb_dev) - - # Dump fingerprints - script.Print("Source: %s" % CalculateFingerprint( - oem_props, oem_dict, OPTIONS.source_info_dict)) - script.Print("Target: %s" % CalculateFingerprint( - oem_props, oem_dict, OPTIONS.target_info_dict)) - - script.Print("Verifying current system...") + # Target file identical to source. + pass - device_specific.IncrementalOTA_VerifyBegin() - - if oem_props is None: - # When blockimgdiff version is less than 3 (non-resumable block-based OTA), - # patching on a device that's already on the target build will damage the - # system. Because operations like move don't check the block state, they - # always apply the changes unconditionally. - if blockimgdiff_version <= 2: - script.AssertSomeFingerprint(source_fp) - else: - script.AssertSomeFingerprint(source_fp, target_fp) - else: - if blockimgdiff_version <= 2: - script.AssertSomeThumbprint( - GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict)) - else: - script.AssertSomeThumbprint( - GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict), - GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict)) + common.ComputeDifferences(diffs) - if updating_boot: - boot_type, boot_device = common.GetTypeAndDevice( - "/boot", OPTIONS.source_info_dict) - d = common.Difference(target_boot, source_boot) - _, _, d = d.ComputePatch() - if d is None: - include_full_boot = True - common.ZipWriteStr(output_zip, "boot.img", target_boot.data) + for diff in diffs: + tf, sf, d = diff.GetPatch() + if d is None or len(d) > tf.size * OPTIONS.patch_threshold: + # patch is almost as big as the file; don't bother patching + tf.AddToZip(output_zip) + verbatim_targets.append((tf.name, tf.size)) else: - include_full_boot = False - - print "boot target: %d source: %d diff: %d" % ( - target_boot.size, source_boot.size, len(d)) - - common.ZipWriteStr(output_zip, "patch/boot.img.p", d) - - script.PatchCheck("%s:%s:%d:%s:%d:%s" % - (boot_type, boot_device, - source_boot.size, source_boot.sha1, - target_boot.size, target_boot.sha1)) - - device_specific.IncrementalOTA_VerifyEnd() - - if OPTIONS.two_step: - script.WriteRawImage("/boot", "recovery.img") - script.AppendExtra(""" -set_stage("%(bcb_dev)s", "2/3"); -reboot_now("%(bcb_dev)s", ""); -else -""" % bcb_dev) - - # Verify the existing partitions. - system_diff.WriteVerifyScript(script) - if vendor_diff: - vendor_diff.WriteVerifyScript(script) - - script.Comment("---- start making changes here ----") - - device_specific.IncrementalOTA_InstallBegin() - - system_diff.WriteScript(script, output_zip, - progress=0.8 if vendor_diff else 0.9) - if vendor_diff: - vendor_diff.WriteScript(script, output_zip, progress=0.1) - - if OPTIONS.two_step: - common.ZipWriteStr(output_zip, "boot.img", target_boot.data) - script.WriteRawImage("/boot", "boot.img") - print "writing full boot image (forced by two-step mode)" - - if not OPTIONS.two_step: - if updating_boot: - if include_full_boot: - print "boot image changed; including full." - script.Print("Installing boot image...") - script.WriteRawImage("/boot", "boot.img") - else: - # Produce the boot image by applying a patch to the current - # contents of the boot partition, and write it back to the - # partition. - print "boot image changed; including patch." - script.Print("Patching boot image...") - script.ShowProgress(0.1, 10) - script.ApplyPatch("%s:%s:%d:%s:%d:%s" - % (boot_type, boot_device, - source_boot.size, source_boot.sha1, - target_boot.size, target_boot.sha1), - "-", - target_boot.size, target_boot.sha1, - source_boot.sha1, "patch/boot.img.p") - else: - print "boot image unchanged; skipping." - - # Do device-specific installation (eg, write radio image). - device_specific.IncrementalOTA_InstallEnd() - - if OPTIONS.extra_script is not None: - script.AppendExtra(OPTIONS.extra_script) - - if OPTIONS.wipe_user_data: - script.Print("Erasing user data...") - script.FormatPartition("/data") - - if OPTIONS.two_step: - script.AppendExtra(""" -set_stage("%(bcb_dev)s", ""); -endif; -endif; -""" % bcb_dev) - - script.SetProgress(1) - script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary) - WriteMetadata(metadata, output_zip) - - -class FileDifference(object): - def __init__(self, partition, source_zip, target_zip, output_zip): - self.deferred_patch_list = None - print "Loading target..." - self.target_data = target_data = LoadPartitionFiles(target_zip, partition) - print "Loading source..." - self.source_data = source_data = LoadPartitionFiles(source_zip, partition) - - self.verbatim_targets = verbatim_targets = [] - self.patch_list = patch_list = [] - diffs = [] - self.renames = renames = {} - known_paths = set() - largest_source_size = 0 - - matching_file_cache = {} - for fn, sf in source_data.items(): - assert fn == sf.name - matching_file_cache["path:" + fn] = sf - if fn in target_data.keys(): - AddToKnownPaths(fn, known_paths) - # Only allow eligibility for filename/sha matching - # if there isn't a perfect path match. - if target_data.get(sf.name) is None: - matching_file_cache["file:" + fn.split("/")[-1]] = sf - matching_file_cache["sha:" + sf.sha1] = sf - - for fn in sorted(target_data.keys()): - tf = target_data[fn] - assert fn == tf.name - # MIUI ADD: START - if fn.startswith("data/") and not fn.startswith("data/miui/"): - continue - # END - sf = ClosestFileMatch(tf, matching_file_cache, renames) - if sf is not None and sf.name != tf.name: - print "File has moved from " + sf.name + " to " + tf.name - renames[sf.name] = tf - - if sf is None or fn in OPTIONS.require_verbatim: - # This file should be included verbatim - if fn in OPTIONS.prohibit_verbatim: - raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,)) - print "send", fn, "verbatim" - tf.AddToZip(output_zip) - verbatim_targets.append((fn, tf.size, tf.sha1)) - if fn in target_data.keys(): - AddToKnownPaths(fn, known_paths) - elif tf.sha1 != sf.sha1: - # File is different; consider sending as a patch - diffs.append(common.Difference(tf, sf)) - else: - # Target file data identical to source (may still be renamed) - pass - - common.ComputeDifferences(diffs) - - for diff in diffs: - tf, sf, d = diff.GetPatch() - path = "/".join(tf.name.split("/")[:-1]) - if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \ - path not in known_paths: - # patch is almost as big as the file; don't bother patching - # or a patch + rename cannot take place due to the target - # directory not existing - tf.AddToZip(output_zip) - verbatim_targets.append((tf.name, tf.size, tf.sha1)) - if sf.name in renames: - del renames[sf.name] - AddToKnownPaths(tf.name, known_paths) - else: - common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d) - patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest())) - largest_source_size = max(largest_source_size, sf.size) - - self.largest_source_size = largest_source_size - - def EmitVerification(self, script): - so_far = 0 - for tf, sf, _, _ in self.patch_list: - if tf.name != sf.name: - script.SkipNextActionIfTargetExists(tf.name, tf.sha1) - script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1) - so_far += sf.size - return so_far - - def EmitExplicitTargetVerification(self, script): - for fn, _, sha1 in self.verbatim_targets: - if fn[-1] != "/": - script.FileCheck("/"+fn, sha1) - for tf, _, _, _ in self.patch_list: - script.FileCheck(tf.name, tf.sha1) - - def RemoveUnneededFiles(self, script, extras=()): - script.DeleteFiles( - ["/" + i[0] for i in self.verbatim_targets] + - ["/" + i for i in sorted(self.source_data) - if i not in self.target_data and i not in self.renames] + - list(extras)) - - def TotalPatchSize(self): - return sum(i[1].size for i in self.patch_list) - - def EmitPatches(self, script, total_patch_size, so_far): - self.deferred_patch_list = deferred_patch_list = [] - for item in self.patch_list: - tf, sf, _, _ = item - if tf.name == "system/build.prop": - deferred_patch_list.append(item) - continue - if sf.name != tf.name: - script.SkipNextActionIfTargetExists(tf.name, tf.sha1) - script.ApplyPatch("/" + sf.name, "-", tf.size, tf.sha1, sf.sha1, - "patch/" + sf.name + ".p") - so_far += tf.size - script.SetProgress(so_far / total_patch_size) - return so_far - - def EmitDeferredPatches(self, script): - for item in self.deferred_patch_list: - tf, sf, _, _ = item - script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, - "patch/" + sf.name + ".p") - script.SetPermissions("/system/build.prop", 0, 0, 0o644, None, None) - - def EmitRenames(self, script): - if len(self.renames) > 0: - script.Print("Renaming files...") - for src, tgt in self.renames.iteritems(): - print "Renaming " + src + " to " + tgt.name - script.RenameFile(src, tgt.name) - - -def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip): - target_has_recovery_patch = HasRecoveryPatch(target_zip) - source_has_recovery_patch = HasRecoveryPatch(source_zip) - - if (OPTIONS.block_based and - target_has_recovery_patch and - source_has_recovery_patch): - return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip) - - source_version = OPTIONS.source_info_dict["recovery_api_version"] - target_version = OPTIONS.target_info_dict["recovery_api_version"] - - if source_version == 0: - print ("WARNING: generating edify script for a source that " - "can't install it.") - script = edify_generator.EdifyGenerator( - source_version, OPTIONS.target_info_dict, - fstab=OPTIONS.source_info_dict["fstab"]) - - oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties") - recovery_mount_options = OPTIONS.source_info_dict.get( - "recovery_mount_options") - oem_dict = None - if oem_props is not None and len(oem_props) > 0: - if OPTIONS.oem_source is None: - raise common.ExternalError("OEM source required for this build") - script.Mount("/oem", recovery_mount_options) - oem_dict = common.LoadDictionaryFromLines( - open(OPTIONS.oem_source).readlines()) - - metadata = { - "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict, - OPTIONS.source_info_dict), - "post-timestamp": GetBuildProp("ro.build.date.utc", - OPTIONS.target_info_dict), - } - - device_specific = common.DeviceSpecificParams( - source_zip=source_zip, - source_version=source_version, - target_zip=target_zip, - target_version=target_version, - output_zip=output_zip, - script=script, - metadata=metadata, - info_dict=OPTIONS.info_dict) - - # MIUI ADD: - data_diff = FileDifference("data", source_zip, target_zip, output_zip) - - # MIUI ADD: START - if "selinux_fc" in OPTIONS.info_dict: - WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip) - # END - - system_diff = FileDifference("system", source_zip, target_zip, output_zip) - script.Mount("/system", recovery_mount_options) - if HasVendorPartition(target_zip): - vendor_diff = FileDifference("vendor", source_zip, target_zip, output_zip) - script.Mount("/vendor", recovery_mount_options) - else: - vendor_diff = None - - target_fp = CalculateFingerprint(oem_props, oem_dict, - OPTIONS.target_info_dict) - source_fp = CalculateFingerprint(oem_props, oem_dict, - OPTIONS.source_info_dict) - - if oem_props is None: - script.AssertSomeFingerprint(source_fp, target_fp) - else: - script.AssertSomeThumbprint( - GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict), - GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict)) + common.ZipWriteStr(output_zip, "patch/" + tf.name + ".p", d) + patch_list.append((tf.name, tf, sf, tf.size, common.sha1(d).hexdigest())) + largest_source_size = max(largest_source_size, sf.size) + source_fp = GetBuildProp("ro.build.fingerprint", source_zip) + target_fp = GetBuildProp("ro.build.fingerprint", target_zip) metadata["pre-build"] = source_fp metadata["post-build"] = target_fp + script.Mount("/system") + script.AssertSomeFingerprint(source_fp, target_fp) + source_boot = common.GetBootableImage( - "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT", - OPTIONS.source_info_dict) + "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT") target_boot = common.GetBootableImage( "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT") - updating_boot = (not OPTIONS.two_step and - (source_boot.data != target_boot.data)) + # updating_boot = (source_boot != None and target_boot != None and source_boot.data != target_boot.data) + updating_boot = False + need_install_boot = (source_boot != None and target_boot != None and source_boot.data != target_boot.data) source_recovery = common.GetBootableImage( - "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY", - OPTIONS.source_info_dict) + "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY") target_recovery = common.GetBootableImage( "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY") - updating_recovery = (source_recovery.data != target_recovery.data) - + #updating_recovery = (source_recovery.data != target_recovery.data) + updating_recovery = False # Here's how we divide up the progress bar: # 0.1 for verifying the start state (PatchCheck calls) # 0.8 for applying patches (ApplyPatch calls) # 0.1 for unpacking verbatim files, symlinking, and doing the # device-specific commands. - AppendAssertions(script, OPTIONS.target_info_dict, oem_dict) + AppendAssertions(script, target_zip) device_specific.IncrementalOTA_Assertions() - # MIUI ADD - cust_diff = None - if HasCustPartition(target_zip): - if not HasCustPartition(source_zip): - cust_items = ItemSet("cust", "META/cust_filesystem_config.txt") - - script.FormatPartition("/cust") - script.Mount("/cust", recovery_mount_options) - script.UnpackPackageDir("cust", "/cust") - - symlinks = CopyPartitionFiles(cust_items, target_zip, output_zip) - script.MakeSymlinks(symlinks) - - cust_items.GetMetadata(target_zip) - cust_items.Get("cust").SetPermissions(script) - else: - cust_diff = FileDifference("cust", source_zip, target_zip, output_zip) - script.Mount("/cust", recovery_mount_options) - - # Two-step incremental package strategy (in chronological order, - # which is *not* the order in which the generated script has - # things): - # - # if stage is not "2/3" or "3/3": - # do verification on current system - # write recovery image to boot partition - # set stage to "2/3" - # reboot to boot partition and restart recovery - # else if stage is "2/3": - # write recovery image to recovery partition - # set stage to "3/3" - # reboot to recovery partition and restart recovery - # else: - # (stage must be "3/3") - # perform update: - # patch system files, etc. - # force full install of new boot image - # set up system to update recovery partition on first boot - # complete script normally - # (allow recovery to mark itself finished and reboot) - - if OPTIONS.two_step: - if not OPTIONS.source_info_dict.get("multistage_support", None): - assert False, "two-step packages not supported by this build" - fs = OPTIONS.source_info_dict["fstab"]["/misc"] - assert fs.fs_type.upper() == "EMMC", \ - "two-step packages only supported on devices with EMMC /misc partitions" - bcb_dev = {"bcb_dev": fs.device} - common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data) - script.AppendExtra(""" -if get_stage("%(bcb_dev)s") == "2/3" then -""" % bcb_dev) - script.AppendExtra("sleep(20);\n") - script.WriteRawImage("/recovery", "recovery.img") - script.AppendExtra(""" -set_stage("%(bcb_dev)s", "3/3"); -reboot_now("%(bcb_dev)s", "recovery"); -else if get_stage("%(bcb_dev)s") != "3/3" then -""" % bcb_dev) - - # Dump fingerprints - script.Print("Source: %s" % (source_fp,)) - script.Print("Target: %s" % (target_fp,)) - script.Print("Verifying current system...") - device_specific.IncrementalOTA_VerifyBegin() - script.ShowProgress(0.1, 0) - so_far = system_diff.EmitVerification(script) - if vendor_diff: - so_far += vendor_diff.EmitVerification(script) - - # MIUI ADD - if cust_diff: - so_far += cust_diff.EmitVerification(script) + total_verify_size = float(sum([i[2].size for i in patch_list]) + 1) + if updating_boot: + total_verify_size += source_boot.size + so_far = 0 + + for fn, tf, sf, size, patch_sha in patch_list: + # MIUI ADD: + # skip to check /data patch + if fn.startswith("data/"): + continue + script.PatchCheck("/"+fn, tf.sha1, sf.sha1) + so_far += sf.size + script.SetProgress(so_far / total_verify_size) if updating_boot: d = common.Difference(target_boot, source_boot) @@ -1354,215 +618,127 @@ else if get_stage("%(bcb_dev)s") != "3/3" then common.ZipWriteStr(output_zip, "patch/boot.img.p", d) - boot_type, boot_device = common.GetTypeAndDevice( - "/boot", OPTIONS.source_info_dict) + boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict) script.PatchCheck("%s:%s:%d:%s:%d:%s" % (boot_type, boot_device, source_boot.size, source_boot.sha1, target_boot.size, target_boot.sha1)) so_far += source_boot.size + script.SetProgress(so_far / total_verify_size) - size = [] - if system_diff.patch_list: - size.append(system_diff.largest_source_size) - if vendor_diff: - if vendor_diff.patch_list: - size.append(vendor_diff.largest_source_size) - # MIUI ADD - if cust_diff: - if cust_diff.patch_list: - size.append(cust_diff.largest_source_size) - - if size or updating_recovery or updating_boot: - script.CacheFreeSpaceCheck(max(size)) + if patch_list or updating_recovery or updating_boot: + script.CacheFreeSpaceCheck(largest_source_size) device_specific.IncrementalOTA_VerifyEnd() - if OPTIONS.two_step: - script.WriteRawImage("/boot", "recovery.img") - script.AppendExtra(""" -set_stage("%(bcb_dev)s", "2/3"); -reboot_now("%(bcb_dev)s", ""); -else -""" % bcb_dev) - script.Comment("---- start making changes here ----") - device_specific.IncrementalOTA_InstallBegin() - - if OPTIONS.two_step: - common.ZipWriteStr(output_zip, "boot.img", target_boot.data) - script.WriteRawImage("/boot", "boot.img") - print "writing full boot image (forced by two-step mode)" + if OPTIONS.wipe_user_data: + script.Print("Erasing user data...") + script.FormatPartition("/data") script.Print("Removing unneeded files...") - system_diff.RemoveUnneededFiles(script, ("/system/recovery.img",)) - if vendor_diff: - vendor_diff.RemoveUnneededFiles(script) - # MIUI ADD - if cust_diff: - cust_diff.RemoveUnneededFiles(script) + script.DeleteFiles(["/"+i[0] for i in verbatim_targets] + + ["/"+i for i in sorted(source_data) + if i not in target_data] + + ["/system/recovery.img"]) script.ShowProgress(0.8, 0) - total_patch_size = 1.0 + system_diff.TotalPatchSize() - if vendor_diff: - total_patch_size += vendor_diff.TotalPatchSize() - # MIUI ADD - if cust_diff: - total_patch_size += cust_diff.TotalPatchSize() - + total_patch_size = float(sum([i[1].size for i in patch_list]) + 1) if updating_boot: total_patch_size += target_boot.size + so_far = 0 script.Print("Patching system files...") - so_far = system_diff.EmitPatches(script, total_patch_size, 0) - if vendor_diff: - script.Print("Patching vendor files...") - so_far = vendor_diff.EmitPatches(script, total_patch_size, so_far) - # MIUI ADD - if cust_diff: - script.Print("Patching cust files...") - so_far = cust_diff.EmitPatches(script, total_patch_size, so_far) - - - if not OPTIONS.two_step: - if updating_boot: - # Produce the boot image by applying a patch to the current - # contents of the boot partition, and write it back to the - # partition. - script.Print("Patching boot image...") - script.ApplyPatch("%s:%s:%d:%s:%d:%s" - % (boot_type, boot_device, - source_boot.size, source_boot.sha1, - target_boot.size, target_boot.sha1), - "-", - target_boot.size, target_boot.sha1, - source_boot.sha1, "patch/boot.img.p") - so_far += target_boot.size - script.SetProgress(so_far / total_patch_size) - print "boot image changed; including." - else: - print "boot image unchanged; skipping." + deferred_patch_list = [] + for item in patch_list: + fn, tf, sf, size, _ = item + if tf.name == "system/build.prop": + deferred_patch_list.append(item) + continue + script.ApplyPatch("/"+fn, "-", tf.size, tf.sha1, sf.sha1, "patch/"+fn+".p") + so_far += tf.size + script.SetProgress(so_far / total_patch_size) - system_items = ItemSet("system", "META/filesystem_config.txt") - if vendor_diff: - vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt") - # MIUI ADD - if cust_diff: - cust_items = ItemSet("cust", "META/cust_filesystem_config.txt") + if updating_boot: + # Produce the boot image by applying a patch to the current + # contents of the boot partition, and write it back to the + # partition. + script.Print("Patching boot image...") + script.ApplyPatch("%s:%s:%d:%s:%d:%s" + % (boot_type, boot_device, + source_boot.size, source_boot.sha1, + target_boot.size, target_boot.sha1), + "-", + target_boot.size, target_boot.sha1, + source_boot.sha1, "patch/boot.img.p") + so_far += target_boot.size + script.SetProgress(so_far / total_patch_size) + print "boot image changed; including." + else: + print "boot image unchanged; skipping." + + if need_install_boot: + boot_img = common.GetBootableImage("boot.img", "boot.img", + OPTIONS.input_tmp, "BOOT") + script.Print("Update Boot image...") + if boot_img: + common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict) + common.ZipWriteStr(output_zip, "boot.img", boot_img.data) + if boot_img and not device_specific.WriteRawImage("/boot", "boot.img"): + script.WriteRawImage("/boot", "boot.img") if updating_recovery: - # Recovery is generated as a patch using both the boot image - # (which contains the same linux kernel as recovery) and the file - # /system/etc/recovery-resource.dat (which contains all the images - # used in the recovery UI) as sources. This lets us minimize the - # size of the patch, which must be included in every OTA package. + # Is it better to generate recovery as a patch from the current + # boot image, or from the previous recovery image? For large + # updates with significant kernel changes, probably the former. + # For small updates where the kernel hasn't changed, almost + # certainly the latter. We pick the first option. Future + # complicated schemes may let us effectively use both. # - # For older builds where recovery-resource.dat is not present, we - # use only the boot image as the source. - - if not target_has_recovery_patch: - def output_sink(fn, data): - common.ZipWriteStr(output_zip, "recovery/" + fn, data) - system_items.Get("system/" + fn) - - common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink, - target_recovery, target_boot) - script.DeleteFiles(["/system/recovery-from-boot.p", - "/system/etc/install-recovery.sh"]) + # A wacky possibility: as long as there is room in the boot + # partition, include the binaries and image files from recovery in + # the boot image (though not in the ramdisk) so they can be used + # as fodder for constructing the recovery image. + MakeRecoveryPatch(output_zip, target_recovery, target_boot) + script.DeleteFiles(["/system/recovery-from-boot.p", + "/system/etc/install-recovery.sh"]) print "recovery image changed; including as patch from boot." else: print "recovery image unchanged; skipping." script.ShowProgress(0.1, 10) - target_symlinks = CopyPartitionFiles(system_items, target_zip, None) - if vendor_diff: - target_symlinks.extend(CopyPartitionFiles(vendor_items, target_zip, None)) - # MIUI ADD - if cust_diff: - target_symlinks.extend(CopyPartitionFiles(cust_items, target_zip, None)) + (target_symlinks, target_retouch_dummies) = CopySystemFiles(target_zip, None) + target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks]) temp_script = script.MakeTemporary() - system_items.GetMetadata(target_zip) - system_items.Get("system").SetPermissions(temp_script) - if vendor_diff: - vendor_items.GetMetadata(target_zip) - vendor_items.Get("vendor").SetPermissions(temp_script) - # MIUI ADD - if cust_diff: - cust_items.GetMetadata(target_zip) - cust_items.Get("cust").SetPermissions(temp_script) - - # Note that this call will mess up the trees of Items, so make sure - # we're done with them. - source_symlinks = CopyPartitionFiles(system_items, source_zip, None) - if vendor_diff: - source_symlinks.extend(CopyPartitionFiles(vendor_items, source_zip, None)) - # MIUI ADD - if cust_diff: - source_symlinks.extend(CopyPartitionFiles(cust_items, source_zip, None)) + Item.GetMetadata(target_zip) + Item.Get("system").SetPermissions(temp_script) - target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks]) + # Note that this call will mess up the tree of Items, so make sure + # we're done with it. + (source_symlinks, source_retouch_dummies) = CopySystemFiles(source_zip, None) source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks]) # Delete all the symlinks in source that aren't in target. This # needs to happen before verbatim files are unpacked, in case a # symlink in the source is replaced by a real file in the target. - - # If a symlink in the source will be replaced by a regular file, we cannot - # delete the symlink/file in case the package gets applied again. For such - # a symlink, we prepend a sha1_check() to detect if it has been updated. - # (Bug: 23646151) - replaced_symlinks = dict() - if system_diff: - for i in system_diff.verbatim_targets: - replaced_symlinks["/%s" % (i[0],)] = i[2] - if vendor_diff: - for i in vendor_diff.verbatim_targets: - replaced_symlinks["/%s" % (i[0],)] = i[2] - - if system_diff: - for tf in system_diff.renames.values(): - replaced_symlinks["/%s" % (tf.name,)] = tf.sha1 - if vendor_diff: - for tf in vendor_diff.renames.values(): - replaced_symlinks["/%s" % (tf.name,)] = tf.sha1 - - always_delete = [] - may_delete = [] + to_delete = [] for dest, link in source_symlinks: if link not in target_symlinks_d: - if link in replaced_symlinks: - may_delete.append((link, replaced_symlinks[link])) - else: - always_delete.append(link) - script.DeleteFiles(always_delete) - script.DeleteFilesIfNotMatching(may_delete) + to_delete.append(link) + script.DeleteFiles(to_delete) - if system_diff.verbatim_targets: - script.Print("Unpacking new system files...") + if verbatim_targets: + script.Print("Unpacking new files...") script.UnpackPackageDir("system", "/system") - if vendor_diff and vendor_diff.verbatim_targets: - script.Print("Unpacking new vendor files...") - script.UnpackPackageDir("vendor", "/vendor") - # MIUI ADD - if cust_diff and cust_diff.verbatim_targets: - script.Print("Unpacking new cust files...") - script.UnpackPackageDir("cust", "/cust") - - if updating_recovery and not target_has_recovery_patch: + + if updating_recovery: script.Print("Unpacking new recovery...") script.UnpackPackageDir("recovery", "/system") - system_diff.EmitRenames(script) - if vendor_diff: - vendor_diff.EmitRenames(script) - # MIUI ADD - if cust_diff: - cust_diff.EmitRenames(script) - script.Print("Symlinks and permissions...") # Create all the symlinks that don't already exist, or point to @@ -1577,13 +753,16 @@ else to_create.append((dest, link)) script.DeleteFiles([i[1] for i in to_create]) script.MakeSymlinks(to_create) + # if OPTIONS.aslr_mode: + # script.RetouchBinaries(target_retouch_files) + # else: + # script.UndoRetouchBinaries(target_retouch_files) # Now that the symlinks are created, we can set all the # permissions. script.AppendScript(temp_script) # Do device-specific installation (eg, write radio image). - device_specific.IncrementalOTA_InstallEnd() if OPTIONS.extra_script is not None: script.AppendExtra(OPTIONS.extra_script) @@ -1592,52 +771,31 @@ else # device can still come up, it appears to be the old build and will # get set the OTA package again to retry. script.Print("Patching remaining system files...") - system_diff.EmitDeferredPatches(script) - - if OPTIONS.wipe_user_data: - script.Print("Erasing user data...") - script.FormatPartition("/data") + for item in deferred_patch_list: + fn, tf, sf, size, _ = item + script.ApplyPatch("/"+fn, "-", tf.size, tf.sha1, sf.sha1, "patch/"+fn+".p") + + device_specific.IncrementalOTA_InstallEnd() - if OPTIONS.two_step: - script.AppendExtra(""" -set_stage("%(bcb_dev)s", ""); -endif; -endif; -""" % bcb_dev) - - if OPTIONS.verify and system_diff: - script.Print("Remounting and verifying system partition files...") - script.Unmount("/system") - script.Mount("/system") - system_diff.EmitExplicitTargetVerification(script) - - if OPTIONS.verify and vendor_diff: - script.Print("Remounting and verifying vendor partition files...") - script.Unmount("/vendor") - script.Mount("/vendor") - vendor_diff.EmitExplicitTargetVerification(script) - script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary) + script.SetPermissions("/system/build.prop", 0, 0, 0644) + script.AddToZip(target_zip, output_zip) WriteMetadata(metadata, output_zip) def main(argv): def option_handler(o, a): - if o == "--board_config": + if o in ("-b", "--board_config"): pass # deprecated elif o in ("-k", "--package_key"): OPTIONS.package_key = a elif o in ("-i", "--incremental_from"): OPTIONS.incremental_source = a - elif o == "--full_radio": - OPTIONS.full_radio = True elif o in ("-w", "--wipe_user_data"): OPTIONS.wipe_user_data = True elif o in ("-n", "--no_prereq"): OPTIONS.omit_prereq = True - elif o in ("-o", "--oem_settings"): - OPTIONS.oem_source = a elif o in ("-e", "--extra_script"): OPTIONS.extra_script = a elif o in ("-a", "--aslr_mode"): @@ -1645,48 +803,24 @@ def main(argv): OPTIONS.aslr_mode = True else: OPTIONS.aslr_mode = False - elif o in ("-t", "--worker_threads"): - if a.isdigit(): - OPTIONS.worker_threads = int(a) - else: - raise ValueError("Cannot parse value %r for option %r - only " - "integers are allowed." % (a, o)) - elif o in ("-2", "--two_step"): - OPTIONS.two_step = True - elif o == "--no_signing": - OPTIONS.no_signing = True - elif o == "--verify": - OPTIONS.verify = True - elif o == "--block": - OPTIONS.block_based = True - elif o in ("-b", "--binary"): - OPTIONS.updater_binary = a - elif o in ("--no_fallback_to_full",): - OPTIONS.fallback_to_full = False + elif o in ("--worker_threads"): + OPTIONS.worker_threads = int(a) else: return False return True args = common.ParseOptions(argv, __doc__, - extra_opts="b:k:i:d:wne:t:a:2o:", - extra_long_opts=[ - "board_config=", - "package_key=", - "incremental_from=", - "full_radio", - "wipe_user_data", - "no_prereq", - "extra_script=", - "worker_threads=", - "aslr_mode=", - "two_step", - "no_signing", - "block", - "binary=", - "oem_settings=", - "verify", - "no_fallback_to_full", - ], extra_option_handler=option_handler) + extra_opts="b:k:i:d:wne:a:", + extra_long_opts=["board_config=", + "package_key=", + "incremental_from=", + "wipe_user_data", + "no_prereq", + "extra_script=", + "worker_threads=", + "aslr_mode=", + ], + extra_option_handler=option_handler) if len(args) != 2: common.Usage(__doc__) @@ -1700,88 +834,46 @@ def main(argv): OPTIONS.target_tmp = OPTIONS.input_tmp OPTIONS.info_dict = common.LoadInfoDict(input_zip) - - # If this image was originally labelled with SELinux contexts, make sure we - # also apply the labels in our new image. During building, the "file_contexts" - # is in the out/ directory tree, but for repacking from target-files.zip it's - # in the root directory of the ramdisk. - if "selinux_fc" in OPTIONS.info_dict: - OPTIONS.info_dict["selinux_fc"] = os.path.join( - OPTIONS.input_tmp, "BOOT", "RAMDISK", "file_contexts") - if OPTIONS.verbose: print "--- target info ---" common.DumpInfoDict(OPTIONS.info_dict) - # If the caller explicitly specified the device-specific extensions - # path via -s/--device_specific, use that. Otherwise, use - # META/releasetools.py if it is present in the target target_files. - # Otherwise, take the path of the file from 'tool_extensions' in the - # info dict and look for that in the local filesystem, relative to - # the current directory. - if OPTIONS.device_specific is None: - from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py") - if os.path.exists(from_input): - print "(using device-specific extensions from target_files)" - OPTIONS.device_specific = from_input - else: - OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None) - + OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None) if OPTIONS.device_specific is not None: - OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific) - - while True: - - if OPTIONS.no_signing: - if os.path.exists(args[1]): - os.unlink(args[1]) - output_zip = zipfile.ZipFile(args[1], "w", - compression=zipfile.ZIP_DEFLATED) - else: - temp_zip_file = tempfile.NamedTemporaryFile() - output_zip = zipfile.ZipFile(temp_zip_file, "w", - compression=zipfile.ZIP_DEFLATED) - - if OPTIONS.incremental_source is None: - WriteFullOTAPackage(input_zip, output_zip) - if OPTIONS.package_key is None: - OPTIONS.package_key = OPTIONS.info_dict.get( - "default_system_dev_certificate", - "build/target/product/security/testkey") - common.ZipClose(output_zip) - break - - else: - print "unzipping source target-files..." - OPTIONS.source_tmp, source_zip = common.UnzipTemp( - OPTIONS.incremental_source) - OPTIONS.target_info_dict = OPTIONS.info_dict - OPTIONS.source_info_dict = common.LoadInfoDict(source_zip) - if "selinux_fc" in OPTIONS.source_info_dict: - OPTIONS.source_info_dict["selinux_fc"] = os.path.join( - OPTIONS.source_tmp, "BOOT", "RAMDISK", "file_contexts") - if OPTIONS.package_key is None: - OPTIONS.package_key = OPTIONS.source_info_dict.get( - "default_system_dev_certificate", - "build/target/product/security/testkey") - if OPTIONS.verbose: - print "--- source info ---" - common.DumpInfoDict(OPTIONS.source_info_dict) - try: - WriteIncrementalOTAPackage(input_zip, source_zip, output_zip) - common.ZipClose(output_zip) - break - except ValueError: - if not OPTIONS.fallback_to_full: - raise - print "--- failed to build incremental; falling back to full ---" - OPTIONS.incremental_source = None - common.ZipClose(output_zip) - - if not OPTIONS.no_signing: - SignOutput(temp_zip_file.name, args[1]) - temp_zip_file.close() + OPTIONS.device_specific = os.path.normpath(OPTIONS.device_specific) + print "using device-specific extensions in", OPTIONS.device_specific + + temp_zip_file = tempfile.NamedTemporaryFile() + output_zip = zipfile.ZipFile(temp_zip_file, "w", + compression=zipfile.ZIP_DEFLATED) + + if OPTIONS.incremental_source is None: + WriteFullOTAPackage(input_zip, output_zip) + if OPTIONS.package_key is None: + OPTIONS.package_key = OPTIONS.info_dict.get( + "default_system_dev_certificate", + "build/target/product/security/testkey") + else: + print "unzipping source target-files..." + OPTIONS.source_tmp, source_zip = common.UnzipTemp(OPTIONS.incremental_source) + OPTIONS.target_info_dict = OPTIONS.info_dict + OPTIONS.source_info_dict = common.LoadInfoDict(source_zip) + if OPTIONS.package_key is None: + OPTIONS.package_key = OPTIONS.source_info_dict.get( + "default_system_dev_certificate", + "build/target/product/security/testkey") + if OPTIONS.verbose: + print "--- source info ---" + common.DumpInfoDict(OPTIONS.source_info_dict) + WriteIncrementalOTAPackage(input_zip, source_zip, output_zip) + + output_zip.close() + + SignOutput(temp_zip_file.name, args[1]) + temp_zip_file.close() + + common.Cleanup() print "done." @@ -1790,10 +882,8 @@ if __name__ == '__main__': try: common.CloseInheritedPipes() main(sys.argv[1:]) - except common.ExternalError as e: + except common.ExternalError, e: print print " ERROR: %s" % (e,) print sys.exit(1) - finally: - common.Cleanup() diff --git a/releasetools/ota_target_from_phone b/releasetools/ota_target_from_phone index 218d02d..677b5d7 100755 --- a/releasetools/ota_target_from_phone +++ b/releasetools/ota_target_from_phone @@ -170,46 +170,28 @@ function build_apkcerts { # build filesystem_config.txt from device function build_filesystem_config { echo "Run getfilesysteminfo to build filesystem_config.txt" - if [ $ANDROID_PLATFORM -gt 19 ];then - adb push $TOOL_DIR/target_files_template/OTA/bin/busybox /data/local/tmp/ - adb shell chmod 755 /data/local/tmp/busybox - bash $TOOL_DIR/get_filesystem_config --info /data/local/tmp/busybox | tee $META_DIR/filesystem_config.txt - if [ $? -ne 0 ];then - echo "Get file info failed" - exit 1 - fi - else - adb push $TOOL_DIR/releasetools/getfilesysteminfo /system/xbin - adb shell chmod 0777 /system/xbin/getfilesysteminfo - adb shell /system/xbin/getfilesysteminfo --info /system >> $META_DIR/filesystem_config.txt - fs_config=`cat $META_DIR/filesystem_config.txt | col -b | sed -e '/getfilesysteminfo/d'` - OLD_IFS=$IFS - IFS=$'\n' - for line in $fs_config - do - echo $line | grep -q -e "\" && continue - echo $line | grep -q -e "\" && continue - echo $line >> $META_DIR/tmp.txt - done - IFS=$OLD_IFS - cat $META_DIR/tmp.txt | sort > $META_DIR/filesystem_config.txt - rm $META_DIR/tmp.txt - fi + + adb push $TOOL_DIR/releasetools/getfilesysteminfo /system/xbin + adb shell chmod 0777 /system/xbin/getfilesysteminfo + adb shell /system/xbin/getfilesysteminfo --info /system >> $META_DIR/filesystem_config.txt + fs_config=`cat $META_DIR/filesystem_config.txt | col -b | sed -e '/getfilesysteminfo/d'` + OLD_IFS=$IFS + IFS=$'\n' + for line in $fs_config + do + echo $line | grep -q -e "\" && continue + echo $line | grep -q -e "\" && continue + echo $line >> $META_DIR/tmp.txt + done + IFS=$OLD_IFS + cat $META_DIR/tmp.txt | sort > $META_DIR/filesystem_config.txt + rm $META_DIR/tmp.txt } # recover the device files' symlink information function recover_symlink { echo "Run getfilesysteminfo and recoverylink.py to recover symlink" - if [ $ANDROID_PLATFORM -gt 19 ];then - bash $TOOL_DIR/get_filesystem_config --link /data/local/tmp/busybox | tee $SYSTEM_DIR/linkinfo.txt - if [ $? -ne 0 ];then - echo "Get file symlink failed" - exit 1 - fi - else - adb shell /system/xbin/getfilesysteminfo --link /system | sed -e '/\/d;/\/d' | sort > $SYSTEM_DIR/linkinfo.txt - adb shell rm /system/xbin/getfilesysteminfo - fi + adb shell /system/xbin/getfilesysteminfo --link /system | sed -e '/\/d;/\/d' | sort > $SYSTEM_DIR/linkinfo.txt python $TOOL_DIR/releasetools/recoverylink.py $TARGET_FILES_DIR adb shell rm /system/xbin/getfilesysteminfo } @@ -260,14 +242,6 @@ function build_SYSTEM { recover_symlink } -function deoat { - if [ $ANDROID_PLATFORM -le 19 ];then - return - fi - echo "Decode oat files" - $TOOL_DIR/deoat.sh $TARGET_FILES_DIR -} - # compress the target_files dir into a zip file function zip_target_files { echo "Compress the target_files dir into zip file" @@ -321,7 +295,6 @@ fi build_SYSTEM build_apkcerts gen_metadata -deoat zip_target_files build_ota_package diff --git a/releasetools/pylintrc b/releasetools/pylintrc deleted file mode 100644 index 90de1af..0000000 --- a/releasetools/pylintrc +++ /dev/null @@ -1,382 +0,0 @@ -[MASTER] - -# Specify a configuration file. -#rcfile= - -# Python code to execute, usually for sys.path manipulation such as -# pygtk.require(). -#init-hook= - -# Profiled execution. -profile=no - -# Add files or directories to the blacklist. They should be base names, not -# paths. -ignore=CVS - -# Pickle collected data for later comparisons. -persistent=yes - -# List of plugins (as comma separated values of python modules names) to load, -# usually to register additional checkers. -load-plugins= - -# Use multiple processes to speed up Pylint. -jobs=1 - -# Allow loading of arbitrary C extensions. Extensions are imported into the -# active Python interpreter and may run arbitrary code. -unsafe-load-any-extension=no - -# A comma-separated list of package or module names from where C extensions may -# be loaded. Extensions are loading into the active Python interpreter and may -# run arbitrary code -extension-pkg-whitelist= - -# Allow optimization of some AST trees. This will activate a peephole AST -# optimizer, which will apply various small optimizations. For instance, it can -# be used to obtain the result of joining multiple strings with the addition -# operator. Joining a lot of strings can lead to a maximum recursion error in -# Pylint and this flag can prevent that. It has one side effect, the resulting -# AST will be different than the one from reality. -optimize-ast=no - - -[MESSAGES CONTROL] - -# Only show warnings with the listed confidence levels. Leave empty to show -# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED -confidence= - -# Enable the message, report, category or checker with the given id(s). You can -# either give multiple identifier separated by comma (,) or put this option -# multiple time. See also the "--disable" option for examples. -#enable= - -# Disable the message, report, category or checker with the given id(s). You -# can either give multiple identifiers separated by comma (,) or put this -# option multiple times (only on the command line, not in the configuration -# file where it should appear only once).You can also use "--disable=all" to -# disable everything first and then reenable specific checks. For example, if -# you want to run only the similarities checker, you can use "--disable=all -# --enable=similarities". If you want to run only the classes checker, but have -# no Warning level messages displayed, use"--disable=all --enable=classes -# --disable=W" -disable=invalid-name,missing-docstring,too-many-branches,too-many-locals,too-many-arguments,too-many-statements,duplicate-code,too-few-public-methods,too-many-instance-attributes,too-many-lines,too-many-public-methods,locally-disabled,fixme - - -[REPORTS] - -# Set the output format. Available formats are text, parseable, colorized, msvs -# (visual studio) and html. You can also give a reporter class, eg -# mypackage.mymodule.MyReporterClass. -output-format=text - -# Put messages in a separate file for each module / package specified on the -# command line instead of printing them on stdout. Reports (if any) will be -# written in a file name "pylint_global.[txt|html]". -files-output=no - -# Tells whether to display a full report or only the messages -reports=yes - -# Python expression which should return a note less than 10 (10 is the highest -# note). You have access to the variables errors warning, statement which -# respectively contain the number of errors / warnings messages and the total -# number of statements analyzed. This is used by the global evaluation report -# (RP0004). -evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) - -# Add a comment according to your evaluation note. This is used by the global -# evaluation report (RP0004). -comment=no - -# Template used to display messages. This is a python new-style format string -# used to format the message information. See doc for all details -#msg-template= - - -[SIMILARITIES] - -# Minimum lines number of a similarity. -min-similarity-lines=4 - -# Ignore comments when computing similarities. -ignore-comments=yes - -# Ignore docstrings when computing similarities. -ignore-docstrings=yes - -# Ignore imports when computing similarities. -ignore-imports=no - - -[TYPECHECK] - -# Tells whether missing members accessed in mixin class should be ignored. A -# mixin class is detected if its name ends with "mixin" (case insensitive). -ignore-mixin-members=yes - -# List of module names for which member attributes should not be checked -# (useful for modules/projects where namespaces are manipulated during runtime -# and thus existing member attributes cannot be deduced by static analysis -ignored-modules= - -# List of classes names for which member attributes should not be checked -# (useful for classes with attributes dynamically set). -ignored-classes=SQLObject - -# When zope mode is activated, add a predefined set of Zope acquired attributes -# to generated-members. -zope=no - -# List of members which are set dynamically and missed by pylint inference -# system, and so shouldn't trigger E0201 when accessed. Python regular -# expressions are accepted. -generated-members=REQUEST,acl_users,aq_parent - - -[MISCELLANEOUS] - -# List of note tags to take in consideration, separated by a comma. -notes=FIXME,XXX,TODO - - -[BASIC] - -# Required attributes for module, separated by a comma -required-attributes= - -# List of builtins function names that should not be used, separated by a comma -bad-functions=map,filter,input - -# Good variable names which should always be accepted, separated by a comma -good-names=i,j,k,ex,Run,_ - -# Bad variable names which should always be refused, separated by a comma -bad-names=foo,bar,baz,toto,tutu,tata - -# Colon-delimited sets of names that determine each other's naming style when -# the name regexes allow several styles. -name-group= - -# Include a hint for the correct naming format with invalid-name -include-naming-hint=no - -# Regular expression matching correct function names -function-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Naming hint for function names -function-name-hint=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression matching correct variable names -variable-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Naming hint for variable names -variable-name-hint=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression matching correct constant names -const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ - -# Naming hint for constant names -const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ - -# Regular expression matching correct attribute names -attr-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Naming hint for attribute names -attr-name-hint=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression matching correct argument names -argument-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Naming hint for argument names -argument-name-hint=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression matching correct class attribute names -class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ - -# Naming hint for class attribute names -class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ - -# Regular expression matching correct inline iteration names -inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ - -# Naming hint for inline iteration names -inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ - -# Regular expression matching correct class names -class-rgx=[A-Z_][a-zA-Z0-9]+$ - -# Naming hint for class names -class-name-hint=[A-Z_][a-zA-Z0-9]+$ - -# Regular expression matching correct module names -module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ - -# Naming hint for module names -module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ - -# Regular expression matching correct method names -method-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Naming hint for method names -method-name-hint=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression which should only match function or class names that do -# not require a docstring. -no-docstring-rgx=__.*__ - -# Minimum line length for functions/classes that require docstrings, shorter -# ones are exempt. -docstring-min-length=-1 - - -[SPELLING] - -# Spelling dictionary name. Available dictionaries: none. To make it working -# install python-enchant package. -spelling-dict= - -# List of comma separated words that should not be checked. -spelling-ignore-words= - -# A path to a file that contains private dictionary; one word per line. -spelling-private-dict-file= - -# Tells whether to store unknown words to indicated private dictionary in -# --spelling-private-dict-file option instead of raising a message. -spelling-store-unknown-words=no - - -[FORMAT] - -# Maximum number of characters on a single line. -max-line-length=80 - -# Regexp for a line that is allowed to be longer than the limit. -ignore-long-lines=^\s*(# )??$ - -# Allow the body of an if to be on the same line as the test if there is no -# else. -single-line-if-stmt=no - -# List of optional constructs for which whitespace checking is disabled -no-space-check=trailing-comma,dict-separator - -# Maximum number of lines in a module -max-module-lines=1000 - -# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 -# tab). -indent-string=' ' - -# Number of spaces of indent required inside a hanging or continued line. -indent-after-paren=4 - -# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. -expected-line-ending-format=LF - - -[LOGGING] - -# Logging modules to check that the string format arguments are in logging -# function parameter format -logging-modules=logging - - -[VARIABLES] - -# Tells whether we should check for unused import in __init__ files. -init-import=no - -# A regular expression matching the name of dummy variables (i.e. expectedly -# not used). -dummy-variables-rgx=_$|dummy - -# List of additional names supposed to be defined in builtins. Remember that -# you should avoid to define new builtins when possible. -additional-builtins= - -# List of strings which can identify a callback function by name. A callback -# name must start or end with one of those strings. -callbacks=cb_,_cb - - -[DESIGN] - -# Maximum number of arguments for function / method -max-args=5 - -# Argument names that match this expression will be ignored. Default to name -# with leading underscore -ignored-argument-names=_.* - -# Maximum number of locals for function / method body -max-locals=15 - -# Maximum number of return / yield for function / method body -max-returns=6 - -# Maximum number of branch for function / method body -max-branches=12 - -# Maximum number of statements in function / method body -max-statements=50 - -# Maximum number of parents for a class (see R0901). -max-parents=7 - -# Maximum number of attributes for a class (see R0902). -max-attributes=7 - -# Minimum number of public methods for a class (see R0903). -min-public-methods=2 - -# Maximum number of public methods for a class (see R0904). -max-public-methods=20 - - -[IMPORTS] - -# Deprecated modules which should not be used, separated by a comma -deprecated-modules=regsub,TERMIOS,Bastion,rexec - -# Create a graph of every (i.e. internal and external) dependencies in the -# given file (report RP0402 must not be disabled) -import-graph= - -# Create a graph of external dependencies in the given file (report RP0402 must -# not be disabled) -ext-import-graph= - -# Create a graph of internal dependencies in the given file (report RP0402 must -# not be disabled) -int-import-graph= - - -[CLASSES] - -# List of interface methods to ignore, separated by a comma. This is used for -# instance to not check methods defines in Zope's Interface base class. -ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by - -# List of method names used to declare (i.e. assign) instance attributes. -defining-attr-methods=__init__,__new__,setUp - -# List of valid names for the first argument in a class method. -valid-classmethod-first-arg=cls - -# List of valid names for the first argument in a metaclass class method. -valid-metaclass-classmethod-first-arg=mcs - -# List of member names, which should be excluded from the protected access -# warning. -exclude-protected=_asdict,_fields,_replace,_source,_make - - -[EXCEPTIONS] - -# Exceptions that will emit a warning when being caught. Defaults to -# "Exception" -overgeneral-exceptions=Exception diff --git a/releasetools/rangelib.py b/releasetools/rangelib.py deleted file mode 100644 index 1506658..0000000 --- a/releasetools/rangelib.py +++ /dev/null @@ -1,266 +0,0 @@ -# Copyright (C) 2014 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import print_function -import heapq -import itertools - -__all__ = ["RangeSet"] - -class RangeSet(object): - """A RangeSet represents a set of nonoverlapping ranges on the - integers (ie, a set of integers, but efficient when the set contains - lots of runs.""" - - def __init__(self, data=None): - self.monotonic = False - if isinstance(data, str): - self._parse_internal(data) - elif data: - self.data = tuple(self._remove_pairs(data)) - else: - self.data = () - - def __iter__(self): - for i in range(0, len(self.data), 2): - yield self.data[i:i+2] - - def __eq__(self, other): - return self.data == other.data - def __ne__(self, other): - return self.data != other.data - def __nonzero__(self): - return bool(self.data) - - def __str__(self): - if not self.data: - return "empty" - else: - return self.to_string() - - def __repr__(self): - return '' - - @classmethod - def parse(cls, text): - """Parse a text string consisting of a space-separated list of - blocks and ranges, eg "10-20 30 35-40". Ranges are interpreted to - include both their ends (so the above example represents 18 - individual blocks. Returns a RangeSet object. - - If the input has all its blocks in increasing order, then returned - RangeSet will have an extra attribute 'monotonic' that is set to - True. For example the input "10-20 30" is monotonic, but the input - "15-20 30 10-14" is not, even though they represent the same set - of blocks (and the two RangeSets will compare equal with ==). - """ - return cls(text) - - def _parse_internal(self, text): - data = [] - last = -1 - monotonic = True - for p in text.split(): - if "-" in p: - s, e = p.split("-") - data.append(int(s)) - data.append(int(e)+1) - if last <= s <= e: - last = e - else: - monotonic = False - else: - s = int(p) - data.append(s) - data.append(s+1) - if last <= s: - last = s+1 - else: - monotonic = True - data.sort() - self.data = tuple(self._remove_pairs(data)) - self.monotonic = monotonic - - @staticmethod - def _remove_pairs(source): - last = None - for i in source: - if i == last: - last = None - else: - if last is not None: - yield last - last = i - if last is not None: - yield last - - def to_string(self): - out = [] - for i in range(0, len(self.data), 2): - s, e = self.data[i:i+2] - if e == s+1: - out.append(str(s)) - else: - out.append(str(s) + "-" + str(e-1)) - return " ".join(out) - - def to_string_raw(self): - return str(len(self.data)) + "," + ",".join(str(i) for i in self.data) - - def union(self, other): - """Return a new RangeSet representing the union of this RangeSet - with the argument. - - >>> RangeSet("10-19 30-34").union(RangeSet("18-29")) - - >>> RangeSet("10-19 30-34").union(RangeSet("22 32")) - - """ - out = [] - z = 0 - for p, d in heapq.merge(zip(self.data, itertools.cycle((+1, -1))), - zip(other.data, itertools.cycle((+1, -1)))): - if (z == 0 and d == 1) or (z == 1 and d == -1): - out.append(p) - z += d - return RangeSet(data=out) - - def intersect(self, other): - """Return a new RangeSet representing the intersection of this - RangeSet with the argument. - - >>> RangeSet("10-19 30-34").intersect(RangeSet("18-32")) - - >>> RangeSet("10-19 30-34").intersect(RangeSet("22-28")) - - """ - out = [] - z = 0 - for p, d in heapq.merge(zip(self.data, itertools.cycle((+1, -1))), - zip(other.data, itertools.cycle((+1, -1)))): - if (z == 1 and d == 1) or (z == 2 and d == -1): - out.append(p) - z += d - return RangeSet(data=out) - - def subtract(self, other): - """Return a new RangeSet representing subtracting the argument - from this RangeSet. - - >>> RangeSet("10-19 30-34").subtract(RangeSet("18-32")) - - >>> RangeSet("10-19 30-34").subtract(RangeSet("22-28")) - - """ - - out = [] - z = 0 - for p, d in heapq.merge(zip(self.data, itertools.cycle((+1, -1))), - zip(other.data, itertools.cycle((-1, +1)))): - if (z == 0 and d == 1) or (z == 1 and d == -1): - out.append(p) - z += d - return RangeSet(data=out) - - def overlaps(self, other): - """Returns true if the argument has a nonempty overlap with this - RangeSet. - - >>> RangeSet("10-19 30-34").overlaps(RangeSet("18-32")) - True - >>> RangeSet("10-19 30-34").overlaps(RangeSet("22-28")) - False - """ - - # This is like intersect, but we can stop as soon as we discover the - # output is going to be nonempty. - z = 0 - for _, d in heapq.merge(zip(self.data, itertools.cycle((+1, -1))), - zip(other.data, itertools.cycle((+1, -1)))): - if (z == 1 and d == 1) or (z == 2 and d == -1): - return True - z += d - return False - - def size(self): - """Returns the total size of the RangeSet (ie, how many integers - are in the set). - - >>> RangeSet("10-19 30-34").size() - 15 - """ - - total = 0 - for i, p in enumerate(self.data): - if i % 2: - total += p - else: - total -= p - return total - - def map_within(self, other): - """'other' should be a subset of 'self'. Returns a RangeSet - representing what 'other' would get translated to if the integers - of 'self' were translated down to be contiguous starting at zero. - - >>> RangeSet("0-9").map_within(RangeSet("3-4")) - - >>> RangeSet("10-19").map_within(RangeSet("13-14")) - - >>> RangeSet("10-19 30-39").map_within(RangeSet("17-19 30-32")) - - >>> RangeSet("10-19 30-39").map_within(RangeSet("12-13 17-19 30-32")) - - """ - - out = [] - offset = 0 - start = None - for p, d in heapq.merge(zip(self.data, itertools.cycle((-5, +5))), - zip(other.data, itertools.cycle((-1, +1)))): - if d == -5: - start = p - elif d == +5: - offset += p-start - start = None - else: - out.append(offset + p - start) - return RangeSet(data=out) - - def extend(self, n): - """Extend the RangeSet by 'n' blocks. - - The lower bound is guaranteed to be non-negative. - - >>> RangeSet("0-9").extend(1) - - >>> RangeSet("10-19").extend(15) - - >>> RangeSet("10-19 30-39").extend(4) - - >>> RangeSet("10-19 30-39").extend(10) - - """ - out = self - for i in range(0, len(self.data), 2): - s, e = self.data[i:i+2] - s1 = max(0, s - n) - e1 = e + n - out = out.union(RangeSet(str(s1) + "-" + str(e1-1))) - return out - - -if __name__ == "__main__": - import doctest - doctest.testmod() diff --git a/releasetools/recoverylink.py b/releasetools/recoverylink.py index 5f9fe9d..e53b078 100644 --- a/releasetools/recoverylink.py +++ b/releasetools/recoverylink.py @@ -13,10 +13,12 @@ line = line.rstrip() filepath = line.split('|') link_name = filepath[0].replace('system', 'SYSTEM') - target = filepath[1] - cmd = 'cd ' + path + ';' + 'mkdir -p ' + os.path.dirname(link_name) + ';' + 'ln -sf ' + target + ' ' + link_name + ';' - print cmd - os.popen(cmd) + target = '/' + filepath[1] + rm = 'rm -f ' + path+ '/' + link_name + os.popen(rm) + ln = 'cd ' + path + ';' + 'ln -s ' + target + ' ' + link_name + #print ln + os.popen(ln) except IOError: print r"%s isn't exist" % linkfile_path sys.exit(1) diff --git a/releasetools/sign_target_files_apks b/releasetools/sign_target_files_apks index ab97b13..fc71b51 100755 --- a/releasetools/sign_target_files_apks +++ b/releasetools/sign_target_files_apks @@ -183,7 +183,7 @@ def RewriteProps(data): for line in data.split("\n"): line = line.strip() original_line = line - if line and line[0] != '#' and "=" in line: + if line and line[0] != '#': key, value = line.split("=", 1) if key == "ro.build.fingerprint": pieces = value.split("/") diff --git a/releasetools/sparse_img.py b/releasetools/sparse_img.py deleted file mode 100644 index 07f3c1c..0000000 --- a/releasetools/sparse_img.py +++ /dev/null @@ -1,247 +0,0 @@ -# Copyright (C) 2014 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import bisect -import os -import struct -from hashlib import sha1 - -import rangelib - - -class SparseImage(object): - """Wraps a sparse image file into an image object. - - Wraps a sparse image file (and optional file map and clobbered_blocks) into - an image object suitable for passing to BlockImageDiff. file_map contains - the mapping between files and their blocks. clobbered_blocks contains the set - of blocks that should be always written to the target regardless of the old - contents (i.e. copying instead of patching). clobbered_blocks should be in - the form of a string like "0" or "0 1-5 8". - """ - - def __init__(self, simg_fn, file_map_fn=None, clobbered_blocks=None): - self.simg_f = f = open(simg_fn, "rb") - - header_bin = f.read(28) - header = struct.unpack("> 2)) - to_read -= this_read - - while to_read > 0: - # continue with following chunks if this range spans multiple chunks. - idx += 1 - chunk_start, chunk_len, filepos, fill_data = self.offset_map[idx] - this_read = min(chunk_len, to_read) - if filepos is not None: - f.seek(filepos, os.SEEK_SET) - yield f.read(this_read * self.blocksize) - else: - yield fill_data * (this_read * (self.blocksize >> 2)) - to_read -= this_read - - def LoadFileBlockMap(self, fn, clobbered_blocks): - remaining = self.care_map - self.file_map = out = {} - - with open(fn) as f: - for line in f: - fn, ranges = line.split(None, 1) - ranges = rangelib.RangeSet.parse(ranges) - out[fn] = ranges - assert ranges.size() == ranges.intersect(remaining).size() - - # Currently we assume that blocks in clobbered_blocks are not part of - # any file. - assert not clobbered_blocks.overlaps(ranges) - remaining = remaining.subtract(ranges) - - remaining = remaining.subtract(clobbered_blocks) - - # For all the remaining blocks in the care_map (ie, those that - # aren't part of the data for any file nor part of the clobbered_blocks), - # divide them into blocks that are all zero and blocks that aren't. - # (Zero blocks are handled specially because (1) there are usually - # a lot of them and (2) bsdiff handles files with long sequences of - # repeated bytes especially poorly.) - - zero_blocks = [] - nonzero_blocks = [] - reference = '\0' * self.blocksize - - f = self.simg_f - for s, e in remaining: - for b in range(s, e): - idx = bisect.bisect_right(self.offset_index, b) - 1 - chunk_start, _, filepos, fill_data = self.offset_map[idx] - if filepos is not None: - filepos += (b-chunk_start) * self.blocksize - f.seek(filepos, os.SEEK_SET) - data = f.read(self.blocksize) - else: - if fill_data == reference[:4]: # fill with all zeros - data = reference - else: - data = None - - if data == reference: - zero_blocks.append(b) - zero_blocks.append(b+1) - else: - nonzero_blocks.append(b) - nonzero_blocks.append(b+1) - - assert zero_blocks or nonzero_blocks or clobbered_blocks - - if zero_blocks: - out["__ZERO"] = rangelib.RangeSet(data=zero_blocks) - if nonzero_blocks: - out["__NONZERO"] = rangelib.RangeSet(data=nonzero_blocks) - if clobbered_blocks: - out["__COPY"] = clobbered_blocks - - def ResetFileMap(self): - """Throw away the file map and treat the entire image as - undifferentiated data.""" - self.file_map = {"__DATA": self.care_map} diff --git a/replace_package_name.sh b/replace_package_name.sh index 20a68a7..511aefc 100755 --- a/replace_package_name.sh +++ b/replace_package_name.sh @@ -13,7 +13,7 @@ des="$3" cd $path #replace xml -for f in $(find . -name "*.xml") +for f in $(find -name "*.xml") do echo $f sed "s/$src/$des/g" $f > tmp @@ -23,7 +23,7 @@ done #replace smali src2=$(echo $src | sed "s#\.#\\\/#g") des2=$(echo $des | sed "s#\.#\\\/#g") -for f in $(find . -name "*.smali") +for f in $(find -name "*.smali") do echo $f sed "s/$src2/$des2/g" $f > tmp diff --git a/set_build_prop.sh b/set_build_prop.sh new file mode 100755 index 0000000..3048c14 --- /dev/null +++ b/set_build_prop.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +build_prop_file=$1 +# other arguments: # product=$2 # number=$3 # version=$4 + +cat $build_prop_file | sed -e "s/ro\.build\.version\.incremental=.*/ro\.build\.version\.incremental=$3/" \ + | sed -e "s/ro\.product\.mod_device=.*//" > $build_prop_file.new + +echo "ro.product.mod_device=$2" >> $build_prop_file.new +echo "ro.skia.use_data_fonts=1" >> $build_prop_file.new +echo "ro.miui.ui.version.code=3" >> $build_prop_file.new +echo "ro.miui.ui.version.name=V5" >> $build_prop_file.new +mv $build_prop_file.new $build_prop_file + diff --git a/signapk.jar b/signapk.jar index fbf121f..f6fe372 100644 Binary files a/signapk.jar and b/signapk.jar differ diff --git a/target_files_template/DATA/media/preset_apps/91xiongmaokanshu.apk b/target_files_template/DATA/media/preset_apps/91xiongmaokanshu.apk new file mode 100644 index 0000000..01a3e10 Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/91xiongmaokanshu.apk differ diff --git a/target_files_template/DATA/media/preset_apps/duokanyuedu.apk b/target_files_template/DATA/media/preset_apps/duokanyuedu.apk new file mode 100644 index 0000000..84557e0 Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/duokanyuedu.apk differ diff --git a/target_files_template/DATA/media/preset_apps/jinshandianchiyisheng.apk b/target_files_template/DATA/media/preset_apps/jinshandianchiyisheng.apk new file mode 100644 index 0000000..b016621 Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/jinshandianchiyisheng.apk differ diff --git a/target_files_template/DATA/media/preset_apps/jinshankuaipan.apk b/target_files_template/DATA/media/preset_apps/jinshankuaipan.apk new file mode 100644 index 0000000..8461f4d Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/jinshankuaipan.apk differ diff --git a/target_files_template/DATA/media/preset_apps/jinshanshoujiweishi.apk b/target_files_template/DATA/media/preset_apps/jinshanshoujiweishi.apk new file mode 100644 index 0000000..266dce1 Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/jinshanshoujiweishi.apk differ diff --git a/target_files_template/DATA/media/preset_apps/kuaijiejiudianguanjia.apk b/target_files_template/DATA/media/preset_apps/kuaijiejiudianguanjia.apk new file mode 100644 index 0000000..b96970b Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/kuaijiejiudianguanjia.apk differ diff --git a/target_files_template/DATA/media/preset_apps/kuwoyinyue.apk b/target_files_template/DATA/media/preset_apps/kuwoyinyue.apk new file mode 100644 index 0000000..268dda0 Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/kuwoyinyue.apk differ diff --git a/target_files_template/DATA/media/preset_apps/laohuditu.apk b/target_files_template/DATA/media/preset_apps/laohuditu.apk new file mode 100644 index 0000000..1a14c49 Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/laohuditu.apk differ diff --git a/target_files_template/DATA/media/preset_apps/meilishuo.apk b/target_files_template/DATA/media/preset_apps/meilishuo.apk new file mode 100644 index 0000000..b34218c Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/meilishuo.apk differ diff --git a/target_files_template/DATA/media/preset_apps/miliao.apk b/target_files_template/DATA/media/preset_apps/miliao.apk new file mode 100644 index 0000000..24c4b53 Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/miliao.apk differ diff --git a/target_files_template/DATA/media/preset_apps/oupengliulanqi.apk b/target_files_template/DATA/media/preset_apps/oupengliulanqi.apk new file mode 100644 index 0000000..04fe624 Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/oupengliulanqi.apk differ diff --git a/target_files_template/DATA/media/preset_apps/souhuxinwen.apk b/target_files_template/DATA/media/preset_apps/souhuxinwen.apk new file mode 100644 index 0000000..13c47f5 Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/souhuxinwen.apk differ diff --git a/target_files_template/DATA/media/preset_apps/ucliulanqi.apk b/target_files_template/DATA/media/preset_apps/ucliulanqi.apk new file mode 100644 index 0000000..5f97aeb Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/ucliulanqi.apk differ diff --git a/target_files_template/DATA/media/preset_apps/vancl.apk b/target_files_template/DATA/media/preset_apps/vancl.apk new file mode 100644 index 0000000..11052cd Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/vancl.apk differ diff --git a/target_files_template/DATA/media/preset_apps/wangyixinwen.apk b/target_files_template/DATA/media/preset_apps/wangyixinwen.apk new file mode 100644 index 0000000..7d9d83c Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/wangyixinwen.apk differ diff --git a/target_files_template/DATA/media/preset_apps/xiechengwuxian.apk b/target_files_template/DATA/media/preset_apps/xiechengwuxian.apk new file mode 100644 index 0000000..7b91e22 Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/xiechengwuxian.apk differ diff --git a/target_files_template/DATA/media/preset_apps/xinlangweibo.apk b/target_files_template/DATA/media/preset_apps/xinlangweibo.apk new file mode 100644 index 0000000..66e80c4 Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/xinlangweibo.apk differ diff --git a/target_files_template/DATA/media/preset_apps/youjia.apk b/target_files_template/DATA/media/preset_apps/youjia.apk new file mode 100644 index 0000000..36f539f Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/youjia.apk differ diff --git a/target_files_template/META/apkcerts.txt b/target_files_template/META/apkcerts.txt index e69de29..e01adc7 100644 --- a/target_files_template/META/apkcerts.txt +++ b/target_files_template/META/apkcerts.txt @@ -0,0 +1,437 @@ +name="CtsVerifier.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsTestStubs.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsAccelerationTestStubs.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsDelegatingAccessibilityService.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ApiDemosReferenceTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsAppAccessData.apk" certificate="cts/tests/appsecurity-tests/certs/cts-testkey2.x509.pem" private_key="cts/tests/appsecurity-tests/certs/cts-testkey2.pk8" +name="CtsAppWithData.apk" certificate="cts/tests/appsecurity-tests/certs/cts-testkey1.x509.pem" private_key="cts/tests/appsecurity-tests/certs/cts-testkey1.pk8" +name="CtsInstrumentationAppDiffCert.apk" certificate="cts/tests/appsecurity-tests/certs/cts-testkey2.x509.pem" private_key="cts/tests/appsecurity-tests/certs/cts-testkey2.pk8" +name="CtsPermissionDeclareApp.apk" certificate="cts/tests/appsecurity-tests/certs/cts-testkey1.x509.pem" private_key="cts/tests/appsecurity-tests/certs/cts-testkey1.pk8" +name="CtsSharedUidInstall.apk" certificate="cts/tests/appsecurity-tests/certs/cts-testkey1.x509.pem" private_key="cts/tests/appsecurity-tests/certs/cts-testkey1.pk8" +name="CtsSharedUidInstallDiffCert.apk" certificate="cts/tests/appsecurity-tests/certs/cts-testkey2.x509.pem" private_key="cts/tests/appsecurity-tests/certs/cts-testkey2.pk8" +name="CtsSimpleAppInstall.apk" certificate="cts/tests/appsecurity-tests/certs/cts-testkey1.x509.pem" private_key="cts/tests/appsecurity-tests/certs/cts-testkey1.pk8" +name="CtsSimpleAppInstallDiffCert.apk" certificate="cts/tests/appsecurity-tests/certs/cts-testkey2.x509.pem" private_key="cts/tests/appsecurity-tests/certs/cts-testkey2.pk8" +name="CtsTargetInstrumentationApp.apk" certificate="cts/tests/appsecurity-tests/certs/cts-testkey1.x509.pem" private_key="cts/tests/appsecurity-tests/certs/cts-testkey1.pk8" +name="CtsUsePermissionDiffCert.apk" certificate="cts/tests/appsecurity-tests/certs/cts-testkey2.x509.pem" private_key="cts/tests/appsecurity-tests/certs/cts-testkey2.pk8" +name="android.core.tests.libcore.package.com.no-core-tests-res.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="android.core.tests.libcore.package.com.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="android.core.tests.libcore.package.dalvik.no-core-tests-res.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="android.core.tests.libcore.package.dalvik.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="android.core.tests.libcore.package.libcore.no-core-tests-res.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="android.core.tests.libcore.package.libcore.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="android.core.tests.libcore.package.org.no-core-tests-res.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="android.core.tests.libcore.package.org.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="android.core.tests.libcore.package.sun.no-core-tests-res.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="android.core.tests.libcore.package.sun.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="android.core.tests.libcore.package.tests.no-core-tests-res.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="android.core.tests.libcore.package.tests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="android.core.tests.runner.no-core-tests-res.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="android.core.tests.runner.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsDeviceAdmin.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ProcessTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="NoShareUidApp.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ShareUidApp.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SignatureTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SignatureTestTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsAccelerationTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsAccessibilityServiceTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsAccountManagerTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsAdminTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsAppTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsBluetoothTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsContentTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsDatabaseTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsDpiTestCases2.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsDpiTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsDrmTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsExampleTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsGestureTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsGraphicsTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsHardwareTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsHoloTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsJniTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsLocationTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsMediaTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsNdefTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsNetTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsOsTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsPermission2TestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsPermissionTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsPreferenceTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsProviderTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsRenderscriptTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsSaxTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsSecurityTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsSpeechTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsTelephonyTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsTextTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsUtilTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsViewTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsWebkitTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsWidgetTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="TestDeviceSetup.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="BluetoothDebug.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="BuildWidget.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CustomLocale.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="Development.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="Fallback.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FontLab.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="GestureBuilder.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="NinePatchLab.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SdkSetup.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="WidgetPreview.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="launchperf.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="AccelerometerPlay.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ActionBarCompat.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="AliasActivity.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="AndroidBeamDemo.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ApiDemos.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ApiDemosTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="BackupRestore.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="BasicGLSurfaceView.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="BluetoothChat.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="BluetoothHDP.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SampleBrowserPlugin.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="BusinessCard.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Compass.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ContactManager.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CubeLiveWallpapers.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FixedGridLayout.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="GlobalTime.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="HelloActivity.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="HelloActivityTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Home.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="HoneycombGallery.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="JETBoy.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="LunarLander.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="LunarLanderTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="MultiResolution.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="NFCDemo.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="NotePad.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ObbApp.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="RSSReader.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="RandomMusicPlayer.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="RsBalls.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="RsFountain.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="RsFountainFbo.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="RsHelloCompute.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="RsHelloWorld.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="RsMiscSamples.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SampleSyncAdapter.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SearchableDictionary.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SimpleJNI.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SipDemo.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SkeletonApp.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SkeletonAppTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Snake.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SnakeTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SoftKeyboard.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="HelloSpellChecker.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SampleSpellChecker.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="StackWidget.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Support13Demos.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Support4Demos.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ToyVpn.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="TtsEngine.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="AdbTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="MissileLauncher.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="VoiceRecognitionService.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="VoicemailProviderDemo.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="WeatherListWidget.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="WiFiDirectDemo.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Wiktionary.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="WiktionarySimple.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="xmladapters.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ConnectivityTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="GpsLocationTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Notepadv1.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Notepadv1Solution.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Notepadv2.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Notepadv2Solution.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Notepadv3.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Notepadv3Solution.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ChromeBookmarksSyncAdapter.apk" certificate="PRESIGNED" private_key="" +name="FaceLock.apk" certificate="PRESIGNED" private_key="" +name="GameCenterSDKService.apk" certificate="PRESIGNED" private_key="" +name="Gmail.apk" certificate="PRESIGNED" private_key="" +name="Gmail_Data.apk" certificate="PRESIGNED" private_key="" +name="GoogleBackupTransport.apk" certificate="PRESIGNED" private_key="" +name="GoogleCalendarSyncAdapter.apk" certificate="PRESIGNED" private_key="" +name="GoogleContactsSyncAdapter.apk" certificate="PRESIGNED" private_key="" +name="GoogleLoginService.apk" certificate="PRESIGNED" private_key="" +name="GooglePartnerSetup.apk" certificate="PRESIGNED" private_key="" +name="GoogleServicesFramework.apk" certificate="PRESIGNED" private_key="" +name="Maps.apk" certificate="PRESIGNED" private_key="" +name="Maps_Data.apk" certificate="PRESIGNED" private_key="" +name="NetworkLocation.apk" certificate="PRESIGNED" private_key="" +name="Talk.apk" certificate="PRESIGNED" private_key="" +name="Talk_Data.apk" certificate="PRESIGNED" private_key="" +name="Vending.apk" certificate="PRESIGNED" private_key="" +name="VoiceSearch.apk" certificate="PRESIGNED" private_key="" +name="VoiceSearch_Data.apk" certificate="PRESIGNED" private_key="" +name="PlatformLibraryClient.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SampleEmailPolicy.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="UpgradeExample.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Quake.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="PicoTts.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="framework-res.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="ConnectivityManagerTest.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="BandwidthTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="BluetoothTests.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="FrameworksCoreTests.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="FrameworkCoreTests_install_decl_perm.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FrameworkCoreTests_install_loc_auto.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FrameworkCoreTests_install_loc_internal.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FrameworkCoreTests_install_loc_sdcard.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FrameworkCoreTests_install_loc_unspecified.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FrameworkCoreTests_install_use_perm_good.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FrameworkCoreTests_install_uses_feature.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FrameworkCoreTests_install_verifier_bad.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FrameworkCoreTests_install_verifier_good.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="DisabledTestApp.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="EnabledTestApp.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="AutoLocTestApp.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="AutoLocVersionedTestApp_v1.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="AutoLocVersionedTestApp_v2.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="DownloadManagerTestApp.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ExternalLocAllPermsTestApp.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ExternalLocPermFLTestApp.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ExternalLocTestApp.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ExternalLocVersionedTestApp_v1.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ExternalLocVersionedTestApp_v2.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ExternalSharedPermsTestApp.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ExternalSharedPermsBTTestApp.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ExternalSharedPermsDiffKeyTestApp.apk" certificate="build/target/product/security/media.x509.pem" private_key="build/target/product/security/media.pk8" +name="ExternalSharedPermsFLTestApp.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="InternalLocTestApp.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="NoLocTestApp.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="NoLocVersionedTestApp_v1.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="NoLocVersionedTestApp_v2.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SimpleTestApp.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="UpdateExternalLocTestApp_v1_ext.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="UpdateExternalLocTestApp_v2_none.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="UpdateExtToIntLocTestApp_v1_ext.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="UpdateExtToIntLocTestApp_v2_int.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="VersatileTestApp_Auto.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="VersatileTestApp_External.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="VersatileTestApp_Internal.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="VersatileTestApp_None.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="NotificationStressTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FrameworksCoreSystemPropertiesTests.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="FrameworksGraphicsTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="KeyStoreTests.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="CameraBrowser.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="MediaDump.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="mediaframeworktest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="scoaudiotest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SoundPoolTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="GL2CameraEye.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="GL2Java.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="GL2JNI.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="GLDual.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="GLJNI.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="GLPerf.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="LightingTest.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="TestFramerate.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="TestLatency.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="TestEGL.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="TestViewport.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="BackupRestoreConfirmation.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="DefaultContainerService.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="SettingsProvider.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="SharedStorageBackup.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="SystemUI.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="SystemUITests.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="MiuiKeyguard.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="VpnDialogs.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="WAPPushManager.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="WAPPushManagerTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FrameworkPolicyTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FrameworksSaxTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FrameworksServicesTests.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="TelephonyMockRilTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FrameworksTelephonyTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FrameworkTestRunnerTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ActivityTest.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="BandwidthEnforcementTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="BatteryWaster.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="BrowserPowerTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="BrowserTestPlugin.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CoreTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="DataIdleTest.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="DensityTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="DumpRenderTree.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="DumpRenderTree2.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FixVibrateSetting.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="FrameworkPerf.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="GridLayoutTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="HugeBackup.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="HwAccelerationTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ImfTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ImfTestTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="LargeAssetTest.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="LocationTracker.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="LotsOfApps.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="lowstoragetest.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="RsComputePerf.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FBOTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ImageProcessing.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ModelViewer.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="PerfTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ShadersTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="RSTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SmokeTestApp.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SmokeTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SslLoad.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="StatusBarTest.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="TileBenchmark.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="TileBenchmarkTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="TransformTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="AppWidgetHostTest.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="AppWidgetProvider.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="BackupTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FrameworkPermissionTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="AndroidCommonTests.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="framework-miui-res.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="LBESEC_MIUI.apk" certificate="PRESIGNED" private_key="" +name="TelocationProvider.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="TelocationProviderTests.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="CalendarCommonTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="MailCommonTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="AndroidVCardTests.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="AntiSpam.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="Backup.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="BasicSmsReceiver.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="BasicSmsReceiverTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Bluetooth.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="Browser.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="BrowserTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="BugReport.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="Calculator.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CalculatorTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Calendar.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CalendarTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Camera.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CameraTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CellBroadcastReceiver.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CellBroadcastReceiverTests.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="CertInstaller.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="CloudService.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="MiuiCompass.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="Contacts.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="ContactsTests.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="DeskClock.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="DeskClockTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Email.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="EmailTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Exchange.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Exchange2.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ExchangeTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FileExplorer.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="Gallery.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Gallery2.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="MiuiGallery.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Gallery2Tests.apk" certificate="build/target/product/security/media.x509.pem" private_key="build/target/product/security/media.pk8" +name="HTMLViewer.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="KeyChain.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="KeyChainTestsSupport.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="KeyChainTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Launcher2.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="LauncherRotationStressTest.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="MiuiHome.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="Music.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="MiuiSystemUI.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="MiuiSystemUITests.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="Mms.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="MmsAppTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="MmsTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="MusicFX.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Nfc.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="NfcTests.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="Notes.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="PackageInstaller.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="Phone.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="PhoneAppTests.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="Protips.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Provision.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="QuickSearchBox.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="QuickSearchBoxBenchmarks.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="QuickSearchBoxTests.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="NaughtySuggestions.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="PartialSuggestions.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="SlowSuggestions.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="SpammySuggestions.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="Settings.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="SettingsTests.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="SoundRecorder.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="SpareParts.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SpeechRecorder.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Stk.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="SuperMarket.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="Tag.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ThemeManager.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="Torch.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="Updater.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="VideoEditor.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="VoiceDialer.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="VoiceDialerTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Weather.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="LatinIME.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="LatinIMETests.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="ApplicationsProvider.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="ApplicationsProviderTests.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="CalendarProvider.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CalendarProviderTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ContactsProvider.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="ContactsProviderTests.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="DownloadProvider.apk" certificate="build/target/product/security/media.x509.pem" private_key="build/target/product/security/media.pk8" +name="DownloadProviderTests.apk" certificate="build/target/product/security/media.x509.pem" private_key="build/target/product/security/media.pk8" +name="DownloadProviderPermissionTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="DownloadPublicApiAccessTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="DownloadProviderUi.apk" certificate="build/target/product/security/media.x509.pem" private_key="build/target/product/security/media.pk8" +name="DrmProvider.apk" certificate="build/target/product/security/media.x509.pem" private_key="build/target/product/security/media.pk8" +name="MediaProvider.apk" certificate="build/target/product/security/media.x509.pem" private_key="build/target/product/security/media.pk8" +name="TelephonyProvider.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="UserDictionaryProvider.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="LiveWallpapers.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="Galaxy4.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="HoloSpiralWallpaper.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="LiveWallpapersPicker.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="MagicSmokeWallpapers.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="VisualizationWallpapers.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="NoiseField.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="PhaseBeam.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="CameraEffectsRecordingSample.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CameraEffectsTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="native-media.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="WeatherProvider.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="GuardProvider.apk" certificate="PRESIGNED" private_key="" +name="XiaomiServiceFramework.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="MiuiVideoPlayer.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="VoiceAssist.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="GameCenter.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="InputMethod.apk" certificate="PRESIGNED" private_key="" +name="AlipayMsp.apk" certificate="PRESIGNED" private_key="" +name="MiuiVideo.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="StockSettings.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="Userbook.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="AirkanPhoneService.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="DataHubProvider.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="Transfer.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="YellowPage.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="baidushurufa_52.apk" certificate="PRESIGNED" private_key="" +name="MiWallpaper.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="BaiduNetworkLocation.apk" certificate="PRESIGNED" private_key="" +name="FusedLocation.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="PaymentService.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="AMAPNetworkLocation.apk" certificate="PRESIGNED" private_key="" +name="VoiceRecognizerXunfei.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="KingSoftCleaner.apk" certificate="PRESIGNED" private_key="" +name="O2O.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="NetworkAssistant2.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="ota-miui-MiShop.apk" certificate="PRESIGNED" private_key="" +name="ota-partner-NetworkAssistant.apk" certificate="PRESIGNED" private_key="" +name="ota-partner-XunfeiSpeechService3.apk" certificate="PRESIGNED" private_key="" +name="ota-MiuiForum.apk" certificate="PRESIGNED" private_key="" +name="MiLinkService.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="TrafficControl.apk" certificate="PRESIGNED" private_key="" diff --git a/target_files_template/META/filesystem_config.txt b/target_files_template/META/filesystem_config.txt index a17445c..7762521 100644 --- a/target_files_template/META/filesystem_config.txt +++ b/target_files_template/META/filesystem_config.txt @@ -1,4 +1,7 @@ -system/bin/app_process32_vendor 0 2000 755 selabel=u:object_r:zygote_exec:s0 capabilities=0x0 -system/bin/app_process64_vendor 0 2000 755 selabel=u:object_r:zygote_exec:s0 capabilities=0x0 -system/xbin/shelld 0 2000 755 selabel=u:object_r:system_file:s0 capabilities=0x0 -system/bin/fdpp 0 2000 755 selabel=u:object_r:system_file:s0 capabilities=0x0 +system/xbin/invoke-as 0 0 6755 +system/xbin/su 0 0 6755 +system/xbin/busybox 0 0 6755 +system/xbin/insecure 0 2000 6755 +system/xbin/shelld 0 1000 6750 +system/xbin/oemfix 0 2000 6755 +system/lib/liblbesec.so 0 0 744 diff --git a/target_files_template/META/misc_info.txt b/target_files_template/META/misc_info.txt index 446d190..33d303e 100644 --- a/target_files_template/META/misc_info.txt +++ b/target_files_template/META/misc_info.txt @@ -1,4 +1,7 @@ recovery_api_version=3 -fstab_version=1 -use_set_metadata=1 +blocksize=131072 +boot_size=0x00280000 +recovery_size=0x00500000 +system_size=0x08400000 +userdata_size=0x0c440000 tool_extensions=. diff --git a/target_files_template/OTA/bin/busybox b/target_files_template/OTA/bin/busybox deleted file mode 100644 index 9539dea..0000000 Binary files a/target_files_template/OTA/bin/busybox and /dev/null differ diff --git a/target_files_template/OTA/bin/relink b/target_files_template/OTA/bin/relink index 98615ac..9086eed 100644 Binary files a/target_files_template/OTA/bin/relink and b/target_files_template/OTA/bin/relink differ diff --git a/target_files_template/OTA/bin/replace_key b/target_files_template/OTA/bin/replace_key deleted file mode 100644 index 300a598..0000000 --- a/target_files_template/OTA/bin/replace_key +++ /dev/null @@ -1,22 +0,0 @@ -debug_platform="308204a830820390a003020102020900b3998086d056cffa300d06092a864886f70d0101040500308194310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e060355040b1307416e64726f69643110300e06035504031307416e64726f69643122302006092a864886f70d0109011613616e64726f696440616e64726f69642e636f6d301e170d3038303431353232343035305a170d3335303930313232343035305a308194310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e060355040b1307416e64726f69643110300e06035504031307416e64726f69643122302006092a864886f70d0109011613616e64726f696440616e64726f69642e636f6d30820120300d06092a864886f70d01010105000382010d003082010802820101009c780592ac0d5d381cdeaa65ecc8a6006e36480c6d7207b12011be50863aabe2b55d009adf7146d6f2202280c7cd4d7bdb26243b8a806c26b34b137523a49268224904dc01493e7c0acf1a05c874f69b037b60309d9074d24280e16bad2a8734361951eaf72a482d09b204b1875e12ac98c1aa773d6800b9eafde56d58bed8e8da16f9a360099c37a834a6dfedb7b6b44a049e07a269fccf2c5496f2cf36d64df90a3b8d8f34a3baab4cf53371ab27719b3ba58754ad0c53fc14e1db45d51e234fbbe93c9ba4edf9ce54261350ec535607bf69a2ff4aa07db5f7ea200d09a6c1b49e21402f89ed1190893aab5a9180f152e82f85a45753cf5fc19071c5eec827020103a381fc3081f9301d0603551d0e041604144fe4a0b3dd9cba29f71d7287c4e7c38f2086c2993081c90603551d230481c13081be80144fe4a0b3dd9cba29f71d7287c4e7c38f2086c299a1819aa48197308194310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e060355040b1307416e64726f69643110300e06035504031307416e64726f69643122302006092a864886f70d0109011613616e64726f696440616e64726f69642e636f6d820900b3998086d056cffa300c0603551d13040530030101ff300d06092a864886f70d01010405000382010100572551b8d93a1f73de0f6d469f86dad6701400293c88a0cd7cd778b73dafcc197fab76e6212e56c1c761cfc42fd733de52c50ae08814cefc0a3b5a1a4346054d829f1d82b42b2048bf88b5d14929ef85f60edd12d72d55657e22e3e85d04c831d613d19938bb8982247fa321256ba12d1d6a8f92ea1db1c373317ba0c037f0d1aff645aef224979fba6e7a14bc025c71b98138cef3ddfc059617cf24845cf7b40d6382f7275ed738495ab6e5931b9421765c491b72fb68e080dbdb58c2029d347c8b328ce43ef6a8b15533edfbe989bd6a48dd4b202eda94c6ab8dd5b8399203daae2ed446232e4fe9bd961394c6300e5138e3cfd285e6e4e483538cb8b1b357" -debug_shared="308204a830820390a003020102020900b3998086d056cffa300d06092a864886f70d0101040500308194310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e060355040b1307416e64726f69643110300e06035504031307416e64726f69643122302006092a864886f70d0109011613616e64726f696440616e64726f69642e636f6d301e170d3038303431353232343035305a170d3335303930313232343035305a308194310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e060355040b1307416e64726f69643110300e06035504031307416e64726f69643122302006092a864886f70d0109011613616e64726f696440616e64726f69642e636f6d30820120300d06092a864886f70d01010105000382010d003082010802820101009c780592ac0d5d381cdeaa65ecc8a6006e36480c6d7207b12011be50863aabe2b55d009adf7146d6f2202280c7cd4d7bdb26243b8a806c26b34b137523a49268224904dc01493e7c0acf1a05c874f69b037b60309d9074d24280e16bad2a8734361951eaf72a482d09b204b1875e12ac98c1aa773d6800b9eafde56d58bed8e8da16f9a360099c37a834a6dfedb7b6b44a049e07a269fccf2c5496f2cf36d64df90a3b8d8f34a3baab4cf53371ab27719b3ba58754ad0c53fc14e1db45d51e234fbbe93c9ba4edf9ce54261350ec535607bf69a2ff4aa07db5f7ea200d09a6c1b49e21402f89ed1190893aab5a9180f152e82f85a45753cf5fc19071c5eec827020103a381fc3081f9301d0603551d0e041604144fe4a0b3dd9cba29f71d7287c4e7c38f2086c2993081c90603551d230481c13081be80144fe4a0b3dd9cba29f71d7287c4e7c38f2086c299a1819aa48197308194310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e060355040b1307416e64726f69643110300e06035504031307416e64726f69643122302006092a864886f70d0109011613616e64726f696440616e64726f69642e636f6d820900b3998086d056cffa300c0603551d13040530030101ff300d06092a864886f70d01010405000382010100572551b8d93a1f73de0f6d469f86dad6701400293c88a0cd7cd778b73dafcc197fab76e6212e56c1c761cfc42fd733de52c50ae08814cefc0a3b5a1a4346054d829f1d82b42b2048bf88b5d14929ef85f60edd12d72d55657e22e3e85d04c831d613d19938bb8982247fa321256ba12d1d6a8f92ea1db1c373317ba0c037f0d1aff645aef224979fba6e7a14bc025c71b98138cef3ddfc059617cf24845cf7b40d6382f7275ed738495ab6e5931b9421765c491b72fb68e080dbdb58c2029d347c8b328ce43ef6a8b15533edfbe989bd6a48dd4b202eda94c6ab8dd5b8399203daae2ed446232e4fe9bd961394c6300e5138e3cfd285e6e4e483538cb8b1b357" -debug_media="308204a830820390a003020102020900f2b98e6123572c4e300d06092a864886f70d0101040500308194310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e060355040b1307416e64726f69643110300e06035504031307416e64726f69643122302006092a864886f70d0109011613616e64726f696440616e64726f69642e636f6d301e170d3038303431353233343035375a170d3335303930313233343035375a308194310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e060355040b1307416e64726f69643110300e06035504031307416e64726f69643122302006092a864886f70d0109011613616e64726f696440616e64726f69642e636f6d30820120300d06092a864886f70d01010105000382010d00308201080282010100ae250c5a16ef97fc2869ac651b3217cc36ba0e86964168d58a049f40ce85867123a3ffb4f6d949c33cf2da3a05c23eacaa57d803889b1759bcf59e7c6f21890ae25085b7ed56aa626c0989ef9ccd36362ca0e8d1b9603fd4d8328767926ccc090c68b775ae7ff30934cc369ef2855a2667df0c667fd0c7cf5d8eba655806737303bb624726eabaedfb72f07ed7a76ab3cb9a381c4b7dcd809b140d891f00213be401f58d6a06a61eadc3a9c2f1c6567285b09ae09342a66fa421eaf93adf7573a028c331d70601ab3af7cc84033ece7c772a3a5b86b0dbe9d777c3a48aa9801edcee2781589f44d9e4113979600576a99410ba81091259dad98c6c68ff784b8f020103a381fc3081f9301d0603551d0e04160414ca293caa8bc0ed3e542eef4205a2bff2b57e4d753081c90603551d230481c13081be8014ca293caa8bc0ed3e542eef4205a2bff2b57e4d75a1819aa48197308194310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e060355040b1307416e64726f69643110300e06035504031307416e64726f69643122302006092a864886f70d0109011613616e64726f696440616e64726f69642e636f6d820900f2b98e6123572c4e300c0603551d13040530030101ff300d06092a864886f70d0101040500038201010084de9516d5e4a87217a73da8487048f53373a5f733f390d61bdf3cc9e5251625bfcaa7c3159cae275d172a9ae1e876d5458127ac542f68290dd510c0029d8f51e0ee156b7b7b5acdb394241b8ec78b74e5c42c5cafae156caf5bd199a23a27524da072debbe378464a533630b0e4d0ffb7e08ecb701fadb6379c74467f6e00c6ed888595380792038756007872c8e3007af423a57a2cab3a282869b64c4b7bd5fc187d0a7e2415965d5aae4e07a6df751b4a75e9793c918a612b81cd0b628aee0168dc44e47b10d3593260849d6adf6d727dc24444c221d3f9ecc368cad07999f2b8105bc1f20d38d41066cc1411c257a96ea4349f5746565507e4e8020a1a81" -debug_testkey="308204a830820390a003020102020900936eacbe07f201df300d06092a864886f70d0101050500308194310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e060355040b1307416e64726f69643110300e06035504031307416e64726f69643122302006092a864886f70d0109011613616e64726f696440616e64726f69642e636f6d301e170d3038303232393031333334365a170d3335303731373031333334365a308194310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e060355040b1307416e64726f69643110300e06035504031307416e64726f69643122302006092a864886f70d0109011613616e64726f696440616e64726f69642e636f6d30820120300d06092a864886f70d01010105000382010d00308201080282010100d6931904dec60b24b1edc762e0d9d8253e3ecd6ceb1de2ff068ca8e8bca8cd6bd3786ea70aa76ce60ebb0f993559ffd93e77a943e7e83d4b64b8e4fea2d3e656f1e267a81bbfb230b578c20443be4c7218b846f5211586f038a14e89c2be387f8ebecf8fcac3da1ee330c9ea93d0a7c3dc4af350220d50080732e0809717ee6a053359e6a694ec2cb3f284a0a466c87a94d83b31093a67372e2f6412c06e6d42f15818dffe0381cc0cd444da6cddc3b82458194801b32564134fbfde98c9287748dbf5676a540d8154c8bbca07b9e247553311c46b9af76fdeeccc8e69e7c8a2d08e782620943f99727d3c04fe72991d99df9bae38a0b2177fa31d5b6afee91f020103a381fc3081f9301d0603551d0e04160414485900563d272c46ae118605a47419ac09ca8c113081c90603551d230481c13081be8014485900563d272c46ae118605a47419ac09ca8c11a1819aa48197308194310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e060355040b1307416e64726f69643110300e06035504031307416e64726f69643122302006092a864886f70d0109011613616e64726f696440616e64726f69642e636f6d820900936eacbe07f201df300c0603551d13040530030101ff300d06092a864886f70d010105050003820101007aaf968ceb50c441055118d0daabaf015b8a765a27a715a2c2b44f221415ffdace03095abfa42df70708726c2069e5c36eddae0400be29452c084bc27eb6a17eac9dbe182c204eb15311f455d824b656dbe4dc2240912d7586fe88951d01a8feb5ae5a4260535df83431052422468c36e22c2a5ef994d61dd7306ae4c9f6951ba3c12f1d1914ddc61f1a62da2df827f603fea5603b2c540dbd7c019c36bab29a4271c117df523cdbc5f3817a49e0efa60cbd7f74177e7a4f193d43f4220772666e4c4d83e1bd5a86087cf34f2dec21e245ca6c2bb016e683638050d2c430eea7c26a1c49d3760a58ab7f1a82cc938b4831384324bd0401fa12163a50570e684d" -patchrom_platform="308203e5308202cda003020102020900b8efb85271e7e740300d06092a864886f70d0101050500308188310b300906035504061302434e3110300e06035504080c074265696a696e673110300e06035504070c074265696a696e67310f300d060355040a0c065869616f6d69310d300b060355040b0c044d4955493111300f06035504030c085061746368526f6d3122302006092a864886f70d01090116137061746368726f6d407869616f6d692e636f6d301e170d3136303132303039303232365a170d3433303630373039303232365a308188310b300906035504061302434e3110300e06035504080c074265696a696e673110300e06035504070c074265696a696e67310f300d060355040a0c065869616f6d69310d300b060355040b0c044d4955493111300f06035504030c085061746368526f6d3122302006092a864886f70d01090116137061746368726f6d407869616f6d692e636f6d30820122300d06092a864886f70d01010105000382010f003082010a0282010100b85b306dc881873256284ea4c77a0b3b55f718afe3de21af829697ca4d348641b55ffb80abf13656c88c16606f0f439ae3d1edd62154bd58b17120b0a184493f9c1170003041f4b2b3e9bb61257f7de1499e8c35a606a81c70c305bd8ea325e4572871ec44e62666b30afb5ffc24148e4194e65478547cd13787284f83da5c6b50bd2223adc8b57e786fb1e49e52eba6a06bfa1c6b44b289a8d6d06906e22eb8a527fc123e1faf387548a026e785dbec5bd2dc207f3b2eef18b5a499f245cec19fa8623556caf1d5e41d5c3274d5413c2b1d4cf15eff297fc36894e80344769f6022afe5bf920f271091e438d98425e3953bedf9967ead1d0646e3967b65ed770203010001a350304e301d0603551d0e04160414a1e9aed0be13a7be6d1299f0f4b9993e53d30d8f301f0603551d23041830168014a1e9aed0be13a7be6d1299f0f4b9993e53d30d8f300c0603551d13040530030101ff300d06092a864886f70d010105050003820101009f3e79672817e5aa5202b5e6120b0f952c51dcc1d8b887271dc326e1ebc7cc33c13eab7f284e009ceea5345af916f4c9d2b7a12ef9eb46ee5c799c82664d744256656ad28815d90676b7d01fcbc1eddaf1dfc8d71472a73dc8ecaf630ccdf91a0ff4e624f8892443a2199ad85b0b037163416dd2207ba499efdb7c95193ed17dbef5875fb7ecfe45359ea57007724b0597d7aaf1e458d1f93a21ca10bd145f73c99e7d1208a5aab091b1f16446e329bd12440509711f2a58f40221dffa10a043a85481667516362931b00b1822851678323fef4596c83cc8f332fa3ff736ceb6b10cb1499a28cefb0c3a19157356adaabef7bd953caca1a7b402a8816951ed78" -patchrom_shared="308203e5308202cda003020102020900f716cbd07088bb40300d06092a864886f70d0101050500308188310b300906035504061302434e3110300e06035504080c074265696a696e673110300e06035504070c074265696a696e67310f300d060355040a0c065869616f6d69310d300b060355040b0c044d4955493111300f06035504030c085061746368526f6d3122302006092a864886f70d01090116137061746368726f6d407869616f6d692e636f6d301e170d3136303132303039303235375a170d3433303630373039303235375a308188310b300906035504061302434e3110300e06035504080c074265696a696e673110300e06035504070c074265696a696e67310f300d060355040a0c065869616f6d69310d300b060355040b0c044d4955493111300f06035504030c085061746368526f6d3122302006092a864886f70d01090116137061746368726f6d407869616f6d692e636f6d30820122300d06092a864886f70d01010105000382010f003082010a0282010100e293b3780f0da7a69fedd06f9922436b1f0fb4605d4287a0f62826d2db767febc4438cafb1addfe888f57cf9720f1fdf5bf9b8f342de1fbc31c8617aaa23c2b50fdb8d95b292798e8dee84a46a304224a9b80735f2abb966dc5b73c7e34693d00a0b9931aa87595ae35582c4d0ad6dd2eefc1372dd4cc776de7fb046e0c6af7867cb9366c73f8fbce9d7b186384e7b3c299217181677b0bc16d69cea6ac26bc5e8424faa4d3caa89e3fa31c822095e45a08697fcb13054c7f17de86e72b09e0e7be627c25a105b327bb0614eecfe37dcfd0b906930c4ab84eb051f430f493a43158bbf7bc0b474e0409378076cc8ea475b76e5f7ea2cb03194aa7184f5f3ce3b0203010001a350304e301d0603551d0e04160414b449dd6f51e3b354619a47dda7c897323ed723c0301f0603551d23041830168014b449dd6f51e3b354619a47dda7c897323ed723c0300c0603551d13040530030101ff300d06092a864886f70d01010505000382010100b2091ff1a0c23b0027d62101918225fad31d9d37e6bfcc126574324a23611a69f2450db2cc10fbdfd96448386d122a6f8b1b6685a9aa538abcbc659958d9038c5d53c2657bac65d951374716648eee9feab23e85c04bae366d9b8027d283f0e6389b03674a0e98a1859d8e2868be49ad199662c6fe0a98f43232c494622e70b74be77f077833464647d909ae5657b63ec58dbd5d91b6fe2be3981a58a6c8f24d04605a0fcbc86f4a298d9f32bef72fb8123f1a323ee3cd95601863ad07fd6e3ba52da120169eadff6b80ca653d730b94a58ae051682b7c9a8a6c06bd0efdd4a9f5d0320fa08419a749b20c66092bc5ee63864850435b381aac789e6be081cd49" -patchrom_media="308203e5308202cda003020102020900b87815ea377b5c04300d06092a864886f70d0101050500308188310b300906035504061302434e3110300e06035504080c074265696a696e673110300e06035504070c074265696a696e67310f300d060355040a0c065869616f6d69310d300b060355040b0c044d4955493111300f06035504030c085061746368526f6d3122302006092a864886f70d01090116137061746368726f6d407869616f6d692e636f6d301e170d3136303132303039303334325a170d3433303630373039303334325a308188310b300906035504061302434e3110300e06035504080c074265696a696e673110300e06035504070c074265696a696e67310f300d060355040a0c065869616f6d69310d300b060355040b0c044d4955493111300f06035504030c085061746368526f6d3122302006092a864886f70d01090116137061746368726f6d407869616f6d692e636f6d30820122300d06092a864886f70d01010105000382010f003082010a02820101009874294fb2f7fcc01605bc4183a001e0f2fc88b130b3b9531ef3a57ddece1628d26b999ba68969c4c575f56105bcfcc62fca5b6183b8fddc93258cb760edca1b71c4c04f492c985e653195bb0f8791304a82989b379d737cb9aaa14d602fe2bde3df68c909175e99673fbb1ecc2a53adf799f620fcd491ec92b42c779ca5460fca443ea777035ee0771c60945fe0ea2fb88be9b60f3e194053c4366887c9609b7891f3019aaa80129f933c3843013292b84d28041fef05852238a860fa33c955c83f139f646c864d7ddda0c57f6d7aa3f03163f401151a2b982b5c895e5fe1aeef47078b4269255070b600a28f4ac0ec8598e04525aa6939ee62459256ec91b90203010001a350304e301d0603551d0e04160414f6807b81a390e6098014f1722fa0aff1fae60240301f0603551d23041830168014f6807b81a390e6098014f1722fa0aff1fae60240300c0603551d13040530030101ff300d06092a864886f70d01010505000382010100658261e32cfe877b2821423285f404f4eeaecf81a3b0b7fb5d3e7b47e0b5ab79d96fc4a032ebb95dba82a04baa96c9780f81328033e405e72040c69733d47bf1bd5e27e07be3deb8fd94595dda580dbe6251a7dcc8e850f9ec85f64b884f0be0f0aac6e029c4f5d1ed857aa42ddbb7792d76b391dc451c8fe881e6dbbfd61c6482e8c1039b32c3afe03eb1fb213f1e629e329d568392e177c0c1dfd80a4171adfdeb346b9dcd1fbd2b24bf4925ac74c53367bf091772b861c4b90b108b759b2192cec83354a8f092bcdfc52b3051abaebc6cda7b1dd0c8f2c21493742dac4d4497b7ecbb2a83882fea9b6f23ce871f4df49f5cde7bd8480cd7a8a4ab8ba503c6" -patchrom_testkey="308203e5308202cda003020102020900eaf7ddf89372f4d4300d06092a864886f70d0101050500308188310b300906035504061302434e3110300e06035504080c074265696a696e673110300e06035504070c074265696a696e67310f300d060355040a0c065869616f6d69310d300b060355040b0c044d4955493111300f06035504030c085061746368526f6d3122302006092a864886f70d01090116137061746368726f6d407869616f6d692e636f6d301e170d3136303132303039303331385a170d3433303630373039303331385a308188310b300906035504061302434e3110300e06035504080c074265696a696e673110300e06035504070c074265696a696e67310f300d060355040a0c065869616f6d69310d300b060355040b0c044d4955493111300f06035504030c085061746368526f6d3122302006092a864886f70d01090116137061746368726f6d407869616f6d692e636f6d30820122300d06092a864886f70d01010105000382010f003082010a0282010100bc35fd9be394cdf0872674ce64a5377fe00739ab9a0719d8371aef6ab10e3efd871d735f0aee09eb4f64f50711f2b974ba7b47b61357782786e6a0ae73e26e965ba2032e73caadad5d21b47f0680b742d78c6526a5de33a6100ce0cc3ad6900115d654294f0c8b5a2f810883c7ece88e41eff55a8b0afbf7710bdf86d450fc433aaf46d38f6e1a97bf52a67857ade83b9047e9db23bdf13ceb98d093597d46cc4e495b1a0e2c07dd2e68f79ddbc0aa68f7c949a845ffef02971560cb50781f615f186e653ef39b8fe77ca85ddaeb7c61875830803d474604cf758049d3c47b68bc2aae91fd39ee9e546fb9afe6b5ac0811f80e9bb4f44f106504dc3fca0983910203010001a350304e301d0603551d0e04160414b8c84855c24ae06e1be97879f727f473db2e7b0c301f0603551d23041830168014b8c84855c24ae06e1be97879f727f473db2e7b0c300c0603551d13040530030101ff300d06092a864886f70d0101050500038201010020f9b9414f0fbfcbf3ab84bd327cb14d5f17fce0f4718cb78a5b2ded7f8b1b05dca9b59227deb342736995b1cfb51d19e602466f84d652b2614491485a8677e87283db3c315dae9784868862ec52c08eaa4860b6d1bf53f9e0d6c718f55580404923c7e30fbed93d98bacd53eb1fd05d69116e98cee4ee42f8eca3bad566c06b04a764a799f513531ae594ca7daf3f7c30a93ad859ce9f8b7ed97ab5575b322480215d2f7bcad419a1b742a042708bfba2c912072e9f1f9e0044a1405b4abc4c25291f660340d2cf30f37f06ddbc37345a8937093df9d75b81aa76f618791f162966721dc7830964b443cefaa8448ddba84199053710b2c99b8b8dcf7d965c42" -user_platform="@user_platform" -user_shared="@user_shared" -user_media="@user_media" -user_testkey="@user_testkey" - -/tmp/busybox sed -i "s/$debug_platform/$user_platform/g" /data/system/packages.xml -/tmp/busybox sed -i "s/$debug_shared/$user_shared/g" /data/system/packages.xml -/tmp/busybox sed -i "s/$debug_media/$user_media/g" /data/system/packages.xml -/tmp/busybox sed -i "s/$debug_testkey/$user_testkey/g" /data/system/packages.xml - -/tmp/busybox sed -i "s/$patchrom_platform/$user_platform/g" /data/system/packages.xml -/tmp/busybox sed -i "s/$patchrom_shared/$user_shared/g" /data/system/packages.xml -/tmp/busybox sed -i "s/$patchrom_media/$user_media/g" /data/system/packages.xml -/tmp/busybox sed -i "s/$patchrom_testkey/$user_testkey/g" /data/system/packages.xml diff --git a/target_files_template/OTA/bin/updater b/target_files_template/OTA/bin/updater index fe34944..57fffaf 100644 Binary files a/target_files_template/OTA/bin/updater and b/target_files_template/OTA/bin/updater differ diff --git a/uniq_first.py b/uniq_first.py index 11b6896..bbb3404 100755 --- a/uniq_first.py +++ b/uniq_first.py @@ -11,16 +11,30 @@ def uniq_first(src_file, dst_file): with open(dst_file, 'a') as df: for line in lines: - if not (line.split()[0] + " " in content): + if not (line.split()[0] in content): df.write(line) +def filter_miui(miui_file, filter_file, make_dir): + lines = [] + miui_apps = os.popen("make -C "+ make_dir + " miui-apps-included").read() + with open(miui_file, 'r') as mf: + lines = mf.readlines() + + with open(filter_file, 'w') as ff: + for line in lines: + if line.split(): + if (line.split()[0].split('"')[1] in miui_apps): + ff.write(line) + def main(args): - if len(args) != 2: - print("Usage: uniq_first src_file dst_file") + if len(args) != 3: + print("Usage: uniq_first src_file dst_file make_dir") sys.exit(1) - uniq_first(args[0], args[1]) - + filtered = args[1] + '.filter' + filter_miui(args[1], filtered, args[2]) + uniq_first(args[0], filtered) + os.rename(filtered, args[1]) if __name__ == '__main__': main(sys.argv[1:]) diff --git a/unpackbootimg b/unpackbootimg new file mode 100755 index 0000000..067cd63 Binary files /dev/null and b/unpackbootimg differ