Home | History | Annotate | Download | only in ndk
      1 #!/bin/bash
      2 #
      3 # Copyright 2016 Google Inc. All Rights Reserved.
      4 #
      5 # This is an example script to show users the steps for bisecting an NDK
      6 # application for Android. Our example is the Teapot app that comes bundled with
      7 # the NDK as a sample app.
      8 #
      9 # Our Teapot app only has 12 or so object files generated per build. Bisection
     10 # for just 12 object files is overkill, but this bisection process easily scales
     11 # to thousands of object files (as seen with the Android source).
     12 #
     13 # Setup:
     14 #   1. Install NDK (make sure it is in your PATH)
     15 #   2. Install compiler_wrapper.py
     16 #   3. Connect an arm7 device (tested with Nexus 5X)
     17 #     a. See README for supporting other device archs
     18 #
     19 # Tested in bash on Linux.
     20 
     21 # Set CWD to where this script lives
     22 pushd "$(dirname "$0")"
     23 
     24 # If Teapot dir already exists remove it.
     25 if [[ -d Teapot ]]; then
     26   rm -rf Teapot
     27 fi
     28 
     29 # Unzip our repository we'll be testing with.
     30 tar -xzf Teapot.tar.gz
     31 
     32 # Apply small setup patch. This patch makes a small change to the build system
     33 # to make this bisecting example a little easier. It inserts the option to only
     34 # build for an arm7. See the patch file for details.
     35 # (This patch file was generated with git, -p1 will remove the a/ and b/)
     36 patch -p1 -i PATCH1
     37 
     38 # We want all of our cached files to be stored in ~/NDK_EXAMPLE_BISECT
     39 # Remove directory if already exists
     40 export BISECT_DIR=~/NDK_EXAMPLE_BISECT
     41 if [[ -d ${BISECT_DIR} ]]; then
     42   rm -rf ${BISECT_DIR}
     43 fi
     44 
     45 # We will now take our normal "good compiler" and do a full build of the app. We
     46 # need to clean before building. This ensures that all objects are generated and
     47 # can be cached.
     48 pushd Teapot
     49 export BISECT_STAGE=POPULATE_GOOD
     50 ./gradlew clean
     51 ./gradlew installArm7Debug
     52 popd
     53 
     54 # Inserting "compiler error". Really this is just a patch that inserts a simple
     55 # error in the code, but this is used to simulate our compiler error. This patch
     56 # will simply cause the app to crash as soon as it starts. See the patch file
     57 # for details.
     58 # (This patch file was generated with git, -p1 will remove the a/ and b/)
     59 patch -p1 -i PATCH2
     60 
     61 # Now that we have installed our bad compiler (i.e. applied the above patch that
     62 # acts like a compiler error), we want to enumerate and cache all objects
     63 # generated by this "bad compiler". So again, we clean the build tree so that
     64 # all objects are regenerated and can be cached.
     65 pushd Teapot
     66 export BISECT_STAGE=POPULATE_BAD
     67 ./gradlew clean
     68 ./gradlew installArm7Debug
     69 popd
     70 
     71 # Now ~/NDK_EXAMPLE_BISECT holds the caches for both good and bad compiler
     72 # outputs. We will now use these to bisect our problem. We should find that
     73 # TeapotRenderer.o is the bad file (because this is where PATCH2 inserted the
     74 # "compiler error").
     75 
     76 # Tell the compiler wrapper to not cache outputs, and instead begin bisecting.
     77 export BISECT_STAGE=TRIAGE
     78 
     79 # Run the actual bisection tool. This will automatically narrow down which
     80 # object file has the error. The test_setup.sh script will rebuild our app
     81 # with gradle, and boot_test.sh will ping the device to see if the app crashed
     82 # or not.
     83 cd ..
     84 ./binary_search_state.py \
     85   --get_initial_items=ndk/get_initial_items.sh \
     86   --switch_to_good=ndk/switch_to_good.sh \
     87   --switch_to_bad=ndk/switch_to_bad.sh \
     88   --test_setup_script=ndk/test_setup.sh \
     89   --test_script=ndk/boot_test.sh \
     90   --file_args
     91 
     92 popd
     93