Merge "Add pre-upload style checker for cpp and java code"
diff --git a/iface_fuzzer/Android.bp b/iface_fuzzer/Android.bp
index 23bdce7..c273479 100644
--- a/iface_fuzzer/Android.bp
+++ b/iface_fuzzer/Android.bp
@@ -27,6 +27,7 @@
     ],
     shared_libs: [
         "libprotobuf-cpp-full",
+        "libvintf",
         "libvts_common",
         "libvts_multidevice_proto",
         "libvts_proto_fuzzer_proto",
diff --git a/iface_fuzzer/ProtoFuzzerMain.cpp b/iface_fuzzer/ProtoFuzzerMain.cpp
index 2975bf5..42803fe 100644
--- a/iface_fuzzer/ProtoFuzzerMain.cpp
+++ b/iface_fuzzer/ProtoFuzzerMain.cpp
@@ -80,8 +80,7 @@
       FindTargetCompSpec(params.comp_specs_, params.target_iface_);
   mutator = make_unique<ProtoFuzzerMutator>(
       random, ExtractPredefinedTypes(params.comp_specs_), mutator_config);
-  hal.reset(
-      InitHalDriver(target_comp_spec, params.service_name_, params.get_stub_));
+  hal.reset(InitHalDriver(target_comp_spec, params.binder_mode_));
   return 0;
 }
 
diff --git a/iface_fuzzer/ProtoFuzzerMutateFns.cpp b/iface_fuzzer/ProtoFuzzerMutateFns.cpp
index 416320f..9960dae 100644
--- a/iface_fuzzer/ProtoFuzzerMutateFns.cpp
+++ b/iface_fuzzer/ProtoFuzzerMutateFns.cpp
@@ -91,8 +91,9 @@
 
 VarInstance ProtoFuzzerMutator::ScalarRandomGen(const VarSpec &var_spec) {
   VarInstance result{VarInstanceStubFromSpec(var_spec)};
+  result.set_scalar_type(var_spec.scalar_type());
   (*result.mutable_scalar_value()) =
-      RandomGen(var_spec.scalar_value(), var_spec.scalar_type());
+      RandomGen(result.scalar_value(), result.scalar_type());
   return result;
 }
 
@@ -103,6 +104,58 @@
   return result;
 }
 
+VarInstance ProtoFuzzerMutator::StringRandomGen(const VarSpec &var_spec) {
+  VarInstance result{VarInstanceStubFromSpec(var_spec)};
+
+  size_t str_size = mutator_config_.default_string_size_;
+  string str(str_size, 0);
+  auto rand_char = std::bind(&ProtoFuzzerMutator::RandomAsciiChar, this);
+  std::generate_n(str.begin(), str_size, rand_char);
+
+  StringDataValueMessage string_data;
+  string_data.set_message(str.c_str());
+  string_data.set_length(str_size);
+
+  *result.mutable_string_value() = string_data;
+  return result;
+}
+
+VarInstance ProtoFuzzerMutator::StringMutate(const VarInstance &var_instance) {
+  VarInstance result{var_instance};
+  string str = result.string_value().message();
+  size_t str_size = result.string_value().length();
+
+  // Three things can happen when mutating a string:
+  // 1. A random char is inserted into a random position.
+  // 2. A randomly selected char is removed from the string.
+  // 3. A randomly selected char in the string is replaced by a random char.
+  size_t dice_roll = str.empty() ? 0 : rand_(3);
+  size_t idx = rand_(str_size);
+  switch (dice_roll) {
+    case 0:
+      // Insert a random char.
+      str.insert(str.begin() + idx, RandomAsciiChar());
+      ++str_size;
+      break;
+    case 1:
+      // Remove a randomly selected char.
+      str.erase(str.begin() + idx);
+      --str_size;
+      break;
+    case 2:
+      // Replace a randomly selected char.
+      str[idx] = RandomAsciiChar();
+      break;
+    default:
+      // Do nothing.
+      break;
+  }
+
+  result.mutable_string_value()->set_message(str);
+  result.mutable_string_value()->set_length(str_size);
+  return result;
+}
+
 VarInstance ProtoFuzzerMutator::StructRandomGen(const VarSpec &var_spec) {
   VarInstance result{VarInstanceStubFromSpec(var_spec)};
   const TypeSpec &blueprint = FindPredefinedType(result.predefined_type());
@@ -270,6 +323,16 @@
   return value;
 }
 
