Forked from ktnr74/get_android_service_call_numbers.sh
Last active
January 25, 2023 19:49
-
-
Save bashenk/b538ce0a60efe6a9c3b446683744d598 to your computer and use it in GitHub Desktop.
POSIX compliant and portable fork. Now has been updated with more optional parameters, more optimizations, and better error handling. If -t or -v are specified, an android device is not required.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env sh | |
set -u | |
# https://stackoverflow.com/questions/2683279/how-to-detect-if-a-script-is-being-sourced#28776166 | |
sourced=0 | |
if [ -n "${ZSH_EVAL_CONTEXT-}" ]; then | |
case $ZSH_EVAL_CONTEXT in *:file) sourced=1;; esac; | |
elif [ -n "${KSH_VERSION-}" ]; then | |
if [ "$(cd "$(dirname -- "$0")" && pwd -P)/$(basename -- "$0")" != "$(cd "$(dirname -- "${.sh.file}")" && pwd -P)/$(basename -- "${.sh.file}")" ]; then | |
sourced=1 | |
fi; | |
elif [ -n "${BASH_VERSION-}" ]; then | |
if (return 0 2>/dev/null); then | |
sourced=1 | |
fi; | |
else # All other shells: examine $0 for known shell binary filenames | |
# Detects `sh` and `dash`; add additional shell filenames as needed. | |
case ${0##*/} in sh|dash) sourced=1;; esac; | |
fi; | |
# if [ $sourced -eq 0 ]; then set -e; fi | |
say () { if [ -z "${_quiet-}" ]; then printf '%s\n' "$@"; fi; } | |
quit () { | |
if [ $# -ge 1 ] && [ "$1" -eq "$1" ] 2>/dev/null; then exitCode="$1"; shift; fi; | |
if [ $# -ge 1 ] ; then printf '%s\n' "$@" 1>&2;fi; | |
if [ $sourced -eq 1 ]; then kill -INT 0; else exit "${exitCode:-0}";fi; | |
} | |
show_help () { | |
cat <<-EOF | |
Get an indexed list of service calls for a particular Android version and Android service. | |
$(basename "$0") [-s SERIAL | -t TAG | -v NUM] [-g GREP_ARGS] [-q] SERVICENAME | |
$(basename "$0") -a [-s SERIAL | -t TAG | -v NUM] [-g GREP_ARGS] [-q] | |
-a Get the output for every Android service available on the specified Android OS version | |
-h Display this help text | |
-g If provided, evaluate the provided argument with grep on each result | |
-q Limit output to only the service calls | |
-s Specify the ADB serial of the device to use for which to get the Android OS version | |
-t Specify the Android version tag from which to search for the service calls | |
-v Specify the Android OS version from which to get the latest version tag to use | |
EOF | |
} | |
while getopts ":ahqg:s:t:v:" OPT; do | |
case "$OPT" in | |
a ) _all=0 ;; | |
h ) show_help; quit ;; | |
g ) _grep="$OPTARG" ;; | |
q ) _quiet=0 ;; | |
s ) _adbSerial="$OPTARG" ;; | |
t ) _androidVersionTag="$OPTARG" ;; | |
v ) _androidVersion="$OPTARG" ;; | |
\? ) quit 2 "Argument '-$OPTARG' not recognized" ;; | |
esac | |
done | |
shift $((OPTIND-1)) | |
if [ -z "${_all-}" ]; then | |
if [ $# -eq 0 ]; then | |
show_help; quit 2 "Please provide a service name argument" | |
else | |
serviceName="$1" | |
fi | |
fi | |
assert_executables_are_available () { | |
bins= | |
for b in "$@"; do [ -n "$(command -v "$b" 2>/dev/null)" ] || bins="${bins-}$b "; done | |
if [ ${#bins} -eq 0 ]; then return 0; fi | |
printf '%s\n' "Cannot find the following executables:" "$bins" | |
printf 'Install them now? ' | |
read -r REPLY | |
[ "$REPLY" != "${REPLY#[Yy]}" ] || quit 1 "Exiting due to insufficient dependencies" | |
exec sudo apt install "$bins" | |
} | |
assert_executables_are_available grep sed wget | |
googleSource="https://android.googlesource.com" | |
repoPath="platform/frameworks/base" | |
get_first_adb_device_serial () { adb devices | sed -e '1d' -e '$d' -e '2s/[[:space:]].*device$//' -e 'q'; } | |
adb_shell () { eval adb "${_adbSerial:+-s $_adbSerial }"wait-for-device shell -T -x "$*" | tr -d '\r'; } | |
get_google_source_file () { wget -qO - "$googleSource/$repoPath/+/$1/$2?format=text" | base64 -d; } | |
get_android_tag_for_version () { | |
allTags="$(wget -qO - "$googleSource/$repoPath/+refs/tags/?format=text" | sed -e '/\^{}/d; s/.*\///' -e 'h' -e '/android-[0-9]/!d' | sort -V )" | |
latestTags="$(echo "$allTags" | sed -e 'h' -e 'N' -e '/^\(android-[0-9.]\+[a-z]*_r\)\([.0-9a-z]*\)\n\1/D' -e 'x' )" | |
localTag="$(echo "$latestTags" | sed -e "/android-$(echo "${1:?No Android version was specified in get_android_tag_for_version}" | sed -e 'y/././')/p;d" | tail -n 1)" | |
[ -n "$localTag" ] || quit 1 "TAG not valid!" "List of valid tags:" "$allTags" | |
echo "${localTag:?TAG not valid!\nList of valid tags:\n$allTags}" | |
} | |
get_service_package_name () { | |
packageName=$(adb_shell service list | sed -e '1d' -e 's/[0-9]*[[:space:]]'"${1:?No package name was specified in get_service_package_name}"': \[\(.*\)\]/\1/p' -e 'd'); | |
echo "${packageName:?Unable to find service package name for "$1"}"; | |
} | |
get_all_services_for_tag () { | |
if [ "${_androidVersion:?Android version was unspecified}" -gt 8 ]; then file='Android.bp'; else file='Android.mk'; fi | |
get_google_source_file "${1:?No tag was specified in get_all_services_for_tag}" "$file" | tr -d ' \\\t,"' | sed -e '/\.aidl$/!d' -e '/^gen:/d' | sort -u | |
} | |
parse_service_aidl () { | |
packageFilePath="$(echo "${3:?No package name was specified in parse_service_aidl}" | tr '.' '/')\.aidl" | |
servicePath="$(echo "${2:?Services list was not specified in parse_service_aidl}" | grep -m 1 "$packageFilePath\$")" | |
get_google_source_file "${1:?No tag was specified in parse_service_aidl}" "$servicePath" | sed -e '1,/interface/d' -e '/^$/d' -e 's/^[[:space:]]*//' -e '/^[^a-zA-Z]/d' -e '/^[^;]*$/{$!N}' -e '$d' -e 's/\(^\|\n\)[[:space:]]*\|\([[:space:]]\)\{2,\}/\2/g' | { if [ -n "${_grep-}" ]; then cat -n | eval grep "$_grep"; else cat -n; fi; } | |
} | |
if [ -n "${_androidVersionTag-}" ] && [ "$_androidVersionTag" -eq "$_androidVersionTag" ] 2>/dev/null; then | |
quit 1 "Tag was specified as '$_androidVersionTag'" "Are you sure you did not mean to specify Android OS Version (-v)?" | |
fi | |
if [ -n "${_androidVersion-}" ]; then | |
: | |
elif [ -n "${_androidVersionTag-}" ]; then | |
_androidVersion="$(echo "${_androidVersionTag}" | sed 's/^[-a-zA-Z]*\([0-9]*\)\.\?.*$/\1/')" | |
if [ "$_androidVersion" -ne "$_androidVersion" ] 2>/dev/null; then quit 1 "Failed to parse Android version from tag."; fi; | |
else | |
# Use _adbSerial variable for device, or grab the first available device's serial number | |
assert_executables_are_available adb | |
if [ -z "${_adbSerial-}" ]; then | |
_adbSerial="$(adb devices | sed -e '1d' -e '$d' -e '2s/[[:space:]].*device$//' -e 'q')"; | |
fi | |
say "ADB Serial = ${_adbSerial:?No devices found}" 1>&2; | |
_androidVersion="$(adb_shell getprop ro.build.version.release)" | |
fi | |
if [ -z "${_androidVersionTag-}" ]; then | |
_androidVersionTag="$(get_android_tag_for_version "$_androidVersion")" | |
fi | |
allServices="$(get_all_services_for_tag "$_androidVersionTag")" | |
if [ -z "${allServices-}" ]; then | |
quit 2 "Failed to find services. It is likely an invalid tag was specified" | |
fi | |
say "Android OS Version = ${_androidVersion:?Android OS Version was null}" 1>&2; | |
say "Android Version Tag = ${_androidVersionTag:?Android Version Tag was null}" 1>&2; | |
if [ -n "${_all-}" ]; then | |
for srv in $allServices; do | |
result="$(get_google_source_file "$_androidVersionTag" "$srv" | sed -e '1,/interface/d' -e '/^$/d' -e 's/^[[:space:]]*//' -e '/^[^a-zA-Z]/d' -e '/^[^;]*$/{$!N}' -e '$d' -e 's/\(^\|\n\)[[:space:]]*\|\([[:space:]]\)\{2,\}/\2/g' | { if [ -n "${_grep-}" ]; then cat -n | eval grep "$_grep" || true; else cat -n; fi; })" | |
if [ -n "${result-}" ]; then | |
printf '%s\n' "Service \"${srv##*/}\":" "$result" | |
fi | |
done | |
else | |
assert_executables_are_available adb | |
if [ -z "${serviceName-}" ]; then say "ServiceName=$serviceName" 1>&2; fi | |
if [ -z "${servicePackage-}" ]; then say "ServicePackageName=${servicePackage:="$(get_service_package_name "$serviceName")"}" 1>&2; fi | |
parse_service_aidl "$_androidVersionTag" "$allServices" "$servicePackage" | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Starting with Android 11 you have to actually search through the entire directory tree to find the aidl files because Android.bp only contains a bunch of glob expressions for the aidl file paths. I got that working in android-svc here:
https://github.com/T-vK/android-svc/blob/7c9d9c590e7ecbe8170086f3aafde54fe5ffd1ce/android-svc-lib.sh#L260
I'm probably not POSIX compliant, but feel free to use that information to update your
get_all_services_for_tag
function.