Merge remote-tracking branch 'aosp/master' into update-to-aosp

These branches had somehow diverged. aosp/master is most up to date,
so replace the contents with that.

Change-Id: I684d1613cc64858662d33584e70e1a463d1536c8
diff --git a/README.md b/README.md
index 96f601b..6f56c4d 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Introduction of simpleperf
+# Simpleperf Introduction
 ## What is simpleperf
 Simpleperf is a native profiling tool for Android. Its command-line interface
 supports broadly the same options as the linux-tools perf, but also supports
@@ -6,6 +6,8 @@
 
 Simpleperf is part of the Android Open Source Project. The source code is at
 https://android.googlesource.com/platform/system/extras/+/master/simpleperf/.
+The latest document is at
+https://android.googlesource.com/platform/system/extras/+show/master/simpleperf/README.md.
 Bugs and feature requests can be submitted at
 http://github.com/android-ndk/ndk/issues.
 
@@ -363,186 +365,197 @@
 report call-graph of a program, we need to dump user stack and register set in
 each record, and then unwind the stack to find the call chain. Simpleperf
 supports unwinding while recording, so it doesn’t need to store user stack in
-perf.data. So we can profile for a longer time with limited space on device.
-3. Build in static binaries. Simpleperf is a static binary, so it doesn’t need
+perf.data. So we can profile for a longer time with limited space on device.'
+3. Support scripts to make profiling on Android more convenient.
+4. Build in static binaries. Simpleperf is a static binary, so it doesn’t need
 supporting shared libraries to run. It means there is no limitation of Android
 version that simpleperf can run on, although some devices don’t support
 profiling.
 
-# Steps to profile native libraries
-After introducing simpleperf, this section uses a simple example to show how to
-profile jni native libraries on Android using simpleperf. The example profiles
-an app called com.example.sudogame, which uses a jni native library
-sudo-game-jni.so. We focus on sudo-game-jni.so, not the java code or system
-libraries.
+# Simpleperf tools in ndk
+Simpleperf tools in ndk contain three parts: simpleperf executable running on
+Android device, simpleperf executable running on host, and python scripts.
 
-## 1. Run a debuggable="true" version of the app on device
-We need to run a copy of the app with android:debuggable=”true” in its
-AndroidManfest.xml <application> element, because we can’t use run-as for
-non-debuggable apps.
+## Simpleperf on device
+Simpleperf running on device is located at bin/android directory. It contains
+static binaries running on Android on different architectures. They can be used
+to profile processes running device, and generate perf.data.
 
-## 2. Download simpleperf to the app’s directory
-Use *uname* to find the architecture on device
+## Simpleperf on host
+Simpleperfs running on host are located at bin/darwin, bin/linux and
+bin/windows.They can be used to parse perf.data on host.
 
-    $adb shell uname -m
-    aarch64
+## Scripts
+Scripts are used to make it convenient to profile and parse profiling results.
+app_profiler.py is used to profile an android application. It prepares
+profiling environments, downloads simpleperf on device, generates and pulls
+perf.data on host. It is configured by app_profiler.config.
+binary_cache_builder.py is used to pull native binaries from device to host.
+It is used by app_profiler.py.
+annotate.py is used to annotate source files using perf.data. It is configured
+by annotate.config.
+report.py reports perf.data in a GUI window.
+simpleperf_report_lib.py is used to enumerate samples in perf.data. Internally
+it uses libsimpleperf_report.so to parse perf.data. It can be used to translate
+samples in perf.data to other forms. One example using simpleperf_report_lib.py
+is report_sample.py.
 
-"aarch64" means we should download arm64 version of simpleperf to device.
+# Examples of using simpleperf tools
+This section shows how to use simpleperf tools to profile an Android
+application.
 
-    $adb push device/arm64/simpleperf /data/local/tmp
-    $adb shell run-as com.example.sudogame cp /data/local/tmp/simpleperf .
-    $adb shell run-as com.example.sudogame chmod a+x simpleperf
-    $adb shell run-as com.example.sudogame ls -l
-    -rwxrwxrwx 1 u0_a90 u0_a90 3059208 2016-01-01 10:40 simpleperf
+## Prepare a debuggable Application
+The package name of the application is com.example.sudogame. It has both java
+code and c++ code. We need to run a copy of the app with
+android:debuggable=”true” in its AndroidManifest.xml <application> element,
+because we can’t use run-as for non-debuggable apps. The application should
+has been installed on device, and we can connect device via adb.
 
-Note that some apps use arm native libraries even on arm64 devices (We can
-verify this by checking /proc/<process\_id\_of\_app>/maps). In that case, we
-should use arm/simpleperf instead of arm64/simpleperf.
+## Profile using command line
+To record profiling data, we need to download simpleperf and native libraries
+with debug information on device, run simpleperf to generate profiling data
+file: perf.data, and run simpleperf to report perf.data. Below are the steps.
 
-## 3. Enable profiling
-Android devices may disable profiling by default, and we need to enable
-profiling.
+### 1. Enable profiling
 
     $adb shell setprop security.perf_harden 0
 
-## 4. Find the target process/thread to record
+### 2. Find the process running the app
+Run `ps` in the app’s context. On >=O devices, run `ps -e` instead.
 
-    # Use `ps` to get process id of sudogame.
-    $adb shell ps  | grep sudogame
-    u0_a102   15869 545   1629824 76888 SyS_epoll_ 0000000000 S com.example.sudogame
+    $adb shell
+    angler:/ $ run-as com.example.sudogame
+    angler:/data/data/com.example.sudogame $ ps
+    u0_a93    10324 570   1030480 58104 SyS_epoll_ 00f41b7528 S com.example.sudogame
+    u0_a93    10447 10441 7716   1588  sigsuspend 753c515d34 S sh
+    u0_a93    10453 10447 9112   1644           0 7ba07ff664 R ps
 
-    # Use `ps -t` to get thread ids of process 15869.
-    # If this doesn’t work, you can try `ps -eT`.
-    $adb shell ps -t  | grep 15869
-    u0_a102   15869 545   1629824 76888 SyS_epoll_ 0000000000 S com.example.sudogame
-    u0_a102   15874 15869 1629824 76888 futex_wait 0000000000 S Jit thread pool
-    ...
+So process 10324 runs the app.
 
-## 5. Record perf.data
+### 3. Download simpleperf to the app’s data directory
+First we need to find out which architecture the app is using. There are many
+ways, here we just check the map of the process.
 
-    # Record process 15869 for 30s, and use the app while recording it.
-    $adb shell run-as com.example.sudogame ./simpleperf record -p 15869 --duration 30
-    simpleperf W 07-12 20:00:33 16022 16022 environment.cpp:485] failed to read /proc/sys/kernel/kptr_restrict: Permission denied
-    simpleperf I 07-12 20:01:03 16022 16022 cmd_record.cpp:315] Samples recorded: 81445. Samples lost: 0.
+    angler:/data/data/com.example.sudogame $cat /proc/10324/maps | grep boot.art
+    70f34000-7144e000 r--p 00000000 fd:00 1082  /system/framework/arm/boot.oat
 
-    $adb shell run-as com.example.sudogame ls -lh perf.data
-    -rw-rw-rw- 1 u0_a102 u0_a102 4.3M 2016-07-12 20:01 perf.data
+The file path shows it is arm. So we download simpleperf in arm directory on
+device.
 
-Now we have recorded perf.data with 81445 records. There is a warning about
-failing to read kptr_restrict. It doesn’t matter in our case, but is a notification that we
-can’t read kernel symbol addresses.
+    $adb push bin/android/arm/simpleperf /data/local/tmp
+    $adb shell
+    angler:/ $ run-as com.example.sudogame
+    angler:/data/data/com.example.sudogame $ cp /data/local/tmp/simpleperf .
 
-## 6. Report perf.data
-Below are several examples reporting on device.
+### 4. Record perf.data
 
-### Report samples in different binaries
+    angler:/data/data/com.example.sudogame $./simpleperf record -p 10324 --duration 30
+    simpleperf I 01-01 09:26:39 10598 10598 cmd_record.cpp:341] Samples recorded: 49471. Samples lost: 0.
+    angler:/data/data/com.example.sudogame $ls -lh perf.data
+    -rw-rw-rw- 1 u0_a93 u0_a93 2.6M 2017-01-01 09:26 perf.data
 
-    # Report how samples distribute on different binaries.
-    $adb shell run-as com.example.sudogame ./simpleperf report -n --sort dso
-    simpleperf W 07-12 19:15:10 11389 11389 dso.cpp:309] Symbol addresses in /proc/kallsyms are all zero. `echo 0 >/proc/sys/kernel/kptr_restrict` if possible.
-    Cmdline: /data/data/com.example.sudogame/simpleperf record -p 15869 --duration 30
+Don’t forget to run the app while recording. Otherwise, we may get no samples
+because the process is always sleeping.
+
+### 5. Report perf.data
+There are different ways to report perf.data. Below shows some examples.
+
+Report samples in different threads.
+
+    angler:/data/data/com.example.sudogame $./simpleperf report --sort pid,tid,comm
+    Cmdline: /data/data/com.example.sudogame/simpleperf record -p 10324 --duration 30
     Arch: arm64
     Event: cpu-cycles (type 0, config 0)
-    Samples: 81445
-    Event count: 34263925309
+    Samples: 49471
+    Event count: 16700769019
 
+    Overhead  Pid    Tid    Command
+    66.31%    10324  10324  xample.sudogame
+    30.97%    10324  10340  RenderThread
+    ...
+
+Report samples in different binaries in the main thread.
+
+    angler:/data/data/com.example.sudogame $./simpleperf report --tids 10324 --sort dso -n
+    ...
     Overhead  Sample  Shared Object
-    75.31%    58231   [kernel.kallsyms]
-    8.44%     6845    /system/lib64/libc.so
-    4.30%     4667    /vendor/lib64/egl/libGLESv2_adreno.so
-    2.30%     2433    /system/lib64/libhwui.so
-    1.88%     1952    /system/lib64/libart.so
-    1.88%     1967    /system/framework/arm64/boot-framework.oat
-    1.59%     1218    /system/lib64/libcutils.so
-    0.69%     728     /system/lib64/libskia.so
-    0.63%     489     /data/app/com.example.sudogame-2/lib/arm64/libsudo-game-jni.so
-    0.34%     312     /system/lib64/libart-compiler.so
+    37.71%    9970    /system/lib/libc.so
+    35.45%    9786    [kernel.kallsyms]
+    8.71%     3305    /system/lib/libart.so
+    6.44%     2405    /system/framework/arm/boot-framework.oat
+    5.64%     1480    /system/lib/libcutils.so
+    1.55%     426     /data/app/com.example.sudogame-1/lib/arm/libsudo-game-jni.so
     ...
 
-According to the report above, most time is spent in kernel, and
-libsudo-game-jni.so costs only 0.63% by itself. It seems libsudo-game-jni.so
-can’t be the bottleneck. However, it is possible we didn’t record long enough
-to hit the hot spot, or code in libsudo-game-jni.so calls other libraries
-consuming most time.
+Report samples in different functions in libsudo-game-jni.so in the main thread.
 
-### Report samples in different functions
-
-    # Report how samples distribute inside libsudo-game-jni.so.
-    $adb shell run-as com.example.sudogame ./simpleperf report -n --dsos /data/app/com.example.sudogame-2/lib/arm64/libsudo-game-jni.so --sort symbol
+    angler:/data/data/com.example.sudogame $./simpleperf report --tids 10324 --dsos  /data/app/com.example.sudogame-1/lib/arm/libsudo-game-jni.so --sort symbol -n
     ...
     Overhead  Sample  Symbol
-    94.45%    461     unknown
-    5.22%     26      @plt
-    0.20%     1       Java_com_example_sudogame_GameModel_findConflictPairs
-    0.14%     1       Java_com_example_sudogame_GameModel_canFindSolution
-
-In the report above, most samples belong to unknown symbol. It is because the
-libsudo-game-jni.so used on device doesn’t contain symbol table. We need to
-download shared library with symbol table to device. In android studio 2.1.2,
-the binary with symbol table is in
-[app_dir]/app/build/intermediates/binaries/debug/obj/arm64-v8a (for amr64).
-
-    # Make a proper directory to download binary to device. This directory
-    # should be the same as the directory of
-    # /data/app/com.example.sudogame-2/lib/arm64/libsudo-game-jni.so.
-    $adb shell run-as com.example.sudogame mkdir -p data/app/com.example.sudogame-2/lib/arm64
-    # Download binary with symbol table.
-    $adb push [app_dir]/app/build/intermediates/binaries/debug/obj/arm64-v8a/libsudo-game-jni.so /data/local/tmp
-    $adb shell run-as com.example.sudogame cp /data/local/tmp/libsudo-game-jni.so data/app/com.example.sudogame-2/lib/arm64
-
-    # Report how samples distribute inside libsudo-game-jni.so with debug binary
-    # support.
-    $adb shell run-as com.example.sudogame ./simpleperf report -n --dsos /data/app/com.example.sudogame-2/lib/arm64/libsudo-game-jni.so --sort symbol --symfs .
+    8.94%     35      libsudo-game-jni.so[+1d54]
+    5.71%     25      libsudo-game-jni.so[+1dae]
+    5.70%     23      @plt
+    5.09%     22      libsudo-game-jni.so[+1d88]
+    4.54%     19      libsudo-game-jni.so[+1d82]
+    3.61%     14      libsudo-game-jni.so[+1f3c]
     ...
-    Overhead  Sample  Symbol
-    71.08%    347     checkValid(Board const&, int, int)
-    15.13%    74      randomBlock_r(Board&, int, int, int, int, int)
-    7.94%     38      canFindSolution_r(Board&, int, int)
-    5.22%     26      @plt
-    0.30%     2       randomBoard(Board&)
-    0.20%     1       Java_com_example_sudogame_GameModel_findConflictPairs
-    0.14%     1       Java_com_example_sudogame_GameModel_canFindSolution
 
-With the help of debug version of libsudo-game-jni.so, the report above shows that most
-time in libsudo-game-jni.so is spent in function checkValid. So now we can look
-into it further.
+In the above result, most symbols are binary name[+virual_addr]. It is because
+libsudo-game-jni.so used on device has stripped .symbol section. We can
+download libsudo-game-jni.so having debug information on device. In android
+studio project, it locates at
+app/build/intermediates/binaries/debug/arm/obj/armeabi-v7a/libsudo-game-jni.so.
+We have to download libsudo-game-jni.so to the same relative path as recorded
+in perf.data (otherwise, simpleperf can’t find it). In this case, it is
+/data/app/com.example.sudogame-1/lib/arm/libsudo-game-jni.so.
 
-### Report samples in one function
+Report symbols using libraries with debug information.
 
-    # Report how samples distribute inside checkValid() function.
-    # adb shell command can’t pass ‘(‘ in arguments, so we run the command
-    # inside `adb shell`.
+    $adb push app/build/intermediates/binaries/debug/arm/obj/armeabi-v7a/libsudo-game-jni.so /data/local/tmp
     $adb shell
-    device$ run-as com.example.sudogame ./simpleperf report -n --symbols "checkValid(Board const&, int, int)" --sort vaddr_in_file --symfs .
+    angler:/ $ run-as com.example.sudogame
+    angler:/data/data/com.example.sudogame $ mkdir -p data/app/com.example.sudogame-1/lib/arm
+    angler:/data/data/com.example.sudogame $cp /data/local/tmp/libsudo-game-jni.so data/app/com.example.sudogame-1/lib/arm
+    angler:/data/data/com.example.sudogame $./simpleperf report --tids 10324 --dsos  /data/app/com.example.sudogame-1/lib/arm/libsudo-game-jni.so --sort symbol -n --symfs .
+    ...
+    Overhead  Sample  Symbol
+    75.18%    317     checkValid(Board const&, int, int)
+    14.43%    60      canFindSolution_r(Board&, int, int)
+    5.70%     23      @plt
+    3.51%     20      randomBlock_r(Board&, int, int, int, int, int)
+    ...
+
+Report samples in one function
+
+    angler:/data/data/com.example.sudogame $./simpleperf report --tids 10324 --dsos  /data/app/com.example.sudogame-1/lib/arm/libsudo-game-jni.so --symbols “checkValid(Board const&, int, int)” --sort vaddr_in_file -n --symfs .
     ...
     Overhead  Sample  VaddrInFile
-    14.90%    50      0x24d8
-    8.48%     29      0x251c
-    5.52%     19      0x2468
+    11.89%    35      0x1d54
+    7.59%     25      0x1dae
+    6.77%     22      0x1d88
+    6.03%     19      0x1d82
     ...
 
-The report above shows samples hitting different places inside function
-checkValid(). By using objdump to disassemble libsudo-game-jni.so, we can find
-which are the hottest instructions in checkValid() function.
+### 6. Record and report call graph
+A call graph is a tree showing function call relations. Below is an example.
 
-    # Disassemble libsudo-game-jni.so.
-    $aarch64-linux-android-objdump -d -S -l libsudo-game-jni.so >libsudo-game-jni.asm
+    main() {
+        FunctionOne();
+        FunctionTwo();
+    }
+    FunctionOne() {
+        FunctionTwo();
+        FunctionThree();
+    }
+    callgraph:
+        main-> FunctionOne
+           |    |
+           |    |-> FunctionTwo
+           |    |-> FunctionThree
+           |
+           |-> FunctionTwo
 
-## 7. Record and report call graph
-### What is a call graph
-A call graph is a tree showing function call relations. For example, a program
-starts at main() function, and main() calls functionOne() and functionTwo(),
-and functionOne() calls functionTwo() and functionThree(). Then the call graph
-is as below.
-
-    main() -> functionOne()
-          |    |
-          |    |-> functionTwo()
-          |    |
-          |     ->  functionThree()
-           -> functionTwo()
-
-### Record dwarf based call graph
+#### Record dwarf based call graph
 To generate call graph, simpleperf needs to generate call chain for each record.
 Simpleperf requests kernel to dump user stack and user register set for each
 record, then it backtraces the user stack to find the function call chain. To
@@ -550,220 +563,255 @@
 usually resides in .eh_frame or .debug_frame section of the binary.  So we need
 to use --symfs to point out where is libsudo-game-jni.so with debug information.
 
-    # Record thread 11546 for 30s, use the app while recording it.
-    $adb shell run-as com.example.sudogame ./simpleperf record -t 11546 -g --symfs . --duration 30
-    simpleperf I 01-01 07:13:08  9415  9415 cmd_record.cpp:336] Samples recorded: 65279. Samples lost: 16740.
-    simpleperf W 01-01 07:13:08  9415  9415 cmd_record.cpp:343] Lost 20.4099% of samples, consider increasing mmap_pages(-m), or decreasing sample frequency(-f), or increasing sample period(-c).
-
-    $adb shell run-as com.example.sudogame ls -lh perf.data
-    -rw-rw-rw- 1 u0_a96 u0_a96 8.3M 2016-01-01 08:49 perf.data
+    angler:/data/data/com.example.sudogame $./simpleperf record -p 10324 -g --symfs . --duration 30
+    simpleperf I 01-01 09:59:42 11021 11021 cmd_record.cpp:341] Samples recorded: 60700. Samples lost: 1240.
 
 Note that kernel can’t dump user stack >= 64K, so the dwarf based call graph
-doesn’t contain call chains consuming >= 64K stack. So avoiding allocating
-large memory on stack is a good way to improve dwarf based call graph.
+doesn’t contain call chains consuming >= 64K stack. What’s more, because we
+need to dump stack in each record, it is likely to lost records. Usually, it
+doesn’t matter to lost some records.
 
-### Record stack frame based call graph
+#### Record stack frame based call graph
 Another way to generate call graph is to rely on the kernel parsing the call
 chain for each record. To make it possible, kernel has to be able to identify
 the stack frame of each function call. This is not always possible, because
 compilers can optimize away stack frames, or use a stack frame style not
-recognized by the kernel. So how well it works depends.
+recognized by the kernel. So how well it works depends (It works well on arm64,
+but not well on arm).
 
-    # Record thread 11546 for 30s, use the app while recording it.
-    $adb shell run-as com.example.sudogame ./simpleperf record -t 11546 --call-graph fp --symfs . --duration 30
-    simpleperf W 01-02 05:43:24 23277 23277 environment.cpp:485] failed to read /proc/sys/kernel/kptr_restrict: Permission denied
-    simpleperf I 01-02 05:43:54 23277 23277 cmd_record.cpp:323] Samples recorded: 95023. Samples lost: 0.
+    angler:/data/data/com.example.sudogame $./simpleperf record -p 10324 --call-graph fp --symfs . --duration 30
+    simpleperf I 01-01 10:03:58 11267 11267 cmd_record.cpp:341] Samples recorded: 56736. Samples lost: 0.
 
-    $adb shell run-as com.example.sudogame ls -lh perf.data
-    -rw-rw-rw- 1 u0_a96 u0_a96 39M 2016-01-02 05:43 perf.data
+#### Report call graph
+Report accumulated period. In the table below, the first column is “Children”,
+it is the cpu cycle percentage of a function and functions called by that
+function. The second column is “Self”, it is the cpu cycle percentage of just a
+function. For example, checkValid() itself takes 1.28% cpus, but it takes
+29.43% by running itself and calling other functions.
 
-### Report call graph
-#### Report call graph on device
-    # Report call graph.
-    $adb shell run-as com.example.sudogame ./simpleperf report -n -g --symfs .
-    Cmdline: /data/data/com.example.sudogame/simpleperf record -t 11546 -g --symfs . -f 1000 --duration 30
-    Arch: arm64
-    Event: cpu-cycles (type 0, config 0)
-    Samples: 23840
-    Event count: 41301992088
-
-    Children  Self    Sample  Command          Pid    Tid    Shared Object                                                   Symbol
-    97.98%    0.69%   162     xample.sudogame  11546  11546  /data/app/com.example.sudogame-1/lib/arm64/libsudo-game-jni.so  checkValid(Board const&, int, int)
-       |
-       -- checkValid(Board const&, int, int)
-          |
-          |--99.95%-- __android_log_print
-          |           |
-          |           |--92.19%-- __android_log_buf_write
-          |           |           |
-          |           |           |--73.50%-- libcutils.so[+1120c]
+    angler:/data/data/com.example.sudogame $./simpleperf report --children --symfs .
+    ...
+    Children  Self   Command          Pid    Tid    Shared Object                                                 Symbol
+    31.94%    0.00%  xample.sudogame  10324  10324  [kernel.kallsyms]                                             [kernel.kallsyms][+ffffffc000204268]
+    31.10%    0.92%  xample.sudogame  10324  10324  /system/lib/libc.so                                           writev
+    29.43%    1.28%  xample.sudogame  10324  10324  /data/app/com.example.sudogame-1/lib/arm/libsudo-game-jni.so  checkValid(Board const&, int, int)
+    28.43%    0.34%  xample.sudogame  10324  10324  /system/lib/liblog.so                                         __android_log_print
+    28.24%    0.00%  xample.sudogame  10324  10324  /system/lib/libcutils.so                                      libcutils.so[+107b7]
+    28.10%    0.27%  xample.sudogame  10324  10324  /data/app/com.example.sudogame-1/lib/arm/libsudo-game-jni.so  canFindSolution_r(Board&, int, int)
     ...
 
-#### Report call graph in callee mode
-Call graph can be shown in two modes. One is caller mode, showing how functions
-call others. The other is callee mode, showing how functions are called by
-others. We can use  *-g callee* option to show call graph in callee mode.
+Report call graph.
 
-    # Report call graph.
-    $host/simpleperf report -n -g callee --symfs .
-    Cmdline: /data/data/com.example.sudogame/simpleperf record -t 11546 -g --symfs . -f 1000 --duration 30
-    Arch: arm64
-    Event: cpu-cycles (type 0, config 0)
-    Samples: 23840
-    Event count: 41301992088
-
-    Children  Self    Sample  Command          Pid    Tid    Shared Object                                                   Symbol
-    97.58%    0.21%   48      xample.sudogame  11546  11546  /system/lib64/liblog.so                                         __android_log_print
-       |
-       -- __android_log_print
-          |
-          |--99.70%-- checkValid(Board const&, int, int)
-          |           |
-          |           |--99.31%-- canFindSolution_r(Board&, int, int)
+    angler:/data/data/com.example.sudogame $./simpleperf report -g --symfs . >report
+    angler:/data/data/com.example.sudogame $exit
+    angler:/ $cp /data/data/com.example.sudogame/report /data/local/tmp
+    angler:/ $exit
+    $adb pull /data/local/tmp/report .
+    $cat report
+    ...
+    29.43%    1.28%  xample.sudogame  10324  10324  /data/app/com.example.sudogame-1/lib/arm/libsudo-game-jni.so  checkValid(Board const&, int, int)
+           |
+           -- checkValid(Board const&, int, int)
+              |
+              |--95.50%-- __android_log_print
+              |    |--0.68%-- [hit in function]
+              |    |
+              |    |--51.84%-- __android_log_buf_write
+              |    |    |--2.07%-- [hit in function]
+              |    |    |
+              |    |    |--30.74%-- libcutils.so[+c69d]
     ...
 
-#### Report using report.py
-The call graph generated by simpleperf report may be hard to read in text mode.
-Simpleperf provides a python script showing GUI of call graph.
-It can be used as below.
+Report call graph in callee mode. We can also show how a function is called by
+other functions.
 
