Example #1
0
void PassImpl::run_pass(DexStoresVector& stores,
                        ConfigFiles& config,
                        PassManager& mgr) {
  if (m_config.create_runtime_asserts) {
    m_config.runtime_assert =
        RuntimeAssertTransform::Config(config.get_proguard_map());
  }

  auto scope = build_class_scope(stores);
  run(scope);
  mgr.incr_metric("branches_removed", m_transform_stats.branches_removed);
  mgr.incr_metric("materialized_consts", m_transform_stats.materialized_consts);
  mgr.incr_metric("constant_fields", m_stats.constant_fields);
  mgr.incr_metric("constant_methods", m_stats.constant_methods);
}
Example #2
0
void StaticSinkPass::run_pass(DexClassesVector& dexen, ConfigFiles& cfg) {
  auto method_list = cfg.get_coldstart_methods();
  auto methods = strings_to_dexmethods(method_list);
  TRACE(SINK, 1, "methods used in coldstart: %lu\n", methods.size());
  auto coldstart_classes = get_coldstart_classes(dexen, cfg);
  count_coldstart_statics(coldstart_classes);
  auto statics = get_noncoldstart_statics(coldstart_classes, methods);
  TRACE(SINK, 1, "statics not used in coldstart: %lu\n", statics.size());
  remove_primary_dex_refs(dexen[0], statics);
  TRACE(SINK, 1, "statics after removing primary dex: %lu\n", statics.size());
  auto sink_map = get_sink_map(dexen, coldstart_classes, statics);
  TRACE(SINK, 1, "statics with sinkable callsite: %lu\n", sink_map.size());
  auto holder = move_statics_out(statics, sink_map);
  TRACE(SINK, 1, "methods in static holder: %lu\n",
          holder->get_dmethods().size());
  DexClasses dc(1);
  dc.insert_at(holder, 0);
  dexen.emplace_back(std::move(dc));
}
Example #3
0
/*
 * Format: array of "Lpkg/Class;"
 */
