void PassManager::run_passes(DexStoresVector& stores, ConfigFiles& conf) { DexStoreClassesIterator it(stores); Scope scope = build_class_scope(it); { Timer t("API Level Checker"); api::LevelChecker::init(m_redex_options.min_sdk, scope); } char* seeds_output_file = std::getenv("REDEX_SEEDS_FILE"); if (seeds_output_file) { std::string seed_filename = seeds_output_file; Timer t("Writing seeds file " + seed_filename); std::ofstream seeds_file(seed_filename); redex::print_seeds(seeds_file, conf.get_proguard_map(), scope, false, false); } if (!conf.get_printseeds().empty()) { Timer t("Writing seeds to file " + conf.get_printseeds()); std::ofstream seeds_file(conf.get_printseeds()); redex::print_seeds(seeds_file, conf.get_proguard_map(), scope); std::ofstream config_file(conf.get_printseeds() + ".pro"); redex::show_configuration(config_file, scope, *m_pg_config); std::ofstream incoming(conf.get_printseeds() + ".incoming"); redex::print_classes(incoming, conf.get_proguard_map(), scope); std::ofstream shrinking_file(conf.get_printseeds() + ".allowshrinking"); redex::print_seeds(shrinking_file, conf.get_proguard_map(), scope, true, false); std::ofstream obfuscation_file(conf.get_printseeds() + ".allowobfuscation"); redex::print_seeds(obfuscation_file, conf.get_proguard_map(), scope, false, true); } // Enable opt decision logging if specified in config. const Json::Value& opt_decisions_args = conf.get_json_config()["opt_decisions"]; if (opt_decisions_args.get("enable_logs", false).asBool()) { opt_metadata::OptDataMapper::get_instance().enable_logs(); } // Load configurations regarding the scope. conf.load(scope); // TODO(fengliu) : Remove Pass::eval_pass API for (size_t i = 0; i < m_activated_passes.size(); ++i) { Pass* pass = m_activated_passes[i]; TRACE(PM, 1, "Evaluating %s...\n", pass->name().c_str()); Timer t(pass->name() + " (eval)"); m_current_pass_info = &m_pass_info[i]; pass->eval_pass(stores, conf, *this); m_current_pass_info = nullptr; } // Retrieve the type checker's settings. const Json::Value& type_checker_args = conf.get_json_config()["ir_type_checker"]; bool run_after_each_pass = type_checker_args.get("run_after_each_pass", false).asBool(); // When verify_none is enabled, it's OK to have polymorphic constants. bool polymorphic_constants = type_checker_args.get("polymorphic_constants", false).asBool() || get_redex_options().verify_none_enabled; bool verify_moves = type_checker_args.get("verify_moves", false).asBool(); bool check_no_overwrite_this = type_checker_args.get("check_no_overwrite_this", false).asBool(); std::unordered_set<std::string> trigger_passes; for (auto& trigger_pass : type_checker_args["run_after_passes"]) { trigger_passes.insert(trigger_pass.asString()); } for (size_t i = 0; i < m_activated_passes.size(); ++i) { Pass* pass = m_activated_passes[i]; TRACE(PM, 1, "Running %s...\n", pass->name().c_str()); Timer t(pass->name() + " (run)"); m_current_pass_info = &m_pass_info[i]; { ScopedCommandProfiling cmd_prof( m_profiler_info && m_profiler_info->pass == pass ? boost::make_optional(m_profiler_info->command) : boost::none); jemalloc_util::ScopedProfiling malloc_prof(m_malloc_profile_pass == pass); pass->run_pass(stores, conf, *this); } if (run_after_each_pass || trigger_passes.count(pass->name()) > 0) { scope = build_class_scope(it); // It's OK to overwrite the `this` register if we are not yet at the // output phase -- the register allocator can fix it up later. run_type_checker(scope, polymorphic_constants, verify_moves, /* check_no_overwrite_this */ false); } m_current_pass_info = nullptr; } // Always run the type checker before generating the optimized dex code. scope = build_class_scope(it); run_type_checker(scope, polymorphic_constants, verify_moves, check_no_overwrite_this); if (!conf.get_printseeds().empty()) { Timer t("Writing outgoing classes to file " + conf.get_printseeds() + ".outgoing"); // Recompute the scope. scope = build_class_scope(it); std::ofstream outgoing(conf.get_printseeds() + ".outgoing"); redex::print_classes(outgoing, conf.get_proguard_map(), scope); } }