Ejemplo n.º 1
0
void UnterfacePass::run_pass(DexClassesVector& dexen, ConfigFiles& cfg) {
  Scope scope = build_class_scope(dexen);

  InterfaceImplementations interfaces(scope);
  assert(interfaces.print_all());

  auto one_level = exclude(interfaces,
      HAS_SUPER | HAS_CHILDREN | NO_VMETHODS,
      IMPL_MULTIPLE_INTERFACES |
          HAS_SUPER |
          HAS_CHILDREN |
          IS_ABSTRACT |
          NO_MATCH_INTERFACE_METHODS |
          HAS_MULTIPLE_INSTANCE_FIELDS |
          MULTIPLE_ARGS_CTOR |
          HAS_CLINIT |
          NO_VMETHODS |
          HAS_STATIC_FIELDS |
          HAS_DIRECT_METHODS);
  interfaces.analyze_candidates(one_level, "No hierarchy, perfect match");

  // optimize
  std::vector<DexClass*> untfs;
  std::unordered_set<DexClass*> removed;
  //optimize(scope, candidates, untfs, removed);

  // write back
  DexClassesVector outdex;
  DexClasses& orig_classes = dexen[0];
  DexClasses classes(orig_classes.size() + untfs.size() - removed.size());
  int pos = 0;
  for (int i = 0; i < orig_classes.size(); ++i) {
    auto cls = orig_classes.get(i);
    if (removed.find(cls) == removed.end()) {
      classes.insert_at(cls, pos++);
    }
  }
  for (auto untf : untfs) {
    classes.insert_at(untf, pos++);
  }
  outdex.emplace_back(std::move(classes));
  for (size_t i = 1; i < dexen.size(); i++) {
    outdex.emplace_back(std::move(dexen[i]));
  }
  dexen = std::move(outdex);
}
Ejemplo n.º 2
0
void InterDexPass::run_pass(DexClassesVector& dexen, PgoFiles& pgo) {

  bool static_prune = false;
  if (m_config["static_prune"] != nullptr) {
    auto prune_str = m_config["static_prune"].asString().toStdString();
    if (prune_str == "1") {
      static_prune = true;
    }
  }

  auto first_attempt = run_interdex(dexen, pgo, true, static_prune);
  if (first_attempt.size() > dexen.size()) {
    fprintf(stderr, "Warning, Interdex grew the number of dexes from %lu to %lu! \n \
        Retrying without cutting off interdex dexes. \n", dexen.size(), first_attempt.size());
    dexen = run_interdex(dexen, pgo, false, static_prune);
  } else {
Ejemplo n.º 3
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));
}
Ejemplo n.º 4
0
int main(int argc, char* argv[]) {
  signal(SIGSEGV, crash_backtrace);
  signal(SIGABRT, crash_backtrace);
  signal(SIGBUS, crash_backtrace);

  g_redex = new RedexContext();

  auto passes = create_passes();

  Arguments args;
  std::vector<KeepRule> rules;
  // Currently there are two sources that specify the library jars:
  // 1. The jar_path argument, which may specify one library jar.
  // 2. The library_jars vector, which lists the library jars specified in
  //    the ProGuard configuration.
  // If -jarpath specified a library jar it is appended to the
  // library_jars vector so this vector can be used to iterate over
  // all the library jars regardless of whether they were specified
  // on the command line or ProGuard file.
  // TODO: Make the command line -jarpath option like a colon separated
  //       list of library JARS.
  std::set<std::string> library_jars;
  auto start = parse_args(argc, argv, args);
  if (!dir_is_writable(args.out_dir)) {
    fprintf(stderr,
            "outdir %s is not a writable directory\n",
            args.out_dir.c_str());
    exit(1);
  }

  if (!args.proguard_config.empty()) {
    if (!load_proguard_config_file(
            args.proguard_config.c_str(), &rules, &library_jars)) {
      fprintf(stderr,
              "ERROR: Unable to open proguard config %s\n",
              args.proguard_config.c_str());
      // For now tolerate missing or unparseable ProGuard configuration files.
      // start = 0;
    }
  } else {
    TRACE(MAIN,
          1,
          "Skipping parsing the proguard config file "
          "because no file was specified\n");
  }

  for (const auto jar_path : args.jar_paths) {
    std::stringstream jar_stream(jar_path);
    std::string dependent_jar_path;
    while (std::getline(jar_stream, dependent_jar_path, ':')) {
      TRACE(MAIN,
            2,
            "Dependent JAR specified on command-line: %s\n",
            dependent_jar_path.c_str());
      library_jars.emplace(dependent_jar_path);
    }
  }

  if (start == 0 || start == argc) {
    usage();
    exit(1);
  }

  DexClassesVector dexen;
  for (int i = start; i < argc; i++) {
    dexen.emplace_back(load_classes_from_dex(argv[i]));
  }

  for (const auto& library_jar : library_jars) {
    TRACE(MAIN, 1, "LIBRARY JAR: %s\n", library_jar.c_str());
    if (!load_jar_file(library_jar.c_str())) {
      fprintf(
          stderr,
          "WARNING: Error in jar %s - continue. This may lead to unexpected "
          "behavior, please check your jars\n",
          library_jar.c_str());
    }
  }

  ConfigFiles cfg(args.config);
  cfg.using_seeds = false;
  if (!args.seeds_filename.empty()) {
    cfg.using_seeds = init_seed_classes(args.seeds_filename) > 0;
  }

  PassManager manager(passes, rules, args.config);
  manager.run_passes(dexen, cfg);

  TRACE(MAIN, 1, "Writing out new DexClasses...\n");

  LocatorIndex* locator_index = nullptr;
  if (args.config.get("emit_locator_strings", false).asBool()) {
    TRACE(LOC,
          1,
          "Will emit class-locator strings for classloader optimization\n");
    locator_index = new LocatorIndex(make_locator_index(dexen));
  }

  dex_output_stats_t totals;
  std::vector<dex_output_stats_t> dexes_stats;

  auto pos_output = args.config.get("line_number_map", "").asString();
  std::unique_ptr<PositionMapper> pos_mapper(PositionMapper::make(pos_output));

  for (size_t i = 0; i < dexen.size(); i++) {
    std::stringstream ss;
    ss << args.out_dir + "/classes";
    if (i > 0) {
      ss << (i + 1);
    }
    ss << ".dex";
    auto stats = write_classes_to_dex(
      ss.str(),
      &dexen[i],
      locator_index,
      i,
      cfg,
      args.config,
      pos_mapper.get());
    totals += stats;
    dexes_stats.push_back(stats);
  }

  auto stats_output = args.config.get("stats_output", "").asString();
  auto method_move_map = args.config.get("method_move_map", "").asString();

  pos_mapper->write_map();
  output_stats(stats_output.c_str(), totals, dexes_stats, manager);
  output_moved_methods_map(method_move_map.c_str(), dexen, cfg);
  print_warning_summary();
  delete g_redex;
  TRACE(MAIN, 1, "Done.\n");

  return 0;
}