Home | History | Annotate | Download | only in ndk
      1 #!/bin/sh
      2 #
      3 # Copyright (C) 2010 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 
     18 # This wrapper script is used to launch a native debugging session
     19 # on a given NDK application. The application must be debuggable, i.e.
     20 # its android:debuggable attribute must be set to 'true' in the
     21 # <application> element of its manifest.
     22 #
     23 # See docs/NDK-GDB.TXT for usage description. Essentially, you just
     24 # need to launch ndk-gdb from your application project directory
     25 # after doing ndk-build && ant install && <start-application-on-device>
     26 #
     27 PROGDIR=`dirname $0`
     28 PROGDIR=`cd $PROGDIR && pwd -P`
     29 
     30 # Check if absolute NDK path contain space
     31 #
     32 case $PROGDIR in
     33     *\ *) echo "ERROR: NDK path cannot contain space"
     34           exit 1
     35         ;;
     36 esac
     37 
     38 NDK_BUILDTOOLS_PATH=$PROGDIR/build/tools
     39 . $PROGDIR/build/tools/prebuilt-common.sh
     40 . $PROGDIR/build/tools/ndk-common.sh
     41 
     42 force_32bit_binaries
     43 
     44 # Find if a given shell program is available.
     45 # We need to take care of the fact that the 'which <foo>' command
     46 # may return either an empty string (Linux) or something like
     47 # "no <foo> in ..." (Darwin). Also, we need to redirect stderr
     48 # to /dev/null for Cygwin
     49 #
     50 # $1: program name
     51 # Out: program path, or empty string
     52 # Return: 0 on success, != 0 on error
     53 #
     54 find_program ()
     55 {
     56     local PROG RET
     57     PROG=$(which "$1" 2>/dev/null)
     58     RET=$?
     59     if [ $RET != 0 ]; then
     60         PROG=
     61     fi
     62     echo "$PROG"
     63     return $RET
     64 }
     65 
     66 quote_spaces ()
     67 {
     68     echo "$@" | sed -e 's! !\ !g'
     69 }
     70 
     71 # If ADB_CMD is not defined, try to find a program named 'adb'
     72 # in our path.
     73 ADB_CMD=${ADB_CMD:-$(find_program adb)}
     74 ADB_FLAGS=${ADB_FLAGS:-}
     75 DEVICE_SERIAL=
     76 
     77 JDB_CMD=${JDB_CMD:-$(find_program jdb)}
     78 
     79 AWK_CMD=${AWK_CMD:-$(find_program awk)}
     80 
     81 DEBUG_PORT=5039
     82 JDB_PORT=65534
     83 
     84 UNKNOWN_ABI=$(find_ndk_unknown_archs)
     85 
     86 # Delay in seconds between launching the activity and attaching gdbserver on it.
     87 # This is needed because there is no way to know when the activity has really
     88 # started, and sometimes this takes a few seconds.
     89 DELAY=2
     90 
     91 PARAMETERS=
     92 OPTION_HELP=no
     93 OPTION_PROJECT=
     94 OPTION_FORCE=no
     95 OPTION_ADB=
     96 OPTION_EXEC=
     97 OPTION_START=no
     98 OPTION_LAUNCH=
     99 OPTION_LAUNCH_LIST=no
    100 OPTION_DELAY=
    101 OPTION_WAIT="-D"
    102 OPTION_PACKAGE_NAME=
    103 
    104 check_parameter ()
    105 {
    106     if [ -z "$2" ]; then
    107         echo "ERROR: Missing parameter after option '$1'"
    108         exit 1
    109     fi
    110 }
    111 
    112 check_adb_flags ()
    113 {
    114     if [ -n "$ADB_FLAGS" ] ; then
    115         echo "ERROR: Only one of -e, -d or -s <serial> can be used at the same time!"
    116         exit 1
    117     fi
    118 }
    119 
    120 get_build_var ()
    121 {
    122     if [ -z "$GNUMAKE" ] ; then
    123         GNUMAKE=make
    124     fi
    125     $GNUMAKE --no-print-dir -f $ANDROID_NDK_ROOT/build/core/build-local.mk -C $PROJECT DUMP_$1 | tail -1
    126 }
    127 
    128 get_build_var_for_abi ()
    129 {
    130     if [ -z "$GNUMAKE" ] ; then
    131         GNUMAKE=make
    132     fi
    133     $GNUMAKE --no-print-dir -f $ANDROID_NDK_ROOT/build/core/build-local.mk -C $PROJECT DUMP_$1 APP_ABI=$2 | tail -1
    134 }
    135 
    136 # Used to run an awk script on the manifest
    137 run_awk_manifest_script ()
    138 {
    139     $AWK_CMD -f $AWK_SCRIPTS/$1 $PROJECT/$MANIFEST
    140 }
    141 
    142 if [ "$HOST_OS" = "cygwin" ] ; then
    143 # Return native path representation from cygwin one
    144 # $1: a cygwin-compatible path (e.g. /cygdrive/c/some/thing)
    145 # Return: path in host windows representation, e.g. C:/some/thing
    146 #
    147 # We use mixed mode (i.e. / as the directory separator) because
    148 # all the tools we use recognize it properly, and it avoids lots
    149 # of escaping nonsense associated with "\"
    150 #
    151 native_path ()
    152 {
    153     cygpath -m $1
    154 }
    155 else # HOST_OS != windows
    156 native_path ()
    157 {
    158     echo "$1"
    159 }
    160 fi # HOST_OS != windows
    161 
    162 # We need to ensure the ANDROID_NDK_ROOT is absolute, otherwise calls
    163 # to get_build_var, get_build_var_for_abi and run_awk_manifest_script
    164 # might fail, e.g. when invoked with:
    165 #
    166 #   cd $NDKROOT
    167 #   ./ndk-gdb --project=/path/to/project
    168 #
    169 path_is_absolute ()
    170 {
    171     local P P2
    172     P=$1       # copy path
    173     P2=${P#/}  # remove / prefix, if any
    174     [ "$P" != "$P2" ]
    175 }
    176 
    177 if ! path_is_absolute "$ANDROID_NDK_ROOT"; then
    178     ANDROID_NDK_ROOT=$(pwd)/$ANDROID_NDK_ROOT
    179 fi
    180 
    181 
    182 VERBOSE=no
    183 while [ -n "$1" ]; do
    184     opt="$1"
    185     optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'`
    186     case "$opt" in
    187         --help|-h|-\?)
    188             OPTION_HELP=yes
    189             ;;
    190         --verbose)
    191             VERBOSE=yes
    192             ;;
    193         -s)
    194             check_parameter $1 $2
    195             check_adb_flags
    196             ADB_FLAGS=" -s"
    197             DEVICE_SERIAL=$2
    198             shift
    199             ;;
    200         -s*)
    201             check_adb_flags
    202             optarg=`expr -- "$opt" : '-s\(.*\)'`
    203             ADB_FLAGS=" -s"
    204             DEVICE_SERIAL=$optarg
    205             ;;
    206         -p)
    207             check_parameter $1 $2
    208             OPTION_PROJECT="$2"
    209             shift
    210             ;;
    211         -p*)
    212             optarg=`expr -- "$opt" : '-p\(.*\)'`
    213             OPTION_PROJECT="$optarg"
    214             ;;
    215         --exec=*)
    216             OPTION_EXEC="$optarg"
    217             ;;
    218         -x)
    219             check_parameter $1 $2
    220             OPTION_EXEC="$2"
    221             shift
    222             ;;
    223         -x*)
    224             optarg=`expr -- "$opt" : '-x\(.*\)'`
    225             OPTION_EXEC="$optarg"
    226             ;;
    227         -e)
    228             check_adb_flags
    229             ADB_FLAGS=" -e"
    230             ;;
    231         -d)
    232             check_adb_flags
    233             ADB_FLAGS=" -d"
    234             ;;
    235         --adb=*) # specify ADB command
    236             OPTION_ADB="$optarg"
    237             ;;
    238         --awk=*)
    239             AWK_CMD="$optarg"
    240             ;;
    241         --project=*)
    242             OPTION_PROJECT="$optarg"
    243             ;;
    244         --port=*)
    245             DEBUG_PORT="$optarg"
    246             ;;
    247         --force)
    248             OPTION_FORCE="yes"
    249             ;;
    250         --launch-list)
    251             OPTION_LAUNCH_LIST="yes"
    252             ;;
    253         --launch=*)
    254             OPTION_LAUNCH="$optarg"
    255             ;;
    256         --start)
    257             OPTION_START=yes
    258             ;;
    259         --delay=*)
    260             OPTION_DELAY="$optarg"
    261             ;;
    262         --nowait)
    263             JDB_PORT=
    264             OPTION_WAIT=
    265             ;;
    266         --package=*)
    267             OPTION_PACKAGE_NAME="$optarg"
    268             ;;
    269         -*) # unknown options
    270             echo "ERROR: Unknown option '$opt', use --help for list of valid ones."
    271             exit 1
    272         ;;
    273         *)  # Simply record parameter
    274             if [ -z "$PARAMETERS" ] ; then
    275                 PARAMETERS="$opt"
    276             else
    277                 PARAMETERS="$PARAMETERS $opt"
    278             fi
    279             ;;
    280     esac
    281     shift
    282 done
    283 
    284 if [ -z "$JDB_CMD" ] && [ -n "$OPTION_WAIT" ]; then
    285     echo "ERROR: 'jdb' not found; you must either install the JDK, or specify --nowait"
    286     exit 1
    287 fi
    288 if [ -n "$JDB_PORT" ] && [ "$JDB_PORT" = "$DEBUG_PORT" ]; then
    289     echo "ERROR: --port specified cannot be $JDB_PORT without --nowait"
    290     exit 1
    291 fi
    292 
    293 if [ "$OPTION_HELP" = "yes" ] ; then
    294     echo "Usage: $PROGNAME [options]"
    295     echo ""
    296     echo "Setup a gdb debugging session for your Android NDK application."
    297     echo "Read $$NDK/docs/NDK-GDB.TXT for complete usage instructions."
    298     echo ""
    299     echo "Valid options:"
    300     echo ""
    301     echo "    --help|-h|-?      Print this help"
    302     echo "    --verbose         Enable verbose mode"
    303     echo "    --force           Kill existing debug session if it exists"
    304     echo "    --nowait          Don't have application wait for debugger to attach"
    305     echo "                         (This might cause you to miss some early JNI breakpoints)"
    306     echo "    --start           Launch application instead of attaching to existing one"
    307     echo "    --launch=<name>   Same as --start, but specify activity name (see below)"
    308     echo "    --launch-list     List all launchable activity names from manifest"
    309     echo "    --delay=<secs>    Delay in seconds between activity start and gdbserver attach."
    310     echo "    --project=<path>  Specify application project path"
    311     echo "    -p <path>         Same as --project=<path>"
    312     echo "    --package=<name>  Specify package name"
    313     echo "    --port=<port>     Use tcp:localhost:<port> to communicate with gdbserver [$DEBUG_PORT]"
    314     echo "    --exec=<file>     Execute gdb initialization commands in <file> after connection"
    315     echo "    -x <file>         Same as --exec=<file>"
    316     echo "    --adb=<file>      Use specific adb command [$ADB_CMD]"
    317     echo "    --awk=<file>      Use specific awk command [$AWK_CMD]"
    318     echo "    -e                Connect to single emulator instance"
    319     echo "    -d                Connect to single target device"
    320     echo "    -s <serial>       Connect to specific emulator or device"
    321     echo ""
    322     exit 0
    323 fi
    324 
    325 log "Android NDK installation path: $ANDROID_NDK_ROOT"
    326 
    327 if [ -n "$OPTION_EXEC" ] ; then
    328     if [ ! -f "$OPTION_EXEC" ]; then
    329         echo "ERROR: Invalid initialization file: $OPTION_EXEC"
    330         exit 1
    331     fi
    332 fi
    333 
    334 if [ -n "$OPTION_DELAY" ] ; then
    335     DELAY="$OPTION_DELAY"
    336 fi
    337 
    338 # Check ADB tool version
    339 if [ -n "$OPTION_ADB" ] ; then
    340     ADB_CMD=$OPTION_ADB
    341     log "Using specific adb command: $ADB_CMD"
    342 else
    343     if [ -z "$ADB_CMD" ] ; then
    344         echo "ERROR: The 'adb' tool is not in your path."
    345         echo "       You can change your PATH variable, or use"
    346         echo "       --adb=<executable> to point to a valid one."
    347         exit 1
    348     fi
    349     log "Using default adb command: $ADB_CMD"
    350 fi
    351 
    352 ADB_CMD=$(quote_spaces $ADB_CMD)
    353 ADB_VERSION=$("$ADB_CMD" version 2>/dev/null)
    354 if [ $? != 0 ] ; then
    355     echo "ERROR: Could not run ADB with: $ADB_CMD"
    356     exit 1
    357 fi
    358 log "ADB version found: $ADB_VERSION"
    359 
    360 if [ "x$DEVICE_SERIAL" = "x" ]; then
    361     log "Using ADB flags: $ADB_FLAGS"
    362 else
    363     log "Using ADB flags: $ADB_FLAGS" \"$DEVICE_SERIAL\"
    364 fi
    365 
    366 JDB_CMD=$(quote_spaces $JDB_CMD)
    367 log "Using JDB command: $JDB_CMD"
    368 
    369 # Run an ADB command with the right ADB flags
    370 # $1+: adb command parameter
    371 adb_cmd ()
    372 {
    373     if [ "x$DEVICE_SERIAL" = "x" ]; then
    374         "$ADB_CMD" $ADB_FLAGS "$@"
    375     else
    376         # NOTE: We escape $ADB_CMD and $DEVICE_SERIAL in case they contains spaces.
    377         "$ADB_CMD" $ADB_FLAGS "$DEVICE_SERIAL" "$@"
    378     fi
    379 }
    380 
    381 # Used internally by adb_var_shell and adb_var_shell2.
    382 # $1: 1 to redirect stderr to $1, 0 otherwise.
    383 # $2: Variable name that will contain the result
    384 # $3+: Command options
    385 _adb_var_shell ()
    386 {
    387     # We need a temporary file to store the output of our command
    388     local CMD_OUT RET OUTPUT VARNAME REDIRECT_STDERR
    389     REDIRECT_STDERR=$1
    390     VARNAME=$2
    391     shift; shift;
    392     CMD_OUT=`mktemp /tmp/ndk-gdb-cmdout-XXXXXX`
    393     # Run the command, while storing the standard output to CMD_OUT
    394     # and appending the exit code as the last line.
    395     if [ "$REDIRECT_STDERR" != 0 ]; then
    396         adb_cmd shell "$@" ";" echo \$? | sed -e 's![[:cntrl:]]!!g' > $CMD_OUT 2>&1
    397     else
    398         adb_cmd shell "$@" ";" echo \$? | sed -e 's![[:cntrl:]]!!g' > $CMD_OUT
    399     fi
    400     # Get last line in log, which contains the exit code from the command
    401     RET=`sed -e '$!d' $CMD_OUT`
    402     # Get output, which corresponds to everything except the last line
    403     OUT=`sed -e '$d' $CMD_OUT`
    404     rm -f $CMD_OUT
    405     eval $VARNAME=\"\$OUT\"
    406     return $RET
    407 }
    408 
    409 # Run a command through 'adb shell' and captures its standard output
    410 # into a variable. The function's exit code is the same than the command's.
    411 #
    412 # This is required because there is a bug where "adb shell" always returns
    413 # 0 on the host, even if the command fails on the device.
    414 #
    415 # $1: Variable name (e.g. FOO)
    416 # On exit, $FOO is set to the command's standard output
    417 #
    418 # The return status will be 0 (success) if the command succeeded
    419 # or 1 (failure) otherwise.
    420 adb_var_shell ()
    421 {
    422     _adb_var_shell 0 "$@"
    423 }
    424 
    425 # A variant of adb_var_shell that stores both stdout and stderr in the output
    426 # $1: Variable name
    427 adb_var_shell2 ()
    428 {
    429     _adb_var_shell 1 "$@"
    430 }
    431 
    432 # Return the PID of a given package or program, or 0 if it doesn't run
    433 # $1: Package name ("com.example.hellojni") or program name ("/lib/gdbserver")
    434 # Out: PID number, or 0 if not running
    435 get_pid_of ()
    436 {
    437     adb_cmd shell ps | $AWK_CMD -f $AWK_SCRIPTS/extract-pid.awk -v PACKAGE="$1"
    438 }
    439 
    440 # Check the awk tool
    441 AWK_SCRIPTS=$ANDROID_NDK_ROOT/build/awk
    442 AWK_TEST=`$AWK_CMD -f $AWK_SCRIPTS/check-awk.awk`
    443 if [ $? != 0 ] ; then
    444     echo "ERROR: Could not run '$AWK_CMD' command. Do you have it installed properly?"
    445     exit 1
    446 fi
    447 if [ "$AWK_TEST" != "Pass" ] ; then
    448     echo "ERROR: Your version of 'awk' is obsolete. Please use --awk=<file> to point to Nawk or Gawk!"
    449     exit 1
    450 fi
    451 
    452 # Name of the manifest file
    453 MANIFEST=AndroidManifest.xml
    454 
    455 # Find the root of the application project.
    456 if [ -n "$OPTION_PROJECT" ] ; then
    457     PROJECT=$OPTION_PROJECT
    458     log "Using specified project path: $PROJECT"
    459     if [ ! -d "$PROJECT" ] ; then
    460         echo "ERROR: Your --project option does not point to a directory!"
    461         exit 1
    462     fi
    463     if [ ! -f "$PROJECT/$MANIFEST" ] ; then
    464         echo "ERROR: Your --project does not point to an Android project path!"
    465         echo "       It is missing a $MANIFEST file."
    466         exit 1
    467     fi
    468 else
    469     # Assume we are in the project directory
    470     if [ -f "$MANIFEST" ] ; then
    471         PROJECT=.
    472     else
    473         PROJECT=
    474         CURDIR=`pwd`
    475         while [ "$CURDIR" != "/" ] ; do
    476             if [ -f "$CURDIR/$MANIFEST" ] ; then
    477                 PROJECT="$CURDIR"
    478                 break
    479             fi
    480             CURDIR=`dirname $CURDIR`
    481         done
    482         if [ -z "$PROJECT" ] ; then
    483             echo "ERROR: Launch this script from an application project directory, or use --project=<path>."
    484             exit 1
    485         fi
    486     fi
    487     log "Using auto-detected project path: $PROJECT"
    488 fi
    489 
    490 if [ ! -z "$OPTION_PACKAGE_NAME" ]; then
    491     PACKAGE_NAME="$OPTION_PACKAGE_NAME"
    492     log "Using package name: $PACKAGE_NAME"
    493 else
    494     # Extract the package name from the manifest
    495     PACKAGE_NAME=`run_awk_manifest_script extract-package-name.awk`
    496     if [ $? != 0 -o "$PACKAGE_NAME" = "<none>" ] ; then
    497         echo "ERROR: Could not extract package name from $PROJECT/$MANIFEST."
    498         echo "       Please check that the file is well-formed!"
    499         exit 1
    500     fi
    501     log "Found package name: $PACKAGE_NAME"
    502 fi
    503 
    504 # If --launch-list is used, list all launchable activities, and be done with it
    505 if [ "$OPTION_LAUNCH_LIST" = "yes" ] ; then
    506     log "Extracting list of launchable activities from manifest:"
    507     run_awk_manifest_script extract-launchable.awk
    508     exit 0
    509 fi
    510 
    511 APP_ABIS=`get_build_var APP_ABI`
    512 if [ "$APP_ABIS" != "${APP_ABIS%%all*}" ] ; then
    513 # replace first "all" with all available ABIs
    514   ALL_ABIS=`get_build_var NDK_ALL_ABIS`
    515   APP_ABIS_FRONT="${APP_ABIS%%all*}"
    516   APP_ABIS_BACK="${APP_ABIS#*all}"
    517   APP_ABIS="${APP_ABIS_FRONT}${ALL_ABIS}${APP_ABIS_BACK}"
    518 fi
    519 # replace "armeabi-v7a-hard" with "armeabi-v7a"
    520 APP_ABIS=`echo $APP_ABIS | sed -e 's/armeabi-v7a-hard/armeabi-v7a/g'`
    521 log "ABIs targetted by application: $APP_ABIS"
    522 
    523 # Check the ADB command, and that we can connect to the device/emulator
    524 ADB_TEST=`adb_cmd shell ls`
    525 if [ $? != 0 ] ; then
    526     echo "ERROR: Could not connect to device or emulator!"
    527     echo "       Please check that an emulator is running or a device is connected"
    528     echo "       through USB to this machine. You can use -e, -d and -s <serial>"
    529     echo "       in case of multiple ones."
    530     exit 1
    531 fi
    532 
    533 # Check that the device is running Froyo (API Level 8) or higher
    534 #
    535 adb_var_shell API_LEVEL getprop ro.build.version.sdk
    536 if [ $? != 0 -o -z "$API_LEVEL" ] ; then
    537     echo "ERROR: Could not find target device's supported API level!"
    538     echo "ndk-gdb will only work if your device is running Android 2.2 or higher."
    539     exit 1
    540 fi
    541 log "Device API Level: $API_LEVEL"
    542 if [ "$API_LEVEL" -lt "8" ] ; then
    543     echo "ERROR: ndk-gdb requires a target device running Android 2.2 (API level 8) or higher."
    544     echo "The target device is running API level $API_LEVEL!"
    545     exit 1
    546 fi
    547 
    548 # Get the target device's supported ABI(s)
    549 # And check that they are supported by the application
    550 #
    551 COMPAT_ABI=none
    552 
    553 # All modern Android images must support ro.product.cpu.abilist32
    554 # and ro.product.cpu.abilist64. Otherwise fall back to obsolete
    555 # ro.product.cpu.abi and ro.product.cpu.abi2
    556 adb_var_shell CPU_ABILIST64 getprop ro.product.cpu.abilist64
    557 adb_var_shell CPU_ABILIST32 getprop ro.product.cpu.abilist32
    558 CPU_ABIS="$CPU_ABILIST64,$CPU_ABILIST32"
    559 if [ -z "$CPU_ABILIST64" ] && [ -z "$CPU_ABILIST32" ] ; then
    560     adb_var_shell CPU_ABI1 getprop ro.product.cpu.abi
    561     adb_var_shell CPU_ABI2 getprop ro.product.cpu.abi2
    562     CPU_ABIS="$CPU_ABI1,$CPU_ABI2"
    563 fi
    564 
    565 # Replace all ',' with space and add trailing space to
    566 # ease whole-word matching of APP_ABI
    567 CPU_ABILIST64=$(echo $CPU_ABILIST64 | tr ',' ' ')
    568 CPU_ABILIST32=$(echo $CPU_ABILIST32 | tr ',' ' ')
    569 CPU_ABIS=$(echo $CPU_ABIS | tr ',' ' ')
    570 log "Device CPU ABIs: $CPU_ABIS"
    571 
    572 APP_ABIS=$APP_ABIS" "
    573 
    574 adb_var_shell BCFILES run-as $PACKAGE_NAME /system/bin/sh -c "ls lib/*.bc"
    575 if [ $? = 0 ]; then
    576     COMPAT_ABI="$UNKNOWN_ABI"
    577 else
    578     # Assume that compatible ABI is 32-bit
    579     COMPAT_ABI_BITS=32
    580     # First look compatible ABI in the list of 64-bit ABIs
    581     if [ -n "$CPU_ABILIST64" ] ; then
    582         for CPU_ABI64 in $CPU_ABILIST64; do
    583             if [ "$APP_ABIS" != "${APP_ABIS%$CPU_ABI64 *}" ] ; then
    584                 COMPAT_ABI=$CPU_ABI64
    585                 COMPAT_ABI_BITS=64
    586                 break
    587             fi
    588         done
    589     fi
    590     # If we found nothing - look among 32-bit ABIs
    591     if [ "$COMPAT_ABI" = none ] && [ -n "$CPU_ABILIST32" ] ; then
    592         for CPU_ABI32 in $CPU_ABILIST32; do
    593             if [ "$APP_ABIS" != "${APP_ABIS%$CPU_ABI32 *}" ] ; then
    594                 COMPAT_ABI=$CPU_ABI32
    595                 break
    596             fi
    597         done
    598     fi
    599     # Lastly, lets check ro.product.cpu.abi and ro.product.cpu.abi2
    600     if [ "$COMPAT_ABI" = none ] && [ -z "$CPU_ABILIST64" ] && [ -z "$CPU_ABILIST32" ]; then
    601         for CPU_ABI in $CPU_ABIS; do
    602             if [ "$APP_ABIS" != "${APP_ABIS%$CPU_ABI *}" ] ; then
    603                 COMPAT_ABI=$CPU_ABI
    604                 break
    605             fi
    606         done
    607     fi
    608 fi
    609 
    610 if [ "$COMPAT_ABI" = none ] ; then
    611     echo "ERROR: The device does not support the application's targetted CPU ABIs!"
    612     echo "       Device supports:  $CPU_ABIS"
    613     echo "       Package supports: $APP_ABIS"
    614     exit 1
    615 fi
    616 log "Compatible device ABI: $COMPAT_ABI"
    617 
    618 # Get information from the build system
    619 GDBSETUP_INIT=`get_build_var_for_abi NDK_APP_GDBSETUP $COMPAT_ABI`
    620 log "Using gdb setup init: $GDBSETUP_INIT"
    621 
    622 # Find the prefix for gdb-client
    623 if [ "$COMPAT_ABI" != "$UNKNOWN_ABI" ]; then
    624     TOOLCHAIN_PREFIX=`get_build_var_for_abi TOOLCHAIN_PREFIX $COMPAT_ABI`
    625 else
    626     TOOLCHAIN_ABI=$(echo $CPU_ABIS | awk '{print $NF}')
    627     TOOLCHAIN_PREFIX=`get_build_var_for_abi TOOLCHAIN_PREFIX $TOOLCHAIN_ABI`
    628 fi
    629 log "Using toolchain prefix: $TOOLCHAIN_PREFIX"
    630 
    631 APP_OUT=`get_build_var_for_abi TARGET_OUT $COMPAT_ABI`
    632 log "Using app out directory: $APP_OUT"
    633 
    634 # Check that the application is debuggable, or nothing will work
    635 DEBUGGABLE=`run_awk_manifest_script extract-debuggable.awk`
    636 RET=$?
    637 log "Found debuggable flag: $DEBUGGABLE"
    638 if [ "$RET" != 0 -o "$DEBUGGABLE" != "true" ] ; then
    639     # If gdb.setup exists, then we built with 'ndk-build NDK_DEBUG=1' and it's
    640     # ok to not have android:debuggable set to true in the original manifest.
    641     # However, if this is not the case, then complain!!
    642     if [ -f $PROJECT/libs/$COMPAT_ABI/gdb.setup ] ; then
    643         log "Found gdb.setup under libs/$COMPAT_ABI, assuming app was built with NDK_DEBUG=1"
    644     else
    645         echo "ERROR: Package $PACKAGE_NAME is not debuggable ! You can fix that in two ways:"
    646         echo ""
    647         echo "  - Rebuilt with the NDK_DEBUG=1 option when calling 'ndk-build'."
    648         echo ""
    649         echo "  - Modify your manifest to set android:debuggable attribute to \"true\","
    650         echo "    then rebuild normally."
    651         echo ""
    652         echo "After one of these, re-install to the device!"
    653         exit 1
    654     fi
    655 else
    656     # DEBUGGABLE is true in the manifest. Let's check that the user didn't change the
    657     # debuggable flag in the manifest without calling ndk-build afterwards.
    658     if [ ! -f $PROJECT/libs/$COMPAT_ABI/gdb.setup ] ; then
    659         echo "ERROR: Could not find gdb.setup under $PROJECT/libs/$COMPAT_ABI"
    660         echo "       This usually means you modified your AndroidManifest.xml to set"
    661         echo "       the android:debuggable flag to 'true' but did not rebuild the"
    662         echo "       native binaries. Please call 'ndk-build' to do so,"
    663         echo "       *then* re-install to the device!"
    664         exit 1
    665     fi
    666 fi
    667 
    668 # Find the <dataDir> of the package on the device
    669 adb_var_shell2 DATA_DIR run-as $PACKAGE_NAME /system/bin/sh -c pwd
    670 if [ $? != 0 -o -z "$DATA_DIR" ] ; then
    671     echo "ERROR: Could not extract package's data directory. Are you sure that"
    672     echo "       your installed application is debuggable?"
    673     exit 1
    674 fi
    675 log "Found data directory: '$DATA_DIR'"
    676 
    677 # Let's check that 'gdbserver' is properly installed on the device too. If 'gdbserver'
    678 # is not there, push 'gdbserver' found in prebuilt.
    679 #
    680 DEVICE_GDBSERVER=$DATA_DIR/lib/gdbserver
    681 adb_var_shell2 GDBSERVER_RESULT ls $DEVICE_GDBSERVER
    682 if [ $? != 0 ]; then
    683 
    684     # Figure out what's the target-arch and find gdbserver in prebuilt.
    685     TARGET_ARCH=none
    686 
    687     for ANDROID_ARCH in $ANDROID_NDK_ROOT/prebuilt/android-*; do
    688         ANDROID_ARCH=${ANDROID_ARCH#$ANDROID_NDK_ROOT/prebuilt/android-}
    689         if [ "$COMPAT_ABI" = "$ANDROID_ARCH" ]; then
    690             TARGET_ARCH=$ANDROID_ARCH
    691             break;
    692         fi
    693     done
    694 
    695     if [ $TARGET_ARCH != "none" ]; then
    696         DEVICE_GDBSERVER=/data/local/tmp/gdbserver
    697 
    698         adb shell mkdir -p /data/local/tmp
    699         adb push ${ANDROID_NDK_ROOT}/prebuilt/android-${TARGET_ARCH}/gdbserver/gdbserver \
    700                  $DEVICE_GDBSERVER
    701         log "Push gdbserver in device"
    702     else
    703         echo "ERROR: Non-debuggable application installed on the target device."
    704         echo "       Please re-install the debuggable version!"
    705         exit 1
    706     fi
    707 fi
    708 log "Found device gdbserver: $DEVICE_GDBSERVER"
    709 
    710 # Launch the activity if needed
    711 if [ "$OPTION_START" = "yes" ] ; then
    712     # If --launch is used, ignore --start, otherwise extract the first
    713     # launchable activity name from the manifest and use it as if --launch=<name>
    714     # was used instead.
    715     #
    716     if [ -z "$OPTION_LAUNCH" ] ; then
    717         OPTION_LAUNCH=`run_awk_manifest_script extract-launchable.awk | sed 2q`
    718         if [ $? != 0 ] ; then
    719             echo "ERROR: Could not extract name of launchable activity from manifest!"
    720             echo "       Try to use --launch=<name> directly instead as a work-around."
    721             exit 1
    722         fi
    723         log "Found first launchable activity: $OPTION_LAUNCH"
    724         if [ -z "$OPTION_LAUNCH" ] ; then
    725             echo "ERROR: It seems that your Application does not have any launchable activity!"
    726             echo "       Please fix your manifest file and rebuild/re-install your application."
    727             exit 1
    728         fi
    729     fi
    730 fi
    731 
    732 if [ -n "$OPTION_LAUNCH" ] ; then
    733     log "Launching activity: $PACKAGE_NAME/$OPTION_LAUNCH"
    734     adb_var_shell2 DUMMY am start $OPTION_WAIT -n $PACKAGE_NAME/$OPTION_LAUNCH
    735     if [ $? != 0 ] ; then
    736         echo "ERROR: Could not launch specified activity: $OPTION_LAUNCH"
    737         echo "       Use --launch-list to dump a list of valid values."
    738         exit 1
    739     fi
    740     # Sleep a bit, it sometimes take one second to start properly
    741     # Note that we use the 'sleep' command on the device here.
    742     run adb_cmd shell sleep $DELAY
    743 fi
    744 
    745 # Find the PID of the application being run
    746 PID=$(get_pid_of "$PACKAGE_NAME")
    747 RET=$?
    748 log "Found running PID: $PID"
    749 if [ "$RET" != 0 -o "$PID" = "0" ] ; then
    750     echo "ERROR: Could not extract PID of application on device/emulator."
    751     if [ -n "$OPTION_LAUNCH" ] ; then
    752         echo "       Weird, this probably means one of these:"
    753         echo ""
    754         echo "         - The installed package does not match your current manifest."
    755         echo "         - The application process was terminated."
    756         echo ""
    757         echo "       Try using the --verbose option and look at its output for details."
    758     else
    759         echo "       Are you sure the application is already started?"
    760         echo "       Consider using --start or --launch=<name> if not."
    761     fi
    762     exit 1
    763 fi
    764 
    765 # Check that there is no other instance of gdbserver running
    766 GDBSERVER_PID=$(get_pid_of lib/gdbserver)
    767 if [ "$GDBSERVER_PID" != "0" ]; then
    768     if [ "$OPTION_FORCE" = "no" ] ; then
    769         echo "ERROR: Another debug session running, Use --force to kill it."
    770         exit 1
    771     fi
    772     log "Killing existing debugging session"
    773     run adb_cmd shell kill -9 $GDBSERVER_PID
    774 fi
    775 
    776 # Launch gdbserver now
    777 DEBUG_SOCKET=debug-socket
    778 adb_var_shell2 DUMMY run-as $PACKAGE_NAME $DEVICE_GDBSERVER +$DEBUG_SOCKET --attach $PID &
    779 if [ $? != 0 ] ; then
    780     echo "ERROR: Could not launch gdbserver on the device?"
    781     exit 1
    782 fi
    783 log "Launched gdbserver succesfully."
    784 
    785 # Setup network redirection
    786 log "Setup network redirection"
    787 run adb_cmd forward tcp:$DEBUG_PORT localfilesystem:$DATA_DIR/$DEBUG_SOCKET
    788 if [ $? != 0 ] ; then
    789     echo "ERROR: Could not setup network redirection to gdbserver?"
    790     echo "       Maybe using --port=<port> to use a different TCP port might help?"
    791     exit 1
    792 fi
    793 
    794 # If we are debugging 64-bit app, then we need to pull linker64,
    795 # app_process64 and libc.so from lib64 directory
    796 LINKER_NAME=linker
    797 LIBDIR_NAME=lib
    798 APP_PROCESS_NAME=app_process32
    799 if [ "$COMPAT_ABI_BITS" = 64 ] ; then
    800     LINKER_NAME=linker64
    801     LIBDIR_NAME=lib64
    802     APP_PROCESS_NAME=app_process64
    803 else
    804     # Old 32-bit devices do not have app_process32. Pull
    805     # app_process in this case
    806     adb_var_shell2 DUMMY test -e /system/bin/$APP_PROCESS_NAME
    807     if [ $? != 0 ] ; then
    808         APP_PROCESS_NAME=app_process
    809     fi
    810 fi
    811 
    812 # Get the app_server binary from the device
    813 APP_PROCESS=$APP_OUT/app_process
    814 run adb_cmd pull /system/bin/$APP_PROCESS_NAME `native_path $APP_PROCESS`
    815 log "Pulled $APP_PROCESS_NAME from device/emulator."
    816 
    817 run adb_cmd pull /system/bin/$LINKER_NAME `native_path $APP_OUT/$LINKER_NAME`
    818 log "Pulled $LINKER_NAME from device/emulator."
    819 
    820 run adb_cmd pull /system/$LIBDIR_NAME/libc.so `native_path $APP_OUT/libc.so`
    821 log "Pulled /system/$LIBDIR_NAME/libc.so from device/emulator."
    822 
    823 # Setup JDB connection, for --start or --launch
    824 if [ "$OPTION_START" = "yes" ] || [ -n "$OPTION_LAUNCH" ] ; then
    825     if [ -n "$JDB_PORT" ]; then
    826         log "Setup JDB connection"
    827         run adb_cmd forward tcp:$JDB_PORT jdwp:$PID
    828         sleep 1
    829         $JDB_CMD -connect com.sun.jdi.SocketAttach:hostname=localhost,port=$JDB_PORT &
    830         sleep 1
    831     fi
    832 fi
    833 
    834 # If we are debugging UNKNOWN_ABI, download compiled *.so from device.
    835 #
    836 if [ "$COMPAT_ABI" = "$UNKNOWN_ABI" ]; then
    837     for bc in $BCFILES; do
    838         log "Pulled $(basename $bc .bc).so from device/emulator."
    839         adb pull $DATA_DIR/lib/$(basename $bc .bc).so $PROJECT/obj/local/$UNKNOWN_ABI/
    840     done
    841 fi
    842 
    843 # Now launch the appropriate gdb client with the right init commands
    844 #
    845 GDBCLIENT=${TOOLCHAIN_PREFIX}gdb
    846 GDBSETUP=$APP_OUT/gdb.setup
    847 cp -f $GDBSETUP_INIT $GDBSETUP
    848 #uncomment the following to debug the remote connection only
    849 #echo "set debug remote 1" >> $GDBSETUP
    850 echo "file `native_path $APP_PROCESS`" >> $GDBSETUP
    851 echo "target remote :$DEBUG_PORT" >> $GDBSETUP
    852 if [ -n "$OPTION_EXEC" ] ; then
    853     cat $OPTION_EXEC >> $GDBSETUP
    854 fi
    855 $GDBCLIENT -x `native_path $GDBSETUP`
    856