Files
android_tools_extract-utils/extract_utils.sh
Christopher R. Palmer 9f644084a0 extract-utils: Fix handling of pulling src:dest pairs from dumps
Currently, the priority of the src and dest is inverted between
pulling from adb and pulling from a system dump.

Assume that we have a camera wrapper and write the proprietary-files.txt

lib/hw/camera.msm8996.so:lib/hw/camera.vendor.msm8996.so

If we pull from a phone running Lineage that has both files, we get

camera.vendor.msm8996.so

as the pulled blob.  If we take the exact same build and pull it
from the system dump (aka, your own $OUT directory that built the
installed software) you get

camera.msm8996.so

pull instead!

Make both paths follow the same logic so that you get the same
file independent of the source.

Change-Id: I479e0ae765339cc38fa05fcaad7943c528129463
2017-03-04 05:16:28 -05:00

969 lines
28 KiB
Bash

#!/bin/bash
#
# Copyright (C) 2016 The CyanogenMod 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.
#
PRODUCT_COPY_FILES_LIST=()
PRODUCT_COPY_FILES_HASHES=()
PRODUCT_PACKAGES_LIST=()
PRODUCT_PACKAGES_HASHES=()
PACKAGE_LIST=()
VENDOR_STATE=-1
VENDOR_RADIO_STATE=-1
COMMON=-1
ARCHES=
FULLY_DEODEXED=-1
TMPDIR="/tmp/extractfiles.$$"
mkdir "$TMPDIR"
#
# cleanup
#
# kill our tmpfiles with fire on exit
#
function cleanup() {
rm -rf "${TMPDIR:?}"
}
trap cleanup EXIT INT TERM ERR
#
# setup_vendor
#
# $1: device name
# $2: vendor name
# $3: CM 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 CM_ROOT="$3"
if [ ! -d "$CM_ROOT" ]; then
echo "\$CM_ROOT must be set and valid before including this script!"
exit 1
fi
export OUTDIR=vendor/"$VENDOR"/"$DEVICE"
if [ ! -d "$CM_ROOT/$OUTDIR" ]; then
mkdir -p "$CM_ROOT/$OUTDIR"
fi
VNDNAME="$6"
if [ -z "$VNDNAME" ]; then
VNDNAME="$DEVICE"
fi
export PRODUCTMK="$CM_ROOT"/"$OUTDIR"/"$VNDNAME"-vendor.mk
export ANDROIDMK="$CM_ROOT"/"$OUTDIR"/Android.mk
export BOARDMK="$CM_ROOT"/"$OUTDIR"/BoardConfigVendor.mk
if [ "$4" == "true" ] || [ "$4" == "1" ]; then
COMMON=1
else
COMMON=0
fi
if [ "$5" == "true" ] || [ "$5" == "1" ]; then
VENDOR_STATE=1
VENDOR_RADIO_STATE=1
else
VENDOR_STATE=0
VENDOR_RADIO_STATE=0
fi
}
#
# target_file:
#
# $1: colon delimited list
#
# Returns destination filename without args
#
function target_file() {
local LINE="$1"
local SPLIT=(${LINE//:/ })
local COUNT=${#SPLIT[@]}
if [ "$COUNT" -gt "1" ]; then
if [[ "${SPLIT[1]}" =~ .*/.* ]]; then
printf '%s\n' "${SPLIT[1]}"
return 0
fi
fi
printf '%s\n' "${SPLIT[0]}"
}
#
# target_args:
#
# $1: colon delimited list
#
# Returns optional arguments (last value) for given target
#
function target_args() {
local LINE="$1"
local SPLIT=(${LINE//:/ })
local COUNT=${#SPLIT[@]}
if [ "$COUNT" -gt "1" ]; then
if [[ ! "${SPLIT[$COUNT-1]}" =~ .*/.* ]]; then
printf '%s\n' "${SPLIT[$COUNT-1]}"
fi
fi
}
#
# prefix_match:
#
# $1: the prefix to match on
#
# Internal function which loops thru the packages list and returns a new
# list containing the matched files with the prefix stripped away.
#
function prefix_match() {
local PREFIX="$1"
for FILE in "${PRODUCT_PACKAGES_LIST[@]}"; do
if [[ "$FILE" =~ ^"$PREFIX" ]]; then
printf '%s\n' "${FILE#$PREFIX}"
fi
done
}
#
# write_product_copy_files:
#
# 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=
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")
printf ' %s/proprietary/%s:system/%s%s\n' \
"$OUTDIR" "$TARGET" "$TARGET" "$LINEEND" >> "$PRODUCTMK"
done
return 0
}
#
# write_packages:
#
# $1: The LOCAL_MODULE_CLASS for the given module list
# $2: "true" if this package is part of the vendor/ path
# $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_packages() {
local CLASS="$1"
local VENDOR_PKG="$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=
for P in "${FILELIST[@]}"; do
FILE=$(target_file "$P")
ARGS=$(target_args "$P")
BASENAME=$(basename "$FILE")
EXTENSION=${BASENAME##*.}
PKGNAME=${BASENAME%.*}
# Add to final package list
PACKAGE_LIST+=("$PKGNAME")
SRC="proprietary"
if [ "$VENDOR_PKG" = "true" ]; then
SRC+="/vendor"
fi
printf 'include $(CLEAR_VARS)\n'
printf 'LOCAL_MODULE := %s\n' "$PKGNAME"
printf 'LOCAL_MODULE_OWNER := %s\n' "$VENDOR"
if [ "$CLASS" = "SHARED_LIBRARIES" ]; then
if [ "$EXTRA" = "both" ]; then
printf 'LOCAL_SRC_FILES_64 := %s/lib64/%s\n' "$SRC" "$FILE"
printf 'LOCAL_SRC_FILES_32 := %s/lib/%s\n' "$SRC" "$FILE"
#if [ "$VENDOR_PKG" = "true" ]; then
# echo "LOCAL_MODULE_PATH_64 := \$(TARGET_OUT_VENDOR_SHARED_LIBRARIES)"
# echo "LOCAL_MODULE_PATH_32 := \$(2ND_TARGET_OUT_VENDOR_SHARED_LIBRARIES)"
#else
# echo "LOCAL_MODULE_PATH_64 := \$(TARGET_OUT_SHARED_LIBRARIES)"
# echo "LOCAL_MODULE_PATH_32 := \$(2ND_TARGET_OUT_SHARED_LIBRARIES)"
#fi
elif [ "$EXTRA" = "64" ]; then
printf 'LOCAL_SRC_FILES := %s/lib64/%s\n' "$SRC" "$FILE"
else
printf 'LOCAL_SRC_FILES := %s/lib/%s\n' "$SRC" "$FILE"
fi
if [ "$EXTRA" != "none" ]; then
printf 'LOCAL_MULTILIB := %s\n' "$EXTRA"
fi
elif [ "$CLASS" = "APPS" ]; then
if [ -z "$ARGS" ]; then
if [ "$EXTRA" = "priv-app" ]; then
SRC="$SRC/priv-app"
else
SRC="$SRC/app"
fi
fi
printf 'LOCAL_SRC_FILES := %s/%s\n' "$SRC" "$FILE"
local CERT=platform
if [ ! -z "$ARGS" ]; then
CERT="$ARGS"
fi
printf 'LOCAL_CERTIFICATE := %s\n' "$CERT"
elif [ "$CLASS" = "JAVA_LIBRARIES" ]; then
printf 'LOCAL_SRC_FILES := %s/framework/%s\n' "$SRC" "$FILE"
local CERT=platform
if [ ! -z "$ARGS" ]; then
CERT="$ARGS"
fi
printf 'LOCAL_CERTIFICATE := %s\n' "$CERT"
elif [ "$CLASS" = "ETC" ]; then
printf 'LOCAL_SRC_FILES := %s/etc/%s\n' "$SRC" "$FILE"
elif [ "$CLASS" = "EXECUTABLES" ]; then
if [ "$ARGS" = "rootfs" ]; then
SRC="$SRC/rootfs"
if [ "$EXTRA" = "sbin" ]; then
SRC="$SRC/sbin"
printf '%s\n' "LOCAL_MODULE_PATH := \$(TARGET_ROOT_OUT_SBIN)"
printf '%s\n' "LOCAL_UNSTRIPPED_PATH := \$(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)"
fi
else
SRC="$SRC/bin"
fi
printf 'LOCAL_SRC_FILES := %s/%s\n' "$SRC" "$FILE"
unset EXTENSION
else
printf 'LOCAL_SRC_FILES := %s/%s\n' "$SRC" "$FILE"
fi
printf 'LOCAL_MODULE_TAGS := optional\n'
printf 'LOCAL_MODULE_CLASS := %s\n' "$CLASS"
if [ "$CLASS" = "APPS" ]; then
printf 'LOCAL_DEX_PREOPT := false\n'
fi
if [ ! -z "$EXTENSION" ]; then
printf 'LOCAL_MODULE_SUFFIX := .%s\n' "$EXTENSION"
fi
if [ "$EXTRA" = "priv-app" ]; then
printf 'LOCAL_PRIVILEGED_MODULE := true\n'
fi
if [ "$VENDOR_PKG" = "true" ]; then
printf 'LOCAL_PROPRIETARY_MODULE := true\n'
fi
printf 'include $(BUILD_PREBUILT)\n\n'
done
}
#
# write_product_packages:
#
# This function will create BUILD_PREBUILT entries in the
# Android.mk 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=()
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=( $(comm -12 <(printf '%s\n' "${T_LIB32[@]}") <(printf '%s\n' "${T_LIB64[@]}")) )
local LIB32=( $(comm -23 <(printf '%s\n' "${T_LIB32[@]}") <(printf '%s\n' "${MULTILIBS[@]}")) )
local LIB64=( $(comm -23 <(printf '%s\n' "${T_LIB64[@]}") <(printf '%s\n' "${MULTILIBS[@]}")) )
if [ "${#MULTILIBS[@]}" -gt "0" ]; then
write_packages "SHARED_LIBRARIES" "false" "both" "MULTILIBS" >> "$ANDROIDMK"
fi
if [ "${#LIB32[@]}" -gt "0" ]; then
write_packages "SHARED_LIBRARIES" "false" "32" "LIB32" >> "$ANDROIDMK"
fi
if [ "${#LIB64[@]}" -gt "0" ]; then
write_packages "SHARED_LIBRARIES" "false" "64" "LIB64" >> "$ANDROIDMK"
fi
local T_V_LIB32=( $(prefix_match "vendor/lib/") )
local T_V_LIB64=( $(prefix_match "vendor/lib64/") )
local V_MULTILIBS=( $(comm -12 <(printf '%s\n' "${T_V_LIB32[@]}") <(printf '%s\n' "${T_V_LIB64[@]}")) )
local V_LIB32=( $(comm -23 <(printf '%s\n' "${T_V_LIB32[@]}") <(printf '%s\n' "${V_MULTILIBS[@]}")) )
local V_LIB64=( $(comm -23 <(printf '%s\n' "${T_V_LIB64[@]}") <(printf '%s\n' "${V_MULTILIBS[@]}")) )
if [ "${#V_MULTILIBS[@]}" -gt "0" ]; then
write_packages "SHARED_LIBRARIES" "true" "both" "V_MULTILIBS" >> "$ANDROIDMK"
fi
if [ "${#V_LIB32[@]}" -gt "0" ]; then
write_packages "SHARED_LIBRARIES" "true" "32" "V_LIB32" >> "$ANDROIDMK"
fi
if [ "${#V_LIB64[@]}" -gt "0" ]; then
write_packages "SHARED_LIBRARIES" "true" "64" "V_LIB64" >> "$ANDROIDMK"
fi
# Apps
local APPS=( $(prefix_match "app/") )
if [ "${#APPS[@]}" -gt "0" ]; then
write_packages "APPS" "false" "" "APPS" >> "$ANDROIDMK"
fi
local PRIV_APPS=( $(prefix_match "priv-app/") )
if [ "${#PRIV_APPS[@]}" -gt "0" ]; then
write_packages "APPS" "false" "priv-app" "PRIV_APPS" >> "$ANDROIDMK"
fi
local V_APPS=( $(prefix_match "vendor/app/") )
if [ "${#V_APPS[@]}" -gt "0" ]; then
write_packages "APPS" "true" "" "V_APPS" >> "$ANDROIDMK"
fi
local V_PRIV_APPS=( $(prefix_match "vendor/priv-app/") )
if [ "${#V_PRIV_APPS[@]}" -gt "0" ]; then
write_packages "APPS" "true" "priv-app" "V_PRIV_APPS" >> "$ANDROIDMK"
fi
# Framework
local FRAMEWORK=( $(prefix_match "framework/") )
if [ "${#FRAMEWORK[@]}" -gt "0" ]; then
write_packages "JAVA_LIBRARIES" "false" "" "FRAMEWORK" >> "$ANDROIDMK"
fi
# Etc
local ETC=( $(prefix_match "etc/") )
if [ "${#ETC[@]}" -gt "0" ]; then
write_packages "ETC" "false" "" "ETC" >> "$ANDROIDMK"
fi
local V_ETC=( $(prefix_match "vendor/etc/") )
if [ "${#V_ETC[@]}" -gt "0" ]; then
write_packages "ETC" "false" "" "V_ETC" >> "$ANDROIDMK"
fi
# Executables
local BIN=( $(prefix_match "bin/") )
if [ "${#BIN[@]}" -gt "0" ]; then
write_packages "EXECUTABLES" "false" "" "BIN" >> "$ANDROIDMK"
fi
local V_BIN=( $(prefix_match "vendor/bin/") )
if [ "${#V_BIN[@]}" -gt "0" ]; then
write_packages "EXECUTABLES" "true" "" "V_BIN" >> "$ANDROIDMK"
fi
local SBIN=( $(prefix_match "sbin/") )
if [ "${#SBIN[@]}" -gt "0" ]; then
write_packages "EXECUTABLES" "false" "sbin" "SBIN" >> "$ANDROIDMK"
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_header:
#
# $1: file which will be written to
#
# writes out the copyright header with the current year.
# note that this is not an append operation, and should
# be executed first!
#
function write_header() {
if [ -f $1 ]; then
rm $1
fi
YEAR=$(date +"%Y")
[ "$COMMON" -eq 1 ] && local DEVICE="$DEVICE_COMMON"
NUM_REGEX='^[0-9]+$'
if [[ $INITIAL_COPYRIGHT_YEAR =~ $NUM_REGEX ]] && [ $INITIAL_COPYRIGHT_YEAR -le $YEAR ]; then
if [ $INITIAL_COPYRIGHT_YEAR -lt 2016 ]; then
printf "# Copyright (C) $INITIAL_COPYRIGHT_YEAR-2016 The CyanogenMod Project\n" > $1
elif [ $INITIAL_COPYRIGHT_YEAR -eq 2016 ]; then
printf "# Copyright (C) 2016 The CyanogenMod Project\n" > $1
fi
if [ $YEAR -eq 2017 ]; then
printf "# Copyright (C) 2017 The LineageOS Project\n" >> $1
elif [ $INITIAL_COPYRIGHT_YEAR -eq $YEAR ]; then
printf "# Copyright (C) $YEAR The LineageOS Project\n" >> $1
elif [ $INITIAL_COPYRIGHT_YEAR -le 2017 ]; then
printf "# Copyright (C) 2017-$YEAR The LineageOS Project\n" >> $1
else
printf "# Copyright (C) $INITIAL_COPYRIGHT_YEAR-$YEAR The LineageOS Project\n" >> $1
fi
else
printf "# Copyright (C) $YEAR The LineageOS Project\n" > $1
fi
cat << EOF >> $1
#
# 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.
# 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_header for each of the makefiles and creates
# the initial path declaration and device guard for the
# Android.mk
#
function write_headers() {
write_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_header "$BOARDMK"
write_header "$PRODUCTMK"
}
#
# 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
#
# 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
PRODUCT_PACKAGES_LIST=()
PRODUCT_PACKAGES_HASHES=()
PRODUCT_COPY_FILES_LIST=()
PRODUCT_COPY_FILES_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"
if [ "$COUNT" -gt "1" ]; then
HASH=${SPLIT[1]}
fi
# if line starts with a dash, it needs to be packaged
if [[ "$SPEC" =~ ^- ]]; then
PRODUCT_PACKAGES_LIST+=("${SPEC#-}")
PRODUCT_PACKAGES_HASHES+=("$HASH")
else
PRODUCT_COPY_FILES_LIST+=("$SPEC")
PRODUCT_COPY_FILES_HASHES+=("$HASH")
fi
done < <(egrep -v '(^#|^[[:space:]]*$)' "$1" | sort | uniq)
}
#
# write_makefiles:
#
# $1: file containing the list of items to extract
#
# Calls write_product_copy_files and write_product_packages on
# the given file and appends to the Android.mk as well as
# the product makefile.
#
function write_makefiles() {
parse_file_list "$1"
write_product_copy_files
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
return 1
else
# try to copy
cp -r "$SRC/$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 CM_TARGET="$1"
local OEM_TARGET="$2"
local SRC="$3"
local TARGET=
local OAT=
if [ -z "$BAKSMALIJAR" ] || [ -z "$SMALIJAR" ]; then
export BAKSMALIJAR="$CM_ROOT"/vendor/cm/build/tools/smali/baksmali.jar
export SMALIJAR="$CM_ROOT"/vendor/cm/build/tools/smali/smali.jar
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 "$TMPDIR/system/framework/$ARCH"
if get_file "system/framework/$ARCH/" "$TMPDIR/system/framework/" "$SRC"; then
ARCHES+="$ARCH "
else
rmdir "$TMPDIR/system/framework/$ARCH"
fi
done
fi
if [ -z "$ARCHES" ]; then
FULLY_DEODEXED=1 && return 0 # system is fully deodexed, return
fi
if [ ! -f "$CM_TARGET" ]; then
return;
fi
if grep "classes.dex" "$CM_TARGET" >/dev/null; then
return 0 # target apk|jar is already odexed, return
fi
for ARCH in $ARCHES; do
BOOTOAT="$TMPDIR/system/framework/$ARCH/boot.oat"
local OAT="$(dirname "$OEM_TARGET")/oat/$ARCH/$(basename "$OEM_TARGET" ."${OEM_TARGET##*.}").odex"
if get_file "$OAT" "$TMPDIR" "$SRC"; then
java -jar "$BAKSMALIJAR" deodex -o "$TMPDIR/dexout" -b "$BOOTOAT" -d "$TMPDIR" "$TMPDIR/$(basename "$OAT")"
elif [[ "$CM_TARGET" =~ .jar$ ]]; then
# try to extract classes.dex from boot.oats for framework jars
JAROAT="$TMPDIR/system/framework/$ARCH/boot-$(basename ${OEM_TARGET%.*}).oat"
if [ ! -f "$JAROAT" ]; then
JAROAT=$BOOTOAT;
fi
java -jar "$BAKSMALIJAR" deodex -o "$TMPDIR/dexout" -b "$BOOTOAT" -d "$TMPDIR" "$JAROAT/$OEM_TARGET"
else
continue
fi
java -jar "$SMALIJAR" assemble "$TMPDIR/dexout" -o "$TMPDIR/classes.dex" && break
done
rm -rf "$TMPDIR/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 | egrep '^[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="$TMPDIR/`basename "$XML"`.temp"
grep '^<?xml version' "$XML" > "$TEMP_XML"
grep -v '^<?xml version' "$XML" >> "$TEMP_XML"
mv "$TEMP_XML" "$XML"
}
#
# extract:
#
# $1: file containing the list of items to extract
# $2: path to extracted system folder, or "adb" to extract from device
#
function extract() {
if [ -z "$OUTDIR" ]; then
echo "Output dir not set!"
exit 1
fi
parse_file_list "$1"
# 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 COUNT=${#FILELIST[@]}
local SRC="$2"
local OUTPUT_ROOT="$CM_ROOT"/"$OUTDIR"/proprietary
local OUTPUT_TMP="$TMPDIR"/"$OUTDIR"/proprietary
if [ "$SRC" = "adb" ]; then
init_adb_connection
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 $1 from $SRC:"
for (( i=1; i<COUNT+1; i++ )); do
local FROM=$(target_file "${FILELIST[$i-1]}")
local ARGS=$(target_args "${FILELIST[$i-1]}")
local SPLIT=(${FILELIST[$i-1]//:/ })
local FILE="${SPLIT[0]#-}"
local OUTPUT_DIR="$OUTPUT_ROOT"
local TMP_DIR="$OUTPUT_TMP"
local TARGET=
if [ "$ARGS" = "rootfs" ]; then
TARGET="$FROM"
OUTPUT_DIR="$OUTPUT_DIR/rootfs"
TMP_DIR="$TMP_DIR/rootfs"
else
TARGET="system/$FROM"
FILE="system/$FILE"
fi
if [ "$SRC" = "adb" ]; then
printf ' - %s .. ' "/$TARGET"
else
printf ' - %s \n' "/$TARGET"
fi
local DIR=$(dirname "$FROM")
if [ ! -d "$OUTPUT_DIR/$DIR" ]; then
mkdir -p "$OUTPUT_DIR/$DIR"
fi
local DEST="$OUTPUT_DIR/$FROM"
if [ "$SRC" = "adb" ]; then
# Try CM target first
adb pull "/$TARGET" "$DEST"
# if file does not exist try OEM target
if [ "$?" != "0" ]; then
adb pull "/$FILE" "$DEST"
fi
else
# Try CM target first
if [ -f "$SRC/$TARGET" ]; then
cp "$SRC/$TARGET" "$DEST"
# if file does not exist try OEM target
elif [ -f "$SRC/$FILE" ]; then
cp "$SRC/$FILE" "$DEST"
else
printf ' !! file not found in source\n'
fi
fi
if [ "$?" == "0" ]; then
# Deodex apk|jar if that's the case
if [[ "$FULLY_DEODEXED" -ne "1" && "$DEST" =~ .(apk|jar)$ ]]; then
oat2dex "$DEST" "$FILE" "$SRC"
if [ -f "$TMPDIR/classes.dex" ]; then
zip -gjq "$DEST" "$TMPDIR/classes.dex"
rm "$TMPDIR/classes.dex"
printf ' (updated %s from odex files)\n' "/$FILE"
fi
elif [[ "$DEST" =~ .xml$ ]]; then
fix_xml "$DEST"
fi
fi
# Check pinned files
local HASH="${HASHLIST[$i-1]}"
if [ "$DISABLE_PINNING" != "1" ] && [ ! -z "$HASH" ] && [ "$HASH" != "x" ]; then
local KEEP=""
local TMP="$TMP_DIR/$FROM"
if [ -f "$TMP" ]; then
if [ ! -f "$DEST" ]; then
KEEP="1"
else
if [ "$(uname)" == "Darwin" ]; then
local DEST_HASH=$(shasum "$DEST" | awk '{print $1}' )
else
local DEST_HASH=$(sha1sum "$DEST" | awk '{print $1}' )
fi
if [ "$DEST_HASH" != "$HASH" ]; then
KEEP="1"
fi
fi
if [ "$KEEP" = "1" ]; then
if [ "$(uname)" == "Darwin" ]; then
local TMP_HASH=$(shasum "$TMP" | awk '{print $1}' )
else
local TMP_HASH=$(sha1sum "$TMP" | awk '{print $1}' )
fi
if [ "$TMP_HASH" = "$HASH" ]; then
printf ' + (keeping pinned file with hash %s)\n' "$HASH"
cp -p "$TMP" "$DEST"
fi
fi
fi
fi
if [ -f "$DEST" ]; then
local TYPE="${DIR##*/}"
if [ "$TYPE" = "bin" -o "$TYPE" = "sbin" ]; then
chmod 755 "$DEST"
else
chmod 644 "$DEST"
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="$CM_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
}