Allow DexFile#getDexOptNeeded to check case when downgrading is required
The change in the API will allow comparison of compiler filter in case when
downgrade is required. Previously, it used to only consider cases of compiler
filter upgrades.
Test: make & boot
Bug: 36598475
(cherry-picked from commit cf3d122a9234414b7cd2aab340d1450f3e9da213)
Change-Id: Ice292ef4f16c373297821c40e39987f3de914c67
diff --git a/dexoptanalyzer/dexoptanalyzer.cc b/dexoptanalyzer/dexoptanalyzer.cc
index e2c159a..fc72bbd 100644
--- a/dexoptanalyzer/dexoptanalyzer.cc
+++ b/dexoptanalyzer/dexoptanalyzer.cc
@@ -97,6 +97,9 @@
UsageError(" --android-data=<directory>: optional, the directory which should be used as");
UsageError(" android-data. By default ANDROID_DATA env variable is used.");
UsageError("");
+ UsageError(" --downgrade: optional, if the purpose of dexopt is to downgrade the dex file");
+ UsageError(" By default, dexopt considers upgrade case.");
+ UsageError("");
UsageError("Return code:");
UsageError(" To make it easier to integrate with the internal tools this command will make");
UsageError(" available its result (dexoptNeeded) as the exit/return code. i.e. it will not");
@@ -121,7 +124,9 @@
class DexoptAnalyzer FINAL {
public:
- DexoptAnalyzer() : assume_profile_changed_(false) {}
+ DexoptAnalyzer() :
+ assume_profile_changed_(false),
+ downgrade_(false) {}
void ParseArgs(int argc, char **argv) {
original_argc = argc;
@@ -160,9 +165,9 @@
// compute dalvik-cache folder). This is mostly used in tests.
std::string new_android_data = option.substr(strlen("--android-data=")).ToString();
setenv("ANDROID_DATA", new_android_data.c_str(), 1);
- } else {
- Usage("Unknown argument '%s'", option.data());
- }
+ } else if (option.starts_with("--downgrade")) {
+ downgrade_ = true;
+ } else { Usage("Unknown argument '%s'", option.data()); }
}
if (image_.empty()) {
@@ -225,7 +230,7 @@
return kNoDexOptNeeded;
}
int dexoptNeeded = oat_file_assistant.GetDexOptNeeded(
- compiler_filter_, assume_profile_changed_);
+ compiler_filter_, assume_profile_changed_, downgrade_);
// Convert OatFileAssitant codes to dexoptanalyzer codes.
switch (dexoptNeeded) {
@@ -249,6 +254,7 @@
InstructionSet isa_;
CompilerFilter::Filter compiler_filter_;
bool assume_profile_changed_;
+ bool downgrade_;
std::string image_;
};
diff --git a/dexoptanalyzer/dexoptanalyzer_test.cc b/dexoptanalyzer/dexoptanalyzer_test.cc
index 1703ff4..1cbf546 100644
--- a/dexoptanalyzer/dexoptanalyzer_test.cc
+++ b/dexoptanalyzer/dexoptanalyzer_test.cc
@@ -71,12 +71,13 @@
// as the output of OatFileAssistant::GetDexOptNeeded.
void Verify(const std::string& dex_file,
CompilerFilter::Filter compiler_filter,
- bool assume_profile_changed = false) {
+ bool assume_profile_changed = false,
+ bool downgrade = false) {
int dexoptanalyzerResult = Analyze(dex_file, compiler_filter, assume_profile_changed);
dexoptanalyzerResult = DexoptanalyzerToOatFileAssistant(dexoptanalyzerResult);
OatFileAssistant oat_file_assistant(dex_file.c_str(), kRuntimeISA, /*load_executable*/ false);
int assistantResult = oat_file_assistant.GetDexOptNeeded(
- compiler_filter, assume_profile_changed);
+ compiler_filter, assume_profile_changed, downgrade);
EXPECT_EQ(assistantResult, dexoptanalyzerResult);
}
};
@@ -118,6 +119,16 @@
Verify(dex_location, CompilerFilter::kQuicken, true);
}
+TEST_F(DexoptAnalyzerTest, Downgrade) {
+ std::string dex_location = GetScratchDir() + "/Downgrade.jar";
+ Copy(GetDexSrc1(), dex_location);
+ GenerateOatForTest(dex_location.c_str(), CompilerFilter::kQuicken);
+
+ Verify(dex_location, CompilerFilter::kSpeedProfile, false, true);
+ Verify(dex_location, CompilerFilter::kQuicken, false, true);
+ Verify(dex_location, CompilerFilter::kVerify, false, true);
+}
+
// Case: We have a MultiDEX file and up-to-date OAT file for it.
TEST_F(DexoptAnalyzerTest, MultiDexOatUpToDate) {
std::string dex_location = GetScratchDir() + "/MultiDexOatUpToDate.jar";
diff --git a/runtime/compiler_filter.cc b/runtime/compiler_filter.cc
index 4847f38..7b2dd05 100644
--- a/runtime/compiler_filter.cc
+++ b/runtime/compiler_filter.cc
@@ -165,6 +165,10 @@
return current >= target;
}
+bool CompilerFilter::IsBetter(Filter current, Filter target) {
+ return current > target;
+}
+
std::string CompilerFilter::NameOfFilter(Filter filter) {
switch (filter) {
case CompilerFilter::kAssumeVerified: return "assume-verified";
diff --git a/runtime/compiler_filter.h b/runtime/compiler_filter.h
index f802439..60975b0 100644
--- a/runtime/compiler_filter.h
+++ b/runtime/compiler_filter.h
@@ -84,6 +84,11 @@
// not as good as kSpeed.
static bool IsAsGoodAs(Filter current, Filter target);
+ // Returns true if 'current' compiler filter is better than 'target' compiler
+ // filter. Compared to IsAsGoodAs, this returns false if the compiler filters are
+ // equal.
+ static bool IsBetter(Filter current, Filter target);
+
// Return the flag name of the given filter.
// For example: given kVerifyAtRuntime, returns "verify-at-runtime".
// The name returned corresponds to the name accepted by
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index ad00966..bd9eb82 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -458,7 +458,8 @@
const char* filename,
const char* instruction_set,
const char* compiler_filter_name,
- bool profile_changed) {
+ bool profile_changed,
+ bool downgrade) {
if ((filename == nullptr) || !OS::FileExists(filename)) {
LOG(ERROR) << "DexFile_getDexOptNeeded file '" << filename << "' does not exist";
ScopedLocalRef<jclass> fnfe(env, env->FindClass("java/io/FileNotFoundException"));
@@ -492,7 +493,7 @@
if (oat_file_assistant.IsInBootClassPath()) {
return OatFileAssistant::kNoDexOptNeeded;
}
- return oat_file_assistant.GetDexOptNeeded(filter, profile_changed);
+ return oat_file_assistant.GetDexOptNeeded(filter, profile_changed, downgrade);
}
static jstring DexFile_getDexFileStatus(JNIEnv* env,
@@ -528,7 +529,8 @@
jstring javaFilename,
jstring javaInstructionSet,
jstring javaTargetCompilerFilter,
- jboolean newProfile) {
+ jboolean newProfile,
+ jboolean downgrade) {
ScopedUtfChars filename(env, javaFilename);
if (env->ExceptionCheck()) {
return -1;
@@ -548,7 +550,8 @@
filename.c_str(),
instruction_set.c_str(),
target_compiler_filter.c_str(),
- newProfile == JNI_TRUE);
+ newProfile == JNI_TRUE,
+ downgrade == JNI_TRUE);
}
// public API
@@ -725,7 +728,7 @@
NATIVE_METHOD(DexFile, getClassNameList, "(Ljava/lang/Object;)[Ljava/lang/String;"),
NATIVE_METHOD(DexFile, isDexOptNeeded, "(Ljava/lang/String;)Z"),
NATIVE_METHOD(DexFile, getDexOptNeeded,
- "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)I"),
+ "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZ)I"),
NATIVE_METHOD(DexFile, openDexFileNative,
"(Ljava/lang/String;"
"Ljava/lang/String;"
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index c876657..96423c3 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -187,9 +187,11 @@
return true;
}
-int OatFileAssistant::GetDexOptNeeded(CompilerFilter::Filter target, bool profile_changed) {
+int OatFileAssistant::GetDexOptNeeded(CompilerFilter::Filter target,
+ bool profile_changed,
+ bool downgrade) {
OatFileInfo& info = GetBestInfo();
- DexOptNeeded dexopt_needed = info.GetDexOptNeeded(target, profile_changed);
+ DexOptNeeded dexopt_needed = info.GetDexOptNeeded(target, profile_changed, downgrade);
if (info.IsOatLocation() || dexopt_needed == kDex2OatFromScratch) {
return dexopt_needed;
}
@@ -230,7 +232,7 @@
}
OatFileInfo& info = GetBestInfo();
- switch (info.GetDexOptNeeded(target, profile_changed)) {
+ switch (info.GetDexOptNeeded(target, profile_changed, /*downgrade*/ false)) {
case kNoDexOptNeeded:
return kUpdateSucceeded;
@@ -1005,9 +1007,9 @@
}
OatFileAssistant::DexOptNeeded OatFileAssistant::OatFileInfo::GetDexOptNeeded(
- CompilerFilter::Filter target, bool profile_changed) {
+ CompilerFilter::Filter target, bool profile_changed, bool downgrade) {
bool compilation_desired = CompilerFilter::IsAotCompilationEnabled(target);
- bool filter_okay = CompilerFilterIsOkay(target, profile_changed);
+ bool filter_okay = CompilerFilterIsOkay(target, profile_changed, downgrade);
if (filter_okay && Status() == kOatUpToDate) {
// The oat file is in good shape as is.
@@ -1064,7 +1066,7 @@
}
bool OatFileAssistant::OatFileInfo::CompilerFilterIsOkay(
- CompilerFilter::Filter target, bool profile_changed) {
+ CompilerFilter::Filter target, bool profile_changed, bool downgrade) {
const OatFile* file = GetFile();
if (file == nullptr) {
return false;
@@ -1075,7 +1077,8 @@
VLOG(oat) << "Compiler filter not okay because Profile changed";
return false;
}
- return CompilerFilter::IsAsGoodAs(current, target);
+ return downgrade ? !CompilerFilter::IsBetter(current, target) :
+ CompilerFilter::IsAsGoodAs(current, target);
}
bool OatFileAssistant::OatFileInfo::IsExecutable() {
diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h
index 92d87ea..320aa4f 100644
--- a/runtime/oat_file_assistant.h
+++ b/runtime/oat_file_assistant.h
@@ -147,13 +147,24 @@
bool Lock(std::string* error_msg);
// Return what action needs to be taken to produce up-to-date code for this
- // dex location that is at least as good as an oat file generated with the
- // given compiler filter. profile_changed should be true to indicate the
- // profile has recently changed for this dex location.
+ // dex location. If "downgrade" is set to false, it verifies if the current
+ // compiler filter is at least as good as an oat file generated with the
+ // given compiler filter otherwise, if its set to true, it checks whether
+ // the oat file generated with the target filter will be downgraded as
+ // compared to the current state. For example, if the current compiler filter is
+ // quicken, and target filter is verify, it will recommend to dexopt, while
+ // if the target filter is speed profile, it will recommend to keep it in its
+ // current state.
+ // profile_changed should be true to indicate the profile has recently changed
+ // for this dex location.
+ // If the purpose of the dexopt is to downgrade the compiler filter,
+ // set downgrade to true.
// Returns a positive status code if the status refers to the oat file in
// the oat location. Returns a negative status code if the status refers to
// the oat file in the odex location.
- int GetDexOptNeeded(CompilerFilter::Filter target_compiler_filter, bool profile_changed = false);
+ int GetDexOptNeeded(CompilerFilter::Filter target_compiler_filter,
+ bool profile_changed = false,
+ bool downgrade = false);
// Returns true if there is up-to-date code for this dex location,
// irrespective of the compiler filter of the up-to-date code.
@@ -310,8 +321,11 @@
// given target_compilation_filter.
// profile_changed should be true to indicate the profile has recently
// changed for this dex location.
+ // downgrade should be true if the purpose of dexopt is to downgrade the
+ // compiler filter.
DexOptNeeded GetDexOptNeeded(CompilerFilter::Filter target_compiler_filter,
- bool profile_changed);
+ bool profile_changed,
+ bool downgrade);
// Returns the loaded file.
// Loads the file if needed. Returns null if the file failed to load.
@@ -344,7 +358,9 @@
// least as good as the given target filter. profile_changed should be
// true to indicate the profile has recently changed for this dex
// location.
- bool CompilerFilterIsOkay(CompilerFilter::Filter target, bool profile_changed);
+ // downgrade should be true if the purpose of dexopt is to downgrade the
+ // compiler filter.
+ bool CompilerFilterIsOkay(CompilerFilter::Filter target, bool profile_changed, bool downgrade);
// Release the loaded oat file.
// Returns null if the oat file hasn't been loaded.