1#!/bin/bash 2# 3# Copyright (C) 2020 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17# This program fixes prebuilt ELF check errors by updating the "shared_libs" 18# fields in Android.bp. 19# 20# Example: 21# $ source build/envsetup.sh 22# $ m fix_android_bp_prebuilt bpflatten bpmodify 23# $ fix_android_bp_prebuilt --in-place path_to_problematic_android_bp 24 25set -e 26 27function usage() { 28 cat <<EOF 29Usage: 30 $0 [OPTION]... FILE 31 32Options: 33 --in-place 34 Edit file in place (overwrites source file) 35 --diff 36 Show diffs 37 -h, --help, --usage 38 Display this message and exit 39EOF 40} 41 42function exit_handler() { 43 readonly EXIT_CODE="$?" 44 # Cleanup any temporary files 45 rm -rf "$TEMP_DIR" 46 exit "$EXIT_CODE" 47} 48 49trap exit_handler EXIT 50 51function trim_space() { 52 echo "$1" | sed -E 's/^[[:space:]]+//;s/[[:space:]]+$//' 53} 54 55function get_prop() { 56 echo "${MODULE_PROP_VALUES_DICT[${1}:${2}]}" 57} 58 59function rewrite_prop() { 60 local ORIGINAL_VALUE=$(trim_space "$(get_prop "$1" "$2")") 61 if [[ -n "$ORIGINAL_VALUE" ]]; then 62 bpmodify -m "$1" -property "$2" -r "$ORIGINAL_VALUE" -w "$TEMP_ANDROID_BP" 63 fi 64 if [[ -n "$3" ]]; then 65 bpmodify -m "$1" -property "$2" -a "$3" -w "$TEMP_ANDROID_BP" 66 fi 67} 68 69function get_dt_needed() { 70 local DYNAMIC_TABLE=$($READELF -d "${ANDROID_BP_DIR}/$1") 71 if [[ "$?" -ne 0 ]]; then 72 return 1 73 fi 74 echo "$DYNAMIC_TABLE" | 75 sed -n -E 's/^[[:space:]]*0x[[:xdigit:]]+[[:space:]]+\(NEEDED\).*\[(.+)\.so\].*$/\1/p' | 76 xargs 77} 78 79function unique() { 80 echo "$1" | xargs -n1 | sort | uniq | xargs 81} 82 83 84while [[ "$1" =~ ^- ]]; do 85 case "$1" in 86 -h | --help | --usage) 87 usage 88 exit 0 89 ;; 90 --in-place) 91 EDIT_IN_PLACE=1 92 ;; 93 --diff) 94 SHOW_DIFF=1 95 ;; 96 -x) 97 set -x 98 ;; 99 --) 100 shift 101 break 102 ;; 103 *) 104 echo >&2 "Unexpected flag: $1" 105 usage >&2 106 exit 1 107 ;; 108 esac 109 shift 110done 111 112if ! [[ -f "$1" ]]; then 113 echo >&2 "No such file: '$1'" 114 exit 1 115fi 116 117if [[ -e "$(command -v llvm-readelf)" ]]; then 118 READELF="llvm-readelf" 119elif [[ -e "$(command -v readelf)" ]]; then 120 READELF="readelf -W" 121else 122 echo >&2 'Cannot find readelf in $PATH, please run:' 123 echo >&2 '$ source build/envsetup.sh' 124 exit 1 125fi 126 127if ! [[ -e "$(command -v bpflatten)" && -e "$(command -v bpmodify)" ]]; then 128 echo >&2 'Cannot find bpflatten and bpmodify in $PATH, please run:' 129 echo >&2 '$ source build/envsetup.sh' 130 echo >&2 '$ m blueprint_tools' 131 exit 1 132fi 133 134readonly EDIT_IN_PLACE 135readonly SHOW_DIFF 136readonly READELF 137readonly ANDROID_BP="$1" 138readonly ANDROID_BP_DIR=$(dirname "$ANDROID_BP") 139readonly TEMP_DIR=$(mktemp -d) 140readonly TEMP_ANDROID_BP="${TEMP_DIR}/Android.bp" 141 142cp -L "$ANDROID_BP" "$TEMP_ANDROID_BP" 143 144# This subshell and `eval` must be on separate lines, so that eval would not 145# shadow the subshell's exit code. 146# In other words, if `bpflatten` fails, we mustn't eval its output. 147FLATTEN_COMMAND=$(bpflatten --bash "$ANDROID_BP") 148eval "$FLATTEN_COMMAND" 149 150for MODULE_NAME in "${MODULE_NAMES[@]}" ; do 151 MODULE_TYPE="${MODULE_TYPE_DICT[${MODULE_NAME}]}" 152 if ! [[ "$MODULE_TYPE" =~ ^(.+_)?prebuilt(_.+)?$ ]]; then 153 continue 154 fi 155 156 SRCS=$(get_prop "$MODULE_NAME" "srcs") 157 SHARED_LIBS=$(get_prop "$MODULE_NAME" "shared_libs") 158 if [[ -n "${SRCS}" ]]; then 159 DT_NEEDED=$(get_dt_needed "$SRCS") 160 if [[ $(unique "$DT_NEEDED") != $(unique "$SHARED_LIBS") ]]; then 161 rewrite_prop "$MODULE_NAME" "shared_libs" "$DT_NEEDED" 162 fi 163 fi 164 165 # Handle different arch / target variants... 166 for PROP in ${MODULE_PROP_KEYS_DICT[${MODULE_NAME}]} ; do 167 if ! [[ "$PROP" =~ \.srcs$ ]]; then 168 continue 169 fi 170 SRCS=$(get_prop "$MODULE_NAME" "$PROP") 171 DT_NEEDED=$(get_dt_needed "$SRCS") 172 SHARED_LIBS_PROP="${PROP%.srcs}.shared_libs" 173 VARIANT_SHARED_LIBS="${SHARED_LIBS} $(get_prop "$MODULE_NAME" "$SHARED_LIBS_PROP")" 174 if [[ $(unique "$DT_NEEDED") != $(unique "$VARIANT_SHARED_LIBS") ]]; then 175 rewrite_prop "$MODULE_NAME" "$SHARED_LIBS_PROP" "$DT_NEEDED" 176 fi 177 done 178done 179 180if [[ -n "$SHOW_DIFF" ]]; then 181 diff -u "$ANDROID_BP" "$TEMP_ANDROID_BP" || true 182fi 183 184if [[ -n "$EDIT_IN_PLACE" ]]; then 185 cp "$TEMP_ANDROID_BP" "$ANDROID_BP" 186fi 187 188if [[ -z "${SHOW_DIFF}${EDIT_IN_PLACE}" ]]; then 189 cat "$TEMP_ANDROID_BP" 190fi 191