/*
* Copyright ( C ) 2018 The Android Open Source Project
*
* Licensed under the Apache License , Version 2 . 0 ( the " License " ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an " AS IS " BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
*/
#include <android-base/file.h>
#include <cstdint>
#include <iostream>
#include <set>
#include <sstream>
#include "base/mem_map.h"
#include "dex/code_item_accessors-inl.h"
#include "dex/dex_file.h"
#include "dex/dex_file_loader.h"
#include "dex/dex_instruction-inl.h"
#include "dexanalyze_bytecode.h"
#include "dexanalyze_experiments.h"
#include "dexanalyze_strings.h"
namespace art {
namespace dexanalyze {
class DexAnalyze {
static constexpr int kExitCodeUsageError = 1 ;
static constexpr int kExitCodeFailedToOpenFile = 2 ;
static constexpr int kExitCodeFailedToOpenDex = 3 ;
static constexpr int kExitCodeFailedToProcessDex = 4 ;
static void StdoutLogger(android::base::LogId,
android::base::LogSeverity,
const char *,
const char *,
unsigned int ,
const char * message) {
std::cout << message << std::endl;
}
static int Usage(char ** argv) {
LOG(ERROR)
<< "Usage " << argv[0 ] << " [options] <dex files>\n"
<< " [options] is a combination of the following\n"
<< " -count-indices (Count dex indices accessed from code items)\n"
<< " -analyze-strings (Analyze string data)\n"
<< " -analyze-debug-info (Analyze debug info)\n"
<< " -new-bytecode (Bytecode optimizations)\n"
<< " -i (Ignore Dex checksum and verification failures)\n"
<< " -a (Run all experiments)\n"
<< " -n <int> (run experiment with 1 .. n as argument)\n"
<< " -d (Dump on per Dex basis)\n"
<< " -v (quiet(0) to everything(2))\n" ;
return kExitCodeUsageError;
}
struct Options {
int Parse(int argc, char ** argv) {
int i;
for (i = 1 ; i < argc; ++i) {
const std::string arg = argv[i];
if (arg == "-i" ) {
verify_checksum_ = false ;
run_dex_file_verifier_ = false ;
} else if (arg == "-v" ) {
if (i + 1 >= argc) {
return Usage(argv);
}
std::istringstream iss(argv[i + 1 ]);
size_t verbose_level = 0 u;
iss >> verbose_level;
if (verbose_level > static_cast <size_t>(VerboseLevel::kEverything)) {
return Usage(argv);
}
++i;
verbose_level_ = static_cast <VerboseLevel>(verbose_level);
} else if (arg == "-a" ) {
run_all_experiments_ = true ;
} else if (arg == "-n" ) {
if (i + 1 >= argc) {
return Usage(argv);
}
std::istringstream iss(argv[i + 1 ]);
iss >> experiment_max_;
++i;
} else if (arg == "-count-indices" ) {
exp_count_indices_ = true ;
} else if (arg == "-analyze-strings" ) {
exp_analyze_strings_ = true ;
} else if (arg == "-analyze-debug-info" ) {
exp_debug_info_ = true ;
} else if (arg == "-new-bytecode" ) {
exp_bytecode_ = true ;
} else if (arg == "-d" ) {
dump_per_input_dex_ = true ;
} else if (!arg.empty() && arg[0 ] == '-' ) {
return Usage(argv);
} else {
break ;
}
}
filenames_.insert(filenames_.end(), argv + i, argv + argc);
if (filenames_.empty()) {
return Usage(argv);
}
return 0 ;
}
VerboseLevel verbose_level_ = VerboseLevel::kNormal;
bool verify_checksum_ = true ;
bool run_dex_file_verifier_ = true ;
bool dump_per_input_dex_ = false ;
bool exp_count_indices_ = false ;
bool exp_code_metrics_ = false ;
bool exp_analyze_strings_ = false ;
bool exp_debug_info_ = false ;
bool exp_bytecode_ = false ;
bool run_all_experiments_ = false ;
uint64_t experiment_max_ = 1 u;
std::vector<std::string> filenames_;
};
class Analysis {
public :
explicit Analysis(const Options* options) : options_(options) {
if (options->run_all_experiments_ || options->exp_count_indices_) {
experiments_.emplace_back(new CountDexIndices);
}
if (options->run_all_experiments_ || options->exp_analyze_strings_) {
experiments_.emplace_back(new AnalyzeStrings);
}
if (options->run_all_experiments_ || options->exp_code_metrics_) {
experiments_.emplace_back(new CodeMetrics);
}
if (options->run_all_experiments_ || options->exp_debug_info_) {
experiments_.emplace_back(new AnalyzeDebugInfo);
}
if (options->run_all_experiments_ || options->exp_bytecode_) {
for (size_t i = 0 ; i < options->experiment_max_; ++i) {
uint64_t exp_value = 0 u;
if (i == 0 ) {
exp_value = std::numeric_limits<uint64_t>::max();
} else if (i == 1 ) {
exp_value = 0 u;
} else {
exp_value = 1 u << (i - 2 );
}
experiments_.emplace_back(new NewRegisterInstructions(exp_value));
}
}
for (const std::unique_ptr<Experiment>& experiment : experiments_) {
experiment->verbose_level_ = options->verbose_level_;
}
}
bool ProcessDexFiles(const std::vector<std::unique_ptr<const DexFile>>& dex_files) {
for (std::unique_ptr<Experiment>& experiment : experiments_) {
experiment->ProcessDexFiles(dex_files);
}
for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
total_size_ += dex_file->Size();
}
dex_count_ += dex_files.size();
return true ;
}
void Dump(std::ostream& os) {
for (std::unique_ptr<Experiment>& experiment : experiments_) {
experiment->Dump(os, total_size_);
os << "\n" ;
}
}
const Options* const options_;
std::vector<std::unique_ptr<Experiment>> experiments_;
size_t dex_count_ = 0 ;
uint64_t total_size_ = 0 u;
};
public :
static int Run(int argc, char ** argv) {
android::base::SetLogger(StdoutLogger);
Options options;
int result = options.Parse(argc, argv);
if (result != 0 ) {
return result;
}
DexFileLoaderErrorCode error_code;
std::string error_msg;
Analysis cumulative(&options);
for (const std::string& filename : options.filenames_) {
std::string content;
// TODO: once added, use an API to android::base to read a std::vector<uint8_t>.
if (!android::base::ReadFileToString(filename, &content)) {
LOG(ERROR) << "ReadFileToString failed for " + filename << std::endl;
return kExitCodeFailedToOpenFile;
}
std::vector<std::unique_ptr<const DexFile>> dex_files;
DexFileLoader dex_file_loader(
reinterpret_cast <const uint8_t*>(content.data()), content.size(), filename);
if (!dex_file_loader.Open(options.run_dex_file_verifier_,
options.verify_checksum_,
&error_code,
&error_msg,
&dex_files)) {
LOG(ERROR) << "OpenAll failed for " + filename << " with " << error_msg << std::endl;
return kExitCodeFailedToOpenDex;
}
if (options.dump_per_input_dex_) {
Analysis current(&options);
if (!current.ProcessDexFiles(dex_files)) {
LOG(ERROR) << "Failed to process " << filename << " with error " << error_msg;
return kExitCodeFailedToProcessDex;
}
LOG(INFO) << "Analysis for " << filename << std::endl;
current.Dump(LOG_STREAM(INFO));
}
cumulative.ProcessDexFiles(dex_files);
}
LOG(INFO) << "Cumulative analysis for " << cumulative.dex_count_ << " DEX files" << std::endl;
cumulative.Dump(LOG_STREAM(INFO));
return 0 ;
}
};
} // namespace dexanalyze
} // namespace art
int main(int argc, char ** argv) {
art::MemMap::Init();
return art::dexanalyze::DexAnalyze::Run(argc, argv);
}
Messung V0.5 in Prozent C=75 H=88 G=81
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet am 2026-06-29)
¤
*© Formatika GbR, Deutschland