std::vector ServiceSourceGenerator::emit_method_models()

in source/model-generator/ServiceSourceGenerator.cpp [49:114]


std::vector<Model> ServiceSourceGenerator::emit_method_models(
    const Methods& methods) {
  std::vector<Model> models;

  std::unordered_set<std::string> manifest_services = {};

  try {
    auto android_resources = create_resource_reader(options_.apk_directory());
    const auto manifest_class_info =
        android_resources->get_manifest_class_info();

    for (const auto& tag_info : manifest_class_info.component_tags) {
      if (tag_info.tag == ComponentTag::Service) {
        auto* dex_class = redex::get_class(tag_info.classname);
        if (dex_class) {
          std::unordered_set<std::string> parent_classes =
              generator::get_custom_parents_from_class(dex_class);
          for (const auto& parent_class : parent_classes) {
            auto manifest_class_start =
                parent_class.substr(0, parent_class.find(";", 0));
            manifest_services.emplace(manifest_class_start);
          }
        }
        auto manifest_class_start =
            tag_info.classname.substr(0, tag_info.classname.find(";", 0));
        manifest_services.emplace(manifest_class_start);
      }
    }
  } catch (const std::exception& e) {
    // Redex may assert, or throw `std::runtime_error` if the file is missing.
    ERROR(2, "Manifest could not be parsed: {}", e.what());
  }

  std::mutex mutex;
  std::unordered_map<DexClass*, bool> permission_services = {};
  auto queue = sparta::work_queue<const Method*>([&](const Method* method) {
    const auto method_name = generator::get_method_name(method);
    const auto argument_types = generator::get_argument_types(method);
    const auto class_name = generator::get_class_name(method);

    if (boost::starts_with(class_name, "Landroid") ||
        argument_types.size() < 1) {
      return;
    }

    if (boost::equals(method_name, "handleMessage") &&
        boost::contains(class_name, "ervice") && argument_types.size() == 1) {
      auto model = source_first_argument(method, context_);
      std::lock_guard<std::mutex> lock(mutex);
      models.push_back(model);
    }

    if (service_methods.find(method_name) != service_methods.end() &&
        manifest_services.find(generator::get_outer_class(class_name)) !=
            manifest_services.end()) {
      auto model = source_first_argument(method, context_);
      std::lock_guard<std::mutex> lock(mutex);
      models.push_back(model);
    }
  });
  for (const auto* method : methods) {
    queue.add_item(method);
  }
  queue.run_all();
  return models;
}