std::unordered_set<DexType*> keep_class_member_annos(
  const std::vector<std::string>& annos,
  ConfigFiles& cfg
) {
  std::unordered_set<DexType*> keep;
  for (const auto& anno : cfg.get_no_optimizations_annos()) {
    keep.emplace(anno);
  }
  try {
    for (auto const& keep_anno : annos) {
      auto type = DexType::get_type(DexString::get_string(keep_anno.c_str()));
      if (type != nullptr) {
        keep.emplace(type);
      }
    }
  } catch (...) {
    // Swallow exception if the field isn't there.
  }
  return keep;
}
Example #4
0
void AddRedexTxtToApkPass::run_pass(DexStoresVector& /* unused */,
                                    ConfigFiles& conf,
                                    PassManager& /* unused */) {
  std::string apk_dir;
  conf.get_json_config().get("apk_dir", "", apk_dir);

  if (!apk_dir.size()) {
    TRACE(ADD_REDEX_TXT, 2, "apk_dir not set, so not writing redex.txt\n");
    return;
  }
  std::string out_file_name = apk_dir + "/redex.txt";
  std::ofstream redex_txt(out_file_name);
  if (redex_txt.is_open()) {
    redex_txt << "Optimized by Redex" << std::endl
              << "http://fbredex.com/" << std::endl;
    redex_txt.close();
  } else {
    opt_warn(CANT_WRITE_FILE, "Unable to write file %s\n", out_file_name.c_str());
  }
}
Example #5
0
void PassManager::run_passes(DexClassesVector& dexen, ConfigFiles& cfg) {
  init_reachable_classes(build_class_scope(dexen), m_config,
      m_proguard_rules, cfg.get_no_optimizations_annos());
  Scope scope = build_class_scope(dexen);
  // reportReachableClasses(scope, "reachable");
  for (auto pass : m_activated_passes) {
    using namespace std::chrono;
    TRACE(PM, 1, "Running %s...\n", pass->name().c_str());
    m_current_pass_metrics = &m_pass_metrics[pass->name()];
    auto start = high_resolution_clock::now();
    if (pass->assumes_sync()) {
      MethodTransform::sync_all();
    }
    pass->run_pass(dexen, cfg, *this);
    auto end = high_resolution_clock::now();
    TRACE(PM, 1, "Pass %s completed in %.1lf seconds\n",
          pass->name().c_str(), duration<double>(end - start).count());
    m_current_pass_metrics = nullptr;
  }

  MethodTransform::sync_all();
}
Example #6
0
void RenameClassesPass::run_pass(DexStoresVector& stores,
                                 ConfigFiles& cfg,
                                 PassManager& mgr) {
  const JsonWrapper& json_cfg = cfg.get_json_config();
  if (json_cfg.get("emit_name_based_locators", false)) {
    // TODO: Purge the old RenameClassesPass entirely everywhere.
    fprintf(stderr,
            "[RenameClassesPass] error: Configuration option "
            "emit_locator_strings is not compatible with RenameClassesPass. "
            "Upgrade to RenameClassesPassV2 instead.\n");
    exit(EXIT_FAILURE);
  }

  auto scope = build_class_scope(stores);
  ClassHierarchy ch = build_type_hierarchy(scope);
  std::unordered_set<const DexType*> untouchables;
  for (const auto& base : m_untouchable_hierarchies) {
    auto base_type = DexType::get_type(base.c_str());
    if (base_type != nullptr) {
      untouchables.insert(base_type);
      TypeSet children;
      get_all_children(ch, base_type, children);
      untouchables.insert(children.begin(), children.end());
    }
  }
  mgr.incr_metric(METRIC_CLASSES_IN_SCOPE, scope.size());
  rename_classes(
      scope, m_pre_filter_whitelist, m_post_filter_whitelist,
      untouchables, m_rename_annotations, mgr);
  TRACE(RENAME, 1,
      "renamed classes: %d anon classes, %d from single char patterns, "
      "%d from multi char patterns\n",
      match_inner,
      match_short,
      match_long);
  TRACE(RENAME, 1, "String savings, at least %d bytes \n",
      base_strings_size - ren_strings_size);
}
Example #7
0
void RenameClassesPass::run_pass(DexClassesVector& dexen, ConfigFiles& cfg) {
  auto scope = build_class_scope(dexen);
  std::unordered_set<const DexType*> untouchables;
  for (const auto& base : m_untouchable_hierarchies) {
    auto base_type = DexType::get_type(base.c_str());
    if (base_type != nullptr) {
      untouchables.insert(base_type);
      TypeVector children;
      get_all_children(base_type, children);
      untouchables.insert(children.begin(), children.end());
    }
  }
  rename_classes(
      scope, m_pre_filter_whitelist, m_post_filter_whitelist, m_path,
      untouchables, cfg.get_proguard_map(), m_rename_annotations);
  TRACE(RENAME, 1,
      "renamed classes: %d anon classes, %d from single char patterns, "
      "%d from multi char patterns\n",
      match_inner,
      match_short,
      match_long);
  TRACE(RENAME, 1, "String savings, at least %d bytes \n",
      base_strings_size - ren_strings_size);
}
Example #8
0
void RemoveUnreachablePass::run_pass(DexStoresVector& stores,
                                     ConfigFiles& conf,
                                     PassManager& pm) {
  // Store names of removed classes and methods
  ConcurrentSet<std::string> removed_symbols;

  if (pm.no_proguard_rules()) {
    TRACE(RMU,
          1,
          "RemoveUnreachablePass not run because no "
          "ProGuard configuration was provided.");
    return;
  }
  bool output_unreachable_symbols = pm.get_current_pass_info()->repeat == 0 &&
                                    !m_unreachable_symbols_file_name.empty();
  int num_ignore_check_strings = 0;
  auto reachables = reachability::compute_reachable_objects(
      stores, m_ignore_sets, &num_ignore_check_strings);
  reachability::ObjectCounts before = reachability::count_objects(stores);
  TRACE(RMU, 1, "before: %lu classes, %lu fields, %lu methods\n",
        before.num_classes, before.num_fields, before.num_methods);
  reachability::sweep(stores, *reachables,
                      output_unreachable_symbols ? &removed_symbols : nullptr);
  reachability::ObjectCounts after = reachability::count_objects(stores);
  TRACE(RMU, 1, "after: %lu classes, %lu fields, %lu methods\n",
        after.num_classes, after.num_fields, after.num_methods);
  pm.incr_metric("num_ignore_check_strings", num_ignore_check_strings);
  pm.incr_metric("classes_removed", before.num_classes - after.num_classes);
  pm.incr_metric("fields_removed", before.num_fields - after.num_fields);
  pm.incr_metric("methods_removed", before.num_methods - after.num_methods);

  if (output_unreachable_symbols) {
    std::string filepath = conf.metafile(m_unreachable_symbols_file_name);
    write_out_removed_symbols(filepath, removed_symbols);
  }
}
Example #9
0
void PassManager::run_passes(DexStoresVector& stores, ConfigFiles& cfg) {
  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, cfg.get_proguard_map(), scope, false, false);
  }
  if (!cfg.get_printseeds().empty()) {
    Timer t("Writing seeds to file " + cfg.get_printseeds());
    std::ofstream seeds_file(cfg.get_printseeds());
    redex::print_seeds(seeds_file, cfg.get_proguard_map(), scope);
    std::ofstream config_file(cfg.get_printseeds() + ".pro");
    redex::show_configuration(config_file, scope, *m_pg_config);
    std::ofstream incoming(cfg.get_printseeds() + ".incoming");
    redex::print_classes(incoming, cfg.get_proguard_map(), scope);
    std::ofstream shrinking_file(cfg.get_printseeds() + ".allowshrinking");
    redex::print_seeds(shrinking_file, cfg.get_proguard_map(), scope, true,
                       false);
    std::ofstream obfuscation_file(cfg.get_printseeds() + ".allowobfuscation");
    redex::print_seeds(obfuscation_file, cfg.get_proguard_map(), scope, false,
                       true);
  }

  // Enable opt decision logging if specified in config.
  const Json::Value& opt_decisions_args =
      cfg.get_json_config()["opt_decisions"];
  if (opt_decisions_args.get("enable_logs", false).asBool()) {
    opt_metadata::OptDataMapper::get_instance().enable_logs();
  }

  // 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, cfg, *this);
    m_current_pass_info = nullptr;
  }

  // Retrieve the type checker's settings.
  const Json::Value& type_checker_args =
      cfg.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, cfg, *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 (!cfg.get_printseeds().empty()) {
    Timer t("Writing outgoing classes to file " + cfg.get_printseeds() +
            ".outgoing");
    // Recompute the scope.
    scope = build_class_scope(it);
    std::ofstream outgoing(cfg.get_printseeds() + ".outgoing");
    redex::print_classes(outgoing, cfg.get_proguard_map(), scope);
  }
}
Example #10
0
void ShortenSrcStringsPass::run_pass(DexStoresVector& stores,
                                     ConfigFiles& conf,
                                     PassManager& mgr) {
  m_filename_mappings = conf.metafile(m_filename_mappings);
  strip_src_strings(stores, m_filename_mappings.c_str(), mgr);
}