+char ProtoFuzzerMutator::RandomAsciiChar() {
+  const char char_set[] =
+      "0123456789"
+      "`~!@#$%^&*()-_=+[{]};:',<.>/? "
+      "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+      "abcdefghijklmnopqrstuvwxyz";
+  size_t num_chars = sizeof(char_set) - 1;
+  return char_set[rand_(num_chars)];
+}
+
 }  // namespace fuzzer
 }  // namespace vts
 }  // namespace android
diff --git a/iface_fuzzer/ProtoFuzzerMutator.cpp b/iface_fuzzer/ProtoFuzzerMutator.cpp
index a52b0c9..3a20976 100644
--- a/iface_fuzzer/ProtoFuzzerMutator.cpp
+++ b/iface_fuzzer/ProtoFuzzerMutator.cpp
@@ -61,11 +61,21 @@
   random_gen_fns_[TYPE_HIDL_INTERFACE] = default_transform;
   mutate_fns_[TYPE_HIDL_INTERFACE] = default_transform;
 
+  // Interpret masks as enums.
+  random_gen_fns_[TYPE_MASK] =
+      std::bind(&ProtoFuzzerMutator::EnumRandomGen, this, _1);
+  mutate_fns_[TYPE_MASK] = std::bind(&ProtoFuzzerMutator::EnumMutate, this, _1);
+
   random_gen_fns_[TYPE_SCALAR] =
       std::bind(&ProtoFuzzerMutator::ScalarRandomGen, this, _1);
   mutate_fns_[TYPE_SCALAR] =
       std::bind(&ProtoFuzzerMutator::ScalarMutate, this, _1);
 
+  random_gen_fns_[TYPE_STRING] =
+      std::bind(&ProtoFuzzerMutator::StringRandomGen, this, _1);
+  mutate_fns_[TYPE_STRING] =
+      std::bind(&ProtoFuzzerMutator::StringMutate, this, _1);
+
   random_gen_fns_[TYPE_STRUCT] =
       std::bind(&ProtoFuzzerMutator::StructRandomGen, this, _1);
   mutate_fns_[TYPE_STRUCT] =
diff --git a/iface_fuzzer/ProtoFuzzerUtils.cpp b/iface_fuzzer/ProtoFuzzerUtils.cpp
index 870f1a7..0a14a25 100644
--- a/iface_fuzzer/ProtoFuzzerUtils.cpp
+++ b/iface_fuzzer/ProtoFuzzerUtils.cpp
@@ -23,8 +23,12 @@
 #include <sstream>
 
 #include "specification_parser/InterfaceSpecificationParser.h"
+#include "vintf/HalManifest.h"
+#include "vintf/VintfObject.h"
 #include "utils/InterfaceSpecUtil.h"
 
+using android::vintf::HalManifest;
+
 using std::cout;
 using std::cerr;
 using std::string;
@@ -40,15 +44,20 @@
       stdout,
       "Usage:\n"
       "\n"
-      "./<fuzzer> <vts flags> -- <libfuzzer flags>\n"
+      "./vts_proto_fuzzer <vts flags> -- <libfuzzer flags>\n"
       "\n"
       "VTS flags (strictly in form --flag=value):\n"
       "\n"
-      " vts_spec_files \tColumn-separated list of paths to vts spec files.\n"
-      " vts_exec_size \t\tNumber of function calls per fuzzer execution.\n"
+      "\tvts_binder_mode: if set, fuzzer will open the HAL in binder mode.\n"
+      "\tvts_exec_size: number of function calls per 1 run of "
+      "LLVMFuzzerTestOneInput.\n"
+      "\tvts_spec_dir: \":\"-separated list of directories on the target "
+      "containing .vts spec files.\n"
+      "\tvts_target_iface: name of interface targeted for fuzz, e.g. "
+      "\"INfc\".\n"
       "\n"
       "libfuzzer flags (strictly in form -flag=value):\n"
-      " Use -help=1 to see libfuzzer flags\n"
+      "\tUse -help=1 to see libfuzzer flags\n"
       "\n");
 }
 
@@ -57,7 +66,6 @@
     {"vts_binder_mode", no_argument, 0, 'b'},
     {"vts_spec_dir", required_argument, 0, 'd'},
     {"vts_exec_size", required_argument, 0, 'e'},
-    {"vts_service_name", required_argument, 0, 's'},
     {"vts_target_iface", required_argument, 0, 't'}};
 
 static string GetDriverName(const CompSpec &comp_spec) {
@@ -70,9 +78,25 @@
 }
 
 static string GetServiceName(const CompSpec &comp_spec) {
-  // Infer HAL service name from its package name.
-  string prefix = "android.hardware.";
-  string service_name = comp_spec.package().substr(prefix.size());
+  static const HalManifest *vendor_manifest =
+      ::android::vintf::VintfObject::GetDeviceHalManifest();
+  string hal_name = comp_spec.package();
+  string iface_name = comp_spec.component_name();
+
+  auto instance_names = vendor_manifest->getInstances(hal_name, iface_name);
+  if (instance_names.empty()) {
+    cerr << "HAL service name not available in VINTF." << endl;
+    exit(1);
+  }
+
+  // For fuzzing we don't care which instance of the HAL is targeted.
+  string service_name = *instance_names.begin();
+  cout << "Available HAL instances: " << endl;
+  for (const string &instance_name : instance_names) {
+    cout << instance_name << endl;
+  }
+  cout << "Using HAL instance: " << service_name << endl;
+
   return service_name;
 }
 
@@ -90,23 +114,28 @@
   }
 }
 
