* This is used by a lot of things, and the script removes the entire directory. That can cause issues with other things, that don't expect the root TMPDIR to go away, or some contents within it. * Let's use our own variable * You can still keep setting TMPDIR since mktemp respects that Change-Id: I6c71ce38bab781cd7a8d285499f127c2bf248eb8
1780 lines
60 KiB
Bash
1780 lines
60 KiB
Bash
#!/bin/bash
|
|
#
|
|
# Copyright (C) 2016 The CyanogenMod Project
|
|
# Copyright (C) 2017-2020 The LineageOS Project
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
#
|
|
|
|
PRODUCT_COPY_FILES_LIST=()
|
|
PRODUCT_COPY_FILES_HASHES=()
|
|
PRODUCT_COPY_FILES_FIXUP_HASHES=()
|
|
PRODUCT_PACKAGES_LIST=()
|
|
PRODUCT_PACKAGES_HASHES=()
|
|
PRODUCT_PACKAGES_FIXUP_HASHES=()
|
|
PACKAGE_LIST=()
|
|
VENDOR_STATE=-1
|
|
VENDOR_RADIO_STATE=-1
|
|
COMMON=-1
|
|
ARCHES=
|
|
FULLY_DEODEXED=-1
|
|
|
|
SKIP_CLEANUP=${SKIP_CLEANUP:-0}
|
|
EXTRACT_TMP_DIR=$(mktemp -d)
|
|
HOST="$(uname | tr '[:upper:]' '[:lower:]')"
|
|
|
|
#
|
|
# cleanup
|
|
#
|
|
# kill our tmpfiles with fire on exit
|
|
#
|
|
function cleanup() {
|
|
if [ "$SKIP_CLEANUP" == "true" ] || [ "$SKIP_CLEANUP" == "1" ]; then
|
|
echo "Skipping cleanup of $EXTRACT_TMP_DIR"
|
|
else
|
|
rm -rf "${EXTRACT_TMP_DIR:?}"
|
|
fi
|
|
}
|
|
|
|
trap cleanup 0
|
|
|
|
#
|
|
# setup_vendor_deps
|
|
#
|
|
# $1: Android root directory
|
|
# Sets up common dependencies for extraction
|
|
#
|
|
function setup_vendor_deps() {
|
|
export ANDROID_ROOT="$1"
|
|
if [ ! -d "$ANDROID_ROOT" ]; then
|
|
echo "\$ANDROID_ROOT must be set and valid before including this script!"
|
|
exit 1
|
|
fi
|
|
|
|
export BINARIES_LOCATION="$ANDROID_ROOT"/prebuilts/extract-tools/${HOST}-x86/bin
|
|
|
|
export SIMG2IMG="$BINARIES_LOCATION"/simg2img
|
|
export LPUNPACK="$BINARIES_LOCATION"/lpunpack
|
|
export SIGSCAN="$BINARIES_LOCATION"/SigScan
|
|
|
|
for version in 0_8 0_9; do
|
|
export PATCHELF_${version}="$BINARIES_LOCATION"/patchelf-"${version}"
|
|
done
|
|
|
|
if [ -z "$PATCHELF_VERSION" ]; then
|
|
export PATCHELF_VERSION=0_9
|
|
fi
|
|
|
|
if [ -z "$PATCHELF" ]; then
|
|
local patchelf_variable="PATCHELF_${PATCHELF_VERSION}"
|
|
export PATCHELF=${!patchelf_variable}
|
|
fi
|
|
}
|
|
|
|
#
|
|
# setup_vendor
|
|
#
|
|
# $1: device name
|
|
# $2: vendor name
|
|
# $3: Android root directory
|
|
# $4: is common device - optional, default to false
|
|
# $5: cleanup - optional, default to true
|
|
# $6: custom vendor makefile name - optional, default to false
|
|
#
|
|
# Must be called before any other functions can be used. This
|
|
# sets up the internal state for a new vendor configuration.
|
|
#
|
|
function setup_vendor() {
|
|
local DEVICE="$1"
|
|
if [ -z "$DEVICE" ]; then
|
|
echo "\$DEVICE must be set before including this script!"
|
|
exit 1
|
|
fi
|
|
|
|
export VENDOR="$2"
|
|
if [ -z "$VENDOR" ]; then
|
|
echo "\$VENDOR must be set before including this script!"
|
|
exit 1
|
|
fi
|
|
|
|
export ANDROID_ROOT="$3"
|
|
if [ ! -d "$ANDROID_ROOT" ]; then
|
|
echo "\$ANDROID_ROOT must be set and valid before including this script!"
|
|
exit 1
|
|
fi
|
|
|
|
export OUTDIR=vendor/"$VENDOR"/"$DEVICE"
|
|
if [ ! -d "$ANDROID_ROOT/$OUTDIR" ]; then
|
|
mkdir -p "$ANDROID_ROOT/$OUTDIR"
|
|
fi
|
|
|
|
VNDNAME="$6"
|
|
if [ -z "$VNDNAME" ]; then
|
|
VNDNAME="$DEVICE"
|
|
fi
|
|
|
|
export PRODUCTMK="$ANDROID_ROOT"/"$OUTDIR"/"$VNDNAME"-vendor.mk
|
|
export ANDROIDBP="$ANDROID_ROOT"/"$OUTDIR"/Android.bp
|
|
export ANDROIDMK="$ANDROID_ROOT"/"$OUTDIR"/Android.mk
|
|
export BOARDMK="$ANDROID_ROOT"/"$OUTDIR"/BoardConfigVendor.mk
|
|
|
|
if [ "$4" == "true" ] || [ "$4" == "1" ]; then
|
|
COMMON=1
|
|
else
|
|
COMMON=0
|
|
fi
|
|
|
|
if [ "$5" == "false" ] || [ "$5" == "0" ]; then
|
|
VENDOR_STATE=1
|
|
VENDOR_RADIO_STATE=1
|
|
else
|
|
VENDOR_STATE=0
|
|
VENDOR_RADIO_STATE=0
|
|
fi
|
|
|
|
setup_vendor_deps "$ANDROID_ROOT"
|
|
}
|
|
|
|
# Helper functions for parsing a spec.
|
|
# notes: an optional "|SHA1" that may appear in the format is stripped
|
|
# early from the spec in the parse_file_list function, and
|
|
# should not be present inside the input parameter passed
|
|
# to these functions.
|
|
|
|
#
|
|
# input: spec in the form of "src[:dst][;args]"
|
|
# output: "src"
|
|
#
|
|
function src_file() {
|
|
local SPEC="$1"
|
|
local SPLIT=(${SPEC//:/ })
|
|
local ARGS="$(target_args ${SPEC})"
|
|
# Regardless of there being a ":" delimiter or not in the spec,
|
|
# the source file is always either the first, or the only entry.
|
|
local SRC="${SPLIT[0]}"
|
|
# Remove target_args suffix, if present
|
|
echo "${SRC%;${ARGS}}"
|
|
}
|
|
|
|
#
|
|
# input: spec in the form of "src[:dst][;args]"
|
|
# output: "dst" if present, "src" otherwise.
|
|
#
|
|
function target_file() {
|
|
local SPEC="${1%%;*}"
|
|
local SPLIT=(${SPEC//:/ })
|
|
local ARGS="$(target_args ${SPEC})"
|
|
local DST=
|
|
case ${#SPLIT[@]} in
|
|
1)
|
|
# The spec doesn't have a : delimiter
|
|
DST="${SPLIT[0]}"
|
|
;;
|
|
*)
|
|
# The spec actually has a src:dst format
|
|
DST="${SPLIT[1]}"
|
|
;;
|
|
esac
|
|
# Remove target_args suffix, if present
|
|
echo "${DST%;${ARGS}}"
|
|
}
|
|
|
|
#
|
|
# input: spec in the form of "src[:dst][;args]"
|
|
# output: "args" if present, "" otherwise.
|
|
#
|
|
function target_args() {
|
|
local SPEC="$1"
|
|
local SPLIT=(${SPEC//;/ })
|
|
local ARGS=
|
|
case ${#SPLIT[@]} in
|
|
1)
|
|
# No ";" delimiter in the spec.
|
|
;;
|
|
*)
|
|
# The "args" are whatever comes after the ";" character.
|
|
# Basically the spec stripped of whatever is to the left of ";".
|
|
ARGS="${SPEC#${SPLIT[0]};}"
|
|
;;
|
|
esac
|
|
echo "${ARGS}"
|
|
}
|
|
|
|
#
|
|
# prefix_match:
|
|
#
|
|
# input:
|
|
# - $1: prefix
|
|
# - (global variable) PRODUCT_PACKAGES_LIST: array of [src:]dst[;args] specs.
|
|
# output:
|
|
# - new array consisting of dst[;args] entries where $1 is a prefix of ${dst}.
|
|
#
|
|
function prefix_match() {
|
|
local PREFIX="$1"
|
|
for LINE in "${PRODUCT_PACKAGES_LIST[@]}"; do
|
|
local FILE=$(target_file "$LINE")
|
|
if [[ "$FILE" =~ ^"$PREFIX" ]]; then
|
|
local ARGS=$(target_args "$LINE")
|
|
if [ -z "${ARGS}" ]; then
|
|
echo "${FILE#$PREFIX}"
|
|
else
|
|
echo "${FILE#$PREFIX};${ARGS}"
|
|
fi
|
|
fi
|
|
done
|
|
}
|
|
|
|
#
|
|
# prefix_match_file:
|
|
#
|
|
# $1: the prefix to match on
|
|
# $2: the file to match the prefix for
|
|
#
|
|
# Internal function which returns true if a filename contains the
|
|
# specified prefix.
|
|
#
|
|
function prefix_match_file() {
|
|
local PREFIX="$1"
|
|
local FILE="$2"
|
|
if [[ "$FILE" =~ ^"$PREFIX" ]]; then
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
#
|
|
# suffix_match_file:
|
|
#
|
|
# $1: the suffix to match on
|
|
# $2: the file to match the suffix for
|
|
#
|
|
# Internal function which returns true if a filename contains the
|
|
# specified suffix.
|
|
#
|
|
function suffix_match_file() {
|
|
local SUFFIX="$1"
|
|
local FILE="$2"
|
|
if [[ "$FILE" = *"$SUFFIX" ]]; then
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
#
|
|
# truncate_file
|
|
#
|
|
# $1: the filename to truncate
|
|
# $2: the argument to output the truncated filename to
|
|
#
|
|
# Internal function which truncates a filename by removing the first dir
|
|
# in the path. ex. vendor/lib/libsdmextension.so -> lib/libsdmextension.so
|
|
#
|
|
function truncate_file() {
|
|
local FILE="$1"
|
|
RETURN_FILE="$2"
|
|
local FIND="${FILE%%/*}"
|
|
local LOCATION="${#FIND}+1"
|
|
echo ${FILE:$LOCATION}
|
|
}
|
|
|
|
#
|
|
# write_product_copy_files:
|
|
#
|
|
# $1: make treble compatible makefile - optional and deprecated, default to true
|
|
#
|
|
# Creates the PRODUCT_COPY_FILES section in the product makefile for all
|
|
# items in the list which do not start with a dash (-).
|
|
#
|
|
function write_product_copy_files() {
|
|
local COUNT=${#PRODUCT_COPY_FILES_LIST[@]}
|
|
local TARGET=
|
|
local FILE=
|
|
local LINEEND=
|
|
local TREBLE_COMPAT=$1
|
|
|
|
if [ "$COUNT" -eq "0" ]; then
|
|
return 0
|
|
fi
|
|
|
|
printf '%s\n' "PRODUCT_COPY_FILES += \\" >> "$PRODUCTMK"
|
|
for (( i=1; i<COUNT+1; i++ )); do
|
|
FILE="${PRODUCT_COPY_FILES_LIST[$i-1]}"
|
|
LINEEND=" \\"
|
|
if [ "$i" -eq "$COUNT" ]; then
|
|
LINEEND=""
|
|
fi
|
|
|
|
TARGET=$(target_file "$FILE")
|
|
if prefix_match_file "product/" $TARGET ; then
|
|
local OUTTARGET=$(truncate_file $TARGET)
|
|
printf ' %s/proprietary/%s:$(TARGET_COPY_OUT_PRODUCT)/%s%s\n' \
|
|
"$OUTDIR" "$TARGET" "$OUTTARGET" "$LINEEND" >> "$PRODUCTMK"
|
|
elif prefix_match_file "system/product/" $TARGET ; then
|
|
local OUTTARGET=$(truncate_file $TARGET)
|
|
printf ' %s/proprietary/%s:$(TARGET_COPY_OUT_PRODUCT)/%s%s\n' \
|
|
"$OUTDIR" "$TARGET" "$OUTTARGET" "$LINEEND" >> "$PRODUCTMK"
|
|
elif prefix_match_file "system_ext/" $TARGET ; then
|
|
local OUTTARGET=$(truncate_file $TARGET)
|
|
printf ' %s/proprietary/%s:$(TARGET_COPY_OUT_SYSTEM_EXT)/%s%s\n' \
|
|
"$OUTDIR" "$TARGET" "$OUTTARGET" "$LINEEND" >> "$PRODUCTMK"
|
|
elif prefix_match_file "system/system_ext/" $TARGET ; then
|
|
local OUTTARGET=$(truncate_file $TARGET)
|
|
printf ' %s/proprietary/%s:$(TARGET_COPY_OUT_SYSTEM_EXT)/%s%s\n' \
|
|
"$OUTDIR" "$TARGET" "$OUTTARGET" "$LINEEND" >> "$PRODUCTMK"
|
|
elif prefix_match_file "odm/" $TARGET ; then
|
|
local OUTTARGET=$(truncate_file $TARGET)
|
|
printf ' %s/proprietary/%s:$(TARGET_COPY_OUT_ODM)/%s%s\n' \
|
|
"$OUTDIR" "$TARGET" "$OUTTARGET" "$LINEEND" >> "$PRODUCTMK"
|
|
elif prefix_match_file "vendor/odm/" $TARGET ; then
|
|
local OUTTARGET=$(truncate_file $TARGET)
|
|
printf ' %s/proprietary/%s:$(TARGET_COPY_OUT_ODM)/%s%s\n' \
|
|
"$OUTDIR" "$TARGET" "$OUTTARGET" "$LINEEND" >> "$PRODUCTMK"
|
|
elif prefix_match_file "system/vendor/odm/" $TARGET ; then
|
|
local OUTTARGET=$(truncate_file $TARGET)
|
|
printf ' %s/proprietary/%s:$(TARGET_COPY_OUT_ODM)/%s%s\n' \
|
|
"$OUTDIR" "$TARGET" "$OUTTARGET" "$LINEEND" >> "$PRODUCTMK"
|
|
elif prefix_match_file "vendor/" $TARGET ; then
|
|
local OUTTARGET=$(truncate_file $TARGET)
|
|
printf ' %s/proprietary/%s:$(TARGET_COPY_OUT_VENDOR)/%s%s\n' \
|
|
"$OUTDIR" "$TARGET" "$OUTTARGET" "$LINEEND" >> "$PRODUCTMK"
|
|
elif prefix_match_file "vendor_dlkm/" $TARGET ; then
|
|
local OUTTARGET=$(truncate_file $TARGET)
|
|
printf ' %s/proprietary/%s:$(TARGET_COPY_OUT_VENDOR_DLKM)/%s%s\n' \
|
|
"$OUTDIR" "$TARGET" "$OUTTARGET" "$LINEEND" >> "$PRODUCTMK"
|
|
elif prefix_match_file "system/vendor/" $TARGET ; then
|
|
local OUTTARGET=$(truncate_file $TARGET)
|
|
printf ' %s/proprietary/%s:$(TARGET_COPY_OUT_VENDOR)/%s%s\n' \
|
|
"$OUTDIR" "$TARGET" "$OUTTARGET" "$LINEEND" >> "$PRODUCTMK"
|
|
elif prefix_match_file "system/" $TARGET ; then
|
|
local OUTTARGET=$(truncate_file $TARGET)
|
|
printf ' %s/proprietary/%s:$(TARGET_COPY_OUT_SYSTEM)/%s%s\n' \
|
|
"$OUTDIR" "$TARGET" "$OUTTARGET" "$LINEEND" >> "$PRODUCTMK"
|
|
elif prefix_match_file "recovery/" $TARGET ; then
|
|
local OUTTARGET=$(truncate_file $TARGET)
|
|
printf ' %s/proprietary/%s:$(TARGET_COPY_OUT_RECOVERY)/%s%s\n' \
|
|
"$OUTDIR" "$TARGET" "$OUTTARGET" "$LINEEND" >> "$PRODUCTMK"
|
|
elif prefix_match_file "vendor_ramdisk/" $TARGET ; then
|
|
local OUTTARGET=$(truncate_file $TARGET)
|
|
printf ' %s/proprietary/%s:$(TARGET_COPY_OUT_VENDOR_RAMDISK)/%s%s\n' \
|
|
"$OUTDIR" "$TARGET" "$OUTTARGET" "$LINEEND" >> "$PRODUCTMK"
|
|
else
|
|
printf ' %s/proprietary/%s:$(TARGET_COPY_OUT_SYSTEM)/%s%s\n' \
|
|
"$OUTDIR" "$TARGET" "$TARGET" "$LINEEND" >> "$PRODUCTMK"
|
|
fi
|
|
done
|
|
return 0
|
|
}
|
|
|
|
#
|
|
# write_blueprint_packages:
|
|
#
|
|
# $1: The LOCAL_MODULE_CLASS for the given module list
|
|
# $2: /system, /odm, /product, /system_ext, or /vendor partition
|
|
# $3: type-specific extra flags
|
|
# $4: Name of the array holding the target list
|
|
#
|
|
# Internal function which writes out the BUILD_PREBUILT stanzas
|
|
# for all modules in the list. This is called by write_product_packages
|
|
# after the modules are categorized.
|
|
#
|
|
function write_blueprint_packages() {
|
|
|
|
local CLASS="$1"
|
|
local PARTITION="$2"
|
|
local EXTRA="$3"
|
|
|
|
# Yes, this is a horrible hack - we create a new array using indirection
|
|
local ARR_NAME="$4[@]"
|
|
local FILELIST=("${!ARR_NAME}")
|
|
|
|
local FILE=
|
|
local ARGS=
|
|
local BASENAME=
|
|
local EXTENSION=
|
|
local PKGNAME=
|
|
local SRC=
|
|
local STEM=
|
|
local OVERRIDEPKG=
|
|
|
|
for P in "${FILELIST[@]}"; do
|
|
FILE=$(target_file "$P")
|
|
ARGS=$(target_args "$P")
|
|
ARGS=(${ARGS//;/ })
|
|
|
|
BASENAME=$(basename "$FILE")
|
|
DIRNAME=$(dirname "$FILE")
|
|
EXTENSION=${BASENAME##*.}
|
|
PKGNAME=${BASENAME%.*}
|
|
|
|
if [ "$CLASS" = "EXECUTABLES" ] && [ "$EXTENSION" != "sh" ]; then
|
|
PKGNAME="$BASENAME"
|
|
EXTENSION=""
|
|
fi
|
|
|
|
# Allow overriding module name
|
|
STEM=
|
|
for ARG in "${ARGS[@]}"; do
|
|
if [[ "$ARG" =~ "MODULE" ]]; then
|
|
STEM="$PKGNAME"
|
|
PKGNAME=${ARG#*=}
|
|
fi
|
|
done
|
|
|
|
# Add to final package list
|
|
PACKAGE_LIST+=("$PKGNAME")
|
|
|
|
SRC="proprietary"
|
|
if [ "$PARTITION" = "system" ]; then
|
|
SRC+="/system"
|
|
elif [ "$PARTITION" = "vendor" ]; then
|
|
SRC+="/vendor"
|
|
elif [ "$PARTITION" = "product" ]; then
|
|
SRC+="/product"
|
|
elif [ "$PARTITION" = "system_ext" ]; then
|
|
SRC+="/system_ext"
|
|
elif [ "$PARTITION" = "odm" ]; then
|
|
SRC+="/odm"
|
|
fi
|
|
|
|
if [ "$CLASS" = "SHARED_LIBRARIES" ]; then
|
|
printf 'cc_prebuilt_library_shared {\n'
|
|
printf '\tname: "%s",\n' "$PKGNAME"
|
|
if [ ! -z "$STEM" ]; then
|
|
printf '\tstem: "%s",\n' "$STEM"
|
|
fi
|
|
printf '\towner: "%s",\n' "$VENDOR"
|
|
printf '\tstrip: {\n'
|
|
printf '\t\tnone: true,\n'
|
|
printf '\t},\n'
|
|
printf '\ttarget: {\n'
|
|
if [ "$EXTRA" = "both" ]; then
|
|
printf '\t\tandroid_arm: {\n'
|
|
printf '\t\t\tsrcs: ["%s/lib/%s"],\n' "$SRC" "$FILE"
|
|
printf '\t\t},\n'
|
|
printf '\t\tandroid_arm64: {\n'
|
|
printf '\t\t\tsrcs: ["%s/lib64/%s"],\n' "$SRC" "$FILE"
|
|
printf '\t\t},\n'
|
|
elif [ "$EXTRA" = "64" ]; then
|
|
printf '\t\tandroid_arm64: {\n'
|
|
printf '\t\t\tsrcs: ["%s/lib64/%s"],\n' "$SRC" "$FILE"
|
|
printf '\t\t},\n'
|
|
else
|
|
printf '\t\tandroid_arm: {\n'
|
|
printf '\t\t\tsrcs: ["%s/lib/%s"],\n' "$SRC" "$FILE"
|
|
printf '\t\t},\n'
|
|
fi
|
|
printf '\t},\n'
|
|
if [ "$EXTRA" != "none" ]; then
|
|
printf '\tcompile_multilib: "%s",\n' "$EXTRA"
|
|
fi
|
|
printf '\tcheck_elf_files: false,\n'
|
|
elif [ "$CLASS" = "APEX" ]; then
|
|
printf 'prebuilt_apex {\n'
|
|
printf '\tname: "%s",\n' "$PKGNAME"
|
|
printf '\towner: "%s",\n' "$VENDOR"
|
|
SRC="$SRC/apex"
|
|
printf '\tsrc: "%s/%s",\n' "$SRC" "$FILE"
|
|
printf '\tfilename: "%s",\n' "$FILE"
|
|
elif [ "$CLASS" = "APPS" ]; then
|
|
printf 'android_app_import {\n'
|
|
printf '\tname: "%s",\n' "$PKGNAME"
|
|
printf '\towner: "%s",\n' "$VENDOR"
|
|
if [ "$EXTRA" = "priv-app" ]; then
|
|
SRC="$SRC/priv-app"
|
|
else
|
|
SRC="$SRC/app"
|
|
fi
|
|
printf '\tapk: "%s/%s",\n' "$SRC" "$FILE"
|
|
USE_PLATFORM_CERTIFICATE="true"
|
|
for ARG in "${ARGS[@]}"; do
|
|
if [ "$ARG" = "PRESIGNED" ]; then
|
|
USE_PLATFORM_CERTIFICATE="false"
|
|
printf '\tpresigned: true,\n'
|
|
elif [[ "$ARG" =~ "OVERRIDES" ]]; then
|
|
OVERRIDEPKG=${ARG#*=}
|
|
OVERRIDEPKG=${OVERRIDEPKG//,/\", \"}
|
|
printf '\toverrides: ["%s"],\n' "$OVERRIDEPKG"
|
|
elif [ ! -z "$ARG" ]; then
|
|
USE_PLATFORM_CERTIFICATE="false"
|
|
printf '\tcertificate: "%s",\n' "$ARG"
|
|
fi
|
|
done
|
|
if [ "$USE_PLATFORM_CERTIFICATE" = "true" ]; then
|
|
printf '\tcertificate: "platform",\n'
|
|
fi
|
|
elif [ "$CLASS" = "JAVA_LIBRARIES" ]; then
|
|
printf 'dex_import {\n'
|
|
printf '\tname: "%s",\n' "$PKGNAME"
|
|
printf '\towner: "%s",\n' "$VENDOR"
|
|
printf '\tjars: ["%s/framework/%s"],\n' "$SRC" "$FILE"
|
|
elif [ "$CLASS" = "ETC" ]; then
|
|
if [ "$EXTENSION" = "xml" ]; then
|
|
printf 'prebuilt_etc_xml {\n'
|
|
else
|
|
printf 'prebuilt_etc {\n'
|
|
fi
|
|
printf '\tname: "%s",\n' "$PKGNAME"
|
|
printf '\towner: "%s",\n' "$VENDOR"
|
|
printf '\tsrc: "%s/etc/%s",\n' "$SRC" "$FILE"
|
|
printf '\tfilename_from_src: true,\n'
|
|
elif [ "$CLASS" = "EXECUTABLES" ]; then
|
|
if [ "$EXTENSION" = "sh" ]; then
|
|
printf 'sh_binary {\n'
|
|
else
|
|
printf 'cc_prebuilt_binary {\n'
|
|
fi
|
|
printf '\tname: "%s",\n' "$PKGNAME"
|
|
printf '\towner: "%s",\n' "$VENDOR"
|
|
if [ "$EXTENSION" != "sh" ]; then
|
|
printf '\tsrcs: ["%s/bin/%s"],\n' "$SRC" "$FILE"
|
|
printf '\tcheck_elf_files: false,\n'
|
|
printf '\tstrip: {\n'
|
|
printf '\t\tnone: true,\n'
|
|
printf '\t},\n'
|
|
printf '\tprefer: true,\n'
|
|
else
|
|
printf '\tsrc: "%s/bin/%s",\n' "$SRC" "$FILE"
|
|
fi
|
|
unset EXTENSION
|
|
else
|
|
printf '\tsrcs: ["%s/%s"],\n' "$SRC" "$FILE"
|
|
fi
|
|
if [ "$CLASS" = "APPS" ]; then
|
|
printf '\tdex_preopt: {\n'
|
|
printf '\t\tenabled: false,\n'
|
|
printf '\t},\n'
|
|
fi
|
|
if [ "$CLASS" = "SHARED_LIBRARIES" ] || [ "$CLASS" = "EXECUTABLES" ] ; then
|
|
if [ "$DIRNAME" != "." ]; then
|
|
printf '\trelative_install_path: "%s",\n' "$DIRNAME"
|
|
fi
|
|
fi
|
|
if [ "$CLASS" = "ETC" ] ; then
|
|
if [ "$DIRNAME" != "." ]; then
|
|
printf '\tsub_dir: "%s",\n' "$DIRNAME"
|
|
fi
|
|
fi
|
|
if [ "$CLASS" = "SHARED_LIBRARIES" ]; then
|
|
printf '\tprefer: true,\n'
|
|
fi
|
|
if [ "$EXTRA" = "priv-app" ]; then
|
|
printf '\tprivileged: true,\n'
|
|
fi
|
|
if [ "$PARTITION" = "vendor" ]; then
|
|
printf '\tsoc_specific: true,\n'
|
|
elif [ "$PARTITION" = "product" ]; then
|
|
printf '\tproduct_specific: true,\n'
|
|
elif [ "$PARTITION" = "system_ext" ]; then
|
|
printf '\tsystem_ext_specific: true,\n'
|
|
elif [ "$PARTITION" = "odm" ]; then
|
|
printf '\tdevice_specific: true,\n'
|
|
fi
|
|
printf '}\n\n'
|
|
done
|
|
}
|
|
|
|
#
|
|
# write_product_packages:
|
|
#
|
|
# This function will create prebuilt entries in the
|
|
# Android.bp and associated PRODUCT_PACKAGES list in the
|
|
# product makefile for all files in the blob list which
|
|
# start with a single dash (-) character.
|
|
#
|
|
function write_product_packages() {
|
|
PACKAGE_LIST=()
|
|
|
|
# Sort the package list for comm
|
|
PRODUCT_PACKAGES_LIST=($( printf '%s\n' "${PRODUCT_PACKAGES_LIST[@]}" | LC_ALL=C sort))
|
|
|
|
local COUNT=${#PRODUCT_PACKAGES_LIST[@]}
|
|
|
|
if [ "$COUNT" = "0" ]; then
|
|
return 0
|
|
fi
|
|
|
|
# Figure out what's 32-bit, what's 64-bit, and what's multilib
|
|
# I really should not be doing this in bash due to shitty array passing :(
|
|
local T_LIB32=( $(prefix_match "lib/") )
|
|
local T_LIB64=( $(prefix_match "lib64/") )
|
|
local MULTILIBS=( $(LC_ALL=C comm -12 <(printf '%s\n' "${T_LIB32[@]}") <(printf '%s\n' "${T_LIB64[@]}")) )
|
|
local LIB32=( $(LC_ALL=C comm -23 <(printf '%s\n' "${T_LIB32[@]}") <(printf '%s\n' "${MULTILIBS[@]}")) )
|
|
local LIB64=( $(LC_ALL=C comm -23 <(printf '%s\n' "${T_LIB64[@]}") <(printf '%s\n' "${MULTILIBS[@]}")) )
|
|
|
|
if [ "${#MULTILIBS[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "SHARED_LIBRARIES" "" "both" "MULTILIBS" >> "$ANDROIDBP"
|
|
fi
|
|
if [ "${#LIB32[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "SHARED_LIBRARIES" "" "32" "LIB32" >> "$ANDROIDBP"
|
|
fi
|
|
if [ "${#LIB64[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "SHARED_LIBRARIES" "" "64" "LIB64" >> "$ANDROIDBP"
|
|
fi
|
|
|
|
local T_S_LIB32=( $(prefix_match "system/lib/") )
|
|
local T_S_LIB64=( $(prefix_match "system/lib64/") )
|
|
local S_MULTILIBS=( $(LC_ALL=C comm -12 <(printf '%s\n' "${T_S_LIB32[@]}") <(printf '%s\n' "${T_S_LIB64[@]}")) )
|
|
local S_LIB32=( $(LC_ALL=C comm -23 <(printf '%s\n' "${T_S_LIB32[@]}") <(printf '%s\n' "${S_MULTILIBS[@]}")) )
|
|
local S_LIB64=( $(LC_ALL=C comm -23 <(printf '%s\n' "${T_S_LIB64[@]}") <(printf '%s\n' "${S_MULTILIBS[@]}")) )
|
|
|
|
if [ "${#S_MULTILIBS[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "SHARED_LIBRARIES" "system" "both" "S_MULTILIBS" >> "$ANDROIDBP"
|
|
fi
|
|
if [ "${#S_LIB32[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "SHARED_LIBRARIES" "system" "32" "S_LIB32" >> "$ANDROIDBP"
|
|
fi
|
|
if [ "${#S_LIB64[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "SHARED_LIBRARIES" "system" "64" "S_LIB64" >> "$ANDROIDBP"
|
|
fi
|
|
|
|
local T_V_LIB32=( $(prefix_match "vendor/lib/") )
|
|
local T_V_LIB64=( $(prefix_match "vendor/lib64/") )
|
|
local V_MULTILIBS=( $(LC_ALL=C comm -12 <(printf '%s\n' "${T_V_LIB32[@]}") <(printf '%s\n' "${T_V_LIB64[@]}")) )
|
|
local V_LIB32=( $(LC_ALL=C comm -23 <(printf '%s\n' "${T_V_LIB32[@]}") <(printf '%s\n' "${V_MULTILIBS[@]}")) )
|
|
local V_LIB64=( $(LC_ALL=C comm -23 <(printf '%s\n' "${T_V_LIB64[@]}") <(printf '%s\n' "${V_MULTILIBS[@]}")) )
|
|
|
|
if [ "${#V_MULTILIBS[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "SHARED_LIBRARIES" "vendor" "both" "V_MULTILIBS" >> "$ANDROIDBP"
|
|
fi
|
|
if [ "${#V_LIB32[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "SHARED_LIBRARIES" "vendor" "32" "V_LIB32" >> "$ANDROIDBP"
|
|
fi
|
|
if [ "${#V_LIB64[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "SHARED_LIBRARIES" "vendor" "64" "V_LIB64" >> "$ANDROIDBP"
|
|
fi
|
|
|
|
local T_P_LIB32=( $(prefix_match "product/lib/") )
|
|
local T_P_LIB64=( $(prefix_match "product/lib64/") )
|
|
local P_MULTILIBS=( $(LC_ALL=C comm -12 <(printf '%s\n' "${T_P_LIB32[@]}") <(printf '%s\n' "${T_P_LIB64[@]}")) )
|
|
local P_LIB32=( $(LC_ALL=C comm -23 <(printf '%s\n' "${T_P_LIB32[@]}") <(printf '%s\n' "${P_MULTILIBS[@]}")) )
|
|
local P_LIB64=( $(LC_ALL=C comm -23 <(printf '%s\n' "${T_P_LIB64[@]}") <(printf '%s\n' "${P_MULTILIBS[@]}")) )
|
|
|
|
if [ "${#P_MULTILIBS[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "SHARED_LIBRARIES" "product" "both" "P_MULTILIBS" >> "$ANDROIDBP"
|
|
fi
|
|
if [ "${#P_LIB32[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "SHARED_LIBRARIES" "product" "32" "P_LIB32" >> "$ANDROIDBP"
|
|
fi
|
|
if [ "${#P_LIB64[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "SHARED_LIBRARIES" "product" "64" "P_LIB64" >> "$ANDROIDBP"
|
|
fi
|
|
|
|
local T_SE_LIB32=( $(prefix_match "system_ext/lib/") )
|
|
local T_SE_LIB64=( $(prefix_match "system_ext/lib64/") )
|
|
local SE_MULTILIBS=( $(LC_ALL=C comm -12 <(printf '%s\n' "${T_SE_LIB32[@]}") <(printf '%s\n' "${T_SE_LIB64[@]}")) )
|
|
local SE_LIB32=( $(LC_ALL=C comm -23 <(printf '%s\n' "${T_SE_LIB32[@]}") <(printf '%s\n' "${SE_MULTILIBS[@]}")) )
|
|
local SE_LIB64=( $(LC_ALL=C comm -23 <(printf '%s\n' "${T_SE_LIB64[@]}") <(printf '%s\n' "${SE_MULTILIBS[@]}")) )
|
|
|
|
if [ "${#SE_MULTILIBS[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "SHARED_LIBRARIES" "system_ext" "both" "SE_MULTILIBS" >> "$ANDROIDBP"
|
|
fi
|
|
if [ "${#SE_LIB32[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "SHARED_LIBRARIES" "system_ext" "32" "SE_LIB32" >> "$ANDROIDBP"
|
|
fi
|
|
if [ "${#SE_LIB64[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "SHARED_LIBRARIES" "system_ext" "64" "SE_LIB64" >> "$ANDROIDBP"
|
|
fi
|
|
|
|
local T_O_LIB32=( $(prefix_match "odm/lib/") )
|
|
local T_O_LIB64=( $(prefix_match "odm/lib64/") )
|
|
local O_MULTILIBS=( $(LC_ALL=C comm -12 <(printf '%s\n' "${T_O_LIB32[@]}") <(printf '%s\n' "${T_O_LIB64[@]}")) )
|
|
local O_LIB32=( $(LC_ALL=C comm -23 <(printf '%s\n' "${T_O_LIB32[@]}") <(printf '%s\n' "${O_MULTILIBS[@]}")) )
|
|
local O_LIB64=( $(LC_ALL=C comm -23 <(printf '%s\n' "${T_O_LIB64[@]}") <(printf '%s\n' "${O_MULTILIBS[@]}")) )
|
|
|
|
if [ "${#O_MULTILIBS[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "SHARED_LIBRARIES" "odm" "both" "O_MULTILIBS" >> "$ANDROIDBP"
|
|
fi
|
|
if [ "${#O_LIB32[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "SHARED_LIBRARIES" "odm" "32" "O_LIB32" >> "$ANDROIDBP"
|
|
fi
|
|
if [ "${#O_LIB64[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "SHARED_LIBRARIES" "odm" "64" "O_LIB64" >> "$ANDROIDBP"
|
|
fi
|
|
|
|
# APEX
|
|
local APEX=( $(prefix_match "apex/") )
|
|
if [ "${#APEX[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "APEX" "" "" "APEX" >> "$ANDROIDBP"
|
|
fi
|
|
local S_APEX=( $(prefix_match "system/apex/") )
|
|
if [ "${#S_APEX[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "APEX" "system" "" "S_APEX" >> "$ANDROIDBP"
|
|
fi
|
|
local V_APEX=( $(prefix_match "vendor/apex/") )
|
|
if [ "${#V_APEX[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "APEX" "vendor" "" "V_APEX" >> "$ANDROIDBP"
|
|
fi
|
|
local SE_APEX=( $(prefix_match "system_ext/apex/") )
|
|
if [ "${#SE_APEX[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "APEX" "system_ext" "" "SE_APEX" >> "$ANDROIDBP"
|
|
fi
|
|
|
|
# Apps
|
|
local APPS=( $(prefix_match "app/") )
|
|
if [ "${#APPS[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "APPS" "" "" "APPS" >> "$ANDROIDBP"
|
|
fi
|
|
local PRIV_APPS=( $(prefix_match "priv-app/") )
|
|
if [ "${#PRIV_APPS[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "APPS" "" "priv-app" "PRIV_APPS" >> "$ANDROIDBP"
|
|
fi
|
|
local S_APPS=( $(prefix_match "system/app/") )
|
|
if [ "${#S_APPS[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "APPS" "system" "" "S_APPS" >> "$ANDROIDBP"
|
|
fi
|
|
local S_PRIV_APPS=( $(prefix_match "system/priv-app/") )
|
|
if [ "${#S_PRIV_APPS[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "APPS" "system" "priv-app" "S_PRIV_APPS" >> "$ANDROIDBP"
|
|
fi
|
|
local V_APPS=( $(prefix_match "vendor/app/") )
|
|
if [ "${#V_APPS[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "APPS" "vendor" "" "V_APPS" >> "$ANDROIDBP"
|
|
fi
|
|
local V_PRIV_APPS=( $(prefix_match "vendor/priv-app/") )
|
|
if [ "${#V_PRIV_APPS[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "APPS" "vendor" "priv-app" "V_PRIV_APPS" >> "$ANDROIDBP"
|
|
fi
|
|
local P_APPS=( $(prefix_match "product/app/") )
|
|
if [ "${#P_APPS[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "APPS" "product" "" "P_APPS" >> "$ANDROIDBP"
|
|
fi
|
|
local P_PRIV_APPS=( $(prefix_match "product/priv-app/") )
|
|
if [ "${#P_PRIV_APPS[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "APPS" "product" "priv-app" "P_PRIV_APPS" >> "$ANDROIDBP"
|
|
fi
|
|
local SE_APPS=( $(prefix_match "system_ext/app/") )
|
|
if [ "${#SE_APPS[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "APPS" "system_ext" "" "SE_APPS" >> "$ANDROIDBP"
|
|
fi
|
|
local SE_PRIV_APPS=( $(prefix_match "system_ext/priv-app/") )
|
|
if [ "${#SE_PRIV_APPS[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "APPS" "system_ext" "priv-app" "SE_PRIV_APPS" >> "$ANDROIDBP"
|
|
fi
|
|
local O_APPS=( $(prefix_match "odm/app/") )
|
|
if [ "${#O_APPS[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "APPS" "odm" "" "O_APPS" >> "$ANDROIDBP"
|
|
fi
|
|
local O_PRIV_APPS=( $(prefix_match "odm/priv-app/") )
|
|
if [ "${#O_PRIV_APPS[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "APPS" "odm" "priv-app" "O_PRIV_APPS" >> "$ANDROIDBP"
|
|
fi
|
|
|
|
# Framework
|
|
local FRAMEWORK=( $(prefix_match "framework/") )
|
|
if [ "${#FRAMEWORK[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "JAVA_LIBRARIES" "" "" "FRAMEWORK" >> "$ANDROIDBP"
|
|
fi
|
|
local S_FRAMEWORK=( $(prefix_match "system/framework/") )
|
|
if [ "${#S_FRAMEWORK[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "JAVA_LIBRARIES" "system" "" "S_FRAMEWORK" >> "$ANDROIDBP"
|
|
fi
|
|
local V_FRAMEWORK=( $(prefix_match "vendor/framework/") )
|
|
if [ "${#V_FRAMEWORK[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "JAVA_LIBRARIES" "vendor" "" "V_FRAMEWORK" >> "$ANDROIDBP"
|
|
fi
|
|
local P_FRAMEWORK=( $(prefix_match "product/framework/") )
|
|
if [ "${#P_FRAMEWORK[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "JAVA_LIBRARIES" "product" "" "P_FRAMEWORK" >> "$ANDROIDBP"
|
|
fi
|
|
local SE_FRAMEWORK=( $(prefix_match "system_ext/framework/") )
|
|
if [ "${#SE_FRAMEWORK[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "JAVA_LIBRARIES" "system_ext" "" "SE_FRAMEWORK" >> "$ANDROIDBP"
|
|
fi
|
|
local O_FRAMEWORK=( $(prefix_match "odm/framework/") )
|
|
if [ "${#O_FRAMEWORK[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "JAVA_LIBRARIES" "odm" "" "O_FRAMEWORK" >> "$ANDROIDBP"
|
|
fi
|
|
|
|
# Etc
|
|
local ETC=( $(prefix_match "etc/") )
|
|
if [ "${#ETC[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "ETC" "" "" "ETC" >> "$ANDROIDBP"
|
|
fi
|
|
local S_ETC=( $(prefix_match "system/etc/") )
|
|
if [ "${#S_ETC[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "ETC" "system" "" "S_ETC" >> "$ANDROIDBP"
|
|
fi
|
|
local V_ETC=( $(prefix_match "vendor/etc/") )
|
|
if [ "${#V_ETC[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "ETC" "vendor" "" "V_ETC" >> "$ANDROIDBP"
|
|
fi
|
|
local P_ETC=( $(prefix_match "product/etc/") )
|
|
if [ "${#P_ETC[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "ETC" "product" "" "P_ETC" >> "$ANDROIDBP"
|
|
fi
|
|
local SE_ETC=( $(prefix_match "system_ext/etc/") )
|
|
if [ "${#SE_ETC[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "ETC" "system_ext" "" "SE_ETC" >> "$ANDROIDBP"
|
|
fi
|
|
local O_ETC=( $(prefix_match "odm/etc/") )
|
|
if [ "${#O_ETC[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "ETC" "odm" "" "O_ETC" >> "$ANDROIDBP"
|
|
fi
|
|
|
|
# Executables
|
|
local BIN=( $(prefix_match "bin/") )
|
|
if [ "${#BIN[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "EXECUTABLES" "" "" "BIN" >> "$ANDROIDBP"
|
|
fi
|
|
local S_BIN=( $(prefix_match "system/bin/") )
|
|
if [ "${#S_BIN[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "EXECUTABLES" "system" "" "S_BIN" >> "$ANDROIDBP"
|
|
fi
|
|
local V_BIN=( $(prefix_match "vendor/bin/") )
|
|
if [ "${#V_BIN[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "EXECUTABLES" "vendor" "" "V_BIN" >> "$ANDROIDBP"
|
|
fi
|
|
local P_BIN=( $(prefix_match "product/bin/") )
|
|
if [ "${#P_BIN[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "EXECUTABLES" "product" "" "P_BIN" >> "$ANDROIDBP"
|
|
fi
|
|
local SE_BIN=( $(prefix_match "system_ext/bin/") )
|
|
if [ "${#SE_BIN[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "EXECUTABLES" "system_ext" "" "SE_BIN" >> "$ANDROIDBP"
|
|
fi
|
|
local O_BIN=( $(prefix_match "odm/bin/") )
|
|
if [ "${#O_BIN[@]}" -gt "0" ]; then
|
|
write_blueprint_packages "EXECUTABLES" "odm" "" "O_BIN" >> "$ANDROIDBP"
|
|
fi
|
|
|
|
# Actually write out the final PRODUCT_PACKAGES list
|
|
local PACKAGE_COUNT=${#PACKAGE_LIST[@]}
|
|
|
|
if [ "$PACKAGE_COUNT" -eq "0" ]; then
|
|
return 0
|
|
fi
|
|
|
|
printf '\n%s\n' "PRODUCT_PACKAGES += \\" >> "$PRODUCTMK"
|
|
for (( i=1; i<PACKAGE_COUNT+1; i++ )); do
|
|
local LINEEND=" \\"
|
|
if [ "$i" -eq "$PACKAGE_COUNT" ]; then
|
|
LINEEND=""
|
|
fi
|
|
printf ' %s%s\n' "${PACKAGE_LIST[$i-1]}" "$LINEEND" >> "$PRODUCTMK"
|
|
done
|
|
}
|
|
|
|
#
|
|
# write_blueprint_header:
|
|
#
|
|
# $1: file which will be written to
|
|
#
|
|
# writes out the warning message regarding manual file modifications.
|
|
# note that this is not an append operation, and should
|
|
# be executed first!
|
|
#
|
|
function write_blueprint_header() {
|
|
if [ -f $1 ]; then
|
|
rm $1
|
|
fi
|
|
|
|
[ "$COMMON" -eq 1 ] && local DEVICE="$DEVICE_COMMON"
|
|
|
|
cat << EOF >> $1
|
|
// Automatically generated file. DO NOT MODIFY
|
|
//
|
|
// This file is generated by device/$VENDOR/$DEVICE/setup-makefiles.sh
|
|
|
|
EOF
|
|
}
|
|
|
|
#
|
|
# write_makefile_header:
|
|
#
|
|
# $1: file which will be written to
|
|
#
|
|
# writes out the warning message regarding manual file modifications.
|
|
# note that this is not an append operation, and should
|
|
# be executed first!
|
|
#
|
|
function write_makefile_header() {
|
|
if [ -f $1 ]; then
|
|
rm $1
|
|
fi
|
|
|
|
[ "$COMMON" -eq 1 ] && local DEVICE="$DEVICE_COMMON"
|
|
|
|
cat << EOF >> $1
|
|
# Automatically generated file. DO NOT MODIFY
|
|
#
|
|
# This file is generated by device/$VENDOR/$DEVICE/setup-makefiles.sh
|
|
|
|
EOF
|
|
}
|
|
|
|
#
|
|
# write_headers:
|
|
#
|
|
# $1: devices falling under common to be added to guard - optional
|
|
# $2: custom guard - optional
|
|
#
|
|
# Calls write_makefile_header for each of the makefiles and
|
|
# write_blueprint_header for Android.bp and creates the initial
|
|
# path declaration and device guard for the Android.mk
|
|
#
|
|
function write_headers() {
|
|
write_makefile_header "$ANDROIDMK"
|
|
|
|
GUARD="$2"
|
|
if [ -z "$GUARD" ]; then
|
|
GUARD="TARGET_DEVICE"
|
|
fi
|
|
|
|
cat << EOF >> "$ANDROIDMK"
|
|
LOCAL_PATH := \$(call my-dir)
|
|
|
|
EOF
|
|
if [ "$COMMON" -ne 1 ]; then
|
|
cat << EOF >> "$ANDROIDMK"
|
|
ifeq (\$($GUARD),$DEVICE)
|
|
|
|
EOF
|
|
else
|
|
if [ -z "$1" ]; then
|
|
echo "Argument with devices to be added to guard must be set!"
|
|
exit 1
|
|
fi
|
|
cat << EOF >> "$ANDROIDMK"
|
|
ifneq (\$(filter $1,\$($GUARD)),)
|
|
|
|
EOF
|
|
fi
|
|
|
|
write_makefile_header "$BOARDMK"
|
|
write_makefile_header "$PRODUCTMK"
|
|
write_blueprint_header "$ANDROIDBP"
|
|
|
|
cat << EOF >> "$ANDROIDBP"
|
|
soong_namespace {
|
|
}
|
|
|
|
EOF
|
|
|
|
[ "$COMMON" -eq 1 ] && local DEVICE="$DEVICE_COMMON"
|
|
cat << EOF >> "$PRODUCTMK"
|
|
PRODUCT_SOONG_NAMESPACES += \\
|
|
vendor/$VENDOR/$DEVICE
|
|
|
|
EOF
|
|
}
|
|
|
|
#
|
|
# write_footers:
|
|
#
|
|
# Closes the inital guard and any other finalization tasks. Must
|
|
# be called as the final step.
|
|
#
|
|
function write_footers() {
|
|
cat << EOF >> "$ANDROIDMK"
|
|
endif
|
|
EOF
|
|
}
|
|
|
|
# Return success if adb is up and not in recovery
|
|
function _adb_connected {
|
|
{
|
|
if [[ "$(adb get-state)" == device ]]
|
|
then
|
|
return 0
|
|
fi
|
|
} 2>/dev/null
|
|
|
|
return 1
|
|
};
|
|
|
|
#
|
|
# parse_file_list:
|
|
#
|
|
# $1: input file
|
|
# $2: blob section in file - optional
|
|
#
|
|
# Sets PRODUCT_PACKAGES and PRODUCT_COPY_FILES while parsing the input file
|
|
#
|
|
function parse_file_list() {
|
|
if [ -z "$1" ]; then
|
|
echo "An input file is expected!"
|
|
exit 1
|
|
elif [ ! -f "$1" ]; then
|
|
echo "Input file "$1" does not exist!"
|
|
exit 1
|
|
fi
|
|
|
|
if [ -n "$2" ]; then
|
|
echo "Using section \"$2\""
|
|
LIST=$EXTRACT_TMP_DIR/files.txt
|
|
# Match all lines starting with first line found to start* with '#'
|
|
# comment and contain** $2, and ending with first line to be empty*.
|
|
# *whitespaces (tabs, spaces) at the beginning of lines are discarded
|
|
# **the $2 match is case-insensitive
|
|
cat $1 | sed -n '/^[[:space:]]*#.*'"$2"'/I,/^[[:space:]]*$/ p' > $LIST
|
|
else
|
|
LIST=$1
|
|
fi
|
|
|
|
|
|
PRODUCT_PACKAGES_LIST=()
|
|
PRODUCT_PACKAGES_HASHES=()
|
|
PRODUCT_PACKAGES_FIXUP_HASHES=()
|
|
PRODUCT_COPY_FILES_LIST=()
|
|
PRODUCT_COPY_FILES_HASHES=()
|
|
PRODUCT_COPY_FILES_FIXUP_HASHES=()
|
|
|
|
while read -r line; do
|
|
if [ -z "$line" ]; then continue; fi
|
|
|
|
# If the line has a pipe delimiter, a sha1 hash should follow.
|
|
# This indicates the file should be pinned and not overwritten
|
|
# when extracting files.
|
|
local SPLIT=(${line//\|/ })
|
|
local COUNT=${#SPLIT[@]}
|
|
local SPEC=${SPLIT[0]}
|
|
local HASH="x"
|
|
local FIXUP_HASH="x"
|
|
if [ "$COUNT" -gt "1" ]; then
|
|
HASH=${SPLIT[1]}
|
|
fi
|
|
if [ "$COUNT" -gt "2" ]; then
|
|
FIXUP_HASH=${SPLIT[2]}
|
|
fi
|
|
|
|
# if line starts with a dash, it needs to be packaged
|
|
if [[ "$SPEC" =~ ^- ]]; then
|
|
PRODUCT_PACKAGES_LIST+=("${SPEC#-}")
|
|
PRODUCT_PACKAGES_HASHES+=("$HASH")
|
|
PRODUCT_PACKAGES_FIXUP_HASHES+=("$FIXUP_HASH")
|
|
# if line contains apex, apk, jar or vintf fragment, it needs to be packaged
|
|
elif suffix_match_file ".apex" "$(src_file "$SPEC")" || \
|
|
suffix_match_file ".apk" "$(src_file "$SPEC")" || \
|
|
suffix_match_file ".jar" "$(src_file "$SPEC")" || \
|
|
[[ "$SPEC" == *"etc/vintf/manifest/"* ]]; then
|
|
PRODUCT_PACKAGES_LIST+=("$SPEC")
|
|
PRODUCT_PACKAGES_HASHES+=("$HASH")
|
|
PRODUCT_PACKAGES_FIXUP_HASHES+=("$FIXUP_HASH")
|
|
else
|
|
PRODUCT_COPY_FILES_LIST+=("$SPEC")
|
|
PRODUCT_COPY_FILES_HASHES+=("$HASH")
|
|
PRODUCT_COPY_FILES_FIXUP_HASHES+=("$FIXUP_HASH")
|
|
fi
|
|
|
|
done < <(grep -v -E '(^#|^[[:space:]]*$)' "$LIST" | LC_ALL=C sort | uniq)
|
|
}
|
|
|
|
#
|
|
# write_makefiles:
|
|
#
|
|
# $1: file containing the list of items to extract
|
|
# $2: make treble compatible makefile - optional
|
|
#
|
|
# Calls write_product_copy_files and write_product_packages on
|
|
# the given file and appends to the Android.bp as well as
|
|
# the product makefile.
|
|
#
|
|
function write_makefiles() {
|
|
parse_file_list "$1"
|
|
write_product_copy_files "$2"
|
|
write_product_packages
|
|
}
|
|
|
|
#
|
|
# append_firmware_calls_to_makefiles:
|
|
#
|
|
# Appends to Android.mk the calls to all images present in radio folder
|
|
# (filesmap file used by releasetools to map firmware images should be kept in the device tree)
|
|
#
|
|
function append_firmware_calls_to_makefiles() {
|
|
cat << EOF >> "$ANDROIDMK"
|
|
ifeq (\$(LOCAL_PATH)/radio, \$(wildcard \$(LOCAL_PATH)/radio))
|
|
|
|
RADIO_FILES := \$(wildcard \$(LOCAL_PATH)/radio/*)
|
|
\$(foreach f, \$(notdir \$(RADIO_FILES)), \\
|
|
\$(call add-radio-file,radio/\$(f)))
|
|
\$(call add-radio-file,../../../device/$VENDOR/$DEVICE/radio/filesmap)
|
|
|
|
endif
|
|
|
|
EOF
|
|
}
|
|
|
|
#
|
|
# get_file:
|
|
#
|
|
# $1: input file
|
|
# $2: target file/folder
|
|
# $3: source of the file (can be "adb" or a local folder)
|
|
#
|
|
# Silently extracts the input file to defined target
|
|
# Returns success if file can be pulled from the device or found locally
|
|
#
|
|
function get_file() {
|
|
local SRC="$3"
|
|
|
|
if [ "$SRC" = "adb" ]; then
|
|
# try to pull
|
|
adb pull "$1" "$2" >/dev/null 2>&1 && return 0
|
|
adb pull "${1#/system}" "$2" >/dev/null 2>&1 && return 0
|
|
adb pull "system/$1" "$2" >/dev/null 2>&1 && return 0
|
|
|
|
return 1
|
|
else
|
|
# try to copy
|
|
cp -r "$SRC/$1" "$2" 2>/dev/null && return 0
|
|
cp -r "$SRC/${1#/system}" "$2" 2>/dev/null && return 0
|
|
cp -r "$SRC/system/$1" "$2" 2>/dev/null && return 0
|
|
|
|
return 1
|
|
fi
|
|
};
|
|
|
|
#
|
|
# oat2dex:
|
|
#
|
|
# $1: extracted apk|jar (to check if deodex is required)
|
|
# $2: odexed apk|jar to deodex
|
|
# $3: source of the odexed apk|jar
|
|
#
|
|
# Convert apk|jar .odex in the corresposing classes.dex
|
|
#
|
|
function oat2dex() {
|
|
local CUSTOM_TARGET="$1"
|
|
local OEM_TARGET="$2"
|
|
local SRC="$3"
|
|
local TARGET=
|
|
local OAT=
|
|
|
|
if [ -z "$BAKSMALIJAR" ] || [ -z "$SMALIJAR" ]; then
|
|
export BAKSMALIJAR="$ANDROID_ROOT"/prebuilts/extract-tools/common/smali/baksmali.jar
|
|
export SMALIJAR="$ANDROID_ROOT"/prebuilts/extract-tools/common/smali/smali.jar
|
|
fi
|
|
|
|
if [ -z "$VDEXEXTRACTOR" ]; then
|
|
export VDEXEXTRACTOR="$ANDROID_ROOT"/prebuilts/extract-tools/${HOST}-x86/bin/vdexExtractor
|
|
fi
|
|
|
|
if [ -z "$CDEXCONVERTER" ]; then
|
|
export CDEXCONVERTER="$ANDROID_ROOT"/prebuilts/extract-tools/${HOST}-x86/bin/compact_dex_converter
|
|
fi
|
|
|
|
# Extract existing boot.oats to the temp folder
|
|
if [ -z "$ARCHES" ]; then
|
|
echo "Checking if system is odexed and locating boot.oats..."
|
|
for ARCH in "arm64" "arm" "x86_64" "x86"; do
|
|
mkdir -p "$EXTRACT_TMP_DIR/system/framework/$ARCH"
|
|
if get_file "/system/framework/$ARCH" "$EXTRACT_TMP_DIR/system/framework/" "$SRC"; then
|
|
ARCHES+="$ARCH "
|
|
else
|
|
rmdir "$EXTRACT_TMP_DIR/system/framework/$ARCH"
|
|
fi
|
|
done
|
|
fi
|
|
|
|
if [ -z "$ARCHES" ]; then
|
|
FULLY_DEODEXED=1 && return 0 # system is fully deodexed, return
|
|
fi
|
|
|
|
if [ ! -f "$CUSTOM_TARGET" ]; then
|
|
return;
|
|
fi
|
|
|
|
if grep "classes.dex" "$CUSTOM_TARGET" >/dev/null; then
|
|
return 0 # target apk|jar is already odexed, return
|
|
fi
|
|
|
|
for ARCH in $ARCHES; do
|
|
BOOTOAT="$EXTRACT_TMP_DIR/system/framework/$ARCH/boot.oat"
|
|
|
|
local OAT="$(dirname "$OEM_TARGET")/oat/$ARCH/$(basename "$OEM_TARGET" ."${OEM_TARGET##*.}").odex"
|
|
local VDEX="$(dirname "$OEM_TARGET")/oat/$ARCH/$(basename "$OEM_TARGET" ."${OEM_TARGET##*.}").vdex"
|
|
|
|
if get_file "$OAT" "$EXTRACT_TMP_DIR" "$SRC"; then
|
|
if get_file "$VDEX" "$EXTRACT_TMP_DIR" "$SRC"; then
|
|
"$VDEXEXTRACTOR" -o "$EXTRACT_TMP_DIR/" -i "$EXTRACT_TMP_DIR/$(basename "$VDEX")" > /dev/null
|
|
CLASSES=$(ls "$EXTRACT_TMP_DIR/$(basename "${OEM_TARGET%.*}")_classes"*)
|
|
for CLASS in $CLASSES; do
|
|
NEWCLASS=$(echo "$CLASS" | sed 's/.*_//;s/cdex/dex/')
|
|
# Check if we have to deal with CompactDex
|
|
if [[ "$CLASS" == *.cdex ]]; then
|
|
"$CDEXCONVERTER" "$CLASS" &>/dev/null
|
|
mv "$CLASS.new" "$EXTRACT_TMP_DIR/$NEWCLASS"
|
|
else
|
|
mv "$CLASS" "$EXTRACT_TMP_DIR/$NEWCLASS"
|
|
fi
|
|
done
|
|
else
|
|
java -jar "$BAKSMALIJAR" deodex -o "$EXTRACT_TMP_DIR/dexout" -b "$BOOTOAT" -d "$EXTRACT_TMP_DIR" "$EXTRACT_TMP_DIR/$(basename "$OAT")"
|
|
java -jar "$SMALIJAR" assemble "$EXTRACT_TMP_DIR/dexout" -o "$EXTRACT_TMP_DIR/classes.dex"
|
|
fi
|
|
elif [[ "$CUSTOM_TARGET" =~ .jar$ ]]; then
|
|
JAROAT="$EXTRACT_TMP_DIR/system/framework/$ARCH/boot-$(basename ${OEM_TARGET%.*}).oat"
|
|
JARVDEX="/system/framework/boot-$(basename ${OEM_TARGET%.*}).vdex"
|
|
if [ ! -f "$JAROAT" ]; then
|
|
JAROAT=$BOOTOAT
|
|
fi
|
|
# try to extract classes.dex from boot.vdex for frameworks jars
|
|
# fallback to boot.oat if vdex is not available
|
|
if get_file "$JARVDEX" "$EXTRACT_TMP_DIR" "$SRC"; then
|
|
"$VDEXEXTRACTOR" -o "$EXTRACT_TMP_DIR/" -i "$EXTRACT_TMP_DIR/$(basename "$JARVDEX")" > /dev/null
|
|
CLASSES=$(ls "$EXTRACT_TMP_DIR/$(basename "${JARVDEX%.*}")_classes"*)
|
|
for CLASS in $CLASSES; do
|
|
NEWCLASS=$(echo "$CLASS" | sed 's/.*_//;s/cdex/dex/')
|
|
# Check if we have to deal with CompactDex
|
|
if [[ "$CLASS" == *.cdex ]]; then
|
|
"$CDEXCONVERTER" "$CLASS" &>/dev/null
|
|
mv "$CLASS.new" "$EXTRACT_TMP_DIR/$NEWCLASS"
|
|
else
|
|
mv "$CLASS" "$EXTRACT_TMP_DIR/$NEWCLASS"
|
|
fi
|
|
done
|
|
else
|
|
java -jar "$BAKSMALIJAR" deodex -o "$EXTRACT_TMP_DIR/dexout" -b "$BOOTOAT" -d "$EXTRACT_TMP_DIR" "$JAROAT/$OEM_TARGET"
|
|
java -jar "$SMALIJAR" assemble "$EXTRACT_TMP_DIR/dexout" -o "$EXTRACT_TMP_DIR/classes.dex"
|
|
fi
|
|
else
|
|
continue
|
|
fi
|
|
|
|
done
|
|
|
|
rm -rf "$EXTRACT_TMP_DIR/dexout"
|
|
}
|
|
|
|
#
|
|
# init_adb_connection:
|
|
#
|
|
# Starts adb server and waits for the device
|
|
#
|
|
function init_adb_connection() {
|
|
adb start-server # Prevent unexpected starting server message from adb get-state in the next line
|
|
if ! _adb_connected; then
|
|
echo "No device is online. Waiting for one..."
|
|
echo "Please connect USB and/or enable USB debugging"
|
|
until _adb_connected; do
|
|
sleep 1
|
|
done
|
|
echo "Device Found."
|
|
fi
|
|
|
|
# Retrieve IP and PORT info if we're using a TCP connection
|
|
TCPIPPORT=$(adb devices | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:[0-9]+[^0-9]+' \
|
|
| head -1 | awk '{print $1}')
|
|
adb root &> /dev/null
|
|
sleep 0.3
|
|
if [ -n "$TCPIPPORT" ]; then
|
|
# adb root just killed our connection
|
|
# so reconnect...
|
|
adb connect "$TCPIPPORT"
|
|
fi
|
|
adb wait-for-device &> /dev/null
|
|
sleep 0.3
|
|
}
|
|
|
|
#
|
|
# fix_xml:
|
|
#
|
|
# $1: xml file to fix
|
|
#
|
|
function fix_xml() {
|
|
local XML="$1"
|
|
local TEMP_XML="$EXTRACT_TMP_DIR/`basename "$XML"`.temp"
|
|
|
|
grep -a '^<?xml version' "$XML" > "$TEMP_XML"
|
|
grep -av '^<?xml version' "$XML" >> "$TEMP_XML"
|
|
|
|
mv "$TEMP_XML" "$XML"
|
|
}
|
|
|
|
function get_hash() {
|
|
local FILE="$1"
|
|
|
|
if [ "$(uname)" == "Darwin" ]; then
|
|
shasum "${FILE}" | awk '{print $1}'
|
|
else
|
|
sha1sum "${FILE}" | awk '{print $1}'
|
|
fi
|
|
}
|
|
|
|
function print_spec() {
|
|
local SPEC_PRODUCT_PACKAGE="$1"
|
|
local SPEC_SRC_FILE="$2"
|
|
local SPEC_DST_FILE="$3"
|
|
local SPEC_ARGS="$4"
|
|
local SPEC_HASH="$5"
|
|
local SPEC_FIXUP_HASH="$6"
|
|
|
|
local PRODUCT_PACKAGE=""
|
|
if [ ${SPEC_PRODUCT_PACKAGE} = true ]; then
|
|
PRODUCT_PACKAGE="-"
|
|
fi
|
|
local SRC=""
|
|
if [ ! -z "${SPEC_SRC_FILE}" ] && [ "${SPEC_SRC_FILE}" != "${SPEC_DST_FILE}" ]; then
|
|
SRC="${SPEC_SRC_FILE}:"
|
|
fi
|
|
local DST=""
|
|
if [ ! -z "${SPEC_DST_FILE}" ]; then
|
|
DST="${SPEC_DST_FILE}"
|
|
fi
|
|
local ARGS=""
|
|
if [ ! -z "${SPEC_ARGS}" ]; then
|
|
ARGS=";${SPEC_ARGS}"
|
|
fi
|
|
local HASH=""
|
|
if [ ! -z "${SPEC_HASH}" ] && [ "${SPEC_HASH}" != "x" ]; then
|
|
HASH="|${SPEC_HASH}"
|
|
fi
|
|
local FIXUP_HASH=""
|
|
if [ ! -z "${SPEC_FIXUP_HASH}" ] && [ "${SPEC_FIXUP_HASH}" != "x" ] && [ "${SPEC_FIXUP_HASH}" != "${SPEC_HASH}" ]; then
|
|
FIXUP_HASH="|${SPEC_FIXUP_HASH}"
|
|
fi
|
|
printf '%s%s%s%s%s%s\n' "${PRODUCT_PACKAGE}" "${SRC}" "${DST}" "${ARGS}" "${HASH}" "${FIXUP_HASH}"
|
|
}
|
|
|
|
# To be overridden by device-level extract-files.sh
|
|
# Parameters:
|
|
# $1: spec name of a blob. Can be used for filtering.
|
|
# If the spec is "src:dest", then $1 is "dest".
|
|
# If the spec is "src", then $1 is "src".
|
|
# $2: path to blob file. Can be used for fixups.
|
|
#
|
|
function blob_fixup() {
|
|
:
|
|
}
|
|
|
|
#
|
|
# extract:
|
|
#
|
|
# Positional parameters:
|
|
# $1: file containing the list of items to extract (aka proprietary-files.txt)
|
|
# $2: path to extracted system folder, an ota zip file, or "adb" to extract from device
|
|
# $3: section in list file to extract - optional. Setting section via $3 is deprecated.
|
|
#
|
|
# Non-positional parameters (coming after $2):
|
|
# --section: preferred way of selecting the portion to parse and extract from
|
|
# proprietary-files.txt
|
|
# --kang: if present, this option will activate the printing of hashes for the
|
|
# extracted blobs. Useful with --section for subsequent pinning of
|
|
# blobs taken from other origins.
|
|
#
|
|
function extract() {
|
|
# Consume positional parameters
|
|
local PROPRIETARY_FILES_TXT="$1"; shift
|
|
local SRC="$1"; shift
|
|
local SECTION=""
|
|
local KANG=false
|
|
|
|
# Consume optional, non-positional parameters
|
|
while [ "$#" -gt 0 ]; do
|
|
case "$1" in
|
|
-s|--section)
|
|
SECTION="$2"; shift
|
|
;;
|
|
-k|--kang)
|
|
KANG=true
|
|
DISABLE_PINNING=1
|
|
;;
|
|
*)
|
|
# Backwards-compatibility with the old behavior, where $3, if
|
|
# present, denoted an optional positional ${SECTION} argument.
|
|
# Users of ${SECTION} are encouraged to migrate from setting it as
|
|
# positional $3, to non-positional --section ${SECTION}, the
|
|
# reason being that it doesn't scale to have more than 1 optional
|
|
# positional argument.
|
|
SECTION="$1"
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
if [ -z "$OUTDIR" ]; then
|
|
echo "Output dir not set!"
|
|
exit 1
|
|
fi
|
|
|
|
parse_file_list "${PROPRIETARY_FILES_TXT}" "${SECTION}"
|
|
|
|
# Allow failing, so we can try $DEST and/or $FILE
|
|
set +e
|
|
|
|
local FILELIST=( ${PRODUCT_COPY_FILES_LIST[@]} ${PRODUCT_PACKAGES_LIST[@]} )
|
|
local HASHLIST=( ${PRODUCT_COPY_FILES_HASHES[@]} ${PRODUCT_PACKAGES_HASHES[@]} )
|
|
local FIXUP_HASHLIST=( ${PRODUCT_COPY_FILES_FIXUP_HASHES[@]} ${PRODUCT_PACKAGES_FIXUP_HASHES[@]} )
|
|
local PRODUCT_COPY_FILES_COUNT=${#PRODUCT_COPY_FILES_LIST[@]}
|
|
local COUNT=${#FILELIST[@]}
|
|
local OUTPUT_ROOT="$ANDROID_ROOT"/"$OUTDIR"/proprietary
|
|
local OUTPUT_TMP="$EXTRACT_TMP_DIR"/"$OUTDIR"/proprietary
|
|
|
|
if [ "$SRC" = "adb" ]; then
|
|
init_adb_connection
|
|
fi
|
|
|
|
if [ -f "$SRC" ] && [ "${SRC##*.}" == "zip" ]; then
|
|
DUMPDIR="$EXTRACT_TMP_DIR"/system_dump
|
|
|
|
# Check if we're working with the same zip that was passed last time.
|
|
# If so, let's just use what's already extracted.
|
|
MD5=`md5sum "$SRC"| awk '{print $1}'`
|
|
OLDMD5=`cat "$DUMPDIR"/zipmd5.txt`
|
|
|
|
if [ "$MD5" != "$OLDMD5" ]; then
|
|
rm -rf "$DUMPDIR"
|
|
mkdir "$DUMPDIR"
|
|
unzip "$SRC" -d "$DUMPDIR"
|
|
echo "$MD5" > "$DUMPDIR"/zipmd5.txt
|
|
|
|
# Extract A/B OTA
|
|
if [ -a "$DUMPDIR"/payload.bin ]; then
|
|
python3 "$ANDROID_ROOT"/tools/extract-utils/extract_ota.py "$DUMPDIR"/payload.bin -o "$DUMPDIR" -p "system" "odm" "product" "system_ext" "vendor" 2>&1
|
|
fi
|
|
|
|
for PARTITION in "system" "odm" "product" "system_ext" "vendor"
|
|
do
|
|
# If OTA is block based, extract it.
|
|
if [ -a "$DUMPDIR"/"$PARTITION".new.dat.br ]; then
|
|
echo "Converting "$PARTITION".new.dat.br to "$PARTITION".new.dat"
|
|
brotli -d "$DUMPDIR"/"$PARTITION".new.dat.br
|
|
rm "$DUMPDIR"/"$PARTITION".new.dat.br
|
|
fi
|
|
if [ -a "$DUMPDIR"/"$PARTITION".new.dat ]; then
|
|
echo "Converting "$PARTITION".new.dat to "$PARTITION".img"
|
|
python "$ANDROID_ROOT"/tools/extract-utils/sdat2img.py "$DUMPDIR"/"$PARTITION".transfer.list "$DUMPDIR"/"$PARTITION".new.dat "$DUMPDIR"/"$PARTITION".img 2>&1
|
|
rm -rf "$DUMPDIR"/"$PARTITION".new.dat "$DUMPDIR"/"$PARTITION"
|
|
mkdir "$DUMPDIR"/"$PARTITION" "$DUMPDIR"/tmp
|
|
extract_img_data "$DUMPDIR"/"$PARTITION".img "$DUMPDIR"/"$PARTITION"/
|
|
rm "$DUMPDIR"/"$PARTITION".img
|
|
fi
|
|
if [ -a "$DUMPDIR"/"$PARTITION".img ]; then
|
|
extract_img_data "$DUMPDIR"/"$PARTITION".img "$DUMPDIR"/"$PARTITION"/
|
|
fi
|
|
done
|
|
fi
|
|
|
|
SRC="$DUMPDIR"
|
|
fi
|
|
|
|
if [ -d "$SRC" ] && [ -f "$SRC"/super.img ]; then
|
|
DUMPDIR="$EXTRACT_TMP_DIR"/super_dump
|
|
mkdir -p "$DUMPDIR"
|
|
|
|
echo "Unpacking super.img"
|
|
"$SIMG2IMG" "$SRC"/super.img "$DUMPDIR"/super.raw
|
|
|
|
for PARTITION in "system" "odm" "product" "system_ext" "vendor"
|
|
do
|
|
echo "Preparing "$PARTITION""
|
|
if "$LPUNPACK" -p "$PARTITION"_a "$DUMPDIR"/super.raw "$DUMPDIR" ; then
|
|
mv "$DUMPDIR"/"$PARTITION"_a.img "$DUMPDIR"/"$PARTITION".img
|
|
else
|
|
"$LPUNPACK" -p "$PARTITION" "$DUMPDIR"/super.raw "$DUMPDIR"
|
|
fi
|
|
done
|
|
|
|
SRC="$DUMPDIR"
|
|
fi
|
|
|
|
if [ -d "$SRC" ] && [ -f "$SRC"/system.img ]; then
|
|
DUMPDIR="$EXTRACT_TMP_DIR"/system_dump
|
|
mkdir -p "$DUMPDIR"
|
|
|
|
for PARTITION in "system" "odm" "product" "system_ext" "vendor"
|
|
do
|
|
echo "Extracting "$PARTITION""
|
|
local IMAGE="$SRC"/"$PARTITION".img
|
|
if [ -f "$IMAGE" ]; then
|
|
if [[ $(file -b "$IMAGE") == Linux* ]]; then
|
|
extract_img_data "$IMAGE" "$DUMPDIR"/"$PARTITION"
|
|
elif [[ $(file -b "$IMAGE") == Android* ]]; then
|
|
"$SIMG2IMG" "$IMAGE" "$DUMPDIR"/"$PARTITION".raw
|
|
extract_img_data "$DUMPDIR"/"$PARTITION".raw "$DUMPDIR"/"$PARTITION"/
|
|
else
|
|
echo "Unsupported "$IMAGE""
|
|
fi
|
|
fi
|
|
done
|
|
|
|
SRC="$DUMPDIR"
|
|
fi
|
|
|
|
if [ "$VENDOR_STATE" -eq "0" ]; then
|
|
echo "Cleaning output directory ($OUTPUT_ROOT).."
|
|
rm -rf "${OUTPUT_TMP:?}"
|
|
mkdir -p "${OUTPUT_TMP:?}"
|
|
if [ -d "$OUTPUT_ROOT" ]; then
|
|
mv "${OUTPUT_ROOT:?}/"* "${OUTPUT_TMP:?}/"
|
|
fi
|
|
VENDOR_STATE=1
|
|
fi
|
|
|
|
echo "Extracting ${COUNT} files in ${PROPRIETARY_FILES_TXT} from ${SRC}:"
|
|
|
|
for (( i=1; i<COUNT+1; i++ )); do
|
|
|
|
local SPEC_SRC_FILE=$(src_file "${FILELIST[$i-1]}")
|
|
local SPEC_DST_FILE=$(target_file "${FILELIST[$i-1]}")
|
|
local SPEC_ARGS=$(target_args "${FILELIST[$i-1]}")
|
|
local OUTPUT_DIR=
|
|
local TMP_DIR=
|
|
local SRC_FILE=
|
|
local DST_FILE=
|
|
local IS_PRODUCT_PACKAGE=false
|
|
|
|
# Note: this relies on the fact that the ${FILELIST[@]} array
|
|
# contains first ${PRODUCT_COPY_FILES_LIST[@]}, then ${PRODUCT_PACKAGES_LIST[@]}.
|
|
if [ "${i}" -gt "${PRODUCT_COPY_FILES_COUNT}" ]; then
|
|
IS_PRODUCT_PACKAGE=true
|
|
fi
|
|
|
|
OUTPUT_DIR="${OUTPUT_ROOT}"
|
|
TMP_DIR="${OUTPUT_TMP}"
|
|
SRC_FILE="/system/${SPEC_SRC_FILE}"
|
|
DST_FILE="/system/${SPEC_DST_FILE}"
|
|
|
|
# Strip the file path in the vendor repo of "system", if present
|
|
local BLOB_DISPLAY_NAME="${DST_FILE#/system/}"
|
|
local VENDOR_REPO_FILE="$OUTPUT_DIR/${BLOB_DISPLAY_NAME}"
|
|
mkdir -p $(dirname "${VENDOR_REPO_FILE}")
|
|
|
|
# Check pinned files
|
|
local HASH="$(echo ${HASHLIST[$i-1]} | awk '{ print tolower($0); }')"
|
|
local FIXUP_HASH="$(echo ${FIXUP_HASHLIST[$i-1]} | awk '{ print tolower($0); }')"
|
|
local KEEP=""
|
|
if [ "$DISABLE_PINNING" != "1" ] && [ "$HASH" != "x" ]; then
|
|
if [ -f "${VENDOR_REPO_FILE}" ]; then
|
|
local PINNED="${VENDOR_REPO_FILE}"
|
|
else
|
|
local PINNED="${TMP_DIR}${DST_FILE#/system}"
|
|
fi
|
|
if [ -f "$PINNED" ]; then
|
|
local TMP_HASH=$(get_hash "${PINNED}")
|
|
if [ "${TMP_HASH}" = "${HASH}" ] || [ "${TMP_HASH}" = "${FIXUP_HASH}" ]; then
|
|
KEEP="1"
|
|
if [ ! -f "${VENDOR_REPO_FILE}" ]; then
|
|
cp -p "$PINNED" "${VENDOR_REPO_FILE}"
|
|
fi
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
if [ "${KANG}" = false ]; then
|
|
printf ' - %s\n' "${BLOB_DISPLAY_NAME}"
|
|
fi
|
|
|
|
if [ "$KEEP" = "1" ]; then
|
|
if [ "${FIXUP_HASH}" != "x" ]; then
|
|
printf ' + keeping pinned file with hash %s\n' "${FIXUP_HASH}"
|
|
else
|
|
printf ' + keeping pinned file with hash %s\n' "${HASH}"
|
|
fi
|
|
else
|
|
FOUND=false
|
|
# Try custom target first.
|
|
# Also try to search for files stripped of
|
|
# the "/system" prefix, if we're actually extracting
|
|
# from a system image.
|
|
for CANDIDATE in "${DST_FILE}" "${SRC_FILE}"; do
|
|
get_file ${CANDIDATE} ${VENDOR_REPO_FILE} ${SRC} && {
|
|
FOUND=true
|
|
break
|
|
}
|
|
done
|
|
|
|
if [ "${FOUND}" = false ]; then
|
|
colored_echo red " !! ${BLOB_DISPLAY_NAME}: file not found in source"
|
|
continue
|
|
fi
|
|
|
|
# Blob fixup pipeline has 2 parts: one that is fixed and
|
|
# one that is user-configurable
|
|
local PRE_FIXUP_HASH=$(get_hash ${VENDOR_REPO_FILE})
|
|
# Deodex apk|jar if that's the case
|
|
if [[ "$FULLY_DEODEXED" -ne "1" && "${VENDOR_REPO_FILE}" =~ .(apk|jar)$ ]]; then
|
|
oat2dex "${VENDOR_REPO_FILE}" "${SRC_FILE}" "$SRC"
|
|
if [ -f "$EXTRACT_TMP_DIR/classes.dex" ]; then
|
|
touch -t 200901010000 "$EXTRACT_TMP_DIR/classes"*
|
|
zip -gjq "${VENDOR_REPO_FILE}" "$EXTRACT_TMP_DIR/classes"*
|
|
rm "$EXTRACT_TMP_DIR/classes"*
|
|
printf ' (updated %s from odex files)\n' "${SRC_FILE}"
|
|
fi
|
|
elif [[ "${VENDOR_REPO_FILE}" =~ .xml$ ]]; then
|
|
fix_xml "${VENDOR_REPO_FILE}"
|
|
fi
|
|
# Now run user-supplied fixup function
|
|
blob_fixup "${BLOB_DISPLAY_NAME}" "${VENDOR_REPO_FILE}"
|
|
local POST_FIXUP_HASH=$(get_hash ${VENDOR_REPO_FILE})
|
|
|
|
if [ -f "${VENDOR_REPO_FILE}" ]; then
|
|
local DIR=$(dirname "${VENDOR_REPO_FILE}")
|
|
local TYPE="${DIR##*/}"
|
|
if [ "$TYPE" = "bin" ]; then
|
|
chmod 755 "${VENDOR_REPO_FILE}"
|
|
else
|
|
chmod 644 "${VENDOR_REPO_FILE}"
|
|
fi
|
|
fi
|
|
|
|
if [ "${KANG}" = true ]; then
|
|
print_spec "${IS_PRODUCT_PACKAGE}" "${SPEC_SRC_FILE}" "${SPEC_DST_FILE}" "${SPEC_ARGS}" "${PRE_FIXUP_HASH}" "${POST_FIXUP_HASH}"
|
|
fi
|
|
|
|
# Check and print whether the fixup pipeline actually did anything.
|
|
# This isn't done right after the fixup pipeline because we want this print
|
|
# to come after print_spec above, when in kang mode.
|
|
if [ "${PRE_FIXUP_HASH}" != "${POST_FIXUP_HASH}" ]; then
|
|
printf " + Fixed up %s\n" "${BLOB_DISPLAY_NAME}"
|
|
# Now sanity-check the spec for this blob.
|
|
if [ "${KANG}" = false ] && [ "${FIXUP_HASH}" = "x" ] && [ "${HASH}" != "x" ]; then
|
|
colored_echo yellow "WARNING: The ${BLOB_DISPLAY_NAME} file was fixed up, but it is pinned."
|
|
colored_echo yellow "This is a mistake and you want to either remove the hash completely, or add an extra one."
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
done
|
|
|
|
# Don't allow failing
|
|
set -e
|
|
}
|
|
|
|
#
|
|
# extract_firmware:
|
|
#
|
|
# $1: file containing the list of items to extract
|
|
# $2: path to extracted radio folder
|
|
#
|
|
function extract_firmware() {
|
|
if [ -z "$OUTDIR" ]; then
|
|
echo "Output dir not set!"
|
|
exit 1
|
|
fi
|
|
|
|
parse_file_list "$1"
|
|
|
|
# Don't allow failing
|
|
set -e
|
|
|
|
local FILELIST=( ${PRODUCT_COPY_FILES_LIST[@]} )
|
|
local COUNT=${#FILELIST[@]}
|
|
local SRC="$2"
|
|
local OUTPUT_DIR="$ANDROID_ROOT"/"$OUTDIR"/radio
|
|
|
|
if [ "$VENDOR_RADIO_STATE" -eq "0" ]; then
|
|
echo "Cleaning firmware output directory ($OUTPUT_DIR).."
|
|
rm -rf "${OUTPUT_DIR:?}/"*
|
|
VENDOR_RADIO_STATE=1
|
|
fi
|
|
|
|
echo "Extracting $COUNT files in $1 from $SRC:"
|
|
|
|
for (( i=1; i<COUNT+1; i++ )); do
|
|
local FILE="${FILELIST[$i-1]}"
|
|
printf ' - %s \n' "/radio/$FILE"
|
|
|
|
if [ ! -d "$OUTPUT_DIR" ]; then
|
|
mkdir -p "$OUTPUT_DIR"
|
|
fi
|
|
cp "$SRC/$FILE" "$OUTPUT_DIR/$FILE"
|
|
chmod 644 "$OUTPUT_DIR/$FILE"
|
|
done
|
|
}
|
|
|
|
function extract_img_data() {
|
|
local image_file="$1"
|
|
local out_dir="$2"
|
|
local logFile="$EXTRACT_TMP_DIR/debugfs.log"
|
|
|
|
if [ ! -d "$out_dir" ]; then
|
|
mkdir -p "$out_dir"
|
|
fi
|
|
|
|
if [[ "$HOST_OS" == "Darwin" ]]; then
|
|
debugfs -R "rdump / \"$out_dir\"" "$image_file" &> "$logFile" || {
|
|
echo "[-] Failed to extract data from '$image_file'"
|
|
abort 1
|
|
}
|
|
else
|
|
debugfs -R 'ls -p' "$image_file" 2>/dev/null | cut -d '/' -f6 | while read -r entry
|
|
do
|
|
debugfs -R "rdump \"$entry\" \"$out_dir\"" "$image_file" >> "$logFile" 2>&1 || {
|
|
echo "[-] Failed to extract data from '$image_file'"
|
|
abort 1
|
|
}
|
|
done
|
|
fi
|
|
|
|
local symlink_err="rdump: Attempt to read block from filesystem resulted in short read while reading symlink"
|
|
if grep -Fq "$symlink_err" "$logFile"; then
|
|
echo "[-] Symlinks have not been properly processed from $image_file"
|
|
echo "[!] You might not have a compatible debugfs version"
|
|
abort 1
|
|
fi
|
|
}
|
|
|
|
function array_contains() {
|
|
local element
|
|
for element in "${@:2}"; do [[ "$element" == "$1" ]] && return 0; done
|
|
return 1
|
|
}
|
|
|
|
function generate_prop_list_from_image() {
|
|
local image_file="$1"
|
|
local image_dir="$EXTRACT_TMP_DIR/image-temp"
|
|
local output_list="$2"
|
|
local output_list_tmp="$EXTRACT_TMP_DIR/_proprietary-blobs.txt"
|
|
local -n skipped_files="$3"
|
|
local partition="$4"
|
|
|
|
mkdir -p "$image_dir"
|
|
|
|
if [[ $(file -b "$image_file") == Linux* ]]; then
|
|
extract_img_data "$image_file" "$image_dir"
|
|
elif [[ $(file -b "$image_file") == Android* ]]; then
|
|
"$SIMG2IMG" "$image_file" "$image_dir"/"$(basename "$image_file").raw"
|
|
extract_img_data "$image_dir"/"$(basename "$image_file").raw" "$image_dir"
|
|
rm "$image_dir"/"$(basename "$image_file").raw"
|
|
else
|
|
echo "Unsupported "$image_file""
|
|
fi
|
|
|
|
find "$image_dir" -not -type d | sed "s#^$image_dir/##" | while read -r FILE
|
|
do
|
|
if suffix_match_file ".odex" "$FILE" || suffix_match_file ".vdex" "$FILE" ; then
|
|
continue
|
|
fi
|
|
# Skip device defined skipped files since they will be re-generated at build time
|
|
if array_contains "$FILE" "${skipped_files[@]}"; then
|
|
continue
|
|
fi
|
|
if [ -z "$partition" ]; then
|
|
echo "vendor/$FILE" >> "$output_list_tmp"
|
|
else
|
|
echo "$partition/$FILE" >> "$output_list_tmp"
|
|
fi
|
|
done
|
|
|
|
# Sort merged file with all lists
|
|
LC_ALL=C sort -u "$output_list_tmp" > "$output_list"
|
|
|
|
# Clean-up
|
|
rm -f "$output_list_tmp"
|
|
}
|
|
|
|
function colored_echo() {
|
|
IFS=" "
|
|
local color=$1;
|
|
shift
|
|
if ! [[ $color =~ '^[0-9]$' ]] ; then
|
|
case $(echo $color | tr '[:upper:]' '[:lower:]') in
|
|
black) color=0 ;;
|
|
red) color=1 ;;
|
|
green) color=2 ;;
|
|
yellow) color=3 ;;
|
|
blue) color=4 ;;
|
|
magenta) color=5 ;;
|
|
cyan) color=6 ;;
|
|
white|*) color=7 ;; # white or invalid color
|
|
esac
|
|
fi
|
|
if [ -t 1 ] ; then tput setaf $color; fi
|
|
printf '%s\n' "$*"
|
|
if [ -t 1 ] ; then tput sgr0; fi
|
|
}
|