Merge changes I2e5e7b51,I77914112,I8936d9d1,I63c8cf4f,I0a02eb43, ...

* changes:
  gn2bp: properly forward genrule dependency
  gn2bp: remove script from sources
  gn2bp: fix script location
  gn2bp: do not skip //buildtools and buildflag generation
  gn2bp: override deps before soong target is created
  gn2bp: start adding some verbose logging
  gn2bp: ignore copy targets in create_modules_from_target
  gn2bp: add basic action support
  gn2bp: explicitly make tool_files a list
  gn2bp: add basic parser support for copy and action_foreach rules
  gn2bp: allow targets to depend on chromium's libc++ and libunwind
diff --git a/tools/gn2bp/gen_android_bp b/tools/gn2bp/gen_android_bp
index b4942e6..1422b69 100755
--- a/tools/gn2bp/gen_android_bp
+++ b/tools/gn2bp/gen_android_bp
@@ -28,6 +28,7 @@
 import argparse
 import collections
 import json
+import logging as log
 import os
 import re
 import sys
@@ -338,7 +339,7 @@
     self.local_include_dirs = set()
     self.header_libs = set()
     self.required = set()
-    self.tool_files = None
+    self.tool_files = []
     self.android = Target('android')
     self.host = Target('host')
     self.stl = None
@@ -667,6 +668,33 @@
 
   blueprint.add_module(module)
 
+def create_action_module(blueprint, target):
+  bp_module_name = label_to_module_name(target.name)
+  module = Module('genrule', bp_module_name, target.name)
+  script = gn_utils.label_to_path(target.script)
+  module.tool_files = [script]
+
+  arg_string = ' '.join(target.args)
+  module.cmd = '$(location %s) %s' % (script, arg_string)
+
+  if all(os.path.splitext(it)[1] == '.h' for it in target.outputs):
+    module.genrule_headers.add(bp_module_name)
+
+  # For gn actions, sources and inputs are treated equally.
+  # TODO: there should be a label_to_path function that takes a set / list.
+  module.srcs.update(gn_utils.label_to_path(it) for it in target.inputs)
+  module.srcs.update(gn_utils.label_to_path(it) for it in target.sources)
+
+  # Actions using template "action_with_pydeps" also put script inside inputs.
+  # TODO: it might make sense to filter inputs inside GnParser.
+  if script in module.srcs:
+    module.srcs.remove(script)
+
+  module.out.update(target.outputs)
+  blueprint.add_module(module)
+  return module
+
+
 
 def _get_cflags(target):
   cflags = {flag for flag in target.cflags if re.match(cflag_allowlist, flag)}
@@ -690,6 +718,7 @@
   if bp_module_name in blueprint.modules:
     return blueprint.modules[bp_module_name]
   target = gn.get_target(gn_target_name)
+  log.info('create modules for %s (%s)', target.name, target.type)
 
   name_without_toolchain = gn_utils.label_without_toolchain(target.name)
   if target.type == 'executable':
@@ -723,7 +752,13 @@
         name_without_toolchain == gn_utils.GEN_VERSION_TARGET:
       module = create_gen_version_module(blueprint, target, bp_module_name)
     else:
-      raise Error('Unhandled action: {}'.format(target.name))
+      module = create_action_module(blueprint, target)
+  elif target.type == 'copy':
+    # TODO: careful now! copy targets are not supported yet, but this will stop
+    # traversing the dependency tree. For //base:base, this is not a big
+    # problem as libicu contains the only copy target which happens to be a
+    # leaf node.
+    return None
   else:
     raise Error('Unknown target %s (%s)' % (target.name, target.type))
 
@@ -779,17 +814,10 @@
   # dep_name is an unmangled GN target name (e.g. //foo:bar(toolchain)).
   all_deps = target.deps | target.source_set_deps | target.transitive_proto_deps
   for dep_name in all_deps:
-    # If the dependency refers to a library which we can replace with an
-    # Android equivalent, stop recursing and patch the dependency in.
-    # Don't recurse into //buildtools, builtin_deps are intercepted at
-    # the //gn:xxx level.
-    if dep_name.startswith('//buildtools'):
-      continue
-
-    # Ignore the dependency on the gen_buildflags genrule. That is run
-    # separately in this generator and the generated file is copied over
-    # into the repo (see usage of |buildflags_dir| in this script).
-    if dep_name.startswith(gn_utils.BUILDFLAGS_TARGET):
+    # |builtin_deps| override GN deps with Android-specific ones. See the
+    # config in the top of this file.
+    if gn_utils.label_without_toolchain(dep_name) in builtin_deps:
+      builtin_deps[gn_utils.label_without_toolchain(dep_name)](module)
       continue
 
     dep_module = create_modules_from_target(blueprint, gn, dep_name)