-    # Show call graph in GUI.
-    $adb shell run-as com.example.sudogame ./simpleperf report -n -g --symfs . >perf.report
-    $python report.py perf.report
+    angler:/data/data/com.example.sudogame $./simpleperf report -g callee --symfs . >report
+    $adb shell run-as com.example.sudogame cat report >report
+    $cat report
+    …
+    28.43%    0.34%  xample.sudogame  10324  10324  /system/lib/liblog.so                                         __android_log_print
+           |
+           -- __android_log_print
+              |
+              |--97.82%-- checkValid(Board const&, int, int)
+              |    |--0.13%-- [hit in function]
+              |    |
+              |    |--94.89%-- canFindSolution_r(Board&, int, int)
+              |    |    |--0.01%-- [hit in function]
+              |    |    |
+    ...
 
-## 8. Report perf.data on host
-We can also use adb to pull perf.data on host. Then use simpleperf on host to
-report it (Simpleperf on host is not provided, but can be built from source
-code). Because we don’t have any symbol information on host, we need to
-collect symbol information in perf.data while recording.
-
-    # Collect symbol information while recording.
-    device#./simpleperf record -t 25636 --dump-symbols --duration 30
-
-    # pull perf.data on host
-    host$adb shell run-as com.example.sudogame cat perf.data >perf.data
-
-    # report perf.data
-    host$simpleperf report
-
-### Show flamegraph
-Simpleperf supports reading perf.data through libsimpleperf_report.so.
-Currently, libsimpleperf_report.so is only provided on linux x86_64 platform,
-but it can be built for other platforms from source code. It has a python
-interface simpleperf_report_lib.py. So we can write python scripts to read
-perf.data. The shared library and scripts are in
-https://android.googlesource.com/platform/system/extras/+/master/simpleperf/scripts/.
-
-One example is report_sample.py. It can be used to output file used to show
-flame graph as below.
-
-    # Convert perf.data into out.perf.
-    host$python report_sample.py >out.perf
-
-    # show out.perf using flamegraph
-    host$stackcollapse-perf.pl out.perf >out.folded
-    host$./flamegraph.pl out.folded >a.svg
-
-
-# Steps to profile java code on rooted devices
+## Profile java code
 Simpleperf only supports profiling native instructions in binaries in ELF
 format. If the java code is executed by interpreter, or with jit cache, it
 can’t be profiled by simpleperf. As Android supports Ahead-of-time compilation,
-it can compile java bytecode into native instructions. We currently need root
-privilege to force Android fully compiling java code into native instructions
-in ELF binaries with debug information (this could be fixed by a
-profileable=”true” in AndroidManifest that causes PackageManager to pass -g to
-dex2oat). We also need root privilege to read compiled native binaries
-(because installd writes them to a directory whose uid/gid is system:install).
-So profiling java code can currently only be done on rooted devices.
+it can compile java bytecode into native instructions with debug information.
+On devices with Android version <= M, we need root privilege to compile java
+bytecode with debug information. However, on devices with Android version >= N,
+we don't need root privilege to do so.
 
-## 1. Fully compile java code into native instructions
 ### On Android N
+#### 1. Fully compile java code into native instructions.
 
-    # Restart adb as root. It needs root privilege to setprop below.
-    $adb root
-    # Set the property to compile with debug information.
-    $adb shell setprop dalvik.vm.dex2oat-flags -g
-
-    # Fully compile the app instead of using interpreter or jit.
+    $adb shell setprop debug.generate-debug-info true
     $adb shell cmd package compile -f -m speed com.example.sudogame
+    // restart the app to take effect
 
-    # Restart the app on device.
+#### 2. Record perf.data
+
+    angler:/data/data/com.example.sudogame $./simpleperf record -p 11826 -g --symfs . --duration 30
+    simpleperf I 01-01 10:31:40 11859 11859 cmd_record.cpp:341] Samples recorded: 50576. Samples lost: 2139.
+
+#### 3. Report perf.data
+
+    angler:/data/data/com.example.sudogame $./simpleperf report -g --symfs . >report
+    angler:/data/data/com.example.sudogame $exit
+    angler:/ $cp /data/data/com.example.sudogame/report /data/local/tmp
+    angler:/ $exit
+    $adb pull /data/local/tmp/report .
+    $cat report
+    ...
+    21.14%    0.00%  xample.sudogame  11826  11826  /data/app/com.example.sudogame-1/oat/arm/base.odex            boolean com.example.sudogame.MainActivity.onOptionsItemSelected(android.view.MenuItem)
+           |
+           -- boolean com.example.sudogame.MainActivity.onOptionsItemSelected(android.view.MenuItem)
+              |
+               --99.99%-- void com.example.sudogame.GameView.startNewGame()
+                   |--0.01%-- [hit in function]
+                   |
+                   |--99.87%-- void com.example.sudogame.GameModel.reInit()
+                   |    |--0.01%-- [hit in function]
+                   |    |
+                   |    |--89.65%-- boolean com.example.sudogame.GameModel.canFindSolution(int[][])
+                   |    |    |
+                   |    |    |--99.95%-- Java_com_example_sudogame_GameModel_canFindSolution
+                   |    |    |    |
+                   |    |    |    |--99.49%-- canFindSolution(Board&)
+                   |    |    |    |    |--0.01%-- [hit in function]
+                   |    |    |    |    |
+                   |    |    |    |    |--99.97%-- canFindSolution_r(Board&, int, int)
+                   |    |    |    |    |           canFindSolution_r(Board&, int, int)
+    ...
 
 ### On Android M
+On M devices, We need root privilege to force Android fully compiling java code
+into native instructions in ELF binaries with debug information. We also need
+root privilege to read compiled native binaries (because installd writes them
+to a directory whose uid/gid is system:install). So profiling java code can
+only be done on rooted devices.
 
-    # Restart adb as root. It needs root privilege to setprop below.
     $adb root
-    # Set the property to compile with debug information.
     $adb shell setprop dalvik.vm.dex2oat-flags -g
 
     # Reinstall the app.
     $adb install -r app-debug.apk
 
-### On Android L
-
-    # Restart adb as root. It needs root privilege to setprop below.
-    $adb root
-    # Set the property to compile with debug information.
-    $adb shell setprop dalvik.vm.dex2oat-flags --include-debug-symbols
-
-    # Reinstall the app.
-    $adb install -r app-debug.apk
-
-## 2. Record perf.data
-
     # Change to the app’s data directory.
     $ adb root && adb shell
     device# cd `run-as com.example.sudogame pwd`
 
     # Record as root as simpleperf needs to read the generated native binary.
-    device#./simpleperf record -t 25636 -g --symfs . -f 1000 --duration 30
+    device#./simpleperf record -p 25636 -g --symfs . -f 1000 --duration 30
     simpleperf I 01-02 07:18:20 27182 27182 cmd_record.cpp:323] Samples recorded: 23552. Samples lost: 39.
 
-    device#ls -lh perf.data
-    -rw-rw-rw- 1 root root 11M 2016-01-02 07:18 perf.data
+### On Android L
+On L devices, we also need root privilege to compile the app with debug info
+and access the native binaries.
 
-## 3. Report perf.data
-    # Report how samples distribute on different binaries.
-    device#./simpleperf report -n --sort dso
-    Cmdline: /data/data/com.example.sudogame/simpleperf record -t 25636 -g --symfs . -f 1000 --duration 30
-    Arch: arm64
-    Event: cpu-cycles (type 0, config 0)
-    Samples: 23552
-    Event count: 40662494587
+    $adb root
+    $adb shell setprop dalvik.vm.dex2oat-flags --include-debug-symbols
 
-    Overhead  Sample  Shared Object
-    85.73%    20042   [kernel.kallsyms]
-    9.41%     2198    /system/lib64/libc.so
-    2.29%     535     /system/lib64/libcutils.so
-    0.95%     222     /data/app/com.example.sudogame-1/lib/arm64/libsudo-game-jni.so
+    # Reinstall the app.
+    $adb install -r app-debug.apk
+
+## Profile using scripts
+Although using command line is flexible, it can be too complex. So we have
+python scripts to help running commands.
+
+### Record using app_profiler.py
+app_profiler.py is used to profile an Android application. It sets up profiling
+environment, downloads simpleperf and native libraries with debug information,
+runs simpleperf to generate perf.data, and pulls perf.data and binaries from
+device to host.
+It is configured by app_profiler.config. Below is an example.
+
+app_profiler.config:
+
+    app_package_name = “com.example.sudogame”
+    android_studio_project_dir = “/AndroidStudioProjects/SudoGame”  # absolute path of the project
     ...
-    0.04%     16      /system/lib64/libandroid_runtime.so
-    0.03%     10      /data/app/com.example.sudogame-1/oat/arm64/base.odex
+    record_options = "-e cpu-cycles:u -f 4000 -g --dump-symbols --duration 30"
     ...
 
-As in the report above, there are samples in
-/data/app/com.example.sudogame-1/oat/arm64/base.odex, which is the native binary
-compiled from java code.
+run app_profiler.py:
 
-    # Report call graph.
-    device#./simpleperf report -n -g --symfs .
-    Cmdline: /data/data/com.example.sudogame/simpleperf record -t 25636 -g --symfs . -f 1000 --duration 30
-    Arch: arm64
-    Event: cpu-cycles (type 0, config 0)
-    Samples: 23552
-    Event count: 40662494587
+    $python app_profiler.py
+    ...
+    INFO:root:profiling is finished.
 
-    Children  Self    Sample  Command          Pid    Tid    Shared Object                                                   Symbol
-    98.32%    0.00%   1       xample.sudogame  25636  25636  /data/app/com.example.sudogame-1/oat/arm64/base.odex            void com.example.sudogame.GameModel.reInit()
-       |
-       -- void com.example.sudogame.GameModel.reInit()
-          |
-          |--98.98%-- boolean com.example.sudogame.GameModel.canFindSolution(int[][])
-          |           Java_com_example_sudogame_GameModel_canFindSolution
-          |           |
-          |           |--99.93%-- canFindSolution(Board&)
+It pulls generated perf.data on host, and collects binaries from device in
+binary_cache.
+
+### Report using report.py
+
+    $python report.py -g
+
+It generates a GUI interface to report data.
+
+### Process samples using simpleperf_report_lib.py
+simpleperf_report_lib.py provides an interface reading samples from perf.data.
+An example is report_sample.py.
+
+### Show flamegraph
+
+    $python report_sample.py >out.perf
+    $stackcollapse-perf.pl out.perf >out.folded
+    $./flamegraph.pl out.folded >a.svg
+
+### Annotate source code
+annotate.py reads perf.data and binaries in binary_cache. Then it knows which
+source file:line each sample hits. So it can annotate source code. annotate.py
+is configured by annotate.config. Below is an example.
+
+annotate.config:
+
+    ...
+    source_dirs = [“/AndroidStudio/SudoGame”]  # It is a directory containing source code.
     ...
 
-As in the report above, reInit() and canFindSolution() are java
-functions.
+run annotate.py:
+
+    $python annotate.py
+
+It generates annotated_files directory.
+annotated_files/summary file contains summary information for each source file.
+An example is as below.
+
+    /AndroidStudioProjects/SudoGame/app/src/main/jni/sudo-game-jni.cpp: accumulated_period: 25.587937%, period: 1.250961%
+      function (checkValid(Board const&, int, int)): line 99, accumulated_period: 23.564356%, period: 0.908457%
+      function (canFindSolution_r(Board&, int, int)): line 135, accumulated_period: 22.260125%, period: 0.142359%
+      function (canFindSolution(Board&)): line 166, accumulated_period: 22.233101%, period: 0.000000%
+      function (Java_com_example_sudogame_GameModel_canFindSolution): line 470, accumulated_period: 21.983184%, period: 0.000000%
+      function (Java_com_example_sudogame_GameModel_initRandomBoard): line 430, accumulated_period: 2.226896%, period: 0.000000%
+
+      line 27: accumulated_period: 0.011729%, period: 0.000000%
+      line 32: accumulated_period: 0.004362%, period: 0.000000%
+      line 33: accumulated_period: 0.004427%, period: 0.000000%
+      line 36: accumulated_period: 0.003303%, period: 0.000000%
+      line 39: accumulated_period: 0.010367%, period: 0.004123%
+      line 41: accumulated_period: 0.162219%, period: 0.000000%
+
+annotated_files/ also contains annotated source files which are found by
+annotate.py. For example, part of checkValid() function in libsudo-game-jni.cpp
+is annotated as below.
+
+    /* [func] acc_p: 23.564356%, p: 0.908457% */static bool checkValid(const Board& board, int curR, int curC) {
+    /* acc_p: 0.037933%, p: 0.037933%         */    int digit = board.digits[curR][curC];
+    /* acc_p: 0.162355%, p: 0.162355%         */    for (int r = 0; r < BOARD_ROWS; ++r) {
+    /* acc_p: 0.020880%, p: 0.020880%         */        if (r == curR) {
+    /* acc_p: 0.034691%, p: 0.034691%         */            continue;
+                                                        }
+    /* acc_p: 0.176490%, p: 0.176490%         */        if (board.digits[r][curC] == digit) {
+    /* acc_p: 14.957673%, p: 0.059022%        */            LOGI("conflict (%d, %d) (%d, %d)", curR, curC, r, curC);
+    /* acc_p: 0.016296%, p: 0.016296%         */            return false;
+                                                        }
+                                                    }
diff --git a/android/arm/simpleperf b/android/arm/simpleperf
deleted file mode 100755
index 5ef6b61..0000000
--- a/android/arm/simpleperf
+++ /dev/null
Binary files differ
diff --git a/android/arm64/simpleperf b/android/arm64/simpleperf
deleted file mode 100755
index 2dc9afe..0000000
--- a/android/arm64/simpleperf
+++ /dev/null
Binary files differ
diff --git a/android/x86/simpleperf b/android/x86/simpleperf
deleted file mode 100755
index 85244da..0000000
--- a/android/x86/simpleperf
+++ /dev/null
Binary files differ
diff --git a/android/x86_64/simpleperf b/android/x86_64/simpleperf
deleted file mode 100755
index 297ca11..0000000
--- a/android/x86_64/simpleperf
+++ /dev/null
Binary files differ
diff --git a/annotate.config b/annotate.config
new file mode 100644
index 0000000..2e5db55
--- /dev/null
+++ b/annotate.config
@@ -0,0 +1,40 @@
+# This configuration is written in python and used by annotate.py.
+
+import os
+
+# A list of profiling record files. By default it only contains perf.data.
+perf_data_list = ["perf.data"]
+
+
+# Directory used to read binaries with debug info. Ideally, it should be
+# set to the path of binary_cache_dir collected by app_profiler.py.
+# Set to "" if not available.
+symfs_dir = "binary_cache"
+
+
+# File path used to find kernel symbols. Set to "" if not available.
+kallsyms = ""
+
+
+# A list of directories used to find source files.
+source_dirs = []
+
+
+# Directory used to output annotated source files.
+annotate_dest_dir = "annotated_files"
+
+
+# Sample Filters
+# Use samples only in threads with selected names.
+comm_filters = []
+# Use samples only in processes with selected process ids.
+pid_filters = []
+# Use samples only in threads with selected thread ids.
+tid_filters = []
+# Use samples only in selected binaries.
+dso_filters = []
+
+
+# We use addr2line to map virtual address to source file and source line.
+# So set the path to addr2line here.
+addr2line_path = "addr2line"
\ No newline at end of file
diff --git a/annotate.py b/annotate.py
new file mode 100644
index 0000000..b49942f
--- /dev/null
+++ b/annotate.py
@@ -0,0 +1,599 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""annotate.py: annotate source files based on perf.data.
+"""
+
+
+import argparse
+import os
+import os.path
+import shutil
+import subprocess
+import sys
+
+from simpleperf_report_lib import *
+from utils import *
+
+# TODO: using addr2line can't convert from function_start_address to
+# source_file:line very well for java code. Because in .debug_line section,
+# there is some distance between function_start_address and the address
+# of the first instruction which can be mapped to source line.
+class Addr2Line(object):
+    """collect information of how to map [dso_name,vaddr] to [source_file:line].
+    """
+    def __init__(self, annotator, addr2line_path):
+        self.dso_dict = dict()
+        self.annotator = annotator
+        self.addr2line_path = addr2line_path
+
+
+    def add_addr(self, dso_name, addr):
+        dso = self.dso_dict.get(dso_name)
+        if dso is None:
+            self.dso_dict[dso_name] = dso = dict()
+        if not dso.has_key(addr):
+            dso[addr] = None
+
+
+    def convert_addrs_to_lines(self):
+        # store a list of source files
+        self.file_list = []
+        # map from file to id with file_list[id] == file
+        self.file_dict = {}
+
+        for dso_name in self.dso_dict.keys():
+            self._convert_addrs_to_lines(dso_name, self.dso_dict[dso_name])
+        self._combine_source_files()
+
+
+    def _convert_addrs_to_lines(self, dso_name, dso):
+        dso_path = self.annotator.find_dso_path(dso_name)
+        if dso_path is None:
+            log_warning("can't find dso '%s'" % dso_name)
+            dso.clear()
+            return
+        addrs = sorted(dso.keys());
+        addr_str = []
+        for addr in addrs:
+            addr_str.append('0x%x' % addr)
+        addr_str = '\n'.join(addr_str)
+        subproc = subprocess.Popen([self.addr2line_path, '-e', dso_path],
+                                   stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+        (stdoutdata, _) = subproc.communicate(addr_str)
+        stdoutdata = stdoutdata.split('\n')
+        if len(stdoutdata) < len(addrs):
+            log_fatal("addr2line didn't output enough lines")
+        for i in range(len(addrs)):
+            strs = stdoutdata[i].split(':')
+            if len(strs) == 2 and strs[0].find('?') == -1:
+                file = strs[0].strip()
+                if strs[1].find('?') == -1:
+                    line = 0
+                    for c in strs[1]:
+                        if c.isdigit():
+                            line = line * 10 + ord(c) - ord('0')
+                        else:
+                            break
+                else:
+                    line = None
+                id = self.file_dict.get(file)
+                if id is None:
+                    id = len(self.file_list)
+                    self.file_list.append(file)
+                    self.file_dict[file] = id
+                dso[addrs[i]] = (id, line)
+
+
+    def _combine_source_files(self):
+        """It is possible that addr2line gives us different names for the same
+           file, like:
+            /usr/local/.../src/main/jni/sudo-game-jni.cpp
+            sudo-game-jni.cpp
+           We'd better combine these two files. We can do it by combining
+           source files with no conflicts in path.
+        """
+        # Collect files having the same filename.
+        filename_dict = dict()
+        for file in self.file_list:
+            index = max(file.rfind('/'), file.rfind(os.sep))
+            filename = file[index+1:]
+            entry = filename_dict.get(filename)
+            if entry is None:
+                filename_dict[filename] = entry = []
+            entry.append(file)
+
+        # Combine files having the same filename and having no conflicts in path.
+        for filename in filename_dict.keys():
+            files = filename_dict[filename]
+            if len(files) == 1:
+                continue
+            for file in files:
+                to_file = file
+                # Test if we can merge files[i] with another file having longer
+                # path.
+                for f in files:
+                    if len(f) > len(to_file) and f.find(file) != -1:
+                        to_file = f
+                if to_file != file:
+                    from_id = self.file_dict[file]
+                    to_id = self.file_dict[to_file]
+                    self.file_list[from_id] = self.file_list[to_id]
+
+
+    def get_source(self, dso_name, addr):
+        dso = self.dso_dict.get(dso_name)
+        if dso is None:
+            return (None, None)
+        item = dso.get(addr)
+        if item is None:
+            return (None, None)
+        return (self.file_list[item[0]], item[1])
+
+
+class Period(object):
+    """event count information. It can be used to represent event count
+       of a line, a function, a source file, or a binary. It contains two
+       parts: period and acc_period.
+       When used for a line, period is the event count occurred when running
+       that line, acc_period is the accumulated event count occurred when
+       running that line and functions called by that line. Same thing applies
+       when it is used for a function, a source file, or a binary.
+    """
+    def __init__(self, period=0, acc_period=0):
+        self.period = period
+        self.acc_period = acc_period
+
+
+    def __iadd__(self, other):
+        self.period += other.period
+        self.acc_period += other.acc_period
+        return self
+
+
+class DsoPeriod(object):
+    """Period for each shared library"""
+    def __init__(self, dso_name):
+        self.dso_name = dso_name
+        self.period = Period()
+
+
+    def add_period(self, period):
+        self.period += period
+
+
+class FilePeriod(object):
+    """Period for each source file"""
+    def __init__(self, file):
+        self.file = file
+        self.period = Period()
+        # Period for each line in the file.
+        self.line_dict = {}
+        # Period for each function in the source file.
+        self.function_dict = {}
+
+
+    def add_period(self, period):
+        self.period += period
+
+
+    def add_line_period(self, line, period):
+        a = self.line_dict.get(line)
+        if a is None:
+            self.line_dict[line] = a = Period()
+        a += period
+
+
+    def add_function_period(self, function_name, function_start_line, period):
+        a = self.function_dict.get(function_name)
+        if a is None:
+            if function_start_line is None:
+                function_start_line = -1
+            self.function_dict[function_name] = a = [function_start_line, Period()]
+        a[1] += period
+
+
+class SourceFileAnnotator(object):
+    """group code for annotating source files"""
+    def __init__(self, config):
+        # check config variables
+        config_names = ['perf_data_list', 'symfs_dir', 'source_dirs',
+                        'annotate_dest_dir', 'comm_filters', 'pid_filters',
+                        'tid_filters', 'dso_filters', 'addr2line_path']
+        for name in config_names:
+            if not config.has_key(name):
+                log_fatal('config [%s] is missing' % name)
+        symfs_dir = config['symfs_dir']
+        if symfs_dir and not os.path.isdir(symfs_dir):
+            log_fatal('[symfs_dir] "%s" is not a dir' % symfs_dir)
+        kallsyms = config['kallsyms']
+        if kallsyms and not os.path.isfile(kallsyms):
+            log_fatal('[kallsyms] "%s" is not a file' % kallsyms)
+        source_dirs = config['source_dirs']
+        for dir in source_dirs:
+            if not os.path.isdir(dir):
+                log_fatal('[source_dirs] "%s" is not a dir' % dir)
+
+        # init member variables
+        self.config = config
+        self.symfs_dir = None
+        self.kallsyms = None
+        self.comm_filter = None
+        self.pid_filter = None
+        self.tid_filter = None
+        self.dso_filter = None
+        symfs_dir = config['symfs_dir']
+        if symfs_dir:
+            self.symfs_dir = symfs_dir
+        kallsyms = config['kallsyms']
+        if kallsyms:
+            self.kallsyms = kallsyms
+        comm_filter = config['comm_filters']
+        if comm_filter:
+            self.comm_filter = set(comm_filter)
+        pid_filter = config['pid_filters']
+        if pid_filter:
+            self.pid_filter = set()
+            for pid in pid_filter:
+                self.pid_filter.add(int(pid))
+        tid_filter = config['tid_filters']
+        if tid_filter:
+            self.tid_filter = set()
+            for tid in tid_filter:
+                self.tid_filter.add(int(tid))
+        dso_filter = config['dso_filters']
+        if dso_filter:
+            self.dso_filter = set(dso_filter)
+
+        output_dir = config['annotate_dest_dir']
+        if os.path.isdir(output_dir):
+            shutil.rmtree(output_dir)
+        os.makedirs(output_dir)
+
+        self.addr2line = Addr2Line(self, self.config['addr2line_path'])
+
+
+    def annotate(self):
+        self._collect_addrs()
+        self._convert_addrs_to_lines()
+        self._generate_periods()
+        self._write_summary()
+        self._collect_source_files()
+        self._annotate_files()
+
+
+    def _collect_addrs(self):
+        """Read perf.data, collect all addresses we need to convert to
+           source file:line.
+        """
+        for perf_data in self.config['perf_data_list']:
+            lib = ReportLib()
+            if self.symfs_dir is not None:
+                lib.SetSymfs(self.symfs_dir)
+            if self.kallsyms is not None:
+                lib.SetKallsymsFile(self.kallsyms)
+            while True:
+                sample = lib.GetNextSample()
+                if sample is None:
+                    lib.Close()
+                    break
+                if not self._filter_sample(sample):
+                    continue
+                symbols = []
+                symbols.append(lib.GetSymbolOfCurrentSample())
+                callchain = lib.GetCallChainOfCurrentSample()
+                for i in range(callchain.nr):
+                    symbols.append(callchain.entries[i].symbol)
+                for symbol in symbols:
+                    if self._filter_symbol(symbol):
+                        self.addr2line.add_addr(symbol.dso_name, symbol.vaddr_in_file)
+                        self.addr2line.add_addr(symbol.dso_name, symbol.symbol_addr)
+
+
+    def _filter_sample(self, sample):
+        """Return true if the sample can be used."""
+        if self.comm_filter is not None:
+            if sample.thread_comm not in self.comm_filter:
+                return False
+        if self.pid_filter is not None:
+            if sample.pid not in self.pid_filter:
+                return False
+        if self.tid_filter is not None:
+            if sample.tid not in self.tid_filter:
+                return False
+        return True
+
+
+    def _filter_symbol(self, symbol):
+        if self.dso_filter is None or symbol.dso_name in self.dso_filter:
+            return True
+        return False
+
+
+    def _convert_addrs_to_lines(self):
+        self.addr2line.convert_addrs_to_lines()
+
+
+    def find_dso_path(self, dso):
+        if dso[0] != '/' or dso == '//anon':
+            return None
+        if self.symfs_dir is not None:
+            dso_path = os.path.join(self.symfs_dir, dso[1:])
+            if os.path.isfile(dso_path):
+                return dso_path
+        if os.path.isfile(dso):
+            return dso
+        return None
+
+
+    def _generate_periods(self):
+        """read perf.data, collect Period for all types:
+            binaries, source files, functions, lines.
+        """
+        self.period = 0
+        self.dso_periods = dict()
+        self.file_periods = dict()
+        for perf_data in self.config['perf_data_list']:
+            lib = ReportLib()
+            if self.symfs_dir is not None:
+                lib.SetSymfs(self.symfs_dir)
+            if self.kallsyms is not None:
+                lib.SetKallsymsFile(self.kallsyms)
+            while True:
+                sample = lib.GetNextSample()
+                if sample is None:
+                    lib.Close()
+                    break
+                if not self._filter_sample(sample):
+                    continue
+                symbols = []
+                symbols.append(lib.GetSymbolOfCurrentSample())
+                callchain = lib.GetCallChainOfCurrentSample()
+                for i in range(callchain.nr):
+                    symbols.append(callchain.entries[i].symbol)
+                # Each sample has a callchain, but its period is only used once
+                # to add period for each function/source_line/source_file/binary.
+                # For example, if more than one entry in the callchain hits a
+                # function, the event count of that function is only increased once.
+                # Otherwise, we may get periods > 100%.
+                is_sample_used = False
+                used_dso_dict = dict()
+                used_file_dict = dict()
+                used_function_dict = dict()
+                used_line_dict = dict()
+                period = Period(sample.period, sample.period)
+                for i in range(len(symbols)):
+                    symbol = symbols[i]
+                    if i == 1:
+                        period = Period(0, sample.period)
+                    if not self._filter_symbol(symbol):
+                        continue
+                    is_sample_used = True
+                    # Add period to dso.
+                    self._add_dso_period(symbol.dso_name, period, used_dso_dict)
+                    # Add period to source file.
+                    source = self.addr2line.get_source(symbol.dso_name, symbol.vaddr_in_file)
+                    if source[0] is not None:
+                        self._add_file_period(source[0], period, used_file_dict)
+                        # Add period to line.
+                        if source[1] is not None:
+                            self._add_line_period(source, period, used_line_dict)
+                    # Add period to function.
+                    source = self.addr2line.get_source(symbol.dso_name, symbol.symbol_addr)
+                    if source[0] is not None:
+                        self._add_file_period(source[0], period, used_file_dict)
+                        self._add_function_period(source, symbol.symbol_name, period,
+                                                  used_function_dict)
+
+                if is_sample_used:
+                    self.period += sample.period
+
+
+    def _add_dso_period(self, dso_name, period, used_dso_dict):
+        if not used_dso_dict.has_key(dso_name):
+            used_dso_dict[dso_name] = True
+            dso_period = self.dso_periods.get(dso_name)
+            if dso_period is None:
+                dso_period = self.dso_periods[dso_name] = DsoPeriod(dso_name)
+            dso_period.add_period(period)
+
+
+    def _add_file_period(self, file, period, used_file_dict):
+        if not used_file_dict.has_key(file):
+            used_file_dict[file] = True
+            file_period = self.file_periods.get(file)
+            if file_period is None:
+                file_period = self.file_periods[file] = FilePeriod(file)
+            file_period.add_period(period)
+
+
+    def _add_line_period(self, source, period, used_line_dict):
+        if not used_line_dict.has_key(source):
+            used_line_dict[source] = True
+            file_period = self.file_periods[source[0]]
+            file_period.add_line_period(source[1], period)
+
+
+    def _add_function_period(self, source, function_name, period, used_function_dict):
+        if not used_function_dict.has_key((source[0], function_name)):
+            used_function_dict[(source[0], function_name)] = True
+            file_period = self.file_periods[source[0]]
+            file_period.add_function_period(function_name, source[1], period)
+
+
+    def _write_summary(self):
+        summary = os.path.join(self.config['annotate_dest_dir'], 'summary')
+        with open(summary, 'w') as f:
+            f.write('total period: %d\n\n' % self.period)
+            dso_periods = sorted(self.dso_periods.values(),
+                                 cmp=lambda x, y: cmp(y.period.acc_period, x.period.acc_period))
+            for dso_period in dso_periods:
+                f.write('dso %s: %s\n' % (dso_period.dso_name,
+                                          self._get_percentage_str(dso_period.period)))
+            f.write('\n')
+
+            file_periods = sorted(self.file_periods.values(),
+                                  cmp=lambda x, y: cmp(y.period.acc_period, x.period.acc_period))
+            for file_period in file_periods:
+                f.write('file %s: %s\n' % (file_period.file,
+                                           self._get_percentage_str(file_period.period)))
+            for file_period in file_periods:
+                f.write('\n\n%s: %s\n' % (file_period.file,
+                                          self._get_percentage_str(file_period.period)))
+                values = []
+                for func_name in file_period.function_dict.keys():
+                    func_start_line, period = file_period.function_dict[func_name]
+                    values.append((func_name, func_start_line, period))
+                values = sorted(values,
+                                cmp=lambda x, y: cmp(y[2].acc_period, x[2].acc_period))
+                for value in values:
+                    func = file_period.function_dict[func_name]
+                    f.write('\tfunction (%s): line %d, %s\n' % (
+                        value[0], value[1], self._get_percentage_str(value[2])))
+                f.write('\n')
+                for line in sorted(file_period.line_dict.keys()):
+                    f.write('\tline %d: %s\n' % (
+                        line, self._get_percentage_str(file_period.line_dict[line])))
+
+
+    def _get_percentage_str(self, period, short=False):
+        s = 'acc_p: %f%%, p: %f%%' if short else 'accumulated_period: %f%%, period: %f%%'
+        return s % self._get_percentage(period)
+
+
+    def _get_percentage(self, period):
+        if self.period == 0:
+            return (0, 0)
+        acc_p = 100.0 * period.acc_period / self.period
+        p = 100.0 * period.period / self.period
+        return (acc_p, p)
+
+
+    def _collect_source_files(self):
+        self.source_file_dict = dict()
+        source_file_suffix = ['h', 'c', 'cpp', 'cc', 'java']
+        for source_dir in self.config['source_dirs']:
+            for root, _, files in os.walk(source_dir):
+                for file in files:
+                    if file[file.rfind('.')+1:] in source_file_suffix:
+                        entry = self.source_file_dict.get(file)
+                        if entry is None:
+                            entry = self.source_file_dict[file] = []
+                        entry.append(os.path.join(root, file))
+
+
+    def _find_source_file(self, file):
+        filename = file[file.rfind(os.sep)+1:]
+        source_files = self.source_file_dict.get(filename)
+        if source_files is None:
+            return None
+        match_count = 0
+        result = None
+        for path in source_files:
+            if path.find(file) != -1:
+                match_count += 1
+                result = path
+        if match_count > 1:
+            log_warning('multiple source for %s, select %s' % (file, result))
+        return result
+
+
+    def _annotate_files(self):
+        """Annotate Source files: add acc_period/period for each source file.
+           1. Annotate java source files, which have $JAVA_SRC_ROOT prefix.
+           2. Annotate c++ source files.
+        """
+        dest_dir = self.config['annotate_dest_dir']
+        for key in self.file_periods.keys():
+            is_java = False
+            if key.startswith('$JAVA_SRC_ROOT/'):
+                path = key[len('$JAVA_SRC_ROOT/'):]
+                items = path.split('/')
+                path = os.sep.join(items)
+                from_path = self._find_source_file(path)
+                to_path = os.path.join(dest_dir, 'java', path)
+                is_java = True
+            elif key.startswith('/') and os.path.isfile(key):
+                path = key
+                from_path = path
+                to_path = os.path.join(dest_dir, path[1:])
+            else:
+                path = key[1:] if key.startswith('/') else key
+                # Change path on device to path on host
+                path = os.sep.join(path.split('/'))
+                from_path = self._find_source_file(path)
+                to_path = os.path.join(dest_dir, path)
+            if from_path is None:
+                log_warning("can't find source file for path %s" % key)
+                continue
+            self._annotate_file(from_path, to_path, self.file_periods[key], is_java)
+
+
+    def _annotate_file(self, from_path, to_path, file_period, is_java):
+        """Annotate a source file.
+
+        Annotate a source file in three steps:
+          1. In the first line, show periods of this file.
+          2. For each function, show periods of this function.
+          3. For each line not hitting the same line as functions, show
+             line periods.
+        """
+        log_info('annotate file %s' % from_path)
+        with open(from_path, 'r') as rf:
+            lines = rf.readlines()
+
+        annotates = dict()
+        for line in file_period.line_dict.keys():
+            annotates[line] = self._get_percentage_str(file_period.line_dict[line], True)
+        for func_name in file_period.function_dict.keys():
+            func_start_line, period = file_period.function_dict[func_name]
+            if func_start_line == -1:
+                continue
+            line = func_start_line - 1 if is_java else func_start_line
+            annotates[line] = '[func] ' + self._get_percentage_str(period, True)
+        annotates[1] = '[file] ' + self._get_percentage_str(file_period.period, True)
+
+        max_annotate_cols = 0
+        for key in annotates.keys():
+            max_annotate_cols = max(max_annotate_cols, len(annotates[key]))
+
+        empty_annotate = ' ' * (max_annotate_cols + 6)
+
+        dirname = os.path.dirname(to_path)
+        if not os.path.isdir(dirname):
+            os.makedirs(dirname)
+        with open(to_path, 'w') as wf:
+            for line in range(1, len(lines) + 1):
+                annotate = annotates.get(line)
+                if annotate is None:
+                    annotate = empty_annotate
+                else:
+                    annotate = '/* ' + annotate + (
+                        ' ' * (max_annotate_cols - len(annotate))) + ' */'
+                wf.write(annotate)
+                wf.write(lines[line-1])
+
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser(
+        description='Annotate based on perf.data. See configurations in annotate.config.')
+    parser.add_argument('--config', default='annotate.config',
+                        help='Set configuration file. Default is annotate.config.')
+    args = parser.parse_args()
+    config = load_config(args.config)
+    annotator = SourceFileAnnotator(config)
+    annotator.annotate()
\ No newline at end of file
diff --git a/app_profiler.config b/app_profiler.config
new file mode 100644
index 0000000..f3aebde
--- /dev/null
+++ b/app_profiler.config
@@ -0,0 +1,69 @@
+# This configuration is written in python and used by app_profiler.py.
+
+import os
+import os.path
+
+# The name of the android package, like com.example.android.
+app_package_name = "com.example.android"
+
+
+# Path of android studio project. It is used to find debug version of native shared libraries.
+# Set to "" if not available.
+android_studio_project_dir = ""
+
+
+# Path to find debug version of native shared libraries.
+native_lib_dir = ""
+
+if android_studio_project_dir and not native_lib_dir:
+    tmp_dir = os.path.join(android_studio_project_dir,
+        "app/build/intermediates/binaries/debug".replace('/', os.sep))
+    if os.path.isdir(tmp_dir):
+        native_lib_dir = tmp_dir
+
+
+# The path of the apk file. It is used when we need to reinstall the app to
+# fully compile dalvik bytecode into native instructions.
+# Set to "" if not available.
+apk_file_path = ""
+
+
+# To profile java code, we need to compile dalvik bytecode into native binaries
+# with debug information. Set to False if there is no need to do so (For example,
+# when the app has been recompiled.).
+recompile_app = True
+
+
+# Set to true if we want to restart the app before profiling. Otherwise, set to False.
+restart_app = True
+
+
+if recompile_app and not restart_app:
+    raise Exception('[restart_app] is needed for [recompile_app] to take effect.')
+
+
+# We use `am start -n [app_package_name]/[main_activity]` to start the app.
+main_activity = '.MainActivity'
+
+
+# Profiling record options that will be passed directly to `simpleperf record` command on device.
+# As we can't stop profiling by Ctrl-C, we need to set how long to profile using "--duration".
+record_options = "-e cpu-cycles:u -f 4000 -g --dump-symbols --duration 10"
+
+
+# The path to store generated perf.data on host.
+perf_data_path = "perf.data"
+
+
+# The path of adb.
+adb_path = "adb"
+
+
+# The path of readelf, used to read build id of files in binary cache.
+# Set to "" if not available.
+readelf_path = "readelf"
+
+
+# binary_cache_dir is used to cache binaries pulled from device. To report precisely, we pull each
+# binary hit by perf.data on host.
+binary_cache_dir = "binary_cache"
\ No newline at end of file
diff --git a/app_profiler.py b/app_profiler.py
new file mode 100644
index 0000000..919b112
--- /dev/null
+++ b/app_profiler.py
@@ -0,0 +1,293 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""app_profiler.py: manage the process of profiling an android app.
+    It downloads simpleperf on device, uses it to collect samples from
+    user's app, and pulls perf.data and needed binaries on host.
+"""
+
+from __future__ import print_function
+import argparse
+import copy
+import os
+import os.path
+import shutil
+import subprocess
+import sys
+import time
+
+from binary_cache_builder import BinaryCacheBuilder
+from simpleperf_report_lib import *
+from utils import *
+
+class AppProfiler(object):
+    """Used to manage the process of profiling an android app.
+
+    There are three steps:
+       1. Prepare profiling.
+       2. Profile the app.
+       3. Collect profiling data.
+    """
+    def __init__(self, config):
+        # check config variables
+        config_names = ['app_package_name', 'native_lib_dir', 'apk_file_path',
+                        'recompile_app', 'restart_app', 'main_activity',
+                        'record_options', 'perf_data_path', 'adb_path', 'readelf_path',
+                        'binary_cache_dir']
+        for name in config_names:
+            if not config.has_key(name):
+                log_fatal('config [%s] is missing' % name)
+        native_lib_dir = config.get('native_lib_dir')
+        if native_lib_dir and not os.path.isdir(native_lib_dir):
+            log_fatal('[native_lib_dir] "%s" is not a dir' % native_lib_dir)
+        apk_file_path = config.get('apk_file_path')
+        if apk_file_path and not os.path.isfile(apk_file_path):
+            log_fatal('[apk_file_path] "%s" is not a file' % apk_file_path)
+        self.config = config
+        self.adb = AdbHelper(self.config['adb_path'])
+        self.is_root_device = False
+        self.android_version = 0
+        self.device_arch = None
+        self.app_arch = None
+        self.app_pid = None
+
+
+    def profile(self):
+        log_info('prepare profiling')
+        self.prepare_profiling()
+        log_info('start profiling')
+        self.start_and_wait_profiling()
+        log_info('collect profiling data')
+        self.collect_profiling_data()
+        log_info('profiling is finished.')
+
+
+    def prepare_profiling(self):
+        self._get_device_environment()
+        self._enable_profiling()
+        self._recompile_app()
+        self._restart_app()
+        self._get_app_environment()
+        self._download_simpleperf()
+        self._download_native_libs()
+
+
+    def _get_device_environment(self):
+        self.is_root_device = self.adb.switch_to_root()
+
+        # Get android version.
+        build_version = self.adb.get_property('ro.build.version.release')
+        if build_version:
+            if not build_version[0].isdigit():
+                c = build_version[0].upper()
+                if c < 'L':
+                    self.android_version = 0
+                else:
+                    self.android_version = ord(c) - ord('L') + 5
+            else:
+                strs = build_version.split('.')
+                if strs:
+                    self.android_version = int(strs[0])
+
+        # Get device architecture.
+        output = self.adb.check_run_and_return_output(['shell', 'uname', '-m'])
+        if output.find('aarch64') != -1:
+            self.device_arch = 'aarch64'
+        elif output.find('arm') != -1:
+            self.device_arch = 'arm'
+        elif output.find('x86_64') != -1:
+            self.device_arch = 'x86_64'
+        elif output.find('86') != -1:
+            self.device_arch = 'x86'
+        else:
+            log_fatal('unsupported architecture: %s' % output.strip())
+
+
+    def _enable_profiling(self):
+        self.adb.set_property('security.perf_harden', '0')
+        if self.is_root_device:
+            # We can enable kernel symbols
+            self.adb.run(['shell', 'echo', '0', '>/proc/sys/kernel/kptr_restrict'])
+
+
+    def _recompile_app(self):
+        if not self.config['recompile_app']:
+            return
+        if self.android_version == 0:
+            log_warning("Can't fully compile an app on android version < L.")
+        elif self.android_version == 5 or self.android_version == 6:
+            if not self.is_root_device:
+                log_warning("Can't fully compile an app on android version < N on non-root devices.")
+            elif not self.config['apk_file_path']:
+                log_warning("apk file is needed to reinstall the app on android version < N.")
+            else:
+                flag = '-g' if self.android_version == 6 else '--include-debug-symbols'
+                self.adb.set_property('dalvik.vm.dex2oat-flags', flag)
+                self.adb.check_run(['install', '-r', self.config['apk_file_path']])
+        elif self.android_version >= 7:
+            self.adb.set_property('debug.generate-debug-info', 'true')
+            self.adb.check_run(['shell', 'cmd', 'package', 'compile', '-f', '-m', 'speed',
+                                self.config['app_package_name']])
+        else:
+            log_fatal('unreachable')
+
+
+    def _restart_app(self):
+        if not self.config['restart_app']:
+            return
+        pid = self._find_app_process()
+        if pid is not None:
+            self.adb.run(['shell', 'run-as', self.config['app_package_name'],
+                          'kill', '-9', str(pid)])
+            time.sleep(1)
+        activity = self.config['app_package_name'] + '/' + self.config['main_activity']
+        result = self.adb.run(['shell', 'am', 'start', '-n', activity])
+        if not result:
+            log_fatal("Can't start activity %s" % activity)
+        for i in range(10):
+            pid = self._find_app_process()
+            if pid is not None:
+                return pid
+            time.sleep(1)
+            log_info('Wait for the app process for %d seconds' % (i + 1))
+        log_fatal("Can't find the app process")
+
+
+    def _find_app_process(self):
+        result, output = self.adb.run_and_return_output(
+                ['shell', 'run-as', self.config['app_package_name'], 'ps'])
+        if not result:
+            return None
+        output = output.split('\n')
+        for line in output:
+            strs = line.split()
+            if len(strs) > 2 and strs[-1].find(self.config['app_package_name']) != -1:
+                return int(strs[1])
+        return None
+
+
+    def _get_app_environment(self):
+        self.app_pid = self._find_app_process()
+        if self.app_pid is None:
+            log_fatal("can't find process for app [%s]" % self.config['app_package_name'])
+        if self.device_arch in ['aarch64', 'x86_64']:
+            output = self.adb.check_run_and_return_output(
+                ['shell', 'run-as', self.config['app_package_name'],
+                'cat', '/proc/%d/maps' % self.app_pid])
+            if output.find('linker64') != -1:
+                self.app_arch = self.device_arch
+            else:
+                self.app_arch = 'arm' if self.device_arch == 'aarch64' else 'x86'
+        else:
+            self.app_arch = self.device_arch
+        log_info('app_arch: %s' % self.app_arch)
+
+
+    def _download_simpleperf(self):
+        simpleperf_binary = get_target_binary_path(self.app_arch, 'simpleperf')
+        self.adb.check_run(['push', simpleperf_binary, '/data/local/tmp'])
+        self.adb.check_run(['shell', 'run-as', self.config['app_package_name'],
+                            'cp', '/data/local/tmp/simpleperf', '.'])
+        self.adb.check_run(['shell', 'run-as', self.config['app_package_name'],
+                            'chmod', 'a+x', 'simpleperf'])
+
+
+    def _download_native_libs(self):
+        if not self.config['native_lib_dir']:
+            return
+        filename_dict = dict()
+        for root, _, files in os.walk(self.config['native_lib_dir']):
+            for file in files:
+                if not file.endswith('.so'):
+                    continue
+                path = os.path.join(root, file)
+                old_path = filename_dict.get(file)
+                log_info('app_arch = %s' % self.app_arch)
+                if self._is_lib_better(path, old_path):
+                    log_info('%s is better than %s' % (path, old_path))
+                    filename_dict[file] = path
+                else:
+                    log_info('%s is worse than %s' % (path, old_path))
+        maps = self.adb.check_run_and_return_output(['shell', 'run-as',
+                  self.config['app_package_name'], 'cat', '/proc/%d/maps' % self.app_pid])
+        searched_lib = dict()
+        for item in maps.split():
+            if item.endswith('.so') and searched_lib.get(item) is None:
+                searched_lib[item] = True
+                # Use '/' as path separator as item comes from android environment.
+                filename = item[item.rfind('/') + 1:]
+                dirname = item[1:item.rfind('/')]
+                path = filename_dict.get(filename)
+                if path is None:
+                    continue
+                self.adb.check_run(['push', path, '/data/local/tmp'])
+                self.adb.check_run(['shell', 'run-as', self.config['app_package_name'],
+                                    'mkdir', '-p', dirname])
+                self.adb.check_run(['shell', 'run-as', self.config['app_package_name'],
+                                    'cp', '/data/local/tmp/' + filename, dirname])
+
+
+    def _is_lib_better(self, new_path, old_path):
+        """ Return true if new_path is more likely to be used on device. """
+        if old_path is None:
+            return True
+        if self.app_arch == 'arm':
+            result1 = new_path.find('armeabi-v7a/') != -1
+            result2 = old_path.find('armeabi-v7a') != -1
+            if result1 != result2:
+                return result1
+        arch_dir = 'arm64' if self.app_arch == 'aarch64' else self.app_arch + '/'
+        result1 = new_path.find(arch_dir) != -1
+        result2 = old_path.find(arch_dir) != -1
+        if result1 != result2:
+            return result1
+        result1 = new_path.find('obj/') != -1
+        result2 = old_path.find('obj/') != -1
+        if result1 != result2:
+            return result1
+        return False
+
+
+    def start_and_wait_profiling(self):
+        self.adb.check_run(['shell', 'run-as', self.config['app_package_name'],
+            './simpleperf', 'record', self.config['record_options'], '-p',
+            str(self.app_pid), '--symfs', '.'])
+
+
+    def collect_profiling_data(self):
+        self.adb.check_run(['shell', 'run-as', self.config['app_package_name'],
+                            'chmod', 'a+rw', 'perf.data'])
+        self.adb.check_run(['shell', 'cp',
+            '/data/data/%s/perf.data' % self.config['app_package_name'], '/data/local/tmp'])
+        self.adb.check_run(['pull', '/data/local/tmp/perf.data', self.config['perf_data_path']])
+        config = copy.copy(self.config)
+        config['symfs_dirs'] = []
+        if self.config['native_lib_dir']:
+            config['symfs_dirs'].append(self.config['native_lib_dir'])
+        binary_cache_builder = BinaryCacheBuilder(config)
+        binary_cache_builder.build_binary_cache()
+
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser(
+        description='Profile an android app. See configurations in app_profiler.config.')
+    parser.add_argument('--config', default='app_profiler.config',
+                        help='Set configuration file. Default is app_profiler.config.')
+    args = parser.parse_args()
+    config = load_config(args.config)
+    profiler = AppProfiler(config)
+    profiler.profile()
\ No newline at end of file
diff --git a/bin/android/arm/simpleperf b/bin/android/arm/simpleperf
new file mode 100755
index 0000000..c9b5bad
--- /dev/null
+++ b/bin/android/arm/simpleperf
Binary files differ
diff --git a/bin/android/arm64/simpleperf b/bin/android/arm64/simpleperf
new file mode 100755
index 0000000..3a06448
--- /dev/null
+++ b/bin/android/arm64/simpleperf
Binary files differ
diff --git a/bin/android/x86/simpleperf b/bin/android/x86/simpleperf
new file mode 100755
index 0000000..715fc16
--- /dev/null
+++ b/bin/android/x86/simpleperf
Binary files differ
diff --git a/bin/android/x86_64/simpleperf b/bin/android/x86_64/simpleperf
new file mode 100755
index 0000000..42b793e
--- /dev/null
+++ b/bin/android/x86_64/simpleperf
Binary files differ
diff --git a/bin/darwin/x86/libsimpleperf_report.dylib b/bin/darwin/x86/libsimpleperf_report.dylib
new file mode 100755
index 0000000..4191c7d
--- /dev/null
+++ b/bin/darwin/x86/libsimpleperf_report.dylib
Binary files differ
diff --git a/bin/darwin/x86/simpleperf b/bin/darwin/x86/simpleperf
new file mode 100755
index 0000000..67dc20b
--- /dev/null
+++ b/bin/darwin/x86/simpleperf
Binary files differ
diff --git a/bin/darwin/x86_64/libsimpleperf_report.dylib b/bin/darwin/x86_64/libsimpleperf_report.dylib
new file mode 100755
index 0000000..c159556
--- /dev/null
+++ b/bin/darwin/x86_64/libsimpleperf_report.dylib
Binary files differ
diff --git a/bin/darwin/x86_64/simpleperf b/bin/darwin/x86_64/simpleperf
new file mode 100755
index 0000000..b40904b
--- /dev/null
+++ b/bin/darwin/x86_64/simpleperf
Binary files differ
diff --git a/bin/linux/x86/libsimpleperf_report.so b/bin/linux/x86/libsimpleperf_report.so
new file mode 100755
index 0000000..26e586e
--- /dev/null
+++ b/bin/linux/x86/libsimpleperf_report.so
Binary files differ
diff --git a/bin/linux/x86/simpleperf b/bin/linux/x86/simpleperf
new file mode 100755
index 0000000..e0a6a59
--- /dev/null
+++ b/bin/linux/x86/simpleperf
Binary files differ
diff --git a/bin/linux/x86_64/libsimpleperf_report.so b/bin/linux/x86_64/libsimpleperf_report.so
new file mode 100755
index 0000000..f966046
--- /dev/null
+++ b/bin/linux/x86_64/libsimpleperf_report.so
Binary files differ
diff --git a/bin/linux/x86_64/simpleperf b/bin/linux/x86_64/simpleperf
new file mode 100755
index 0000000..8e34fab
--- /dev/null
+++ b/bin/linux/x86_64/simpleperf
Binary files differ
diff --git a/bin/windows/x86/libsimpleperf_report.dll b/bin/windows/x86/libsimpleperf_report.dll
new file mode 100755
index 0000000..48d378f
--- /dev/null
+++ b/bin/windows/x86/libsimpleperf_report.dll
Binary files differ
diff --git a/bin/windows/x86/simpleperf.exe b/bin/windows/x86/simpleperf.exe
new file mode 100755
index 0000000..42bd4c8
--- /dev/null
+++ b/bin/windows/x86/simpleperf.exe
Binary files differ
diff --git a/bin/windows/x86_64/libsimpleperf_report.dll b/bin/windows/x86_64/libsimpleperf_report.dll
new file mode 100755
index 0000000..321d9c8
--- /dev/null
+++ b/bin/windows/x86_64/libsimpleperf_report.dll
Binary files differ
diff --git a/bin/windows/x86_64/simpleperf.exe b/bin/windows/x86_64/simpleperf.exe
new file mode 100755
index 0000000..76360ab
--- /dev/null
+++ b/bin/windows/x86_64/simpleperf.exe
Binary files differ
diff --git a/binary_cache_builder.config b/binary_cache_builder.config
new file mode 100644
index 0000000..49cc5ae
--- /dev/null
+++ b/binary_cache_builder.config
@@ -0,0 +1,27 @@
+# This configuration is written in python and used by binary_cache_builder.py.
+
+import os
+import os.path
+
+# path of profiling record data.
+perf_data_path = "perf.data"
+
+
+# directories to find binaries with symbols and debug information.
+# If binaries are found in any of these directories, having the same build_id
+# as the one recorded in perf.data, then we copy the binary in the directory
+# instead of pulling the binary from device.
+symfs_dirs = []
+
+
+# directory to cache binaries. To report precisely, we pull needed binaries
+# to host. However, We don't need to pull a binary if there is already a binary
+# in binary_cache_dir having the same build_id as the one on device.
+binary_cache_dir = "binary_cache"
+
+
+# path of adb.
+adb_path = "adb"
+
+# path of readelf, set to "" if not available.
+readelf_path = "readelf"
\ No newline at end of file
diff --git a/binary_cache_builder.py b/binary_cache_builder.py
new file mode 100644
index 0000000..13c028d
--- /dev/null
+++ b/binary_cache_builder.py
@@ -0,0 +1,236 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""binary_cache_builder.py: read perf.data, collect binaries needed by
+    it, and put them in binary_cache.
+"""
+
+from __future__ import print_function
+import argparse
+import os
+import os.path
+import re
+import shutil
+import subprocess
+import sys
+import time
+
+from simpleperf_report_lib import *
+from utils import *
+
+
+class BinaryCacheBuilder(object):
+    """Collect all binaries needed by perf.data in binary_cache."""
+    def __init__(self, config):
+        config_names = ['perf_data_path', 'symfs_dirs', 'adb_path',
+                        'readelf_path', 'binary_cache_dir']
+        for name in config_names:
+            if not config.has_key(name):
+                log_fatal('config for "%s" is missing' % name)
+
+        self.perf_data_path = config.get('perf_data_path')
+        if not os.path.isfile(self.perf_data_path):
+            log_fatal("can't find file %s" % self.perf_data_path)
+        self.symfs_dirs = config.get('symfs_dirs')
+        for symfs_dir in self.symfs_dirs:
+            if not os.path.isdir(symfs_dir):
+                log_fatal("symfs_dir '%s' is not a directory" % symfs_dir)
+        self.adb = AdbHelper(config['adb_path'])
+        self.readelf_path = config['readelf_path']
+        self.binary_cache_dir = config['binary_cache_dir']
+        if not os.path.isdir(self.binary_cache_dir):
+            os.makedirs(self.binary_cache_dir)
+
+
+    def build_binary_cache(self):
+        self._collect_used_binaries()
+        self._copy_binaries_from_symfs_dirs()
+        self._pull_binaries_from_device()
+        self._pull_kernel_symbols()
+
+
+    def _collect_used_binaries(self):
+        """read perf.data, collect all used binaries and their build id (if available)."""
+        # A dict mapping from binary name to build_id
+        binaries = dict()
+        lib = ReportLib()
+        lib.SetRecordFile(self.perf_data_path)
+        lib.SetLogSeverity('error')
+        while True:
+            sample = lib.GetNextSample()
+            if sample is None:
+                lib.Close()
+                break
+            symbols = [lib.GetSymbolOfCurrentSample()]
+            callchain = lib.GetCallChainOfCurrentSample()
+            for i in range(callchain.nr):
+                symbols.append(callchain.entries[i].symbol)
+
+            for symbol in symbols:
+                dso_name = symbol.dso_name
+                if not binaries.has_key(dso_name):
+                    binaries[dso_name] = lib.GetBuildIdForPath(dso_name)
+        self.binaries = binaries
+
+
+    def _copy_binaries_from_symfs_dirs(self):
+        """collect all files in symfs_dirs."""
+        if not self.symfs_dirs:
+            return
+
+        # It is possible that the path of the binary in symfs_dirs doesn't match
+        # the one recorded in perf.data. For example, a file in symfs_dirs might
+        # be "debug/arm/obj/armeabi-v7a/libsudo-game-jni.so", but the path in
+        # perf.data is "/data/app/xxxx/lib/arm/libsudo-game-jni.so". So we match
+        # binaries if they have the same filename (like libsudo-game-jni.so)
+        # and same build_id.
+
+        # Map from filename to binary paths.
+        filename_dict = dict()
+        for binary in self.binaries:
+            index = binary.rfind('/')
+            filename = binary[index+1:]
+            paths = filename_dict.get(filename)
+            if paths is None:
+                filename_dict[filename] = paths = []
+            paths.append(binary)
+
+        # Walk through all files in symfs_dirs, and copy matching files to build_cache.
+        for symfs_dir in self.symfs_dirs:
+            for root, _, files in os.walk(symfs_dir):
+                for file in files:
+                    paths = filename_dict.get(file)
+                    if paths is not None:
+                        build_id = self._read_build_id(os.path.join(root, file))
+                        if not build_id:
+                            continue
+                        for binary in paths:
+                            expected_build_id = self.binaries.get(binary)
+                            if expected_build_id == build_id:
+                                self._copy_to_binary_cache(os.path.join(root, file),
+                                                           expected_build_id, binary)
+
+
+    def _copy_to_binary_cache(self, from_path, expected_build_id, target_file):
+        if target_file[0] == '/':
+            target_file = target_file[1:]
+        target_file = target_file.replace('/', os.sep)
+        target_file = os.path.join(self.binary_cache_dir, target_file)
+        if (os.path.isfile(target_file) and self._read_build_id(target_file) == expected_build_id
+            and self._file_has_symbol_table(target_file)):
+            # The existing file in binary_cache can provide more information, so no
+            # need to copy.
+            return
+        target_dir = os.path.dirname(target_file)
+        if not os.path.isdir(target_dir):
+            os.makedirs(target_dir)
+        log_info('copy to binary_cache: %s to %s' % (from_path, target_file))
+        shutil.copy(from_path, target_file)
+
+
+    def _pull_binaries_from_device(self):
+        """pull binaries needed in perf.data to binary_cache."""
+        for binary in self.binaries:
+            build_id = self.binaries[binary]
+            if binary[0] != '/' or binary == "//anon":
+                # [kernel.kallsyms] or unknown, or something we can't find binary.
+                continue
+            binary_cache_file = binary[1:].replace('/', os.sep)
+            binary_cache_file = os.path.join(self.binary_cache_dir, binary_cache_file)
+            self._check_and_pull_binary(binary, build_id, binary_cache_file)
+
+
+    def _check_and_pull_binary(self, binary, expected_build_id, binary_cache_file):
+        """If the binary_cache_file exists and has the expected_build_id, there
+           is no need to pull the binary from device. Otherwise, pull it.
+        """
+        need_pull = True
+        if os.path.isfile(binary_cache_file):
+            need_pull = False
+            if expected_build_id:
+                build_id = self._read_build_id(binary_cache_file)
+                if expected_build_id != build_id:
+                    need_pull = True
+        if need_pull:
+            target_dir = os.path.dirname(binary_cache_file)
+            if not os.path.isdir(target_dir):
+                os.makedirs(target_dir)
+            if os.path.isfile(binary_cache_file):
+                os.remove(binary_cache_file)
+            log_info('pull file to binary_cache: %s to %s' % (binary, binary_cache_file))
+            self._pull_file_from_device(binary, binary_cache_file)
+        else:
+            log_info('use current file in binary_cache: %s' % binary_cache_file)
+
+
+    def _read_build_id(self, file):
+        """read build id of a binary on host."""
+        if not self.readelf_path:
+            return ""
+        output = subprocess.check_output([self.readelf_path, '-n', file])
+        result = re.search(r'Build ID:\s*(\S+)', output)
+        if result:
+            build_id = result.group(1)
+            if len(build_id) < 40:
+                build_id += '0' * (40 - len(build_id))
+            build_id = '0x' + build_id
+            return build_id
+        return ""
+
+
+    def _file_has_symbol_table(self, file):
+        """Test if an elf file has symbol table section."""
+        if not self.readelf_path:
+            return False
+        output = subprocess.check_output([self.readelf_path, '-S', file])
+        if output.find('.symtab') != -1:
+            return True
+        return False
+
+
+    def _pull_file_from_device(self, device_path, host_path):
+        if self.adb.run(['pull', device_path, host_path]):
+            return True
+        # In non-root device, we can't pull /data/app/XXX/base.odex directly.
+        # Instead, we can first copy the file to /data/local/tmp, then pull it.
+        filename = device_path[device_path.rfind('/')+1:]
+        if (self.adb.run(['shell', 'cp', device_path, '/data/local/tmp']) and
+            self.adb.run(['pull', '/data/local/tmp/' + filename, host_path])):
+            self.adb.run(['shell', 'rm', '/data/local/tmp/' + filename])
+            return True
+        log_warning('failed to pull %s from device' % device_path)
+        return False
+
+
+    def _pull_kernel_symbols(self):
+        file = os.path.join(self.binary_cache_dir, 'kallsyms')
+        if os.path.isfile(file):
+            os.remove(file)
+        if self.adb.switch_to_root():
+            self.adb.run(['shell', '"echo 0>/proc/sys/kernel/kptr_restrict"'])
+            self.adb.run(['pull', '/proc/kallsyms', file])
+
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser(
+        description="Pull binaries needed by perf.data from device to binary_cache.")
+    parser.add_argument('--config', default='binary_cache_builder.config',
+                        help='Set configuration file. Default is binary_cache_builder.config.')
+    args = parser.parse_args()
+    config = load_config(args.config)
+    builder = BinaryCacheBuilder(config)
+    builder.build_binary_cache()
\ No newline at end of file
diff --git a/repo.prop b/repo.prop
index a58c4cb..602db30 100644
--- a/repo.prop
+++ b/repo.prop
@@ -1,522 +1,551 @@
-device/asus/fugu 7a16fb337b8ecfe31e1b1a28616059952f49b49d
-device/asus/fugu-kernel 6b92b38472501bcf5e425998ba60dcb8a138fc5a
-device/common eb68cdcc6cb0125e33dc964801c23c768a5c87dc
-device/generic/arm64 59076b7c5c52c55f7b88042788ee231524370533
-device/generic/armv7-a-neon c278a635601d682156eb5048539bcae33606bc4a
+device/asus/fugu 0c2f18350eafd14dd5bd09d9e25085b919ed990c
+device/asus/fugu-kernel fab8e23bb7a33e057135f974477ba9590a36a057
+device/common aec77c28f81468d42289c2b0620e8f2dca63141a
+device/generic/arm64 23d9a6b57c63fbea914ae663a0be693b43d91ffc
+device/generic/armv7-a-neon d988cb11b57956297beef31a62c02628b0f6430e
 device/generic/common 11c092a6cbfcf6207f07a9a8e3398e747e7f5461
-device/generic/goldfish a652a0995fe91ec01bfd224336e57b38b1f50983
+device/generic/goldfish d1dad67cd73d43478dae166fe61e82b62685b5eb
+device/generic/goldfish-opengl 0bff4a1296477ac57dba40d40ba476f014812b60
 device/generic/mini-emulator-arm64 6f2e6974a1b1dc0ef936aec732e33d553c000b5e
 device/generic/mini-emulator-armv7-a-neon 9d7cbb60819a1da8408a7148b965b4cd1ebbb570
 device/generic/mini-emulator-mips 544e69736cff911c286a5d1d300dac228e23a73f
 device/generic/mini-emulator-mips64 b1c36d0847fe6366527efd38fdb29d757ea887ee
 device/generic/mini-emulator-x86 65d59e2be2cfd713513a05d80a0f75794ab60579
-device/generic/mini-emulator-x86_64 673aae8bd65d9708821c4062f6a0364a859e7ae4
-device/generic/mips bf07c7522e80eef53a58a49e5d05b8913d00d1a6
-device/generic/mips64 af38ee08585bcedd169309f3663aec70d0a91856
+device/generic/mini-emulator-x86_64 5f29a14dc6e0d26dd628b502317f6b853028f54b
+device/generic/mips c30795ed4ee4b2ca39871474ceab2c43ae89ca51
+device/generic/mips64 2448fdcbe63ba1ee11fcda2b7b3a8e455fd346da
 device/generic/qemu 99feb6138f39e392495057ef7f2c4a5ed27f9e2d
-device/generic/x86 81ce753ec0014fe404c4eec3ac6d04504356a638
-device/generic/x86_64 f2d6d736a4a45e182349e932bd0708be45da7a4a
+device/generic/x86 b676b41d81d862839ee6670516d21e2f869051d6
+device/generic/x86_64 f00aa59b3af4937ed014701755e9b01c95122187
 device/google/accessory/arduino abc5159a3ca9dbb5c7e364a1eab99901a4440ac5
 device/google/accessory/demokit 7dfe7f89a3b174709c773fe319531006e46440d9
-device/google/atv 77b83d651007cb6998d4019e785133747836e4fe
-device/google/contexthub aba2d911b9c29cb55fa22d95234f9c9b926b8c4d
-device/google/dragon d4f9a3abd2fa25b7b2ee3e03f85725fd043ea942
-device/google/dragon-kernel 1f072d6ed7d6507fe04c6a410ceb93fd66a8cf8a
-device/htc/flounder fcafaaa5db4e5de2fe51a54c716148b22966a476
-device/htc/flounder-kernel d63338449c34b611e91b77d7f42bc7ad277074d7
-device/huawei/angler 22010bfa78d0057549baa6b6cb5777dcf3c2e031
-device/huawei/angler-kernel c2f86ebe7a15500024908dd4f8d856d70ee8368e
-device/lge/bullhead cb1e6e6fc70a41aa517a9384ff02548357c0b41d
-device/lge/bullhead-kernel ce4d793d6ff4f6eb2c22a2c02c4607e23de6125e
-device/linaro/bootloader/OpenPlatformPkg 911a23ccd8744303788510039026b836f919262e
-device/linaro/bootloader/arm-trusted-firmware 1f3ebb070b810262b7fd0538bf5eab2ccabc83a1
-device/linaro/bootloader/edk2 0b5d535b3ac38d5a49326843d51f8e15c32345a9
-device/linaro/hikey 395b044f65745ba0c4f78a21bd8d9390c5aa9b2b
-device/linaro/hikey-kernel 894b3f69c738fc467771e97962512ea1e68e167a
-device/moto/shamu 9be41289a687b862461cf565365d1c928a9cc367
-device/moto/shamu-kernel 933b1d7d081e5e39fb522df22273c98d9037d0fc
-device/sample bfa8cf49b956bd1dd362ec2365527d1911c419bf
-kernel/tests 2fc2b448a0f4279bce164bd0a650f31796479e17
-platform/art a45aedbc88a723fb81355c0f66466ebb20e35e86
-platform/bionic 7afafce8312e97f5f1f2cf99b4641a800055066e
-platform/bootable/recovery 0bedc8e14c8872393ed1a9c3daad4091a3c90b0d
-platform/build e4fb495b09cb919b6517c2ad7b8eea09c34d555d
-platform/build/blueprint ce31b335915cd41bb46ef97b5d810ad0df107335
-platform/build/kati 7e2a7c776b73857214538760ab6aa08c6c831486
-platform/build/soong ebedf678de4a013590c29bfb97bd445c12e7b010
-platform/cts 7045b069264d6a87200160dc226c91b823ba6b6b
-platform/dalvik f4da03e8b1430abc6ce43a28231a1880c131ab29
-platform/developers/build 0161c10b89cc024688e36ac2088fb190c378ec92
+device/google/atv 325f52cd91ed26b9dc9cd05680f1edc6a2d8607c
+device/google/contexthub e23eebad199f8e8ffc8b46e101583a1465b8b74b
+device/google/dragon 2e4ff926c008c832f4512d5952babc0f7d9c1cdf
+device/google/dragon-kernel f68ad40dbfddfbad3d39c954891d09f06101249d
+device/google/marlin 1e4dfe2844f6b454c56410dd224fb0d930fdfd8c
+device/google/marlin-kernel 4f5055726f441b7b61a5ff3d2d2ddf402469c402
+device/htc/flounder 7ca178c5f32bd47629e036c64f2da1d38d943f1f
+device/htc/flounder-kernel 1edc369683182e3353e1b802272d2406ef4f40fe
+device/huawei/angler 399d260a7f424a8821d23ad19b1e84c5cd50154d
+device/huawei/angler-kernel db808069857bd03e573ce3c765dd6df43f2a4318
+device/lge/bullhead ec813b496614b990e79531f499d816930f094b80
+device/lge/bullhead-kernel 3f270065c17302930cc9319d399297436b65b3bc
+device/linaro/bootloader/OpenPlatformPkg 6f399d2f9be9ae6ccd4f7a84bc25cef503561a33
+device/linaro/bootloader/arm-trusted-firmware 36aa82dda56169333aba6b2c55341404c1d631f0
+device/linaro/bootloader/edk2 50b0c33452d080ad9faf4e57006bb09933f77850
+device/linaro/hikey 4ead46e5d541019f22a61a5d580a6709635c3314
+device/linaro/hikey-kernel bf496779afe8891e5918b20af8220853dbe4b96a
+device/moto/shamu 6d29d7ab642db429963d79eb3d9c92b327e86626
+device/moto/shamu-kernel 9ee09a9a4c803663cb0eb415d8ae1d57ba367cfb
+device/sample c3dcea6838d93c52ceeee27803ccf9af747db9c4
+kernel/tests 2fcf8feb45f03216f1db0aa8da9448b2173e3c91
+platform/art 0a384f5beb27b8ebde21af55380caf6679c124c2
+platform/bionic 8d0e0d495209f3bdc20edf0e5c2aa219b4cbe217
+platform/bootable/recovery ebb4e96a716824d54be9469b7a638ad4b15ca224
+platform/build 4a0b494eea36dc66c707e4119ab9257c8bb60667
+platform/build/blueprint bb4c2a054f2a622fd54132c02911c48c4ef6755e
+platform/build/kati dd026a6d01375d1abebc7f5b2e69912515b52cd2
+platform/build/soong 1a01e83725cabcef13941d3cc2216a32bd9ce851
+platform/compatibility/cdd 42b341aabf759bd412359aaec850dd663fcee9c5
+platform/cts f1f39473279284e99cf46951afcfd9793be458fa
+platform/dalvik 373c3f33952ff81ba33cc0dd9c68315ed8d7d16b
+platform/developers/build a28d9123ed438d787021031f7544ffca0c8d6198
 platform/developers/demos 95d49d216223e3431647abd79f5e376958353c95
-platform/developers/samples/android bcdbd6bbd52e6713a452f2bc63233e4b776a67c8
-platform/development 57c81cf7eebe5a137bd95bd263fd5c7217c462c2
-platform/docs/source.android.com 06369cce7efecbca51a227f1d0aff135fcef4383
-platform/external/Microsoft-GSL 2df00914687875d2141dc912b788b5dc6b27abde
-platform/external/aac ed91226cec35c24f4e0cc13bb46ffff98fb37f52
-platform/external/adt-infra 7030eece77332fdd2337fa546324ba0c5b0678bf
-platform/external/android-clat 2dcca6feb91fd917e26c4989af6400de904466a2
+platform/developers/samples/android 24ca2a29037539b7d172080f279664de51df59e2
+platform/development 3646941fc6fa6c781ccc75f763ec049d92d0d3f1
+platform/docs/source.android.com b1e53e0ac3105632164336d6ee69407e2a5c0916
+platform/external/ImageMagick 47d4c9ba5a1931517fa4291e11ae40413997c08e
+platform/external/Microsoft-GSL 5fb579c6c12964ada094e524d17ca2c6d33b04cf
+platform/external/aac 664e5f27946c3949e2f0aa87f48efe6bbce101c1
+platform/external/abi-compliance-checker 6d77d98462f6a6409535a321b105d2e631b95cb9
+platform/external/abi-dumper 75f8ae84ecb8f713b56e35863eada16c6d6606a2
+platform/external/adt-infra d0831349d144c9a947ddeced72b07f94850f595b
+platform/external/android-clat c2f9edd16daf2752bbec4949f513df2e42fdc5c3
 platform/external/androidplot c66727ebf001607cee14521c35bc852b55fd9845
 platform/external/ant-glob a73228afa9540b9c5518d360c5ae630bb634f975
 platform/external/antlr dd5fa6d48b827c5d98b625adbc209f4a05567534
 platform/external/apache-commons-math 18f62fca59d387e3c1ccd8f80087d9c9af40bcc8
-platform/external/apache-harmony 5dfcde90a5aa33894ca65854492bed4b538478ad
-platform/external/apache-http 949206634ed87a0daebf1fcb153f74b3b77e21b6
+platform/external/apache-harmony a9de4c770834049dc96d52867511458dc57bfd35
+platform/external/apache-http 18e4eccff3babfffafc79b949482bc10e749731e
 platform/external/apache-xml 31d7642eb8f37a9166db7f1c9e313ab651bdb8ba
-platform/external/archive-patcher 81918d517897eb07da8eacbd03c57190c6d5edda
-platform/external/autotest 9b642c675f615550c175ec172844ddafc9bec952
-platform/external/avahi c1058119e50353b4f95375a6ec032f90452ec38b
-platform/external/avb baf59e232e48d0111e4b38f74c60c89e6f8f0b14
+platform/external/archive-patcher 5a1c799c43d3c17f95cfe173752a231be2049e16
+platform/external/autotest 6652fe805046155fc6eaaf2a560197ae29e1a0aa
+platform/external/avahi fb25b155142ece7085538b3885be157d9324ceea
+platform/external/avb 57ac06e6e4fae29eb616613eb2e2623d79230290
 platform/external/bison 7467d52af437dd3dfea237a6865ab84bf258dee0
 platform/external/blktrace d345431f16b8f76f30a58193ff2b26d5853e1109
-platform/external/boringssl 95add82835138f09cf7bb4a51c04c6320c241674
-platform/external/bouncycastle f369a5f0c5d077a5b946d7b39149cee4225d6f84
-platform/external/bsdiff f26b5b670aadde708d3279d1eb153d28b226304c
-platform/external/bzip2 b0e77c4d65ab8dc9607b27cf5b36c38c83e85ada
-platform/external/c-ares f4baf84f285bfbdebb89b2fef8a955720f00c677
-platform/external/caliper a67e4782f7f5bc2d7b3f9de6836fc333ef0e1bd1
+platform/external/boringssl 69939df2891f62f7f00ff2ac275f1cd81a67454c
+platform/external/bouncycastle fba1a1dba277746d3be0667de9eb4b98494a1963
+platform/external/bsdiff d355a6343e3e8739413af2724dac8c9a2aa6ddf1
+platform/external/bzip2 2cb42e2caf08d109428a5a9c642eb7868734f5ad
+platform/external/c-ares 6ec5e7a803bdc5b59cb8eaf2717a241183bb996a
+platform/external/caliper 9809f45fa7f8f0fbff56c898ea253cc8f8fde2b8
 platform/external/cblas 53ffe068d9bf5f9b0507a659159dab7bd9c18a49
 platform/external/ceres-solver 233e18458eeb29bf5e4f2b69c5334728c47a6d13
-platform/external/chromium-libpac bb0e12b4e09130018916c6d5ffc3e0344cb6a17b
-platform/external/chromium-trace cd89f5ab72f61143619000946d1b2d8e2fb6a2d1
-platform/external/chromium-webview 7895f9be6b7af84d455af423bf60f3210fbb6b68
-platform/external/clang b167d69629a571ef313688c02dfd0d7ddace8eb4
+platform/external/chromium-libpac 0f76016a30684c158b6ab4867575054a2b7cb638
+platform/external/chromium-trace 0261a8b2beb21733fe958366e6f98cd0bde98a35
+platform/external/chromium-webview 581a777a866d78be6cb4192e46891e418930fc1b
+platform/external/clang 4a477d5f9d606964f1621ac24f7bd1d31f3f90e9
 platform/external/cmockery 9199c7bfafefea32d1884182fa655b6e4578c1c4
-platform/external/compiler-rt a1b6d6325763d05aaf42df7c615f55afc66d9e11
-platform/external/conscrypt a2b717c07418092dc178e1ffb6dcf8f08075d6cc
+platform/external/compiler-rt efe317fe688734ca6566f936ba00a92c9670bbaf
+platform/external/conscrypt fa40b857d171889480260eb595dcbcc6f766b209
 platform/external/crcalc 5559610bea3b267abef3273868f2d6b8c01409a5
-platform/external/cros/system_api 3134975bb960b2f844722e5f844025a23914e46e
-platform/external/curl 044d80e37a7ae71b229ba810fcb4bfd701d88ac4
-platform/external/dagger2 d65ad205f96455938a93529874ba2ee8d7063d3f
-platform/external/dbus d655f577be207c2a1b39406fdc6d4dd1b3c9c5d5
-platform/external/dbus-binding-generator 8ed8a72c162b82527b2124cfae0b5ecf9c9b6289
-platform/external/deqp ac5e3c7c2d8c4eefcd6099a6311a9a11fe2f7695
-platform/external/dexmaker 7a2d6365f327afe4e7210d6f09faa02f19353dae
-platform/external/dhcpcd-6.8.2 b74b4ad38fa162d3fe09e035fa570f419261c7dd
+platform/external/cros/system_api 9ef6fb2e9742050f18c4e08d6e13876d240b23e1
+platform/external/curl a059b92453c5640e1bcd76871f59b584f51bd574
+platform/external/dagger2 f9755a72c1185f83b822a27845a25644a2d9e641
+platform/external/dbus 7aa25cd2ce4d3aac177c1c7401b96d42e30dd8c1
+platform/external/dbus-binding-generator 619b9bdeb82131e8ce2e5e98f982e1d08515f5a9
+platform/external/deqp 0cfa22d49dc615b597d40421e92343fe7575681a
+platform/external/dexmaker db55101b385b9f5289697896df3f374620300b4a
+platform/external/dhcpcd-6.8.2 df64c96f01b3dd2a823d6aa788653c3bedd1efda
 platform/external/dlmalloc 6661f3ca66b55d8f5a57b96fec97efaf8f3897a5
-platform/external/dng_sdk c44c039ac1ffcb07e523c184733c1f11af0c296d
-platform/external/dnsmasq cf2fce4acdf00d9a703c04d01b73bc332bcc61a7
-platform/external/doclava 589d63dec2883e5ccae2fb07fdce41b0e3c2113c
+platform/external/dng_sdk d9529e59d0d8fc97aef642b9d56e366bda884471
+platform/external/dnsmasq 3293d082ff5208a54963264cc34e3065279c11ca
+platform/external/doclava d9d318f067e5a6075071f39e6a225b5e2ea2de91
 platform/external/donuts 005389fb31a67841b5de42f0d25fbfab843e208c
-platform/external/drm_gralloc 63dd4c897693a614f9eedff817116f34590514ad
-platform/external/drm_hwcomposer ff522c77d52cc8324ba0a505706fe5f1c5d30178
-platform/external/droiddriver 4138eed6f44e06a72c6adcad1892008eb4b701e8
-platform/external/dtc fe315a53517fd5792735428f0da232041a8cdce3
-platform/external/e2fsprogs 058a64acf530f379a1ee91e43f58d1c042946251
+platform/external/drm_gralloc e19443ea00d3b27622590b920819e53da68f7fda
+platform/external/drm_hwcomposer 5ad151f3ca7822559559dd5afa57c3bccfbc2648
+platform/external/droiddriver ea213ab0d2fecd61670c63e81c07428c49fbb003
+platform/external/dtc 8c4fe4f3f37bcfdba479b9ad894179a702c9054a
+platform/external/e2fsprogs 22aabbe13b95045a889a2700cc170d121a8ccb12
 platform/external/easymock 8bc2748f2850c88ab6b86c6ceed1ce65bed5ee16
 platform/external/eclipse-basebuilder 076f46888ed346775b8efc564d7694063ef5eea7
 platform/external/eclipse-windowbuilder c533332008088ee5f61745b724361fbde5b7e770
-platform/external/eigen 110f39b2599856ffe6c7781b221b93d00b89d2b4
-platform/external/elfutils 7ece9f0c0f62d36142e25641438e0a859f951308
+platform/external/eigen 5f451c9f14717dd83e05ff10da5e86da618472c7
+platform/external/elfutils 2ed2550b8595fde721dbc6a12091609a598192af
 platform/external/emma deb5711b2635ee9d332605e2e00b63b32bed6777
 platform/external/esd 943c42b6f8e9afe821744aa4c039f4943ebf29f5
-platform/external/expat 12bddbf2b12be35a77daba2a35a4671f84a5c230
+platform/external/expat b05dbe320cc7cecb104c1b7ae38a57d5f3cecc89
 platform/external/eyes-free 16bd4c7a4d1bfe229068b637614dad7c48dd2ceb
-platform/external/f2fs-tools 5bd943d50d103eb6f48a72f199a49dce4feeb61a
+platform/external/f2fs-tools b54dc047e6712368a3eb1213e0b902e353cdc1ae
 platform/external/fdlibm fcd17254a9e59ceb0420d4a2faf29db6b004c443
-platform/external/fec 791afbe58ff9f55145c4adf632ab8cc9ca6e5686
-platform/external/fio b4e247271a45f3e363c2f9afe2977038cc521f78
-platform/external/flac 3c74c11c30cdae95914c0b6a9228a3906b238c73
+platform/external/fec 50cccace66578aa91a824423109b85584a771c26
+platform/external/fio a50924a0d1c098a9503f8b7fd9550801ca45704f
+platform/external/flac c690cad78f2e3d6791c28d305b234570fab7b209
+platform/external/fmtlib 1ce26af6d14810a277a5f62a5619a372b93183cc
 platform/external/fonttools fede58680958e96e6e8f61c3cc6282f798452c53
-platform/external/freetype a66c1d9aa97d87ec047c861201e7f1d6e4bc5ba7
-platform/external/fsck_msdos e5a5c8b9e97ff69a68266e79cca1614802833142
-platform/external/gemmlowp 6de57912630404dc2e210a392878c6d7cf51f1cd
-platform/external/giflib a57aff106d30e39c782e681f8e4aa3aa612f81c3
+platform/external/freetype e513b13b62c280604dc31a5162e0f7385f0f0ae7
+platform/external/fsck_msdos 9d1e7e4558c8b53731ba1d06d33b5516934d1ff7
+platform/external/gemmlowp f531bbe993077ff21201bb795ad809b59056dc7d
+platform/external/giflib 2692afec5d000544f60a14aebbb2e5ad8ee90b8c
 platform/external/glide 31e64acd1e65045471124267a06241eff1f55d26
-platform/external/google-benchmark ac64db9550713bd81fd50fc8d289ffa8a9c1270c
+platform/external/google-benchmark e2b9dee957ad1b437309747d269d7431491b48d3
 platform/external/google-breakpad 19324245f86f3532ca9f90f62f5b84fcdbb6ecbf
 platform/external/google-fonts/carrois-gothic-sc 0062a10458d4c357f3082d66bcb129d11913aaae
 platform/external/google-fonts/coming-soon 2c5cb418c690815545bbb0316eae5fd33b9fc859
 platform/external/google-fonts/cutive-mono bce2136662854076023066602526ba299e6556b2
 platform/external/google-fonts/dancing-script 7b6623bd54cee3e48ae8a4f477f616366643cc78
 platform/external/google-tv-pairing-protocol 9726a938070e2f281219ef3187f54ef758e6a075
-platform/external/googletest 766bcc63f841044e0ab1bd4fde35fd6226ff5b42
-platform/external/gptfdisk 2c054ab90ed2324602410bb505151a4677a7ef00
-platform/external/guava 0839ba9a609002a4b29290a55caa125e363e629e
-platform/external/guice dd02cae677404f96e0359e51d0a77ac91174a057
-platform/external/hamcrest a80259979f535e973382fa9a41bc2fda0a4553b7
-platform/external/harfbuzz_ng e7490844b4f60a593c385dd6777047eb8b67ec01
+platform/external/googletest 90bc60c06ca961116d13a0e07bf945067b61c011
+platform/external/gptfdisk 7424963b5b0ff668ccfa6d692a4b0d7e2896078a
+platform/external/guava da6dc2f68ad8b8e94d666d87b30b1ddda0c4f43c
+platform/external/guice b6e6f3ada89e108db7244c99a74cdd048d20dd01
+platform/external/hamcrest f1015b50e715aefc3070d83d95340cbc29811329
+platform/external/harfbuzz_ng 7be7f017f265081e78892428b162f3ece8e29c96
 platform/external/hyphenation-patterns dedeff64279b77bafff72b6d866efc93e829b4ab
-platform/external/icu bca042f28d616624108ecd9eebe97feda8504f79
-platform/external/iproute2 474d82b0625cfed5c30f670444d7e6aea780450c
-platform/external/ipsec-tools d43551bcaaba3e00f20a061a43a8a3f28329bf97
-platform/external/iptables 8f090169d006a77dcf0a3eef8bda24fb20c32bb6
-platform/external/iputils 15812b1548d303f2d20b3326dd0b1b4f3d0da703
-platform/external/iw 2750da337290a5407e3ee123cc664d4e5cc1820c
-platform/external/jacoco 36e54806edd3b7cce9c86ec8c93fdda2a96d60f4
-platform/external/jarjar 730d9b71d5d139d9fea676d9073dbfa1b71b61ab
+platform/external/icu 22b47ef9ddf9e6a0c70a0fc411918f0ff5ba4f2d
+platform/external/ims 4896eaa6630871b2734b2df1d6301a467536f3e6
+platform/external/iproute2 b072143d789b67c8674b203e667c7343253c1905
+platform/external/ipsec-tools 34538ca0990a369f223bdb00b82a75999e758940
+platform/external/iptables 12846fada94a801302584f944345151a492564f3
+platform/external/iputils 8abbff8308e629bf0f5f5f1bf48052b4b484d0e7
+platform/external/iw 480621336eeac5ac52ad148adf16f1c227296542
+platform/external/jacoco b6ba640a0641e967cdeed76d699bbbd13e310b61
+platform/external/jarjar f828c91d30f743f1d7d0bd5b86fed2f04fd069f2
 platform/external/javasqlite ee41d81872eedc632f42bd231b95bc945690d159
 platform/external/javassist f7c4b954072e563b75f6910c25bb689bbf38a3d1
-platform/external/jcommander 502ef60ae8299347b337c19ad9e831bb856d8c59
-platform/external/jdiff 98ed536fd800bf9ac02a9983da6dc08356a64fa3
-platform/external/jemalloc fb1f094f163a3bf15d8958ba845e83559c0e6dfe
-platform/external/jetty 7354b4f34e693165f4f49d154fe58844bf5d4706
+platform/external/jcommander 2226d7ee4919702d4825bd359ff2be6cb9c7b78b
+platform/external/jdiff 62f4ca1f64eaeb0896416949d6120b912ac67d3b
+platform/external/jemalloc 5a22dd0d39b5f0d1d3f8fe9b27cce100753d24f3
+platform/external/jetty b209239f5a3a8b59418154d8fd1aba9ec4d00ac5
 platform/external/jline 74812032f8d8eddbef387f18c96de9e5c38b8fdb
 platform/external/jmdns 0c71647deb7f7835c473fd3dfb45943083e47794
 platform/external/jsilver b9b84920ba47ddf7f15baa01c56b28e3d3f951ea
 platform/external/jsmn cbfa1a02b28b588e16ec221519c6ec17b1c14568
 platform/external/jsoncpp 90c81b9c9aef09ef4ffb8de1779301734336d897
 platform/external/jsr305 8cb769f8fa9347c83c30c896c8d9084bd6bac756
-platform/external/jsr330 ded32186511387be56e353485f476262d6b14c66
-platform/external/junit 2e7552431cce028d5c9eba8e8cd5b2e4709215aa
-platform/external/junit-params 630c32b92bf3cc6179c211290016089d40319119
-platform/external/kernel-headers 64c647a785e762c65423322410c0c1b79b33e62b
-platform/external/ksoap2 a3e5f27c89b4a64333d6dfb9b9588a1bb1537956
-platform/external/libavc 4b6344b28159ddec7e9eb3de074d5e3affff178a
-platform/external/libbrillo d26b2a3274c08d59b47c87b0418f9df675a8a023
-platform/external/libcap 02403a9504f6bb586c9894d48cef90bd2c9ff8b7
+platform/external/jsr330 997bbb52aa0a62bb41debe7cd715935795f02861
+platform/external/junit 7cfdf040fde78b5bcbe23223f6e3501beddf671d
+platform/external/junit-params ea07fbcef796fdacd3110b41eec7a6c6e55044fc
+platform/external/kernel-headers a3a54a2fc66f6e0c909f5bcd2748887f207a44e7
+platform/external/ksoap2 3f3695df2e974811a5759d43f3532dcd9d6be26c
+platform/external/libavc 41c0f84e92f681e3258a74e20a0278f4a84f12fd
+platform/external/libbrillo b167bbb724bdac160bf94e86f2a9a2167ad51e84
+platform/external/libcap 8a1b764aa06ab354ce1bda55668245a9a269a047
 platform/external/libcap-ng 835f318b9785a70415980fba96c34ee5c6b7e415
-platform/external/libchrome 7f89d64f891855e5a7fb4a52390dd3b463001a49
+platform/external/libchrome eac11262baf5303adce63f392b90472eccda7364
 platform/external/libconstrainedcrypto fca75c837bebfbd51927156158de36fc517742f7
-platform/external/libcxx be9a8c06625a4ad4b2d870cd780776e49d7d3cba
-platform/external/libcxxabi 6c5f2a5a2e44b84e547396fda693eebbf273271d
+platform/external/libcups fe987091f83f0fbaef958c91e87d7f363bad3c67
+platform/external/libcxx 9dbdfe58421f46ce919432093f7a417cec7fba2e
+platform/external/libcxxabi 67e4d55dd44cfde34898ee254e0dc7a13174b6b7
 platform/external/libdaemon e2f604066d97431c95856c73d7b9ee46b348d37e
 platform/external/libdivsufsort 90d90b27c0b82cac20deabac79e97e274856eaf8
-platform/external/libdrm ce429d08fb5d8eb20c9029746f018de9a508c065
+platform/external/libdrm 20208455f21cce2398f91fbb7768614090617f3e
 platform/external/libedit 67e14dfc833aafa400a3aad8cb329cbaec503445
-platform/external/libevent e6958d7c60a5a49b863271dee0aadae5afbbe924
-platform/external/libexif 83884670140be8558eb330b6e68142b56ee46c42
+platform/external/libevent 2730e7ae9dd016066b73989cc45910c23fde0498
+platform/external/libexif c668765a842fba2cf497479bca9c7f014076b37e
+platform/external/libgdx ec8650f5cbccff4111f1d593b5e366de387fd179
 platform/external/libgsm 2f66c771f18317147e446fab5a95082d18a6db20
-platform/external/libhevc a87cdb37caa4ccb3cd42ca6b9f0f8d17e9e99f82
-platform/external/libjpeg-turbo 1b0f60e77f2d691fe4a12620f12efde8a22f8341
+platform/external/libhevc b53595c130362e160705db4331ff1aad78c158a3
+platform/external/libjpeg-turbo 0ce519cbf5448782cbe859c4dcf4606b0218ef51
+platform/external/libldac 9a3015d3e35fa054efbad6c925e712444a3cd07b
 platform/external/liblzf a88b9629447deabe8697d2f8fd4cc70aa6e1b563
 platform/external/libmicrohttpd 1e68f5d827a859ba3b7ab6a70a60247e0b96afa5
-platform/external/libmojo 3d72bec9be57b7d199d2cbd7139308bb3c3c34bb
-platform/external/libmpeg2 b06addc8413286624d02e976b4ff6af5a41b9bee
+platform/external/libmojo 7748449784c8c0c4e88a646166e7a8f0292faeeb
+platform/external/libmpeg2 a087d3f3943e65e457096454d38a98ec811c84a6
 platform/external/libmtp 7ed2065db3ab9851f47426f3a35ba7045ce528b2
-platform/external/libnfc-nci 84fd1332d839befa97d9e9d6675c8c2cecc01285
-platform/external/libnl 3f563dcf99d53a43799e5bd75d7761fcd9716c5a
+platform/external/libnl 821e05033ee1c7c8f0ced18831e02259c4c09b44
 platform/external/libogg 6dba790f3372d03eee07c693789166ca9fa07b0a
-platform/external/libopus e86ddedf1d6703aeac7c40e2f92aa7d365d62838
-platform/external/libpcap 7972587a89ed3966f8685d7f44c3f3674daf0115
-platform/external/libphonenumber 78b57ad8097f172cc084be1b15ee6d2fe446c79c
-platform/external/libpng 0bbba1b52549fa827225b37f465555281ae6c06e
-platform/external/libunwind e1069f1eb15a71dcb9d793951dbb5ce0ef97442f
-platform/external/libunwind_llvm 5dedb3c1c266802f328be58720adf736bfa38762
-platform/external/libusb c830898c125945feec317da1a0b359afeca766c9
+platform/external/libopus e65278181df6dea0ac1dde71f2534d66816119d2
+platform/external/libpcap b7728adcc38c22c009014dacc64a871d2505c85e
+platform/external/libphonenumber 17f4fb05d4103f3ea554a0285b451b288afb939f
+platform/external/libpng ad4a6db68e88059a3e6b9a27065ba7795c68159d
+platform/external/libunwind de858ed3a4d47e1b8b774ed7d99c992c479d0f56
+platform/external/libunwind_llvm a11710620089fbf1004d526abba03819811fae19
+platform/external/libusb beeecbd623dd31db0051aa4dcfb3a4734a0b538b
 platform/external/libusb-compat 759481ae400d02fe99488dcdcd653b4f8139a39c
 platform/external/libutf 853ef375ba2ce430f5b13b556812b2d83ccc82e1
-platform/external/libvncserver bec50fdbf6ec2d61edda4f69913f8a8331b8b364
+platform/external/libvncserver deffae772eaa131111d1c6fe755bb1b18d1847c8
 platform/external/libvorbis dee2e0a12822ec62c89c2d7582f1a7d32cd0875b
-platform/external/libvpx 8a88e03ea00afe1c5cb223e1036ad2cb04c3d132
+platform/external/libvpx 51be1d937c1c806fda801b4c0b36bf2479b91ece
 platform/external/libvterm 6d78f36633063dad0689ca42be1ad8d0313ebfab
-platform/external/libweave d4eabd105d038610c2722f8e6bdff5f5428265c0
-platform/external/libxml2 1b93209e5c65584a80238f52c9e87f57a48a9a59
-platform/external/libyuv bb74e3e19b98261031216de8cadcef34cccd9e4a
+platform/external/libweave c1e1a97bd58d7409e9125d2611342c23aa762666
+platform/external/libxml2 565542d1632ef64ca6fa615529d4745b2e293751
+platform/external/libyuv 9caf0f58f0fc10b99021e9b29ab3e6ba915be45c
+platform/external/linux-kselftest 5cd50f8f553da5a02f9618d04e9b88c6757fb39b
 platform/external/littlemock a3ea6bf9e6fcf63b69f5635b2ecc1fbd9a9a4dfc
 platform/external/lld 26c9bb3b51a7ac4bc45f73d532a03cfd9982043a
-platform/external/llvm 83d37657af4dcd64af0eae6d63ee476654b8a2c2
-platform/external/lz4 32b7e86f6814e15b3aaf0b870142ab6c819da27c
-platform/external/lzma 17dda56f12d674e22266c2aadfcce1c945b2bb2b
+platform/external/llvm 7623033614ff84ea32d22b000ba8b6b1956b1bda
+platform/external/ltp c853e4163853c2f6d94b8ff951e7ff5ee22affac
+platform/external/lz4 f95fb50f7d243a5095879e41da241b26cab46740
+platform/external/lzma b04e8dba446aed0b1b1d1e58945fb9966b4e85eb
 platform/external/markdown 06a8f8b914d477183f68b84424bce8ff4dae7e84
-platform/external/mdnsresponder 55aee11ccdc0ea5ed62ef68a352c3aca112ea01c
+platform/external/mdnsresponder 36db250fcc1cca4ca58516e6d203b820fdd27757
 platform/external/mesa3d 586cfa78861e71160d5a3dbeaff09554829a1027
-platform/external/messageformat ff217fd086ecac137321c1265d0cc1a15194decf
-platform/external/minijail e9740afce623e99ac1abdd01b90446adc423f7d2
-platform/external/mksh cd79a34d28dc40ea887af65aec71e35b74696afd
+platform/external/messageformat 8ea811b59b2ff272dda87793bf78e4cf114e3e25
+platform/external/minijail 0dce7573d8038618505b718308c359c4ed6fabcf
+platform/external/mksh ad7a062c128f3b9c261b77a44206740a56b3b869
 platform/external/mmc-utils 6de31b2b8a09108f9b91bc12bee2b792f783dc62
-platform/external/mockftpserver 56527f4f9cf6e19136c55e8e6f18fd56da628d86
-platform/external/mockito c76860ffac1484ff29dc8966e8a7751ba5c20700
-platform/external/mockwebserver aa66709b3b05ec77c477a68d30d677b4da78d33f
-platform/external/modp_b64 ca8a085abe944c279055910b4d97d0517c759a1d
+platform/external/mockftpserver 5bebd8e5972a3a6bcdb25befd707231d815cbb54
+platform/external/mockito 0c750739024d247cdb9f6e32cf267f818b3f2476
+platform/external/mockwebserver d680f43b995aae01123ee6bc7adb690dafcc47fe
+platform/external/modp_b64 7d25406b602f3c7906ec3faf69a5e5a087c1b671
 platform/external/mp4parser 88bd0c6cfa7fcfbbebcc15c2c565f714cb36b065
-platform/external/mtpd 46998029d80d5e486940c3c6b641569229349641
+platform/external/mtpd 66c4c5b6b715f325a3f262f96148cbe2594aaed1
 platform/external/nanohttpd c6783c32331b3fe78ffd5077e7f180995d0e268e
 platform/external/nanopb-c b225eb267957f24ca2aa2469bc78d418b2e9b795
 platform/external/naver-fonts 91e6e9f94d1d769a8f742649674149ba98ce7d45
 platform/external/netcat b023a43765b15f0b0fd5b52b7d8021f515c59c23
 platform/external/netperf e100a0c4105b94f7044b243287a5da22f5e8e4e7
 platform/external/neven 95e6c4663c640c67a69e1d2b44696753282136f8
-platform/external/nfacct 833985690db54f9ad3ee7e8f3147a67da8c04760
-platform/external/nist-pkits 89fb1b9fdc7f5c48d4983fad62af62c1b780e428
+platform/external/nfacct 68446ae9428dd8e851d796ef30dcc07fb5d184a4
+platform/external/nist-pkits 2b483ecb8b49fbcb797a910224f546ca2fceb916
 platform/external/nist-sip 8445067c3b53e5bd56c32f1c4fb688083c4f4005
-platform/external/noto-fonts f57026f635e85b868c88931bf0e233756bdd7e3f
+platform/external/noto-fonts 60e126f1c096b20d4a3685e1de1147b6595e9012
 platform/external/oauth 49f3624a6d3307b640a012f15b94d04174473501
 platform/external/objenesis 027386d6375a3cb34d9934fd952039254831cbc6
-platform/external/okhttp 7cf56bd49b8d529696b080a1ca6b69ae635b8233
-platform/external/opencv 35dcc67558b63d08c47cd4bb3f989d7a9b77b884
-platform/external/opencv3 0f2a8a9b749849ebda41581b14df8fc6b55df859
+platform/external/okhttp 0663ccec7ffe3cf4c6d7e9beb40ba11af96f3152
+platform/external/opencv 8514df949232a5a8ba4717c8e838c345f819e587
+platform/external/opencv3 a2c73eca5b86d09b4008912f05d6d8e5ae4c488b
 platform/external/owasp/sanitizer bbfb25464ff30c5a62dce351d719a8c533afb2a3
-platform/external/parameter-framework 18cf6a72ebdbc22e47061bc151f9cf0b4024e013
-platform/external/pcre 0b62c4871d43f3602585d34decfc044a836283a6
-platform/external/pdfium 1d14fc6f33e7adb95c7a10003ba5d52846bad4f7
-platform/external/piex ea77571906ff32777967f7ab1c465ae2f3006caa
+platform/external/parameter-framework 0363d80864fa66e86a693272e08ad73d4fe321b3
+platform/external/pcre 6165bed5292cedb181c15ecd4c2cfaad86e58f2d
+platform/external/pdfium f57868c6960961ef477924bd1e872fd63688cd9e
+platform/external/piex 494cbf09785c29685c3f03931a7dd61456eef21a
 platform/external/ppp d9aeba443abce801cd696b3921a559cab88e1e74
 platform/external/proguard af893cdc1242e4cfbeeb10e2323f9a689a825177
-platform/external/protobuf 7d33a02d1558092751915062611de4b29b998a67
+platform/external/protobuf 26c830a601a4be274c27401f2656b4faa0316b92
 platform/external/regex-re2 79cce43a82abc1bc56c65de07a7df47d54e163a9
 platform/external/replicaisland 374426a588bfffc7d0657bffe05b65660b438007
 platform/external/rmi4utils 40eb2d785d3e367c01fc2a3d53820550e7f66739
-platform/external/robolectric f522a207e60af3e8cf895e681fb25278219dc11c
+platform/external/robolectric 021427812fbd09a64f819b5f8e81f06df2fa99ee
 platform/external/roboto-fonts 25fa2dde3aacaeacb2797bcffddce96014f4fcc3
-platform/external/rootdev cd960ab4e9bcd9b6be3cd531eb63e9e73edfe438
+platform/external/rootdev 1fe2b737ad19056bc2bc298b7c30ac93d36a4f6b
 platform/external/safe-iop cd76f998688d145235de78ecd5b340d0eac9239d
-platform/external/scrypt b442b13773a8b79a99a03af14af0e8dc1de85cba
-platform/external/seccomp-tests 3efdf98e3541de21d79fa6347bb2796c5e1363b5
-platform/external/selinux d220a3f399c8acd54857ec3ae137c8ad5ed0b32e
-platform/external/sfntly 61657b2d87b88576ab1b7d7fb5768b0e315c9216
+platform/external/scrypt 99611dfb9ac7513ab39f569744439ee6c7568eba
+platform/external/seccomp-tests 609352cc3a45ead8b6f9d85b39c7ab9c998c7caa
+platform/external/selinux b72c7cfda2e0cd45372cf70cbde0a396829382de
+platform/external/sfntly c4ab35d99cee949d32b4225c6a6a4a5851ceb2c7
 platform/external/shflags c4876e01829b8cf110ee33267bb1bad1f8ebb51d
-platform/external/skia 9bbadff63736989ebedfe805caf0bf31ed38c190
-platform/external/sl4a a1a435ce68fa64439649a6d9170847b373ec5632
-platform/external/slf4j 037a293cd09178f946d5df43e8dff1ad8758c163
-platform/external/smali cb5c5daefce2792ce8641d01eb8bfb7f0b02bd10
-platform/external/snakeyaml 40acbd1fe67b448e47f7e50208f306d9a3a7c4b5
+platform/external/skia 1e3a5887f573ad61a1581532ad41d088e615712d
+platform/external/sl4a fdaf1d4918885afab72f0399cf12756cb6ee7dfa
+platform/external/slf4j c396492264f26581652c878b18766880ec7c6f86
+platform/external/smali 5db2e2633acadd2aae167693a79af88f8cef6245
+platform/external/snakeyaml c7cd0f38aabc2ac85f82ea9db28ee5cdaf8953d1
 platform/external/sonic 0227d834966b304525869d88fd20b2ac835df878
-platform/external/sonivox 070e31de1ec6964cbd78215ef97e5dec9395a380
-platform/external/speex 1752ac1e55a894f2c372b544cb4843ce9605e906
-platform/external/spirv-llvm 90178d28d62d61af255809d52b063663c37bb9fb
-platform/external/sqlite 572c81a44448b94f68cfd28f6a64a9b597c40314
-platform/external/squashfs-tools a16d3bd985d76f2358e09689d808377c528f2b20
+platform/external/sonivox ea5080a2a6db6bfb050aa27465b0a9bbe41059d2
+platform/external/speex c704149eb9fd927da7b82520f69a8545e4f7604a
+platform/external/spirv-llvm e43b16aba2a1b5323b9e40cd93aa0d904cd76247
+platform/external/sqlite 1a7b17477809c6d786c2e1a4a9fa9ceff7dc5384
+platform/external/squashfs-tools 4445cd175ee8ed20fdec0537a76a6e3cb65fdb53
 platform/external/srtp ab8d27c7566de29e3a0af3f2324036e8d5646d76
-platform/external/strace ecaf114d8d7a670aa52e91acbfa43837a57e3558
-platform/external/svox 2dd8f16e4436520b93e93aa72b92acad92c0127d
+platform/external/strace ee18e8ae76b0828006d07262ed6085dca9fd08c1
+platform/external/svox bf6d92d8d874241dfb482e19d2944ad6b9a226b6
 platform/external/tagsoup 9c02d9f506855965ec513685788890dfc856a5bc
-platform/external/tcpdump 8d9e2b3066ed0100523efb4c656f456759006b51
-platform/external/testng aa60862b5f2758a7d2f80f1ca224b310de1d674d
+platform/external/tcpdump cfa7e505ada2860d5d693da0a2f7278779159c48
+platform/external/testng 1f7c52f3ddcd692736f0e4d15a6a3d50a343a705
 platform/external/timezonepicker-support 99e91a76fd74bad10266623d67cdb98d011f709e
-platform/external/tinyalsa 4e3bf637057e8de60e6d0243c35a9fef698f9e2c
+platform/external/tinyalsa fa451c6714e6a1ca1bd5fb6f9a111bfae1e30da5
 platform/external/tinycompress 379571405632a407b8ad0e4cea6a3ec86e5703c1
 platform/external/tinyxml b162e864bd02bb79423b4ef01d0e5e5840aa416b
-platform/external/tinyxml2 c04f69a047fb68e4041a47bf2ae760c047c0baf0
-platform/external/tlsdate 5a3de7f1137f650c5b4da38fcf3da3a00be905d2
-platform/external/toybox 4be718d62ee544f58f1eb7da188a08b610e14c53
-platform/external/tpm2 c5912a41a95c992137228de2466d616080a5f61d
-platform/external/tremolo 23ee6597a66a0963e2c69238138a286f8aaf0885
-platform/external/unicode 92ae6009367b0affedfcb364aa21074ed909127e
-platform/external/v8 8f88a037d1053f646dbef380367f542e6b9eb26b
-platform/external/valgrind 3a6eb653edc92b4717d19178f8f98b194eba173f
-platform/external/vboot_reference 495cf5a9f329f9bdf501579c9a992edffbd883be
-platform/external/vixl 3f4fb67ee6479e65b4e0ad1a6a52782c4ac7f2d6
-platform/external/vogar de2f250e56abb8b08cea424235a308d59115d6cb
-platform/external/vulkan-validation-layers 9a4ddc16e893b24b7e48adbff2a2de57d6e73641
-platform/external/webp 9952695a9090668326a9bcbd4e44928525d6d49b
-platform/external/webrtc b33ba455c4b07b719bf1982ad3e2121709be1c62
-platform/external/wpa_supplicant_8 fa94a1c1e378c11e333ccbe9fb234f561afea4d1
+platform/external/tinyxml2 d4fce1e7d6efcc1bc08de94c7b2f04cfa69495eb
+platform/external/tlsdate 58e367fd6501efc2f11adb0b44f1c7cde9b39c2a
+platform/external/toybox 7a49753b15c998ec82851a7a7f4eb4d9ac67c7d8
+platform/external/tpm2 6ece5a16ed875a5d8d5cb500844d43cae3c1413f
+platform/external/tremolo 1e811d2d499a50dc059c150ca165f574c081c133
+platform/external/unicode 680f240bda39c798480bef3bb36c671af1f575c1
+platform/external/universal-tween-engine ed9d1ca52d022cc2cc54ebc272a74007cf9d577e
+platform/external/v8 a7e90cde16bf95fddae4a5156268e449da86ee36
+platform/external/valgrind 53e80a71928f927b2fa3754b79d55b45864be232
+platform/external/vboot_reference 9f24f3b68307434532a9a4110e40c7eeef4110c3
+platform/external/vixl f822f577a8ced80b1a608e74dc7ad6cff2534e50
+platform/external/vogar 4597c20eccffeefc2cedfe3ca252ad8688d9de72
+platform/external/vulkan-validation-layers ea04d8a697116044ba085f678ec98438883bfc7c
+platform/external/webp ebb26ed7b48af18bd749383168c07e174636a6e7
+platform/external/webrtc 3f1ab425f5c22acf044c61ee209a209de4043537
+platform/external/wpa_supplicant_8 ac98a85716b91fa3b871fa79af4226c2e0ef5473
 platform/external/xmlrpcpp 1d7192fe0d2f788f8f150899c58b86c5ff10456a
 platform/external/xmlwriter e95d92246ee35273dde2bee8b00485cc14c12be5
 platform/external/xmp_toolkit 42ea4dc6d1fc2206a7778029070ed9213e3b0fbf
-platform/external/zlib ece4b39a7a3a4a32927df37e0b80f68f51613a5d
-platform/external/zopfli c01121c52279a02f503bec3275ffb61fd837b555
+platform/external/zlib 540b6fc70bf46713661ee59ce0e66b17d66f2922
+platform/external/zopfli b36f966df9e7767a6b0aeb00fea29af0c57c89be
 platform/external/zxing fedf8f2d8099bf7bb85dc3db8699343d56617deb
-platform/frameworks/av caea9fc26a654c6b856d6e3f4458b52c5d14365f
-platform/frameworks/base 3b379ee94e049bedaddb504136b9fb3d5113cab6
-platform/frameworks/compile/libbcc 50efe38a6c5d84374583c8afcf272d15c131413a
-platform/frameworks/compile/mclinker fa083b9e91969ed6f15fac2fffb619c9e82746b1
-platform/frameworks/compile/slang 32d08d8d740b9f242a3d1d2ed6d6b963d7187b60
-platform/frameworks/data-binding 134eecccdce6a36174a3b10131249303ecab2201
-platform/frameworks/ex 6033321c6f8305aa2f35b6f9c33169d69ec6fc91
-platform/frameworks/minikin 00b9a21209f6a9117f4915eb3fc074564e21aadd
-platform/frameworks/ml 4745c0f6f00ddc50bd2464589384e74e22253d0c
-platform/frameworks/multidex a2e21e78613b5b5ceaadadc2989c592cec6a661c
-platform/frameworks/native 5c58020c006c97bb7b535c3f20c16c1371005ae9
+platform/frameworks/av 59cfe7de39c8f1d2dee6eb6f171934598ba2da78
+platform/frameworks/base a2343a7e78534d82cdb47604481c834ea80b2d75
+platform/frameworks/compile/libbcc bc47cb1dc65be44cf0f8b3504b9eeb8f21d14c90
+platform/frameworks/compile/mclinker 2fbb628cf4c983fadf5971dfd8576368a42107ed
+platform/frameworks/compile/slang 8649d308b904ac8d7f9d26705b89a43693542296
+platform/frameworks/data-binding e1c9fe64b1c20aa86204f0e4ebb6ba043446f8cd
+platform/frameworks/ex bdaaa4e7a8f6a531616636893d28277891b06e9f
+platform/frameworks/minikin 39ab40115fae6d0c948e435233b3dd997ee7d8e5
+platform/frameworks/ml 1226a847e4d067a79843a5acbe59eb3087989552
+platform/frameworks/multidex b504c8f1b2edc203dca3959d29bc0dcf9e6fc8dd
+platform/frameworks/native 950e3f56964a714f68c6494fb4d045fef927bade
 platform/frameworks/opt/bitmap a0d4e3108663202564a6833b76770075b8e5b767
-platform/frameworks/opt/bluetooth b39b00b3dfdb634d96758f378498aca4caac499d
+platform/frameworks/opt/bluetooth 1b71d10d4f0cb68a52a516782c56f9ea809bdda1
 platform/frameworks/opt/calendar 03b18577f8f8f799e87a62b8e03889ddacf6daa2
-platform/frameworks/opt/chips 3bf4c863b357124e421f6d6732ff7b802d9b4260
+platform/frameworks/opt/chips dcc9b5f4faa6e71cbf8e6b7dbc7be542be4ef236
 platform/frameworks/opt/colorpicker c1d5eb2d31fb6a74ed129722754139c759aedbe8
-platform/frameworks/opt/datetimepicker 196f8c05f7585b3fcce1f766750cad4329c58656
+platform/frameworks/opt/datetimepicker b8304e6b062ec71bfd0c18c7e294af3980b4e328
 platform/frameworks/opt/emoji 92eede13edbf22b501edb9aeb92366f91eab9781
 platform/frameworks/opt/inputconnectioncommon 3baece9b20fa480da46d860acd7320fd9eee3386
 platform/frameworks/opt/inputmethodcommon 990fcb1a6dbb5d1204cc8ec86e4bc3f691f4aeeb
-platform/frameworks/opt/net/ethernet 8060ae0aeeea47c8fbe2896b0af3b1dd69f923a3
-platform/frameworks/opt/net/ims 0110b7d9c4e20228931fa915a80f0373b1104762
-platform/frameworks/opt/net/voip 9581957a57cb625ca9124bc9d92fcf080058e083
-platform/frameworks/opt/net/wifi 01282351e9b99a4929a6f30ac9813c2567c7f829
-platform/frameworks/opt/photoviewer 445813db01b5b2f50e80f6baea3254bf16f965bc
-platform/frameworks/opt/setupwizard 218e756c3e1e74a8c63ef7a55644af2cc69c880b
-platform/frameworks/opt/telephony d992bc1a7ef757a40eb53017e5b610df653e9b38
-platform/frameworks/opt/timezonepicker 965bd15605d8d7b3d06442263b368b025b05b0e6
-platform/frameworks/opt/vcard 03bfa415fab150deb666b1b5aad5913511bd7d33
-platform/frameworks/rs 4fe76d31717408419e99d1714e7867578126bec5
-platform/frameworks/support d732fd4f367018165b3881284cf588af9a86fbcf
-platform/frameworks/volley d20f9d3f2375c0eed25dbb76288f611328dcd5ab
-platform/frameworks/webview 33b7fd3f1361d02e941320b606cc7957edc12f4a
-platform/frameworks/wilhelm bb45b9aff58c5d1bb20c70ddb0a086886ffc0ffe
-platform/hardware/akm 7201e557ef616d931adeaa25ded2bd4542ef324a
-platform/hardware/broadcom/libbt 7f75cbfa70784045c741a60a93581d3b5f7985f5
-platform/hardware/broadcom/wlan a8ea89887b8aa9a0dd6f913c87b194e69c758f09
-platform/hardware/google/apf ae7070075ebcbc8e262bc8897616f4b671e38d46
+platform/frameworks/opt/net/ethernet fbba1273031483f336fa6f7127114bbff5b88e77
+platform/frameworks/opt/net/ims 3eb99bdaaa845b60792597b2a51d72209d3d5f84
+platform/frameworks/opt/net/voip 1cb6cefdb366094f018e72786f2d539bf27d5568
+platform/frameworks/opt/net/wifi aba0ba2f764a87e0ac7708bdb13f1e1e51fd0ace
+platform/frameworks/opt/photoviewer 64555a7d3622fcd9a15d2753305877e813455616
+platform/frameworks/opt/setupwizard 2cce48fde424bd078f024d5ddc7c564ca1161e2f
+platform/frameworks/opt/telephony 989070554ae553f65bcdab8af0b837acf1238dab
+platform/frameworks/opt/timezonepicker aa26ed582c2886dd510dc91e2f0a03521735d418
+platform/frameworks/opt/vcard 8d81a74f197c70b01422901634c20d2fb810fa73
+platform/frameworks/rs 9e5255b9589786072b5421f9341614e5f8e7c846
+platform/frameworks/support 721de09a57248324b33d673b8b458b1908e87c52
+platform/frameworks/volley 9424680a52bc7804e0c7f0f71c2f1ea282f10cdd
+platform/frameworks/webview c466c17e706271394e51ebeee629f2a33eebab52
+platform/frameworks/wilhelm a4684029e1730532e7a433815c144b3d6e30c3e3
+platform/hardware/akm 7889f98849ad3913586904e00d91b32cc0ceb75b
+platform/hardware/broadcom/libbt 7cf5a8f4dcc32172957eea387c6e07224ab1a88f
+platform/hardware/broadcom/wlan 0a132191e30f9c0fdbda09b200bf6419a0ce3d7d
+platform/hardware/google/apf dc89abf3134573daa2a408b50536ead82d540465
 platform/hardware/intel/audio_media 218f0d6bc9532d0b707ea325fd96998249fe47bf
 platform/hardware/intel/bootstub c759e5127aa582ac515ee1446da15f601b15a99a
 platform/hardware/intel/common/bd_prov 8af329f2d2b54dfcfa84051d3ce1fae95f79011a
-platform/hardware/intel/common/libmix d2a3d6ec324541ea5ae722d71d5137c02d9a44eb
-platform/hardware/intel/common/libstagefrighthw 51db5bb05715b75ae137e97a98c9a1a8c9a66aa4
-platform/hardware/intel/common/libva 581669db5974cdcb477d088bf74b73c11b3bc007
+platform/hardware/intel/common/libmix a644e4f384a7bd2afa4460da3a9f7951e9fa205e
+platform/hardware/intel/common/libstagefrighthw 9d15c1c031fdf9cd4fa153e76245d7a5f8b82ed8
+platform/hardware/intel/common/libva feff90bd79e7152d06f4275c30209af2826ae8ba
 platform/hardware/intel/common/libwsbm ac747113d4f6739b1462ca7fb40f2091691e209b
-platform/hardware/intel/common/omx-components 7f6133ff56bd48a9afd19aac2575c6f687f1d00a
-platform/hardware/intel/common/utils 1910b7bf5c493bc0d876e5be2b43653dca730a3c
-platform/hardware/intel/common/wrs_omxil_core 058936abe360c150890bb735e7f9b8e07e316620
-platform/hardware/intel/img/hwcomposer 0b9b9ee0b8436147a74734c0a7f86e8258d38170
-platform/hardware/intel/img/psb_headers 2212f33af7e208a3b9e3ab2502fc902c9b464010
+platform/hardware/intel/common/omx-components 68d39939cea6922473bce4912c5cf9bba250ca47
+platform/hardware/intel/common/utils 19355908e4f58daecfd4fa5a022409c7a43ffba6
+platform/hardware/intel/common/wrs_omxil_core 760b9713c84566e6a3a39d114d346d20389f47a8
+platform/hardware/intel/img/hwcomposer bacd48231700ed2481e303d90ed62d96a2112991
+platform/hardware/intel/img/psb_headers aed9716b5467e75728f761ac75a4ba5ca3c51ea0
 platform/hardware/intel/img/psb_video a805f1c63455a00883e066119fb0c5d533d3a116
 platform/hardware/intel/sensors 68dc9e70b79dacddc4e0bf00af0de7f764b04eed
-platform/hardware/interfaces 06a3daad19fa112da423716e6b156150fbf5a1b4
+platform/hardware/interfaces 0bb0ba5f797dac2e959f140e9bd41d94bf3d1d64
 platform/hardware/invensense 11e5ff75af866f91622b6008fa13db1c3685ae69
-platform/hardware/libhardware 9fe1a712fbc0dc52e101105d5014b147fe1125d3
-platform/hardware/libhardware_legacy 815654a3d8257e8fc29354af089969168dc0fee5
+platform/hardware/libhardware c231e024922ef3ffe911ee0942bed325905282f5
+platform/hardware/libhardware_legacy b9344a5773bcf6b035c889c42069b9c17d718f07
 platform/hardware/marvell/bt 3f33d194e8300816b94d1d7b68b1d48c8f903251
-platform/hardware/qcom/audio d29a5ecbbed1410b343a7e84b33f9903bfc0b012
-platform/hardware/qcom/bootctrl 7c119e08ce46a5a655a8320b2e548572a827999c
-platform/hardware/qcom/bt b9e99b576d94c1cff95960c6bf7ec8f0b272f7c6
-platform/hardware/qcom/camera 7bd85b4ae86232adc73483323b257ccc22591d40
-platform/hardware/qcom/display ce3c0609620f02621efb7531811e55c2295c2ade
-platform/hardware/qcom/gps 05ef6c51f694c27068afe280d668b7a430cc503e
-platform/hardware/qcom/keymaster 543927ba34c345d5c70a79613145f671a23b69b1
-platform/hardware/qcom/media a63ba0256cfd3e1baf3e5ffbc6bdefaab0f54a49
+platform/hardware/qcom/audio c25092d47e925c6ad9a87ea8ba01977fceab64dc
+platform/hardware/qcom/bootctrl 9f65b5d829b66006a6b270fb3d91dc68e3dde3e2
+platform/hardware/qcom/bt 485f249242097022e198b7a1232f6076be3ee893
+platform/hardware/qcom/camera e9f0e75160121ca116e0fc285269c6b858fd8616
+platform/hardware/qcom/data/ipacfg-mgr cc379d116231083e1b804fea9b0ef52d9e105ae1
+platform/hardware/qcom/display a0de1d3cc363c22672fa80d892f7652ac17c429f
+platform/hardware/qcom/gps 82dd9367cf0da5917fb6a35bcb9e28aa52a2e57d
+platform/hardware/qcom/keymaster 29565ce1f9219e66b7fb40063d49d14bb84ba606
+platform/hardware/qcom/media 0655dec92ac04cc6084f0f3a32df6a4c492caf4b
 platform/hardware/qcom/msm8960 c25a431842a26b5756b58a9d4a42c776e0457ba2
 platform/hardware/qcom/msm8994 60aaa00b2e0d537c0f51631dd88d919fc1baf439
-platform/hardware/qcom/msm8996 48ac587e6b8f7438860bf68a2deffa7e7902fd42
+platform/hardware/qcom/msm8996 a7626c056b920e780f4784cd810ddd44fd18dfb1
 platform/hardware/qcom/msm8x26 8b098e346cf0899037c10e3a2e7846a7014f0f1f
 platform/hardware/qcom/msm8x27 8ff5c0057cbdecfa09410c1710ba043e191a2862
 platform/hardware/qcom/msm8x74 2b96ffd283fd14d7d153b6b66680da98548679fd
 platform/hardware/qcom/msm8x84 582b414269d8472d17eef65d8a8965aa8105042f
 platform/hardware/qcom/power 3a098ee1f89c398b9d6e7b5dfae9c694994f8bc4
-platform/hardware/qcom/wlan 1af864da9125aeb4b87435d99a312d0cbd222094
-platform/hardware/ril b7f1226866cbaeffe2c525150521358d7a6c5087
-platform/libcore 1b4e76ec5d9912ebc7a64be8ae833ed6f7dc1057
-platform/libnativehelper b1d6844f1d6d3da548a2247e70cd85b706f74e03
-platform/manifest 8d31cd693d6ac0ded4ae875e7948a667d2373715
-platform/packages/apps/BasicSmsReceiver 7bbd1e4029b33ce598035a9767bdaf8433865e23
-platform/packages/apps/Bluetooth a0753c2c964957aac18b3a7b4690e0268147c481
-platform/packages/apps/Browser2 c24a10e63dba19b85b42590b968193053d43cd92
+platform/hardware/qcom/wlan ff71e5bb44242e6020bf40ed2c205143cfcadd42
+platform/hardware/ril c8610f89450ac334e57213caa26f41cb8ddc6fa8
+platform/libcore a2a43b6196d38a389b5593be8bbe421fe7576fe6
+platform/libnativehelper 5076d453e7d88c358d56d5bd7b9c1fd0c9c4c694
+platform/manifest 511c736393b879b1820003529e352ae742eb2ffc
+platform/packages/apps/BasicSmsReceiver 4175f5e7127817eb956c5b957caedc3ded98fa36
+platform/packages/apps/Bluetooth 7e9734439152ce8405ddae72ef104d90fb1843f5
+platform/packages/apps/Browser2 4dbfc60c0ca76a087bb01156e7803a76d6815b91
 platform/packages/apps/Calculator e1bda28f1545111ba7734577f23e194bf3db3f5f
 platform/packages/apps/Calendar 2bbf7b8414ebcff2207b08224d8913241a766a5a
-platform/packages/apps/Camera2 f16c21a499c4fec2339f0527408e9d0d7a33b21d
-platform/packages/apps/CarrierConfig ae76e54e532f55db5ab0c3963f74a10f92a7a019
-platform/packages/apps/CellBroadcastReceiver 489754bc92c14640408baa0a60b46e82bfc20822
-platform/packages/apps/CertInstaller d92ad87497a111256107eb7b06e0bfd1ceafc5cb
-platform/packages/apps/Contacts 47c5b614dd598a95671e02723d8ba8c8cb58ca9f
-platform/packages/apps/ContactsCommon ec5061cda034f7f8507152816785b4d361a3103d
-platform/packages/apps/DeskClock a56610c5125c246eb79812764c1993dfc1835c01
-platform/packages/apps/DevCamera dbe726e31887f9cfda05c4fce57a007314af9f4e
-platform/packages/apps/Dialer d5e3de3253f46bdda4f714db76a83ec0adfbf586
-platform/packages/apps/Email 05ddb0c52e9080c7e2b77bfd94c155701544af71
-platform/packages/apps/EmergencyInfo e0160fb2033544918ef1337640bbcd5775391a00
-platform/packages/apps/ExactCalculator 2b0283187a8f3d73ae16f2f6d398f4e103380797
-platform/packages/apps/Gallery 59a1d8a611f2c9e5b8d0b56e6c9875416a5fd809
-platform/packages/apps/Gallery2 af4651e7422238ca1f6657f6391f0bf11a2ce624
+platform/packages/apps/Camera2 27628b01c64e1acfb104d2fc5366e56ef7ebae91
+platform/packages/apps/CarrierConfig 72a0a6dfd6cae10f2660a1a3c070d52597b7707c
+platform/packages/apps/CellBroadcastReceiver 5c7d9ffd8431e2e4318600ebfe641dca1ddf8363
+platform/packages/apps/CertInstaller 26cfd49791431924b93caf2adbc88d4cb117c3a6
+platform/packages/apps/Contacts 37d983d382ef40fa2ec62ebc3eace5d8838b6604
+platform/packages/apps/ContactsCommon 7aba85a08c4729123a55341e8a0f9eb5a89e1a14
+platform/packages/apps/DeskClock aad7947684335119ee0d420d6fb7a1dfffa6d73e
+platform/packages/apps/DevCamera 85b25ee8ce0c5d19b53963c985869100282b55d1
+platform/packages/apps/Dialer 949a78c26564ec873447368fb66a582fbe081a85
+platform/packages/apps/Email 552ef93f45b6f818bb269920c309741c51e62b1e
+platform/packages/apps/EmergencyInfo 8b64fa7af5060ea66f223c0fec11ee97469750b8
+platform/packages/apps/ExactCalculator dabd82f7376c87fac9e7b0a0c4b5d800846bc27b
+platform/packages/apps/Gallery 09b065b9a794e3e254d40fd4dd2a98f0cd0673e0
+platform/packages/apps/Gallery2 538f6fe844a7c90e211cedbd78f8e8d8835b2b42
 platform/packages/apps/HTMLViewer f19c4a10890cafb17ceaf68cda835dc24aad455c
-platform/packages/apps/KeyChain 6bc410b83c4da356eba55679cbd8419ade64f213
-platform/packages/apps/Launcher2 bb66b0c637a0c47f17bfb1e1aac677661593bd48
-platform/packages/apps/Launcher3 f304453c99b9455198dc733c007bd6eba5922746
-platform/packages/apps/LegacyCamera 529b5485970f23f52513a9a13c1ec96acd34aa58
-platform/packages/apps/ManagedProvisioning 0fa07de3558b5aff8a0d960b741abc6af3b9150d
-platform/packages/apps/Messaging c3b3f3d8f11ce8c80074974110f94d07b027ef58
-platform/packages/apps/Music eda3322d780d9ffeac499d0845e3b1141cde0e01
-platform/packages/apps/MusicFX a015510a46079c764097fe00285f9ebc539e5311
-platform/packages/apps/Nfc 2bada48c89301ee38169d3ed06ef77381f6a06c4
+platform/packages/apps/KeyChain db8c141b5e94b26d7a8605e18af740184abf51ce
+platform/packages/apps/Launcher2 db9e56344d2ef16618aa7227058028229d410431
+platform/packages/apps/Launcher3 26b839d8f6f72a56d611b73b48bc8322fe04886d
+platform/packages/apps/LegacyCamera 79171ff1cb60c83a020cae25c73b415c6812a90e
+platform/packages/apps/ManagedProvisioning f6b069b92eb00dc089326cac9e8df3d5be307823
+platform/packages/apps/Messaging 4b73fb05320cb11ca2b4e34982346b4198e3d196
+platform/packages/apps/Music ef3044c46d342e83c0b21339282f30ac4f1116f0
+platform/packages/apps/MusicFX 3d3e7128737406746fb0ff1767929c0f5aa6abe2
+platform/packages/apps/Nfc 81ab61e51c7f45d1c4020a92ec3352954721380a
 platform/packages/apps/OneTimeInitializer 01e429c08e51291315890de9677151a7e0b6ad35
-platform/packages/apps/PackageInstaller 4e2a5109e509ca65e3a54b2a3c2fa5125a3083cb
+platform/packages/apps/PackageInstaller 5e4d32ccfc3abf68d265ca63c8b8b485036908d3
 platform/packages/apps/Phone 79731f02b7009206a01182d2cca15dfc8491da09
-platform/packages/apps/PhoneCommon dd5b923eaf36c1a137e14e043064ae352280afad
+platform/packages/apps/PhoneCommon 2ec9c307a4287a219ee447689eef50c19dba3c7d
 platform/packages/apps/Protips d686dc74168ed5324b2388133531f30255659ae6
-platform/packages/apps/Provision 53593db784a7425c424ccd52fcd122847ed26a4d
-platform/packages/apps/QuickSearchBox 39e4bb19fac59b9412fee7fa7254233dcd928123
-platform/packages/apps/Settings b4b2c2aa4386fc963b28f3adb7f33ef6e80c9ac8
+platform/packages/apps/Provision 077fc59dd26cdecdfe2ea3af614291b103faa7e2
+platform/packages/apps/QuickSearchBox 9fd59c0b83d97b90fb5bc098155a5a2803a42c5e
+platform/packages/apps/SafetyRegulatoryInfo a1f25b45e3cb478fb2734da6ab61344fb8c4334c
+platform/packages/apps/Settings ab9e269d068bd9c10b5501f26230214ae673c3cd
 platform/packages/apps/SoundRecorder 5f67a8eaea9379d7fce53db77e9ed7b47e49f1e1
 platform/packages/apps/SpareParts 4db997871e3f4c3f84660815096e5276b47c5c91
 platform/packages/apps/SpeechRecorder 51cc8462c082a26810f5d7c5a2648232a77e795c
-platform/packages/apps/Stk ea5113094bb4ba3283488b5fd8a5cafb3bb61471
-platform/packages/apps/TV 919e1ed7e914029a1a0054237d86dc7b19ced898
-platform/packages/apps/Tag 6b0a720eadcb9c33d0a12d36298811e481de2a8a
-platform/packages/apps/Terminal 3cb5403b8dc4709e36aeee24fceea2ed6d4331e9
-platform/packages/apps/Test/connectivity 891717b67018483387cab44683a069f4989f19a6
-platform/packages/apps/TvSettings 1807fa3819c23a0343a86d61431042230831c7b8
+platform/packages/apps/Stk ff30bb073af07d123f946a258c76e6e5be4595c2
+platform/packages/apps/StorageManager f89e8ca407cded7465735d76454c64293ea65d2b
+platform/packages/apps/TV 1cc00e9485f50e59b439aaeaad3d6d0fe12b917c
+platform/packages/apps/Tag d17b7a8bde768cf75dbe9e0402772eda9e3e97a5
+platform/packages/apps/Terminal 2c4b6548ff31f403fb0af8be422331398aff3f13
+platform/packages/apps/Test/connectivity 8a64f93bb58146d5930a0ff30a501f19286c1506
+platform/packages/apps/TvSettings 09d28277bb4bfbff44e2bbc2b483660e2beff4ce
 platform/packages/apps/UnifiedEmail 7d3754cb8144935ca8a9a1f879cc29076c4f642e
-platform/packages/experimental 08ec110e208e7f527cd010ee6455c0697f7a8deb
-platform/packages/inputmethods/LatinIME d2af70179eb9d4b54ac802a5f147c81106590f10
+platform/packages/apps/WallpaperPicker 0e618b2c641020f5b46bf29fbf01825b17e99f0d
+platform/packages/experimental e24ee92653e28ddf0020ffb9e5ddc99931117674
+platform/packages/inputmethods/LatinIME e4ea7e8191ff2a029fed8f0ca18d59970039d871
 platform/packages/inputmethods/OpenWnn 59aefa242169b7a51c2381daee58ff22fd1834ce
 platform/packages/providers/ApplicationsProvider 33d26f5eedb3d3011762ce5b2de66e931bf64b35
-platform/packages/providers/BlockedNumberProvider 0d633224f59f09831887d9fdc8b24a437cbb8144
+platform/packages/providers/BlockedNumberProvider efa2852fb99356ac7fa273d3a9db559f50f6f834
 platform/packages/providers/BookmarkProvider 6ec4bb392332b12162c5a8a1eaba1ee34d389c5c
-platform/packages/providers/CalendarProvider e34e1daee9f6e95cf10900b354bcc41300c9fe35
-platform/packages/providers/CallLogProvider cb13993387ae268581e0fe9c9e998df9a8109738
-platform/packages/providers/ContactsProvider 71c9c8c0c1e077060877d15f2ea5317f7167d4cd
-platform/packages/providers/DownloadProvider d10d8649c0eefd43d064c050e880defd13a5091b
-platform/packages/providers/MediaProvider 9eb770968bfc9f5062367b34e5ce16bec40f6834
+platform/packages/providers/CalendarProvider fbd34141a0f3da64583a24eaf62cac8940cbcc12
+platform/packages/providers/CallLogProvider f1b764bf4bd7da8edf128fa57456a31e067d14c3
+platform/packages/providers/ContactsProvider 9ce8290df035fa24263164435ecfd01f2505f328
+platform/packages/providers/DownloadProvider 675a0f073a775a85e42fd8534b5ec0b453b62869
+platform/packages/providers/MediaProvider 792f244db4fb8da6ba24c9d930114ca90c0a2305
 platform/packages/providers/PartnerBookmarksProvider 96d0a80af45923767baf449fc8c735c2f71d64ae
-platform/packages/providers/TelephonyProvider a615f3daa0b51482f842e08f0c874933c421c35c
-platform/packages/providers/TvProvider bf8a7426e7d535baacf123215f1c3937025373a0
-platform/packages/providers/UserDictionaryProvider f56fdc6cbe18d1b1f7c778a7890901f6a0176087
+platform/packages/providers/TelephonyProvider cd1c178395738380f7181721a709116534a7c150
+platform/packages/providers/TvProvider 1f1bd24ce61c0566b03abcb0fc32826731a9b0ed
+platform/packages/providers/UserDictionaryProvider 2e352c3cb7197283e4d97a64d0810f8a51453ad6
 platform/packages/screensavers/Basic e72ef139782ca896dced7524abe7cfcc9ed35db1
-platform/packages/screensavers/PhotoTable 5a048e44c69d71a9ada339797bbb22b7a8b8d3d5
+platform/packages/screensavers/PhotoTable 48f2eed8d49ce9ac0b848c989237cc8155ba38a9
 platform/packages/screensavers/WebView 6e0a80f6faed6191acc8ce1b6c79eada09e9e042
-platform/packages/services/Car c2f6f6add838f01a4cb232a34ea69171a4ccd148
-platform/packages/services/Mms 6987193d680fe7245b462f98656652e127599dc0
-platform/packages/services/Telecomm fbe4cadff4a0b7fac9fc173517f78d55b6b0069a
-platform/packages/services/Telephony 7b821620a8daf33c9e387d1a19fb9a77af4425f1
-platform/packages/wallpapers/LivePicker f02a37c8b18a6dff94dd721306662cdb8439e9a7
+platform/packages/services/BuiltInPrintService 1d8f17368e4bf8d2af6b1caa51e1535b03822fda
+platform/packages/services/Car 9fe1c3db6692a51d63a2827c5d208db427b60f40
+platform/packages/services/Mms 91aebcecdd61b908221359a9a01a94ae5257d886
+platform/packages/services/NetworkRecommendation f61eea388fae80b34143013412542c109851bb9c
+platform/packages/services/Telecomm de6924cdbced0d6f5d423ca78c9a0a46c8347da3
+platform/packages/services/Telephony 56a30a6647f440b2a5d635fc7d8817c8f4ad533d
+platform/packages/wallpapers/LivePicker d7e58d608a8e6d63d7582473a1f4fd5de316851f
 platform/pdk 708589163e790eb3a7fec09f4832a0f78999bdf3
-platform/platform_testing 1058769d9721b0f54a09d2814027bb4e75a435b3
-platform/prebuilts/android-emulator 8a4758b098908adc6f3fad80c0f9ad04f5660985
-platform/prebuilts/build-tools 3f66f9263b16bec27cbea6b85655d3d0bce4b994
-platform/prebuilts/clang/host/darwin-x86 0aadd8ffdadaa372c2dd1fd79c13af7ff71f0bde
-platform/prebuilts/clang/host/linux-x86 3a1e6a6c6d906c27e69e3a5dd154d1aba09cbe9b
-platform/prebuilts/deqp 9d0fca1c90a2851d918e00ff69a791278bf9364d
+platform/platform_testing 00161da3d2617aa06536737bd95ece37fe2a3f5b
+platform/prebuilts/android-emulator 20fe94517eca44dcd562cb41b67fe4127bb1597e
+platform/prebuilts/build-tools e465fa7f551bc7d4e09456333898cf49937a01d8
+platform/prebuilts/checkstyle 4a7cc7eba1eea41e471ec643840174f6c3299d18
+platform/prebuilts/clang/host/darwin-x86 73e58d09a20724718e3c963ea5867835c43a7544
+platform/prebuilts/clang/host/linux-x86 8eb2cea18ef8672eafca64c10b64c1fa681ad07c
+platform/prebuilts/deqp 3f7b967d7841908159ac5a2b21770a7b703841c2
 platform/prebuilts/devtools d054448a1147fc5294089b6ac7aa3abe92202761
 platform/prebuilts/eclipse cf9f78f8cf41b16edf9f712598a42743d5cea4af
 platform/prebuilts/eclipse-build-deps ceb739d6a7c10f5fb5a6cf6e1f702453b1361ad3
-platform/prebuilts/gcc/darwin-x86/aarch64/aarch64-linux-android-4.9 6bf153df308133f0aeda4f4738537bbeca7f253a
-platform/prebuilts/gcc/darwin-x86/arm/arm-linux-androideabi-4.9 d610c08f90ee2e0d529cb2360ac03b249e037e12
+platform/prebuilts/gcc/darwin-x86/aarch64/aarch64-linux-android-4.9 03e2ae15852449ae81ddaa54c35739af27180581
+platform/prebuilts/gcc/darwin-x86/arm/arm-linux-androideabi-4.9 d8c414fc49e933c074f173e6d87795cc7fdcfedc
 platform/prebuilts/gcc/darwin-x86/host/i686-apple-darwin-4.2.1 ec5aa66aaa4964c27564d0ec84dc1f18a2d72b7e
-platform/prebuilts/gcc/darwin-x86/mips/mips64el-linux-android-4.9 0c0a70932154aaea3e32d616d7971597da608ed8
-platform/prebuilts/gcc/darwin-x86/x86/x86_64-linux-android-4.9 8057ba1ac5539e624df10934bee31c7ece103937
-platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9 5f0aa27de21fbc608e48def3647cdcaef0422820
-platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9 bf02f9b2b4f955d874fdaace765e408d0b31f1e7
-platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.8 7a8824915a05bef8581fb1f614c4eee9564c4ba2
+platform/prebuilts/gcc/darwin-x86/mips/mips64el-linux-android-4.9 c3b7a175640fc59711614c0ad5269a037e06fe7a
+platform/prebuilts/gcc/darwin-x86/x86/x86_64-linux-android-4.9 e8a2f21c1cc7f87069da71bc2f1901acc4ea2bdf
+platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9 ce9d77505072450d2f16a4bf06673f31d8d67ff0
+platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9 ea9c88beb9ffbb1a0833cc3ee94b53950729473d
+platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.8 e9534abf9e4916bc9f0f0c74b64ad2f404a34e97
 platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8 73ca99196723f810dad42390d154654354f57c16
-platform/prebuilts/gcc/linux-x86/host/x86_64-w64-mingw32-4.8 93ce6bc0bd97ae4bb5f7e9e7e2a752262a1ec125
-platform/prebuilts/gcc/linux-x86/mips/mips64el-linux-android-4.9 5365d3f36acfb7b5ee3cc707d14df6fb444f7554
-platform/prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9 e89c079c1b97e6f2cbb17bbac494075fda83c374
-platform/prebuilts/gdb/darwin-x86 b293f0429e4f7797382e1c8d9153459996ba332c
-platform/prebuilts/gdb/linux-x86 01e05a5d0421cd02111b33b359b1e7b40e3efa24
-platform/prebuilts/go/darwin-x86 960f10dc2e9d07589d05ab32a69e3ce379a912dc
-platform/prebuilts/go/linux-x86 ad811e09d6291486ada15c1f7e84982227e9988b
-platform/prebuilts/gradle-plugin 269e773f423c9d8ae762324cc7cb1d0149a983b7
+platform/prebuilts/gcc/linux-x86/host/x86_64-w64-mingw32-4.8 47200031477701f568a772368e3f6c8ce49fe05c
+platform/prebuilts/gcc/linux-x86/mips/mips64el-linux-android-4.9 a332df8dadd78866c2a57f2c7348d499952939c2
+platform/prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9 1944f44167a907969de5138fe4cc442432b7cc37
+platform/prebuilts/gdb/darwin-x86 4a696dd19df2fee0ce24f5bdbd8ae0e03049f97b
+platform/prebuilts/gdb/linux-x86 172e21a7c836e6086c6faae7b080a38c779597ac
+platform/prebuilts/go/darwin-x86 ebae30230ea323ebd5d80796b00cc5234e0a02f1
+platform/prebuilts/go/linux-x86 bbdf6646ffb911ac36720a9ec09f80dd31429b33
+platform/prebuilts/gradle-plugin 7265f3a8f8bcb73523cc5643cfa1dd73b9368920
 platform/prebuilts/libs/libedit d32685dba4011664b590b94ad156bc734c2c9bb5
-platform/prebuilts/maven_repo/android 51c582c7cef5041e3df0906020713c3d97568ed7
-platform/prebuilts/misc e7b8dd9761338cb0d06a7ca849e2ce99b322b47b
-platform/prebuilts/ndk dd39467272dcfcce397fd1765a41f2abb16156e5
+platform/prebuilts/maven_repo/android 7a16389da39a9716a2626bfbc802eb66d8e16c5b
+platform/prebuilts/misc 6c63582b051dc9eb5af5efd6fb23f53be319d99f
+platform/prebuilts/ndk 625fa539e413cbac468ab22e77a98246c008629e
 platform/prebuilts/python/darwin-x86/2.7.5 0c5958b1636c47ed7c284f859c8e805fd06a0e63
-platform/prebuilts/python/linux-x86/2.7.5 a3f090d3e5c1edb1fc7b769fc89ae2f27ea85a02
-platform/prebuilts/qemu-kernel 60495c068240d9b4bd05f478707ac3809178a1d0
-platform/prebuilts/sdk 91f202e7b3d0a38c70016956e327437b29eee6b4
-platform/prebuilts/tools ae68e07e990175496bf162f2db16ccbd266a16c7
-platform/sdk 576f858aaab3793cbed5e61dec31e3d141d1a559
-platform/system/bt 133f0b6503b6adced17795c7a31dd17e084507e1
-platform/system/ca-certificates c36d8eb8071d73528993e024e73d40c6977b1d0d
-platform/system/connectivity/wificond 903b9d029cbb2897fc3b2c2b731bf9e1bc7bb4a0
-platform/system/connectivity/wifilogd fd59221459953a821b9021e00276749ac46ea5ea
-platform/system/core 0673412bb962a2c92830e903acf442506d092ebc
-platform/system/extras ba27872adb19eb5a35989602e85785812cd77f3d
-platform/system/gatekeeper 0c4a1124137981a98331ded6f676417fcffe1bb6
-platform/system/hwservicemanager 2173d3c8d6f5a5a78bd145063ac177d7f0657d33
-platform/system/keymaster eaaa95d0c290d845a4d152b50a61a740bb488611
-platform/system/libhidl b69926a728aa472be47f51dc5fc374571d7da5a8
-platform/system/libhwbinder a0a7e1e16c30c69be497b40b88de79860b0df20c
+platform/prebuilts/python/linux-x86/2.7.5 3229c5a24529bad2a85691f17d9e75a300af5085
+platform/prebuilts/qemu-kernel b0ee028abf8cc13cb773ede3c481ed231322ad45
+platform/prebuilts/sdk 83c99be5148e55f5e6a537732718659ca38b240b
+platform/prebuilts/tools e0a04446d81748385fc75beb82add6db56ffd757
+platform/sdk 1da8730be2203d266be81f9a6e0446f9f8da4717
+platform/system/bt 0c86aad3f588a5d68a2407a60e536f459b10bfeb
+platform/system/ca-certificates e312bd5044fc07e85b8b0c21b8f21a9329ce9636
+platform/system/connectivity/wificond 72312e2e46675ace1560ba71dff3f3020fa7969e
+platform/system/connectivity/wifilogd 8fbb6736ffd23e005396afb793c72cb048bbf7a6
+platform/system/core c160675a93c480ff7cb49c0139c41890127cbeb8
+platform/system/extras 7aa9dd25ee3570bd42fe79891b0f2fbc01f8bea3
+platform/system/gatekeeper 56509312054d667c83e168f01037556edba747a5
+platform/system/hwservicemanager 61ff909c8599f62614df3b1568d8fdfaba62398e
+platform/system/keymaster f9b2839a3404311db4de5c613d314ae96f620636
+platform/system/libfmq 4486ad012294b58932dea1224bb93711b8636682
+platform/system/libhidl b35aa248b85c2a22ce485ab2d322983c793dcc81
+platform/system/libhwbinder a2ce3b82c4a30cc677c536a013a62d5405062bb9
+platform/system/libufdt b63f3b74cc6f87a1106e2afd49e82cac3538ef53
 platform/system/libvintf 745e79f81c15db39e3278e226b35f0959342437a
-platform/system/media 76f97250ff8fc843e321b6aea5d15f9cc1367861
-platform/system/nativepower 92e272cb1f04defd4ea4ca6869e357d72cc780f6
-platform/system/netd 03f1db5be3b6a223cb0fc884c5f5c02611a7ba14
-platform/system/nvram 1172562603a15de574acd9e48f322a77f86d9d63
-platform/system/security 23545340601012981ee4d0f8b99acc7da259ccc1
-platform/system/sepolicy 747c69f43cdcf89258a5c97d776335d9ba16bbfb
-platform/system/tools/aidl 93298ee273b14bb658500fa1c87286bb9ae7aabb
-platform/system/tools/hidl f9dc1bd1b612af829fb6fae31dc11998c8c02351
-platform/system/tpm 7eb694b2d07e2e2bf520850b78bb45c678bc0014
-platform/system/update_engine 063863bbda33704db4628e66444077bc1c33342a
-platform/system/vold dbeebf56aa3c6c4c3977be0effef30bbd92fba27
+platform/system/media 1fb716a12b572b2e788fed4d485512f797684273
+platform/system/nativepower 3813dba8ad14e9347fcd743eb00426ecdac63f12
+platform/system/netd c12d8730e79171081ec390eb217a7631597afd3d
+platform/system/nfc 303fec1d79b7ac30a09713e5db9fff299f7227fb
+platform/system/nvram 50031a52fa6d821a9fd679d0a2cc4f3a6c9b97a0
+platform/system/security 7f35beb6cb1a554e8a9c86ade9b4206deda3d9c2
+platform/system/sepolicy 597a8a4913bce024ff8f1a27b2229136c523cae8
+platform/system/tools/aidl 1a90639de2ce33d514d1e8720eeaefbc67ca373a
+platform/system/tools/hidl 0a344a3e7cb56609ccf510a0e968ba2a5c1a20bc
+platform/system/tpm 3da3faf4ad04fdbf31e524e3b4efa5cafc6ba8cb
+platform/system/update_engine 5fbb110c73158e443efe1fcac87e6648c631b4c0
+platform/system/vold 04c55e6ed7259c5fb0c3d951f4995778feff2a34
+platform/test/vts 1443b352a5aaa4e15b2ca08ef14e551f703ccb6f
+platform/test/vts-testcase/fuzz 458c222617968c861312d98af52d78757481e104
+platform/test/vts-testcase/kernel e20990bbf1f5648c88981c41a0b8a7a72019c4ab
+platform/test/vts-testcase/performance ddcfcd1e5374fa5e7b72510b13439d204547446f
+platform/test/vts-testcase/security 66094098a8c0d60292ecd7d179060cdea5d0f069
 platform/tools/adt/idea d3106c42c5466362da9bfb9f7453e5d60af83579
-platform/tools/apksig 48f3040488dac495c874cc68caf45a11ddbee852
+platform/tools/apksig 85a854b038c28fa2b34eaee0ff34e67c164880ea
 platform/tools/base 908b391a9c006af569dfaff08b37f8fdd6c4da89
 platform/tools/build 69c4b95102b4b9862bfba68b3eaf5b7537a705ee
 platform/tools/external/fat32lib 3880776e41ff7def06e351720f2d162f88b58a03
-platform/tools/external/gradle baf3bbc7a40c290737a5ef29ce23bd65062d906f
+platform/tools/external/gradle 6432f6a84d0e42152929b3904c242959b4c0d66a
 platform/tools/idea 9b5d02ac8c92b1e71523cc15cb3d168d57fbd898
-platform/tools/loganalysis 775ec86c48d93a5c0ee3dae94ac881154aeab37f
+platform/tools/loganalysis 3c8cd0cd4bdf2953345a4465c1de9921069c123a
 platform/tools/motodev 69989786cefbde82527960a1e100ec9afba46a98
-platform/tools/repohooks ec044d3e9b608ce275f02092f86810a3ba13834e
+platform/tools/repohooks d1fd88b71ce4b8b1b65de1081a592510e259fc2c
 platform/tools/studio/cloud 58f06e77e051fff3903adabca7acdaa9dd12ec2d
 platform/tools/swt 8996e71047a2bd11efee46ef14e02435ab5fa07a
-platform/tools/test/connectivity c2bd30c602e402bc84c2e3d20cfedf47e884a8e1
-platform/tools/tradefederation fb8378796bdd86acd9d1d340a4f18aec551ce0d5
-toolchain/binutils 082ed0f10cf59b53381cefda2f90247e2a81015b
+platform/tools/test/connectivity 5d85709b78e62c1a8c285ae86f1cceb396cd17cd
+platform/tools/tradefederation ac6c6e332067cc7f22903d9c70ba23ffc9d91026
+toolchain/binutils 249bab53c3518fccd432baf1447422b25d884732
diff --git a/simpleperf_report.py b/report.py
similarity index 98%
rename from simpleperf_report.py
rename to report.py
index 225998a..b58ac6b 100644
--- a/simpleperf_report.py
+++ b/report.py
@@ -31,6 +31,7 @@
 from tkFont import *
 from Tkinter import *
 from ttk import *
+from utils import *
 
 PAD_X = 3
 PAD_Y = 3
@@ -243,7 +244,8 @@
 
 def call_simpleperf_report(args, report_file):
   output_fh = open(report_file, 'w')
-  args = ['simpleperf', 'report'] + args
+  simpleperf_path = get_host_binary_path('simpleperf')
+  args = [simpleperf_path, 'report'] + args
   subprocess.check_call(args, stdout=output_fh)
   output_fh.close()
 
diff --git a/report_sample.py b/report_sample.py
new file mode 100644
index 0000000..45e884a
--- /dev/null
+++ b/report_sample.py
@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""report_sample.py: report samples in the same format as `perf script`.
+"""
+
+from __future__ import print_function
+import argparse
+import sys
+from simpleperf_report_lib import *
+
+
+def report_sample(record_file, symfs_dir, kallsyms_file=None):
+    """ read record_file, and print each sample"""
+    lib = ReportLib()
+
+    lib.ShowIpForUnknownSymbol()
+    if symfs_dir is not None:
+        lib.SetSymfs(symfs_dir)
+    if record_file is not None:
+        lib.SetRecordFile(record_file)
+    if kallsyms_file is not None:
+        lib.SetKallsymsFile(kallsyms_file)
+
+    while True:
+        sample = lib.GetNextSample()
+        if sample is None:
+            lib.Close()
+            break
+        event = lib.GetEventOfCurrentSample()
+        symbol = lib.GetSymbolOfCurrentSample()
+        callchain = lib.GetCallChainOfCurrentSample()
+
+        sec = sample.time / 1000000000
+        usec = (sample.time - sec * 1000000000) / 1000
+        print('%s\t%d [%03d] %d.%d:\t\t%d %s:' % (sample.thread_comm,
+                                                  sample.tid, sample.cpu, sec,
+                                                  usec, sample.period, event.name))
+        print('%16x\t%s (%s)' % (sample.ip, symbol.symbol_name, symbol.dso_name))
+        for i in range(callchain.nr):
+            entry = callchain.entries[i]
+            print('%16x\t%s (%s)' % (entry.ip, entry.symbol.symbol_name, entry.symbol.dso_name))
+        print('')
+
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser(description='Report samples in perf.data.')
+    parser.add_argument('--symfs',
+                        help='Set the path to find binaries with symbols and debug info.')
+    parser.add_argument('--kallsyms', help='Set the path to find kernel symbols.')
+    parser.add_argument('record_file', nargs='?', default='perf.data',
+                        help='Default is perf.data.')
+    args = parser.parse_args()
+    report_sample(args.record_file, args.symfs, args.kallsyms)
diff --git a/simpleperf_report_lib.py b/simpleperf_report_lib.py
new file mode 100644
index 0000000..3fdc234
--- /dev/null
+++ b/simpleperf_report_lib.py
@@ -0,0 +1,305 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""simpleperf_report_lib.py: a python wrapper of libsimpleperf_report.so.
+   Used to access samples in perf.data.
+"""
+
+import ctypes as ct
+import os
+import subprocess
+import sys
+import unittest
+from utils import *
+
+
+def _get_native_lib():
+    return get_host_binary_path('libsimpleperf_report.so')
+
+
+def _is_null(p):
+    return ct.cast(p, ct.c_void_p).value is None
+
+
+def _char_pt(str):
+    if sys.version_info < (3, 0):
+        return str
+    # In python 3, str are wide strings whereas the C api expects 8 bit strings, hence we have to convert
+    # For now using utf-8 as the encoding.
+    return str.encode('utf-8')
+
+
+def _char_pt_to_str(char_pt):
+    if sys.version_info < (3, 0):
+        return char_pt
+    return char_pt.decode('utf-8')
+
+
+class SampleStruct(ct.Structure):
+    _fields_ = [('ip', ct.c_uint64),
+                ('pid', ct.c_uint32),
+                ('tid', ct.c_uint32),
+                ('thread_comm', ct.c_char_p),
+                ('time', ct.c_uint64),
+                ('in_kernel', ct.c_uint32),
+                ('cpu', ct.c_uint32),
+                ('period', ct.c_uint64)]
+
+
+class EventStruct(ct.Structure):
+    _fields_ = [('name', ct.c_char_p)]
+
+
+class SymbolStruct(ct.Structure):
+    _fields_ = [('dso_name', ct.c_char_p),
+                ('vaddr_in_file', ct.c_uint64),
+                ('symbol_name', ct.c_char_p),
+                ('symbol_addr', ct.c_uint64)]
+
+
+class CallChainEntryStructure(ct.Structure):
+    _fields_ = [('ip', ct.c_uint64),
+                ('symbol', SymbolStruct)]
+
+
+class CallChainStructure(ct.Structure):
+    _fields_ = [('nr', ct.c_uint32),
+                ('entries', ct.POINTER(CallChainEntryStructure))]
+
+
+# convert char_p to str for python3.
+class SampleStructUsingStr(object):
+    def __init__(self, sample):
+        self.ip = sample.ip
+        self.pid = sample.pid
+        self.tid = sample.tid
+        self.thread_comm = _char_pt_to_str(sample.thread_comm)
+        self.time = sample.time
+        self.in_kernel = sample.in_kernel
+        self.cpu = sample.cpu
+        self.period = sample.period
+
+
+class EventStructUsingStr(object):
+    def __init__(self, event):
+        self.name = _char_pt_to_str(event.name)
+
+
+class SymbolStructUsingStr(object):
+    def __init__(self, symbol):
+        self.dso_name = _char_pt_to_str(symbol.dso_name)
+        self.vaddr_in_file = symbol.vaddr_in_file
+        self.symbol_name = _char_pt_to_str(symbol.symbol_name)
+        self.symbol_addr = symbol.symbol_addr
+
+
+class CallChainEntryStructureUsingStr(object):
+    def __init__(self, entry):
+        self.ip = entry.ip
+        self.symbol = SymbolStructUsingStr(entry.symbol)
+
+
+class CallChainStructureUsingStr(object):
+    def __init__(self, callchain):
+        self.nr = callchain.nr
+        self.entries = []
+        for i in range(self.nr):
+            self.entries.append(CallChainEntryStructureUsingStr(callchain.entries[i]))
+
+
+class ReportLibStructure(ct.Structure):
+    _fields_ = []
+
+
+class ReportLib(object):
+
+    def __init__(self, native_lib_path=None):
+        if native_lib_path is None:
+            native_lib_path = _get_native_lib()
+
+        self._load_dependent_lib()
+        self._lib = ct.CDLL(native_lib_path)
+        self._CreateReportLibFunc = self._lib.CreateReportLib
+        self._CreateReportLibFunc.restype = ct.POINTER(ReportLibStructure)
+        self._DestroyReportLibFunc = self._lib.DestroyReportLib
+        self._SetLogSeverityFunc = self._lib.SetLogSeverity
+        self._SetSymfsFunc = self._lib.SetSymfs
+        self._SetRecordFileFunc = self._lib.SetRecordFile
+        self._SetKallsymsFileFunc = self._lib.SetKallsymsFile
+        self._ShowIpForUnknownSymbolFunc = self._lib.ShowIpForUnknownSymbol
+        self._GetNextSampleFunc = self._lib.GetNextSample
+        self._GetNextSampleFunc.restype = ct.POINTER(SampleStruct)
+        self._GetEventOfCurrentSampleFunc = self._lib.GetEventOfCurrentSample
+        self._GetEventOfCurrentSampleFunc.restype = ct.POINTER(EventStruct)
+        self._GetSymbolOfCurrentSampleFunc = self._lib.GetSymbolOfCurrentSample
+        self._GetSymbolOfCurrentSampleFunc.restype = ct.POINTER(SymbolStruct)
+        self._GetCallChainOfCurrentSampleFunc = self._lib.GetCallChainOfCurrentSample
+        self._GetCallChainOfCurrentSampleFunc.restype = ct.POINTER(
+            CallChainStructure)
+        self._GetBuildIdForPathFunc = self._lib.GetBuildIdForPath
+        self._GetBuildIdForPathFunc.restype = ct.c_char_p
+        self._instance = self._CreateReportLibFunc()
+        assert(not _is_null(self._instance))
+
+        self.convert_to_str = (sys.version_info >= (3, 0))
+
+    def _load_dependent_lib(self):
+        # As the windows dll is built with mingw we need to also find "libwinpthread-1.dll".
+        # Load it before libsimpleperf_report.dll if it does exist in the same folder as this script.
+        if is_windows():
+            libwinpthread_path = os.path.join(get_script_dir(), "libwinpthread-1.dll")
+            if os.path.exists(libwinpthread_path):
+                self._libwinpthread = ct.CDLL(libwinpthread_path)
+            else:
+                log_fatal('%s is missing' % libwinpthread_path)
+
+    def Close(self):
+        if self._instance is None:
+            return
+        self._DestroyReportLibFunc(self._instance)
+        self._instance = None
+
+    def SetLogSeverity(self, log_level='info'):
+        """ Set log severity of native lib, can be verbose,debug,info,error,fatal."""
+        cond = self._SetLogSeverityFunc(self.getInstance(), _char_pt(log_level))
+        self._check(cond, "Failed to set log level")
+
+    def SetSymfs(self, symfs_dir):
+        """ Set directory used to find symbols."""
+        cond = self._SetSymfsFunc(self.getInstance(), _char_pt(symfs_dir))
+        self._check(cond, "Failed to set symbols directory")
+
+    def SetRecordFile(self, record_file):
+        """ Set the path of record file, like perf.data."""
+        cond = self._SetRecordFileFunc(self.getInstance(), _char_pt(record_file))
+        self._check(cond, "Failed to set record file")
+
+    def ShowIpForUnknownSymbol(self):
+        self._ShowIpForUnknownSymbolFunc(self.getInstance())
+
+    def SetKallsymsFile(self, kallsym_file):
+        """ Set the file path to a copy of the /proc/kallsyms file (for off device decoding) """
+        cond = self._SetKallsymsFileFunc(self.getInstance(), _char_pt(kallsym_file))
+        self._check(cond, "Failed to set kallsyms file")
+
+    def GetNextSample(self):
+        sample = self._GetNextSampleFunc(self.getInstance())
+        if _is_null(sample):
+            return None
+        if self.convert_to_str:
+            return SampleStructUsingStr(sample[0])
+        return sample[0]
+
+    def GetEventOfCurrentSample(self):
+        event = self._GetEventOfCurrentSampleFunc(self.getInstance())
+        assert(not _is_null(event))
+        if self.convert_to_str:
+            return EventStructUsingStr(event[0])
+        return event[0]
+
+    def GetSymbolOfCurrentSample(self):
+        symbol = self._GetSymbolOfCurrentSampleFunc(self.getInstance())
+        assert(not _is_null(symbol))
+        if self.convert_to_str:
+            return SymbolStructUsingStr(symbol[0])
+        return symbol[0]
+
+    def GetCallChainOfCurrentSample(self):
+        callchain = self._GetCallChainOfCurrentSampleFunc(self.getInstance())
+        assert(not _is_null(callchain))
+        if self.convert_to_str:
+            return CallChainStructureUsingStr(callchain[0])
+        return callchain[0]
+
+    def GetBuildIdForPath(self, path):
+        build_id = self._GetBuildIdForPathFunc(self.getInstance(), _char_pt(path))
+        assert(not _is_null(build_id))
+        return _char_pt_to_str(build_id)
+
+    def getInstance(self):
+        if self._instance is None:
+            raise Exception("Instance is Closed")
+        return self._instance
+
+    def _check(self, cond, failmsg):
+        if not cond:
+            raise Exception(failmsg)
+
+
+class TestReportLib(unittest.TestCase):
+    def setUp(self):
+        self.perf_data_path = os.path.join(os.path.dirname(get_script_dir()),
+                                           'testdata', 'perf_with_symbols.data')
+        if not os.path.isfile(self.perf_data_path):
+            raise Exception("can't find perf_data at %s" % self.perf_data_path)
+        self.report_lib = ReportLib()
+        self.report_lib.SetRecordFile(self.perf_data_path)
+
+    def tearDown(self):
+        self.report_lib.Close()
+
+    def test_build_id(self):
+        build_id = self.report_lib.GetBuildIdForPath('/data/t2')
+        self.assertEqual(build_id, '0x70f1fe24500fc8b0d9eb477199ca1ca21acca4de')
+
+    def test_symbol_addr(self):
+        found_func2 = False
+        while True:
+            sample = self.report_lib.GetNextSample()
+            if sample is None:
+                break
+            symbol = self.report_lib.GetSymbolOfCurrentSample()
+            if symbol.symbol_name == 'func2(int, int)':
+                found_func2 = True
+                self.assertEqual(symbol.symbol_addr, 0x4004ed)
+        self.assertTrue(found_func2)
+
+    def test_sample(self):
+        found_sample = False
+        while True:
+            sample = self.report_lib.GetNextSample()
+            if sample is None:
+                break
+            if sample.ip == 0x4004ff and sample.time == 7637889424953:
+                found_sample = True
+                self.assertEqual(sample.pid, 15926)
+                self.assertEqual(sample.tid, 15926)
+                self.assertEqual(sample.thread_comm, 't2')
+                self.assertEqual(sample.cpu, 5)
+                self.assertEqual(sample.period, 694614)
+                event = self.report_lib.GetEventOfCurrentSample()
+                self.assertEqual(event.name, 'cpu-cycles')
+                callchain = self.report_lib.GetCallChainOfCurrentSample()
+                self.assertEqual(callchain.nr, 0)
+        self.assertTrue(found_sample)
+
+
+def main():
+    test_all = True
+    if len(sys.argv) > 1 and sys.argv[1] == '--test-one':
+        test_all = False
+        del sys.argv[1]
+
+    if test_all:
+        subprocess.check_call(['python', os.path.realpath(__file__), '--test-one'])
+        subprocess.check_call(['python3', os.path.realpath(__file__), '--test-one'])
+    else:
+        sys.exit(unittest.main())
+
+
+if __name__ == '__main__':
+    main()
\ No newline at end of file
diff --git a/update.py b/update.py
index fb381a9..69e24f3 100755
--- a/update.py
+++ b/update.py
@@ -26,6 +26,41 @@
 THIS_DIR = os.path.realpath(os.path.dirname(__file__))
 
 
+class InstallEntry(object):
+    def __init__(self, target, name, install_path, need_strip=False):
+        self.target = target
+        self.name = name
+        self.install_path = install_path
+        self.need_strip = need_strip
+
+
+bin_install_list = [
+    # simpleperf on device
+    InstallEntry('sdk_arm64-sdk', 'simpleperf', 'android/arm64/simpleperf'),
+    InstallEntry('sdk_arm64-sdk', 'simpleperf32', 'android/arm/simpleperf'),
+    InstallEntry('sdk_x86_64-sdk', 'simpleperf', 'android/x86_64/simpleperf'),
+    InstallEntry('sdk_x86_64-sdk', 'simpleperf32', 'android/x86/simpleperf'),
+
+    # simpleperf on host
+    InstallEntry('sdk_arm64-sdk', 'simpleperf_host', 'linux/x86_64/simpleperf', True),
+    InstallEntry('sdk_arm64-sdk', 'simpleperf_host32', 'linux/x86/simpleperf', True),
+    InstallEntry('sdk_mac', 'simpleperf_host', 'darwin/x86_64/simpleperf'),
+    InstallEntry('sdk_mac', 'simpleperf_host32', 'darwin/x86/simpleperf'),
+    InstallEntry('sdk', 'simpleperf.exe', 'windows/x86_64/simpleperf.exe', True),
+    InstallEntry('sdk', 'simpleperf32.exe', 'windows/x86/simpleperf.exe', True),
+
+    # libsimpleperf_report.so on host
+    InstallEntry('sdk_arm64-sdk', 'libsimpleperf_report.so', 'linux/x86_64/libsimpleperf_report.so', True),
+    InstallEntry('sdk_arm64-sdk', 'libsimpleperf_report32.so', 'linux/x86/libsimpleperf_report.so', True),
+    InstallEntry('sdk_mac', 'libsimpleperf_report.dylib', 'darwin/x86_64/libsimpleperf_report.dylib'),
+    InstallEntry('sdk_mac', 'libsimpleperf_report32.so', 'darwin/x86/libsimpleperf_report.dylib'),
+    InstallEntry('sdk', 'libsimpleperf_report.dll', 'windows/x86_64/libsimpleperf_report.dll', True),
+    InstallEntry('sdk', 'libsimpleperf_report32.dll', 'windows/x86/libsimpleperf_report.dll', True),
+]
+
+script_install_entry = InstallEntry('sdk_arm64-sdk', 'simpleperf_script.zip', 'simpleperf_script.zip')
+
+
 def logger():
     """Returns the main logger for this module."""
     return logging.getLogger(__name__)
@@ -66,50 +101,68 @@
     check_call(['git', 'commit', '-m', message])
 
 
-def remove_old_release(install_dir):
+def list_prebuilts():
+    """List all prebuilts in current directory."""
+    result = []
+    if os.path.isdir('bin'):
+        result.append('bin')
+    for item in os.listdir('.'):
+        is_prebuilt = False
+        if os.path.isfile(item):
+            if item == 'README.md':
+                is_prebuilt = True
+            elif item.endswith('.py') and item != 'update.py':
+                is_prebuilt = True
+            elif item.endswith('.config'):
+                is_prebuilt = True
+        if is_prebuilt:
+            result.append(item)
+    return result
+
+
+def remove_old_release():
     """Removes the old prebuilts."""
-    if os.path.exists(install_dir):
-        logger().info('Removing old install directory "%s"', install_dir)
-        check_call(['git', 'rm', '-rf', '--ignore-unmatch', install_dir])
+    old_prebuilts = list_prebuilts()
+    if not old_prebuilts:
+        return
+    logger().info('Removing old prebuilts %s', old_prebuilts)
+    check_call(['git', 'rm', '-rf', '--ignore-unmatch'] + old_prebuilts)
 
     # Need to check again because git won't remove directories if they have
     # non-git files in them.
-    if os.path.exists(install_dir):
-        shutil.rmtree(install_dir)
+    for prebuilt in old_prebuilts:
+        if os.path.exists(prebuilt):
+            shutil.rmtree(prebuilt)
 
 
-def install_new_release(branch, build, install_dir):
+def install_new_release(branch, build):
     """Installs the new release."""
-    for arch in ('arm', 'arm64', 'x86', 'x86_64'):
-        install_device_components(branch, build, arch, install_dir)
-
-    install_simpleperf_report(branch, build)
+    for entry in bin_install_list:
+        install_entry(branch, build, 'bin', entry)
+    install_entry(branch, build, '.', script_install_entry)
     install_repo_prop(branch, build)
 
 
-def install_device_components(branch, build, arch, base_install_dir):
-    """Installs the device specific components of the release."""
-    install_dir = os.path.join(base_install_dir, arch)
-    os.makedirs(install_dir)
-
-    target = {
-        'arm': 'sdk_arm64-sdk',
-        'arm64': 'sdk_arm64-sdk',
-        'x86': 'sdk_x86_64-sdk',
-        'x86_64': 'sdk_x86_64-sdk',
-    }[arch]
-
-    name = {
-        'arm': 'simpleperf32',
-        'arm64': 'simpleperf',
-        'x86': 'simpleperf32',
-        'x86_64': 'simpleperf',
-    }[arch]
+def install_entry(branch, build, install_dir, entry):
+    """Installs one prebuilt file specified by entry."""
+    target = entry.target
+    name = entry.name
+    install_path = os.path.join(install_dir, entry.install_path)
+    need_strip = entry.need_strip
 
     fetch_artifact(branch, build, target, name)
     exe_stat = os.stat(name)
     os.chmod(name, exe_stat.st_mode | stat.S_IEXEC)
-    shutil.move(name, os.path.join(install_dir, 'simpleperf'))
+    if need_strip:
+        check_call(['strip', name])
+    dir = os.path.dirname(install_path)
+    if not os.path.isdir(dir):
+        os.makedirs(dir)
+    shutil.move(name, install_path)
+
+    if install_path.endswith('.zip'):
+        check_call(['unzip', install_path])
+        os.remove(install_path)
 
 
 def install_repo_prop(branch, build):
@@ -119,13 +172,6 @@
     fetch_artifact(branch, build, 'sdk', 'repo.prop')
 
 
-def install_simpleperf_report(branch, build):
-    """Installs simplepef_report.prop."""
-    # We took everything from the same build number, so we only need the
-    # repo.prop from one of our targets.
-    fetch_artifact(branch, build, 'sdk_arm64-sdk', 'simpleperf_report.py')
-
-
 def get_args():
     """Parses and returns command line arguments."""
     parser = argparse.ArgumentParser()
@@ -155,13 +201,11 @@
         verbosity = 2
     logging.basicConfig(level=verbose_map[verbosity])
 
-    install_dir = 'android'
-
     if not args.use_current_branch:
         start_branch(args.build)
-    remove_old_release(install_dir)
-    install_new_release(args.branch, args.build, install_dir)
-    artifacts = [install_dir, 'simpleperf_report.py', 'repo.prop']
+    remove_old_release()
+    install_new_release(args.branch, args.build)
+    artifacts = ['repo.prop'] + list_prebuilts()
     commit(args.branch, args.build, artifacts)
 
 
diff --git a/utils.py b/utils.py
new file mode 100644
index 0000000..ab76c3f
--- /dev/null
+++ b/utils.py
@@ -0,0 +1,148 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""utils.py: export utility functions.
+"""
+
+from __future__ import print_function
+import logging
+import os.path
+import subprocess
+import sys
+
+def get_script_dir():
+    return os.path.dirname(os.path.realpath(__file__))
+
+
+def is_windows():
+    return sys.platform == 'win32' or sys.platform == 'cygwin'
+
+
+def log_debug(msg):
+    logging.debug(msg)
+
+
+def log_info(msg):
+    logging.info(msg)
+
+
+def log_warning(msg):
+    logging.warning(msg)
+
+
+def log_fatal(msg):
+    raise Exception(msg)
+
+
+def get_target_binary_path(arch, binary_name):
+    if arch == 'aarch64':
+        arch = 'arm64'
+    arch_dir = os.path.join(get_script_dir(), "bin", "android", arch)
+    if not os.path.isdir(arch_dir):
+        log_fatal("can't find arch directory: %s" % arch_dir)
+    binary_path = os.path.join(arch_dir, binary_name)
+    if not os.path.isfile(binary_path):
+        log_fatal("can't find binary: %s" % binary_path)
+    return binary_path
+
+
+def get_host_binary_path(binary_name):
+    dir = os.path.join(get_script_dir(), 'bin')
+    if is_windows():
+        if binary_name.endswith('.so'):
+            binary_name = binary_name[0:-3] + '.dll'
+        dir = os.path.join(dir, 'windows')
+    elif sys.platform == 'darwin': # OSX
+        if binary_name.endswith('.so'):
+            binary_name = binary_name[0:-3] + '.dylib'
+        dir = os.path.join(dir, 'darwin')
+    else:
+        dir = os.path.join(dir, 'linux')
+    dir = os.path.join(dir, 'x86_64' if sys.maxsize > 2 ** 32 else 'x86')
+    binary_path = os.path.join(dir, binary_name)
+    if not os.path.isfile(binary_path):
+        log_fatal("can't find binary: %s" % binary_path)
+    return binary_path
+
+
+class AdbHelper(object):
+    def __init__(self, adb_path):
+        self.adb_path = adb_path
+
+
+    def run(self, adb_args):
+        return self.run_and_return_output(adb_args)[0]
+
+
+    def run_and_return_output(self, adb_args):
+        adb_args = [self.adb_path] + adb_args
+        log_debug('run adb cmd: %s' % adb_args)
+        subproc = subprocess.Popen(adb_args, stdout=subprocess.PIPE)
+        (stdoutdata, _) = subproc.communicate()
+        result = (subproc.returncode == 0)
+        if stdoutdata:
+            log_debug(stdoutdata)
+        log_debug('run adb cmd: %s  [result %s]' % (adb_args, result))
+        return (result, stdoutdata)
+
+
+    def check_run(self, adb_args):
+        self.check_run_and_return_output(adb_args)
+
+
+    def check_run_and_return_output(self, adb_args):
+        result, stdoutdata = self.run_and_return_output(adb_args)
+        if not result:
+            log_fatal('run "adb %s" failed' % adb_args)
+        return stdoutdata
+
+
+    def switch_to_root(self):
+        result, stdoutdata = self.run_and_return_output(['shell', 'whoami'])
+        if not result:
+            return False
+        if stdoutdata.find('root') != -1:
+            return True
+        build_type = self.get_property('ro.build.type')
+        if build_type == 'user':
+            return False
+        self.run(['root'])
+        result, stdoutdata = self.run_and_return_output(['shell', 'whoami'])
+        if result and stdoutdata.find('root') != -1:
+            return True
+        return False
+
+    def get_property(self, name):
+        result, stdoutdata = self.run_and_return_output(['shell', 'getprop', name])
+        if not result:
+            return None
+        return stdoutdata
+
+
+    def set_property(self, name, value):
+        return self.run(['shell', 'setprop', name, value])
+
+
+def load_config(config_file):
+    if not os.path.exists(config_file):
+        log_fatal("can't find config_file: %s" % config_file)
+    config = {}
+    execfile(config_file, config)
+    return config
+
+
+logging.getLogger().setLevel(logging.DEBUG)