Merge "ClatCoordinatorTest: override test generateIpv6Address correctly"
diff --git a/bpf_progs/netd.c b/bpf_progs/netd.c
index 10559dd..55856c1 100644
--- a/bpf_progs/netd.c
+++ b/bpf_progs/netd.c
@@ -101,6 +101,10 @@
     DEFINE_BPF_PROG_EXT(SECTION_NAME, prog_uid, prog_gid, the_prog, \
                         KVER_NONE, KVER_INF, false, "fs_bpf_netd_readonly", "")
 
+#define DEFINE_NETD_BPF_PROG_KVER(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv) \
+    DEFINE_BPF_PROG_EXT(SECTION_NAME, prog_uid, prog_gid, the_prog, \
+                        min_kv, KVER_INF, false, "fs_bpf_netd_readonly", "")
+
 // programs that only need to be usable by the system server
 #define DEFINE_SYS_BPF_PROG(SECTION_NAME, prog_uid, prog_gid, the_prog) \
     DEFINE_BPF_PROG_EXT(SECTION_NAME, prog_uid, prog_gid, the_prog, \
@@ -419,7 +423,8 @@
     return BPF_NOMATCH;
 }
 
-DEFINE_NETD_BPF_PROG("cgroupsock/inet/create", AID_ROOT, AID_ROOT, inet_socket_create)
+DEFINE_NETD_BPF_PROG_KVER("cgroupsock/inet/create", AID_ROOT, AID_ROOT, inet_socket_create,
+                          KVER(4, 14, 0))
 (struct bpf_sock* sk) {
     uint64_t gid_uid = bpf_get_current_uid_gid();
     /*
diff --git a/netd/BpfHandler.cpp b/netd/BpfHandler.cpp
index 3f7ed2a..7950ff7 100644
--- a/netd/BpfHandler.cpp
+++ b/netd/BpfHandler.cpp
@@ -87,7 +87,16 @@
     RETURN_IF_NOT_OK(checkProgramAccessible(XT_BPF_INGRESS_PROG_PATH));
     RETURN_IF_NOT_OK(attachProgramToCgroup(BPF_EGRESS_PROG_PATH, cg_fd, BPF_CGROUP_INET_EGRESS));
     RETURN_IF_NOT_OK(attachProgramToCgroup(BPF_INGRESS_PROG_PATH, cg_fd, BPF_CGROUP_INET_INGRESS));
-    RETURN_IF_NOT_OK(attachProgramToCgroup(CGROUP_SOCKET_PROG_PATH, cg_fd, BPF_CGROUP_INET_SOCK_CREATE));
+
+    // For the devices that support cgroup socket filter, the socket filter
+    // should be loaded successfully by bpfloader. So we attach the filter to
+    // cgroup if the program is pinned properly.
+    // TODO: delete the if statement once all devices should support cgroup
+    // socket filter (ie. the minimum kernel version required is 4.14).
+    if (!access(CGROUP_SOCKET_PROG_PATH, F_OK)) {
+        RETURN_IF_NOT_OK(
+                attachProgramToCgroup(CGROUP_SOCKET_PROG_PATH, cg_fd, BPF_CGROUP_INET_SOCK_CREATE));
+    }
     return netdutils::status::ok;
 }
 
diff --git a/tests/mts/bpf_existence_test.cpp b/tests/mts/bpf_existence_test.cpp
index bb07a98..aa5654a 100644
--- a/tests/mts/bpf_existence_test.cpp
+++ b/tests/mts/bpf_existence_test.cpp
@@ -105,7 +105,6 @@
     SHARED "prog_clatd_schedcls_ingress6_clat_rawip",
     NETD "prog_netd_cgroupskb_egress_stats",
     NETD "prog_netd_cgroupskb_ingress_stats",
-    NETD "prog_netd_cgroupsock_inet_create",
     NETD "prog_netd_schedact_ingress_account",
     NETD "prog_netd_skfilter_allowlist_xtbpf",
     NETD "prog_netd_skfilter_denylist_xtbpf",
@@ -113,6 +112,11 @@
     NETD "prog_netd_skfilter_ingress_xtbpf",
 };
 
+// Provided by *current* mainline module for T+ devices with 4.14+ kernels
+static const set<string> MAINLINE_FOR_T_4_14_PLUS = {
+    NETD "prog_netd_cgroupsock_inet_create",
+};
+
 // Provided by *current* mainline module for T+ devices with 5.4+ kernels
 static const set<string> MAINLINE_FOR_T_5_4_PLUS = {
     SHARED "prog_block_bind4_block_port",
@@ -151,6 +155,7 @@
     // Nothing added or removed in SCv2.
 
     DO_EXPECT(IsAtLeastT(), MAINLINE_FOR_T_PLUS);
+    DO_EXPECT(IsAtLeastT() && isAtLeastKernelVersion(4, 14, 0), MAINLINE_FOR_T_4_14_PLUS);
     DO_EXPECT(IsAtLeastT() && isAtLeastKernelVersion(5, 4, 0), MAINLINE_FOR_T_5_4_PLUS);
     DO_EXPECT(IsAtLeastT() && isAtLeastKernelVersion(5, 15, 0), MAINLINE_FOR_T_5_15_PLUS);
 }
diff --git a/tools/gn2bp/gen_android_bp b/tools/gn2bp/gen_android_bp
index 1422b69..ee092db 100755
--- a/tools/gn2bp/gen_android_bp
+++ b/tools/gn2bp/gen_android_bp
@@ -339,7 +339,7 @@
     self.local_include_dirs = set()
     self.header_libs = set()
     self.required = set()
-    self.tool_files = []
+    self.tool_files = set()
     self.android = Target('android')
     self.host = Target('host')
     self.stl = None
@@ -467,7 +467,7 @@
 
 def is_supported_source_file(name):
   """Returns True if |name| can appear in a 'srcs' list."""
-  return os.path.splitext(name)[1] in ['.c', '.cc', '.proto']
+  return os.path.splitext(name)[1] in ['.c', '.cc', '.java', '.proto']
 
 
 def create_proto_modules(blueprint, gn, target):
@@ -598,9 +598,7 @@
 def create_amalgamated_sql_metrics_module(blueprint, target):
   bp_module_name = label_to_module_name(target.name)
   module = Module('genrule', bp_module_name, target.name)
-  module.tool_files = [
-      'tools/gen_amalgamated_sql_metrics.py',
-  ]
+  module.tool_files.add('tools/gen_amalgamated_sql_metrics.py')
   module.cmd = ' '.join([
       '$(location tools/gen_amalgamated_sql_metrics.py)',
       '--cpp_out=$(out)',
@@ -616,9 +614,7 @@
 def create_cc_proto_descriptor_module(blueprint, target):
   bp_module_name = label_to_module_name(target.name)
   module = Module('genrule', bp_module_name, target.name)
-  module.tool_files = [
-      'tools/gen_cc_proto_descriptor.py',
-  ]
+  module.tool_files.add('tools/gen_cc_proto_descriptor.py')
   module.cmd = ' '.join([
       '$(location tools/gen_cc_proto_descriptor.py)', '--gen_dir=$(genDir)',
       '--cpp_out=$(out)', '$(in)'
@@ -639,7 +635,7 @@
   module = Module('genrule', bp_module_name, gn_utils.GEN_VERSION_TARGET)
   script_path = gn_utils.label_to_path(target.script)
   module.genrule_headers.add(bp_module_name)
-  module.tool_files = [script_path]
+  module.tool_files.add(script_path)
   module.out.update(target.outputs)
   module.srcs.update(gn_utils.label_to_path(src) for src in target.inputs)
   module.cmd = ' '.join([
@@ -668,22 +664,39 @@
 
   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]
+  module.tool_files.add(script)
+
+  # Handle passing parameters via response file by piping them into the script
+  # and reading them from /dev/stdin.
+  response_file = '{{response_file_name}}'
+  use_response_file = response_file in target.args
+  if use_response_file:
+    # Replace {{response_file_contents}} with /dev/stdin
+    target.args = ['/dev/stdin' if it == response_file else it for it in target.args]
 
   arg_string = ' '.join(target.args)
   module.cmd = '$(location %s) %s' % (script, arg_string)
 
+  if use_response_file:
+    # Pipe response file contents into script
+    module.cmd = 'echo \'%s\' | %s' % (target.response_file_contents, module.cmd)
+
   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)
+  # gn treats inputs and sources for actions equally.
+  # soong only supports source files inside srcs, non-source files are added as
+  # tool_files dependency.
+  for it in target.sources or target.inputs:
+    if is_supported_source_file(it):
+      module.srcs.add(gn_utils.label_to_path(it))
+    else:
+      module.tool_files.add(gn_utils.label_to_path(it))
 
   # Actions using template "action_with_pydeps" also put script inside inputs.
   # TODO: it might make sense to filter inputs inside GnParser.
@@ -826,11 +839,6 @@
     if not module_is_compiled:
       continue
 
-
-    # Don't recurse in any other //gn dep if not handled by builtin_deps.
-    if dep_name.startswith('//gn:'):
-      continue
-
     if dep_module is None:
       continue
     if dep_module.type == 'cc_library_shared':
diff --git a/tools/gn2bp/gn_utils.py b/tools/gn2bp/gn_utils.py
index 6cf5b7d..ef3bf55 100644
--- a/tools/gn2bp/gn_utils.py
+++ b/tools/gn2bp/gn_utils.py
@@ -120,6 +120,7 @@
       self.outputs = set()
       self.script = None
       self.args = []
+      self.response_file_contents = None
 
       # These variables are propagated up when encountering a dependency
       # on a source_set target.
@@ -169,6 +170,13 @@
     self.actions = {}
     self.proto_libs = {}
 
+  def _get_response_file_contents(self, action_desc):
+    contents = ' '.join(action_desc.get('response_file_contents', []))
+    # escape both single and double quotes.
+    contents.replace('"', '\"')
+    contents.replace("'", '\'')
+    return contents
+
   def get_target(self, gn_target_name):
     """Returns a Target object from the fully qualified GN target name.
 
@@ -225,6 +233,7 @@
       # 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']]
+      target.response_file_contents = self._get_response_file_contents(desc)
     elif target.type == 'copy':
       # TODO: copy rules are not currently implemented.
       self.actions[gn_target_name] = target