Add script to extract format files

Adds a Python script which extracts all files matching:

/sys/kernel/debug/tracing/events/*/*/format

From an Android device into a directory named:

android_productname_buildid_kernelversion
(e.g. android_seed_N2F62_3.10.49)

The layout of the directory matches
/sys/kernel/debug/tracing/events except it only contains the
'format' files.

Usage:
$ .tools/extract_formats.py
$ ls
android_seed_N2F62_3.10.49
$ find . -type f | grep sched_switch
android_seed_N2F62_3.10.49/perf_trace_counters/sched_switch_with_ctrs/format
android_seed_N2F62_3.10.49/sched/sched_switch/format

Change-Id: If5beb4ea98bd7f7f710bcb6ca5d33a919339a4fc
diff --git a/tools/pull_ftrace_format_files.py b/tools/pull_ftrace_format_files.py
new file mode 100755
index 0000000..8cd27f6
--- /dev/null
+++ b/tools/pull_ftrace_format_files.py
@@ -0,0 +1,142 @@
+#!/usr/bin/env python
+# Copyright (C) 2017 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.
+
+from __future__ import print_function
+import argparse
+import datetime
+import os
+import subprocess
+import sys
+
+"""Pulls all format files from an Android device.
+
+Usage: ./tools/pull_ftrace_format_files.py [-s serial] [-p directory_prefix]
+"""
+
+ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+ADB_PATH = os.path.join(ROOT_DIR, 'buildtools/android_sdk/platform-tools/adb')
+
+def adb(*cmd, **kwargs):
+  serial = kwargs.get('serial', None)
+  prefix = [ADB_PATH]
+  if serial:
+    prefix += ['-s', serial]
+  cmd = prefix + list(cmd)
+  output = subprocess.check_output(cmd)
+  return output
+
+
+def get_devices():
+  #  adb devices output looks like:
+  #    List of devices attached
+  #    557dccd8\tdevice
+  #  With a trailing newline.
+  serials = [s.split('\t')[0] for s in adb('devices').split('\n')[1:] if s]
+  return serials
+
+
+def ensure_output_directory_empty(path):
+  if os.path.isfile(path):
+    print('The output directory {} exists as a file.'.format(path))
+    sys.exit(1)
+
+  if os.path.isdir(path) and os.listdir(path):
+    print('The output directory {} exists but is not empty.'.format(path))
+    sys.exit(1)
+
+  if not os.path.isdir(path):
+    os.makedirs(path)
+
+
+def ensure_dir(path):
+  try:
+    os.makedirs(path)
+  except OSError:
+    if not os.path.isdir(path):
+      raise
+
+
+def ensure_single_device(serial):
+  serials = get_devices()
+  if serial is None and len(serials) == 1:
+    return serials[0]
+
+  if serial in serials:
+    return serial
+
+  if not serials:
+    print('No devices connected.')
+  elif serial is None:
+    print('More than one device connected, use -s.')
+  else:
+    print('No device with serial {} found.'.format(serial))
+  sys.exit(1)
+
+
+def pull_format_files(serial, output_directory):
+  # Pulling each file individually is 100x slower so we pipe all together then
+  # split them on the host.
+  cmd = "find /sys/kernel/debug/tracing/events/ " \
+      "-name format -o " \
+      "-name header_event -o " \
+      "-name header_page | " \
+      "while read f; do echo 'path:' $f; cat $f; done"
+
+  output = adb('shell', cmd, serial=serial)
+  sections = output.split('path: /sys/kernel/debug/tracing/events/')
+  for section in sections:
+    if not section:
+      continue
+    path, rest = section.split('\n', 1)
+    path = os.path.join(output_directory, path)
+    ensure_dir(os.path.dirname(path))
+    with open(path, 'wb') as f:
+      f.write(rest)
+
+
+# Produces output of the form: prefix_android_seed_N2F62_3.10.49
+def get_output_directory(prefix=None):
+  build_id = adb('shell', 'getprop', 'ro.build.id').replace('\n', '')
+  product = adb('shell', 'getprop', 'ro.build.product').replace('\n', '')
+  kernel = adb('shell', 'uname', '-r').split('-')[0]
+  parts = ['android', product, build_id, kernel]
+  if prefix:
+    parts = [prefix] + parts
+  return '_'.join(parts)
+
+
+def main():
+  parser = argparse.ArgumentParser(description='Pull format files.')
+  parser.add_argument('-p', dest='prefix', default=None,
+                      help='the output directory prefix')
+  parser.add_argument('-s', dest='serial', default=None,
+                      help='use device with the given serial')
+  args = parser.parse_args()
+
+  prefix = args.prefix
+  serial = args.serial
+
+  serial = ensure_single_device(serial)
+  output_directory = get_output_directory(prefix)
+
+  ensure_output_directory_empty(output_directory)
+  pull_format_files(serial, output_directory)
+
+  return 0
+
+
+if __name__ == '__main__':
+    sys.exit(main())
+