source/model-generator/ServiceSourceGenerator.cpp (91 lines of code) (raw):

/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #include <exception> #include <mutex> #include <boost/algorithm/string.hpp> #include <Walkers.h> #include <mariana-trench/Dependencies.h> #include <mariana-trench/Log.h> #include <mariana-trench/Redex.h> #include <mariana-trench/model-generator/ServiceSourceGenerator.h> namespace marianatrench { namespace { std::unordered_set<std::string> service_methods = { "onBind", "onRebind", "onStart", "onHandleIntent", "onHandleWork", "onStartCommand", "onTaskRemoved", "onUnbind", "handleMessage"}; Model source_first_argument(const Method* method, Context& context) { auto model = Model(method, context); model.add_mode(Model::Mode::NoJoinVirtualOverrides, context); model.add_parameter_source( AccessPath(Root(Root::Kind::Argument, 1)), generator::source( context, method, /* kind */ "ServiceUserInput")); return model; } } // namespace 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; } } // namespace marianatrench