-static vector<CompSpec> ExtractCompSpecs(string dir_path) {
+static vector<CompSpec> ExtractCompSpecs(string arg) {
   vector<CompSpec> result{};
-  DIR *dir;
-  struct dirent *ent;
-  if (!(dir = opendir(dir_path.c_str()))) {
-    cerr << "Could not open directory: " << dir_path << endl;
-    exit(1);
-  }
-  while ((ent = readdir(dir))) {
-    string vts_spec_name{ent->d_name};
-    if (vts_spec_name.find(".vts") != string::npos) {
-      cout << "Loading: " << vts_spec_name << endl;
-      string vts_spec_path = dir_path + "/" + vts_spec_name;
-      CompSpec comp_spec{};
-      InterfaceSpecificationParser::parse(vts_spec_path.c_str(), &comp_spec);
-      TrimCompSpec(&comp_spec);
-      result.emplace_back(std::move(comp_spec));
+  string dir_path;
+  std::istringstream iss(arg);
+
+  while (std::getline(iss, dir_path, ':')) {
+    DIR *dir;
+    struct dirent *ent;
+    if (!(dir = opendir(dir_path.c_str()))) {
+      cerr << "Could not open directory: " << dir_path << endl;
+      exit(1);
+    }
+    while ((ent = readdir(dir))) {
+      string vts_spec_name{ent->d_name};
+      if (vts_spec_name.find(".vts") != string::npos) {
+        cout << "Loading: " << vts_spec_name << endl;
+        string vts_spec_path = dir_path + "/" + vts_spec_name;
+        CompSpec comp_spec{};
+        InterfaceSpecificationParser::parse(vts_spec_path.c_str(), &comp_spec);
+        TrimCompSpec(&comp_spec);
+        result.emplace_back(std::move(comp_spec));
+      }
     }
   }
   return result;
@@ -131,7 +160,7 @@
         usage();
         exit(0);
       case 'b':
-        params.get_stub_ = false;
+        params.binder_mode_ = true;
         break;
       case 'd':
         params.comp_specs_ = ExtractCompSpecs(optarg);
@@ -139,9 +168,6 @@
       case 'e':
         params.exec_size_ = atoi(optarg);
         break;
-      case 's':
-        params.service_name_ = optarg;
-        break;
       case 't':
         params.target_iface_ = optarg;
         break;
@@ -171,8 +197,7 @@
 }
 
 // TODO(trong): this should be done using FuzzerWrapper.
-FuzzerBase *InitHalDriver(const CompSpec &comp_spec, string service_name,
-                          bool get_stub) {
+FuzzerBase *InitHalDriver(const CompSpec &comp_spec, bool binder_mode) {
   const char *error;
   string driver_name = GetDriverName(comp_spec);
   void *handle = dlopen(driver_name.c_str(), RTLD_LAZY);
@@ -194,16 +219,29 @@
   }
 
   FuzzerBase *hal = hal_loader();
+  string service_name = GetServiceName(comp_spec);
+  cerr << "HAL name: " << comp_spec.package() << endl
+       << "Interface name: " << comp_spec.component_name() << endl
+       << "Service name: " << service_name << endl;
+
   // For fuzzing, only passthrough mode provides coverage.
-  if (get_stub) {
-    cout << "HAL used in passthrough mode." << endl;
-  } else {
-    cout << "HAL used in binderized mode." << endl;
+  // If binder mode is not requested, attempt to open HAL in passthrough mode.
+  // If the attempt fails, fall back to binder mode.
+  if (!binder_mode) {
+    if (!hal->GetService(true, service_name.c_str())) {
+      cerr << __func__ << ": Failed to open HAL in passthrough mode. "
+           << "Falling back to binder mode." << endl;
+    } else {
+      cerr << "HAL opened in passthrough mode." << endl;
+      return hal;
+    }
   }
-  if (!hal->GetService(get_stub, service_name.c_str())) {
-    cerr << __func__ << ": GetService(true, " << service_name << ") failed."
-         << endl;
+
+  if (!hal->GetService(false, service_name.c_str())) {
+    cerr << __func__ << ": Failed to open HAL in binder mode." << endl;
     exit(1);
+  } else {
+      cerr << "HAL opened in binder mode." << endl;
   }
   return hal;
 }
@@ -215,6 +253,9 @@
     for (const auto &var_spec : comp_spec.attribute()) {
       ExtractPredefinedTypesFromVar(var_spec, predefined_types);
     }
+    for (const auto &var_spec : comp_spec.interface().attribute()) {
+      ExtractPredefinedTypesFromVar(var_spec, predefined_types);
+    }
   }
   return predefined_types;
 }
diff --git a/iface_fuzzer/include/ProtoFuzzerMutator.h b/iface_fuzzer/include/ProtoFuzzerMutator.h
index 90a0562..0609684 100644
--- a/iface_fuzzer/include/ProtoFuzzerMutator.h
+++ b/iface_fuzzer/include/ProtoFuzzerMutator.h
@@ -47,6 +47,8 @@
   Odds func_mutated_ = {100, 1};
   // Default size used to randomly generate a vector.
   size_t default_vector_size_ = 64;
+  // Default size used to randomly generate a string.
+  size_t default_string_size_ = 16;
 };
 
 // Provides methods for mutation or random generation.
@@ -75,6 +77,8 @@
   VarInstance EnumMutate(const VarInstance &);
   VarInstance ScalarRandomGen(const VarSpec &);
   VarInstance ScalarMutate(const VarInstance &);
+  VarInstance StringRandomGen(const VarSpec &);
+  VarInstance StringMutate(const VarInstance &);
   VarInstance StructRandomGen(const VarSpec &);
   VarInstance StructMutate(const VarInstance &);
   VarInstance UnionRandomGen(const VarSpec &);
@@ -95,6 +99,8 @@
   bool Mutate(bool);
   float Mutate(float);
   double Mutate(double);
+  // Generates a random ASCII character.
+  char RandomAsciiChar();
 
   // Looks up predefined type by name.
   const TypeSpec &FindPredefinedType(std::string);
diff --git a/iface_fuzzer/include/ProtoFuzzerUtils.h b/iface_fuzzer/include/ProtoFuzzerUtils.h
index b5516c3..afa978d 100644
--- a/iface_fuzzer/include/ProtoFuzzerUtils.h
+++ b/iface_fuzzer/include/ProtoFuzzerUtils.h
@@ -69,13 +69,11 @@
   size_t exec_size_;
   // VTS specs supplied to the fuzzer.
   std::vector<CompSpec> comp_specs_;
-  // Service name of target interface, e.g. "INfc".
-  std::string service_name_ = "default";
-  // Name of target interface, e.g. "default".
+  // Name of target interface, e.g. "INfc".
   std::string target_iface_;
   // Controls whether HAL is opened in passthrough or binder mode.
-  // Passthrough mode is default. Used for testsing.
-  bool get_stub_ = true;
+  // Passthrough mode is default. Used for testing.
+  bool binder_mode_ = false;
 };
 
 // Parses command-line flags to create a ProtoFuzzerParams instance.
@@ -85,7 +83,7 @@
 CompSpec FindTargetCompSpec(const std::vector<CompSpec> &, const std::string &);
 
 // Loads VTS HAL driver library.
-FuzzerBase *InitHalDriver(const CompSpec &, std::string, bool);
+FuzzerBase *InitHalDriver(const CompSpec &, bool);
 
 // Creates a key, value look-up table with keys being names of predefined types,
 // and values being their definitions.
diff --git a/template/iface_fuzzer_test/iface_fuzzer_test.py b/template/iface_fuzzer_test/iface_fuzzer_test.py
index 7733a8d..079c4c7 100644
--- a/template/iface_fuzzer_test/iface_fuzzer_test.py
+++ b/template/iface_fuzzer_test/iface_fuzzer_test.py
@@ -45,9 +45,11 @@
             hal_version: string, version of the hal, e.g '7.4'
         """
         # Push .vts spec files.
-        hal_name_dir = hal_name.replace('.', '/')
+        hal_name_dir = vts_spec_utils.HalNameDir(hal_name)
         src_dir = os.path.join(self.data_file_path, 'spec', 'hardware',
                                'interfaces', hal_name_dir, hal_version, 'vts')
+        dst_dir = os.path.join(self._VTS_SPEC_DIR_TARGET, hal_name_dir,
+                               hal_version)
 
         # Push corresponding VTS drivers.
         driver_name = 'android.hardware.%s@%s-vts.driver.so' % (hal_name,
@@ -56,37 +58,63 @@
         driver32 = os.path.join(asan_path, 'lib', driver_name)
         driver64 = os.path.join(asan_path, 'lib64', driver_name)
         try:
-            self._dut.adb.push(src_dir, self._VTS_SPEC_DIR_TARGET)
+            self._dut.adb.push(src_dir, dst_dir)
             self._dut.adb.push(driver32, 'data/local/tmp/32')
             self._dut.adb.push(driver64, 'data/local/tmp/64')
         except adb.AdbError as e:
             logging.exception(e)
 
+    def _VtsSpecDirsTarget(self, hal_name, hal_version):
+        """Returns a list of directories on target with .vts specs.
+
+        Args:
+            hal_name: string, name of the hal, e.g. 'vibrator'.
+            hal_version: string, version of the hal, e.g '7.4'
+
+        Returns:
+            string list, directories on target
+        """
+        hal_name_dir = vts_spec_utils.HalNameDir(hal_name)
+        spec_dirs = [os.path.join(self._VTS_SPEC_DIR_TARGET, hal_name_dir,
+                                  hal_version)]
+
+        imported_hals = self._vts_spec_parser.ImportedHals(hal_name,
+                                                           hal_version)
+        for name, version in imported_hals:
+            spec_dirs.append(
+                os.path.join(self._VTS_SPEC_DIR_TARGET,
+                             vts_spec_utils.HalNameDir(name), version))
+        return spec_dirs
+
     # Override
     def CreateTestCases(self):
         """See base class."""
         hal_package = self.hal_hidl_package_name
         hal_name, hal_version = vts_spec_utils.HalPackageToNameAndVersion(
             hal_package)
+
+        imported_hals = self._vts_spec_parser.ImportedHals(hal_name,
+                                                           hal_version)
         self._PushVtsResources(hal_name, hal_version)
-        vts_spec_names = self._vts_spec_parser.VtsSpecNames(hal_name,
-                                                            hal_version)
-        registered_interfaces = self._RegisteredInterfaces(
-            self.hal_hidl_package_name)
+        for name, version in imported_hals:
+            self._PushVtsResources(name, version)
+
+        registered_interfaces = self._RegisteredInterfaces(hal_package)
+        spec_dirs = ':'.join(self._VtsSpecDirsTarget(hal_name, hal_version))
 
         test_cases = []
         for iface in registered_interfaces:
             additional_params = {
-                'vts_spec_dir': self._VTS_SPEC_DIR_TARGET,
-                'vts_exec_size': 128,
+                'vts_spec_dir': spec_dirs,
+                'vts_exec_size': 16,
                 'vts_target_iface': iface,
             }
             libfuzzer_params = {
                 'max_len': 65536,
-                'max_total_time': 1,
+                'max_total_time': 10,
             }
             bin_host_path = os.path.join(self.data_file_path, 'DATA', 'bin',
-                                           'vts_proto_fuzzer')
+                                         'vts_proto_fuzzer')
             test_case = libfuzzer_test_case.LibFuzzerTestCase(
                 bin_host_path, libfuzzer_params, additional_params)
             test_case.test_name = iface
diff --git a/template/libfuzzer_test/libfuzzer_test_config.py b/template/libfuzzer_test/libfuzzer_test_config.py
index d191404..c330f48 100644
--- a/template/libfuzzer_test/libfuzzer_test_config.py
+++ b/template/libfuzzer_test/libfuzzer_test_config.py
@@ -37,5 +37,6 @@
 FUZZER_DEFAULT_PARAMS = {
     "max_len": 100,
     "max_total_time": 60,
-    "exact_artifact_path": FUZZER_TEST_CRASH_REPORT
+    "exact_artifact_path": FUZZER_TEST_CRASH_REPORT,
+    "timeout": 120,
 }