@@ -798,11 +826,6 @@
     if not module_is_compiled:
       continue
 
-    # |builtin_deps| override GN deps with Android-specific ones. See the
-    # config in the top of this file.
-    if gn_utils.label_without_toolchain(dep_name) in builtin_deps:
-      builtin_deps[gn_utils.label_without_toolchain(dep_name)](module)
-      continue
 
     # Don't recurse in any other //gn dep if not handled by builtin_deps.
     if dep_name.startswith('//gn:'):
@@ -869,12 +892,21 @@
       default=os.path.join(gn_utils.repo_root(), 'Android.bp'),
   )
   parser.add_argument(
+      '-v',
+      '--verbose',
+      help='Print debug logs.',
+      action='store_true',
+  )
+  parser.add_argument(
       'targets',
       nargs=argparse.REMAINDER,
       help='Targets to include in the blueprint (e.g., "//:perfetto_tests")'
   )
   args = parser.parse_args()
 
+  if args.verbose:
+    log.basicConfig(format='%(levelname)s:%(funcName)s:%(message)s', level=log.DEBUG)
+
   with open(args.desc) as f:
     desc = json.load(f)
 
diff --git a/tools/gn2bp/gn_utils.py b/tools/gn2bp/gn_utils.py
index 9cada7b..6cf5b7d 100644
--- a/tools/gn2bp/gn_utils.py
+++ b/tools/gn2bp/gn_utils.py
@@ -98,7 +98,7 @@
       self.name = name  # e.g. //src/ipc:ipc
 
       VALID_TYPES = ('static_library', 'shared_library', 'executable', 'group',
-                     'action', 'source_set', 'proto_library')
+                     'action', 'source_set', 'proto_library', 'copy', 'action_foreach')
       assert (type in VALID_TYPES)
       self.type = type
       self.testonly = False
@@ -185,10 +185,14 @@
     target.toolchain = desc.get('toolchain', None)
     self.all_targets[gn_target_name] = target
 
+    # TODO: determine if below comment should apply for cronet builds in Android.
     # We should never have GN targets directly depend on buidtools. They
     # should hop via //gn:xxx, so we can give generators an opportunity to
     # override them.
-    assert (not gn_target_name.startswith('//buildtools'))
+    # Specifically allow targets to depend on libc++ and libunwind.
+    if not any(match in gn_target_name for match in ['libc++', 'libunwind']):
+      assert (not gn_target_name.startswith('//buildtools'))
+
 
     # Don't descend further into third_party targets. Genrators are supposed
     # to either ignore them or route to other externally-provided targets.
@@ -211,7 +215,7 @@
     elif target.type in LINKER_UNIT_TYPES:
       self.linker_units[gn_target_name] = target
       target.sources.update(desc.get('sources', []))
-    elif target.type == 'action':
+    elif target.type in ['action', 'action_foreach']:
       self.actions[gn_target_name] = target
       target.inputs.update(desc.get('inputs', []))
       target.sources.update(desc.get('sources', []))
@@ -221,6 +225,9 @@
       # Args are typically relative to the root build dir (../../xxx)
       # because root build dir is typically out/xxx/).
       target.args = [re.sub('^../../', '//', x) for x in desc['args']]
+    elif target.type == 'copy':
+      # TODO: copy rules are not currently implemented.
+      self.actions[gn_target_name] = target
 
     # Default for 'public' is //* - all headers in 'sources' are public.
     # TODO(primiano): if a 'public' section is specified (even if empty), then
@@ -251,7 +258,7 @@
         target.update(dep)  # Bubble up source set's cflags/ldflags etc.
       elif dep.type == 'group':
         target.update(dep)  # Bubble up groups's cflags/ldflags etc.
-      elif dep.type == 'action':
+      elif dep.type in ['action', 'action_foreach', 'copy']:
         if proto_target_type is None:
           target.deps.add(dep_name)
       elif dep.type in LINKER_UNIT_TYPES: