Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save bashenk/b538ce0a60efe6a9c3b446683744d598 to your computer and use it in GitHub Desktop.

Select an option

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.
#!/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
@T-vK

T-vK commented Mar 23, 2021

Copy link
Copy Markdown

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment