summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jiakai Zhang <jiakaiz@google.com> 2025-02-03 06:02:53 -0800
committer Treehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com> 2025-02-14 05:55:36 -0800
commit153ccc814f6129c51304f874fcd8ae0512e24e71 (patch)
tree3bdac66e0e803cbc39bdb360114758ae03370cf5
parent4ef61af6f7a96a2fa8b21d5a2535b9a9a60a5e70 (diff)
Revert^2 "Remove old and duplicated logic in picking up the best artifact."
This reverts commit 3796e88d5d9a6ecc095d32e5ebde11b9f27fef6b. Reason for revert: Fixed the issue with the original change. The key is that the oat location must be prioritized over the odex location. No regression on app startup observed after the change. Before: 297.61ms https://dashboards.corp.google.com/android-crystalball.dashboards.invocation_viewer?f=ants_invocation_id:eq:I84300010361891674&fb=metric_key:in:perfetto_android_startup-com.google.android.GoogleCamera-hsc-full_startup-dur_ms-mean&fh=eJxdzLEKAjEQhOF32foa03jeG1hfeRwSNgsubvSIkyKI754sdpbzwT_bhzTRQllQlG8PaTQRv6zm57-iHTLsLSaMsVNEXA_hq_fz-TKHU_D4Hgvctn2iXA26_ooFpcq4UZj_0HfvH00onw.. After: 295.42ms https://dashboards.corp.google.com/android-crystalball.dashboards.invocation_viewer?f=ants_invocation_id:eq:I37700010361929468&fb=metric_key:in:perfetto_android_startup-com.google.android.GoogleCamera-hsc-full_startup-dur_ms-mean&fh=eJxdzLEKAjEQhOF32foa03jeG1hfeRwSNgsubvSIkyKI754sdpbzwT_bhzTRQllQlG8PaTQRv6zm57-iHTLsLSaMsVNEXA_hq_fz-TKHU_D4Hgvctn2iXA26_ooFpcq4UZj_0HfvH00onw.. Bug: 377474232 Test: Presubmit Change-Id: I0c291f195151fdb3b7ea2b63a8015bc8a792a7cd
-rw-r--r--runtime/oat/oat_file_assistant.cc65
-rw-r--r--runtime/oat/oat_file_assistant.h3
-rw-r--r--runtime/oat/oat_file_assistant_test.cc128
-rwxr-xr-xtools/art47
4 files changed, 21 insertions, 222 deletions
diff --git a/runtime/oat/oat_file_assistant.cc b/runtime/oat/oat_file_assistant.cc
index 8e4405d05d..8db02e5679 100644
--- a/runtime/oat/oat_file_assistant.cc
+++ b/runtime/oat/oat_file_assistant.cc
@@ -205,23 +205,6 @@ OatFileAssistant::OatFileAssistant(const char* dex_location,
<< error_msg;
}
}
-
- // Check if the dex directory is writable.
- // This will be needed in most uses of OatFileAssistant and so it's OK to
- // compute it eagerly.
- size_t pos = dex_location_.rfind('/');
- if (pos == std::string::npos) {
- LOG(WARNING) << "Failed to determine dex file parent directory: " << dex_location_;
- } else if (!UseFdToReadFiles()) {
- // We cannot test for parent access when using file descriptors. That's ok
- // because in this case we will always pick the odex file anyway.
- std::string parent = dex_location_.substr(0, pos);
- if (access(parent.c_str(), W_OK) == 0) {
- dex_parent_writable_ = true;
- } else {
- VLOG(oat) << "Dex parent of " << dex_location_ << " is not writable: " << strerror(errno);
- }
- }
}
std::unique_ptr<OatFileAssistant> OatFileAssistant::Create(
@@ -818,52 +801,23 @@ bool OatFileAssistant::IsPrimaryBootImageUsable() {
OatFileAssistant::OatFileInfo& OatFileAssistant::GetBestInfo() {
ScopedTrace trace("GetBestInfo");
- // TODO(calin): Document the side effects of class loading when
- // running dalvikvm command line.
- if (dex_parent_writable_ || UseFdToReadFiles()) {
- // If the parent of the dex file is writable it means that we can
- // create the odex file. In this case we unconditionally pick the odex
- // as the best oat file. This corresponds to the regular use case when
- // apps gets installed or when they load private, secondary dex file.
- // For apps on the system partition the odex location will not be
- // writable and thus the oat location might be more up to date.
-
- // If the odex is not useable, and we have a useable vdex, return the vdex
- // instead.
- VLOG(oat) << ART_FORMAT("GetBestInfo checking odex next to the dex file ({})",
- odex_.DisplayFilename());
- if (!odex_.IsUseable()) {
- VLOG(oat) << ART_FORMAT("GetBestInfo checking vdex next to the dex file ({})",
- vdex_for_odex_.DisplayFilename());
- if (vdex_for_odex_.IsUseable()) {
- return vdex_for_odex_;
- }
- VLOG(oat) << ART_FORMAT("GetBestInfo checking dm ({})", dm_for_odex_.DisplayFilename());
- if (dm_for_odex_.IsUseable()) {
- return dm_for_odex_;
- }
- }
- return odex_;
- }
-
- // We cannot write to the odex location. This must be a system app.
- // If the oat location is useable take it.
+ // If the oat location is useable, take it. This must be an app on a readonly filesystem
+ // (typically, a system app or an incremental app). This must be prioritized over the odex
+ // location, because the odex location probably has the dexpreopt artifacts.
VLOG(oat) << ART_FORMAT("GetBestInfo checking odex in dalvik-cache ({})", oat_.DisplayFilename());
if (oat_.IsUseable()) {
return oat_;
}
- // The oat file is not useable but the odex file might be up to date.
- // This is an indication that we are dealing with an up to date prebuilt
- // (that doesn't need relocation).
+ // The odex location, which is the most common.
VLOG(oat) << ART_FORMAT("GetBestInfo checking odex next to the dex file ({})",
odex_.DisplayFilename());
if (odex_.IsUseable()) {
return odex_;
}
- // Look for a useable vdex file.
+ // No odex/oat available, look for a useable vdex file.
VLOG(oat) << ART_FORMAT("GetBestInfo checking vdex in dalvik-cache ({})",
vdex_for_oat_.DisplayFilename());
if (vdex_for_oat_.IsUseable()) {
@@ -874,6 +828,8 @@ OatFileAssistant::OatFileInfo& OatFileAssistant::GetBestInfo() {
if (vdex_for_odex_.IsUseable()) {
return vdex_for_odex_;
}
+
+ // A .dm file may be available, look for it.
VLOG(oat) << ART_FORMAT("GetBestInfo checking dm ({})", dm_for_oat_.DisplayFilename());
if (dm_for_oat_.IsUseable()) {
return dm_for_oat_;
@@ -884,12 +840,7 @@ OatFileAssistant::OatFileInfo& OatFileAssistant::GetBestInfo() {
return dm_for_odex_;
}
- // We got into the worst situation here:
- // - the oat location is not useable
- // - the prebuild odex location is not up to date
- // - the vdex-only file is not useable
- // - and we don't have the original dex file anymore (stripped).
- // Pick the odex if it exists, or the oat if not.
+ // No usable artifact. Pick the odex if it exists, or the oat if not.
VLOG(oat) << "GetBestInfo no usable artifacts";
return (odex_.Status() == kOatCannotOpen) ? oat_ : odex_;
}
diff --git a/runtime/oat/oat_file_assistant.h b/runtime/oat/oat_file_assistant.h
index 2bfc53a444..9af1051362 100644
--- a/runtime/oat/oat_file_assistant.h
+++ b/runtime/oat/oat_file_assistant.h
@@ -533,9 +533,6 @@ class OatFileAssistant {
// skipped.
ClassLoaderContext* context_;
- // Whether or not the parent directory of the dex file is writable.
- bool dex_parent_writable_ = false;
-
// In a properly constructed OatFileAssistant object, isa_ should be either
// the 32 or 64 bit variant for the current device.
const InstructionSet isa_ = InstructionSet::kNone;
diff --git a/runtime/oat/oat_file_assistant_test.cc b/runtime/oat/oat_file_assistant_test.cc
index 64c648ac8e..580191b355 100644
--- a/runtime/oat/oat_file_assistant_test.cc
+++ b/runtime/oat/oat_file_assistant_test.cc
@@ -238,39 +238,6 @@ class OatFileAssistantTest : public OatFileAssistantBaseTest,
std::vector<std::unique_ptr<const DexFile>> opened_dex_files_;
};
-class ScopedNonWritable {
- public:
- explicit ScopedNonWritable(const std::string& dex_location) {
- is_valid_ = false;
- size_t pos = dex_location.rfind('/');
- if (pos != std::string::npos) {
- is_valid_ = true;
- dex_parent_ = dex_location.substr(0, pos);
- if (chmod(dex_parent_.c_str(), 0555) != 0) {
- PLOG(ERROR) << "Could not change permissions on " << dex_parent_;
- }
- }
- }
-
- bool IsSuccessful() { return is_valid_ && (access(dex_parent_.c_str(), W_OK) != 0); }
-
- ~ScopedNonWritable() {
- if (is_valid_) {
- if (chmod(dex_parent_.c_str(), 0777) != 0) {
- PLOG(ERROR) << "Could not restore permissions on " << dex_parent_;
- }
- }
- }
-
- private:
- std::string dex_parent_;
- bool is_valid_;
-};
-
-static bool IsExecutedAsRoot() {
- return geteuid() == 0;
-}
-
// Case: We have a MultiDEX file and up-to-date ODEX file for it with relative
// encoded dex locations.
// Expect: The oat file status is kNoDexOptNeeded.
@@ -586,20 +553,10 @@ TEST_P(OatFileAssistantTest, OdexUpToDateSymLink) {
// Case: We have a DEX file and up-to-date OAT file for it.
// Expect: The status is kNoDexOptNeeded.
TEST_P(OatFileAssistantTest, OatUpToDate) {
- if (IsExecutedAsRoot()) {
- // We cannot simulate non writable locations when executed as root: b/38000545.
- LOG(ERROR) << "Test skipped because it's running as root";
- return;
- }
-
std::string dex_location = GetScratchDir() + "/OatUpToDate.jar";
Copy(GetDexSrc1(), dex_location);
GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
- // Force the use of oat location by making the dex parent not writable.
- ScopedNonWritable scoped_non_writable(dex_location);
- ASSERT_TRUE(scoped_non_writable.IsSuccessful());
-
auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
@@ -860,12 +817,6 @@ TEST_P(OatFileAssistantTest, EmptyVdexOdex) {
// Case: We have a DEX file and up-to-date (OAT) VDEX file for it, but no OAT
// file.
TEST_P(OatFileAssistantTest, VdexUpToDateNoOat) {
- if (IsExecutedAsRoot()) {
- // We cannot simulate non writable locations when executed as root: b/38000545.
- LOG(ERROR) << "Test skipped because it's running as root";
- return;
- }
-
std::string dex_location = GetScratchDir() + "/VdexUpToDateNoOat.jar";
std::string oat_location;
std::string error_msg;
@@ -877,9 +828,6 @@ TEST_P(OatFileAssistantTest, VdexUpToDateNoOat) {
GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
ASSERT_EQ(0, unlink(oat_location.c_str()));
- ScopedNonWritable scoped_non_writable(dex_location);
- ASSERT_TRUE(scoped_non_writable.IsSuccessful());
-
auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
@@ -896,19 +844,10 @@ TEST_P(OatFileAssistantTest, VdexUpToDateNoOat) {
// Expect: The status is kNoDexOptNeeded if the profile hasn't changed, but
// kDex2Oat if the profile has changed.
TEST_P(OatFileAssistantTest, ProfileOatUpToDate) {
- if (IsExecutedAsRoot()) {
- // We cannot simulate non writable locations when executed as root: b/38000545.
- LOG(ERROR) << "Test skipped because it's running as root";
- return;
- }
-
std::string dex_location = GetScratchDir() + "/ProfileOatUpToDate.jar";
Copy(GetDexSrc1(), dex_location);
GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeedProfile);
- ScopedNonWritable scoped_non_writable(dex_location);
- ASSERT_TRUE(scoped_non_writable.IsSuccessful());
-
auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
@@ -965,19 +904,10 @@ TEST_P(OatFileAssistantTest, ProfileOatUpToDate) {
// Case: We have a MultiDEX file and up-to-date OAT file for it.
// Expect: The status is kNoDexOptNeeded and we load all dex files.
TEST_P(OatFileAssistantTest, MultiDexOatUpToDate) {
- if (IsExecutedAsRoot()) {
- // We cannot simulate non writable locations when executed as root: b/38000545.
- LOG(ERROR) << "Test skipped because it's running as root";
- return;
- }
-
std::string dex_location = GetScratchDir() + "/MultiDexOatUpToDate.jar";
Copy(GetMultiDexSrc1(), dex_location);
GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
- ScopedNonWritable scoped_non_writable(dex_location);
- ASSERT_TRUE(scoped_non_writable.IsSuccessful());
-
auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str(),
@@ -1005,12 +935,6 @@ TEST_P(OatFileAssistantTest, MultiDexOatUpToDate) {
// Case: We have a MultiDEX file where the non-main multdex entry is out of date.
// Expect: The status is kDex2OatNeeded.
TEST_P(OatFileAssistantTest, MultiDexNonMainOutOfDate) {
- if (IsExecutedAsRoot()) {
- // We cannot simulate non writable locations when executed as root: b/38000545.
- LOG(ERROR) << "Test skipped because it's running as root";
- return;
- }
-
std::string dex_location = GetScratchDir() + "/MultiDexNonMainOutOfDate.jar";
// Compile code for GetMultiDexSrc1.
@@ -1021,9 +945,6 @@ TEST_P(OatFileAssistantTest, MultiDexNonMainOutOfDate) {
// is out of date.
Copy(GetMultiDexSrc2(), dex_location);
- ScopedNonWritable scoped_non_writable(dex_location);
- ASSERT_TRUE(scoped_non_writable.IsSuccessful());
-
auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
@@ -1039,12 +960,6 @@ TEST_P(OatFileAssistantTest, MultiDexNonMainOutOfDate) {
// Case: We have a DEX file and an OAT file out of date with respect to the
// dex checksum.
TEST_P(OatFileAssistantTest, OatDexOutOfDate) {
- if (IsExecutedAsRoot()) {
- // We cannot simulate non writable locations when executed as root: b/38000545.
- LOG(ERROR) << "Test skipped because it's running as root";
- return;
- }
-
std::string dex_location = GetScratchDir() + "/OatDexOutOfDate.jar";
// We create a dex, generate an oat for it, then overwrite the dex with a
@@ -1053,9 +968,6 @@ TEST_P(OatFileAssistantTest, OatDexOutOfDate) {
GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
Copy(GetDexSrc2(), dex_location);
- ScopedNonWritable scoped_non_writable(dex_location);
- ASSERT_TRUE(scoped_non_writable.IsSuccessful());
-
auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
@@ -1128,12 +1040,6 @@ TEST_P(OatFileAssistantTest, VdexMultiDexNonMainOutOfDate) {
// Case: We have a DEX file and an OAT file out of date with respect to the
// boot image.
TEST_P(OatFileAssistantTest, OatImageOutOfDate) {
- if (IsExecutedAsRoot()) {
- // We cannot simulate non writable locations when executed as root: b/38000545.
- LOG(ERROR) << "Test skipped because it's running as root";
- return;
- }
-
std::string dex_location = GetScratchDir() + "/OatImageOutOfDate.jar";
Copy(GetDexSrc1(), dex_location);
@@ -1141,9 +1047,6 @@ TEST_P(OatFileAssistantTest, OatImageOutOfDate) {
CompilerFilter::kSpeed,
/* with_alternate_image= */ true);
- ScopedNonWritable scoped_non_writable(dex_location);
- ASSERT_TRUE(scoped_non_writable.IsSuccessful());
-
auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
OatFileAssistant oat_file_assistant = CreateOatFileAssistant(dex_location.c_str());
@@ -1288,7 +1191,7 @@ TEST_P(OatFileAssistantTest, ResourceOnlyDex) {
}
// Case: We have a DEX file, an ODEX file and an OAT file.
-// Expect: It shouldn't crash. We should load the odex file executable.
+// Expect: It shouldn't crash. We should load the oat file executable.
TEST_P(OatFileAssistantTest, OdexOatOverlap) {
std::string dex_location = GetScratchDir() + "/OdexOatOverlap.jar";
std::string odex_location = GetOdexDir() + "/OdexOatOverlap.odex";
@@ -1309,7 +1212,7 @@ TEST_P(OatFileAssistantTest, OdexOatOverlap) {
CompilerFilter::kSpeed,
/*expected_dexopt_needed=*/false,
/*expected_is_vdex_usable=*/true,
- /*expected_location=*/OatFileAssistant::kLocationOdex,
+ /*expected_location=*/OatFileAssistant::kLocationOat,
/*expected_legacy_result=*/OatFileAssistant::kNoDexOptNeeded);
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
@@ -1331,20 +1234,11 @@ TEST_P(OatFileAssistantTest, OdexOatOverlap) {
// Case: We have a DEX file and up-to-date OAT file for it.
// Expect: We should load an executable dex file.
TEST_P(OatFileAssistantTest, LoadOatUpToDate) {
- if (IsExecutedAsRoot()) {
- // We cannot simulate non writable locations when executed as root: b/38000545.
- LOG(ERROR) << "Test skipped because it's running as root";
- return;
- }
-
std::string dex_location = GetScratchDir() + "/LoadOatUpToDate.jar";
Copy(GetDexSrc1(), dex_location);
GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
- ScopedNonWritable scoped_non_writable(dex_location);
- ASSERT_TRUE(scoped_non_writable.IsSuccessful());
-
auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
// Load the oat using an oat file assistant.
@@ -1365,20 +1259,11 @@ TEST_P(OatFileAssistantTest, LoadOatUpToDate) {
// Case: We have a DEX file and up-to-date quicken OAT file for it.
// Expect: We should still load the oat file as executable.
TEST_P(OatFileAssistantTest, LoadExecInterpretOnlyOatUpToDate) {
- if (IsExecutedAsRoot()) {
- // We cannot simulate non writable locations when executed as root: b/38000545.
- LOG(ERROR) << "Test skipped because it's running as root";
- return;
- }
-
std::string dex_location = GetScratchDir() + "/LoadExecInterpretOnlyOatUpToDate.jar";
Copy(GetDexSrc1(), dex_location);
GenerateOatForTest(dex_location.c_str(), CompilerFilter::kVerify);
- ScopedNonWritable scoped_non_writable(dex_location);
- ASSERT_TRUE(scoped_non_writable.IsSuccessful());
-
auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
// Load the oat using an oat file assistant.
@@ -1399,19 +1284,10 @@ TEST_P(OatFileAssistantTest, LoadExecInterpretOnlyOatUpToDate) {
// Case: We have a DEX file and up-to-date OAT file for it.
// Expect: Loading non-executable should load the oat non-executable.
TEST_P(OatFileAssistantTest, LoadNoExecOatUpToDate) {
- if (IsExecutedAsRoot()) {
- // We cannot simulate non writable locations when executed as root: b/38000545.
- LOG(ERROR) << "Test skipped because it's running as root";
- return;
- }
-
std::string dex_location = GetScratchDir() + "/LoadNoExecOatUpToDate.jar";
Copy(GetDexSrc1(), dex_location);
- ScopedNonWritable scoped_non_writable(dex_location);
- ASSERT_TRUE(scoped_non_writable.IsSuccessful());
-
GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
auto scoped_maybe_without_runtime = ScopedMaybeWithoutRuntime();
diff --git a/tools/art b/tools/art
index 47724de9f9..a4ae3d57e5 100755
--- a/tools/art
+++ b/tools/art
@@ -127,34 +127,6 @@ find_cp_in_args() {
done
}
-# Delete the 'oat' directories relative to the classpath's dex files.
-# e.g. (foo/classes.dex bar/classes.dex) would delete (foo/oat bar/oat) directories.
-cleanup_oat_directory() {
- local classpath
- classpath=("$@")
-
- local dirpath
-
- for path in "${classpath[@]}"; do
- dirpath="$(dirname "$path")"
- [[ -d "$dirpath" ]] && verbose_run rm -rf "$dirpath/oat"
- done
-}
-
-# Parse -cp <CP>, -classpath <CP>, and $CLASSPATH to find the dex files.
-# Each dex file's directory will have an 'oat' file directory, delete it.
-# Input: Command line arguments to the art script.
-# e.g. -cp foo/classes.dex:bar/classes.dex would delete (foo/oat bar/oat) directories.
-cleanup_oat_directory_for_classpath() {
- if [ "$CLEAN_OAT_FILES" = "yes" ]; then
- # First try: Use $CLASSPATH environment variable.
- parse_classpath "$CLASSPATH"
- # Second try: Look for latest -cp or -classpath arg which will take precedence.
- find_cp_in_args "$@"
-
- cleanup_oat_directory "${PARSE_CLASSPATH_RESULT[@]}"
- fi
-}
# Attempt to find $ANDROID_ROOT/framework/<isa>/core.art' without knowing what <isa> is.
function check_if_boot_image_file_exists() {
@@ -198,11 +170,17 @@ function run_dex2oat() {
done
# Create oat file directory.
verbose_run mkdir -p $(dirname "$dex_file")/oat/$ISA
- local oat_file=$(basename "$dex_file")
- local oat_file=$(dirname "$dex_file")/oat/$ISA/${oat_file%.*}.odex
+ local oat_file="${dex_file:1}"
+ local oat_file="${oat_file//\//@}"
+ if [[ $dex_file != *.dex ]]; then
+ local oat_file=$ANDROID_DATA/dalvik-cache/$ISA/${oat_file}@classes.dex
+ else
+ local oat_file=$ANDROID_DATA/dalvik-cache/$ISA/${oat_file}
+ fi
if [ "$GENERATE_APP_IMAGE" = "yes" ]; then
- local art_file=$(basename "$dex_file")
- local art_file=$(dirname "$dex_file")/oat/$ISA/${art_file%.*}.art
+ local art_file="${dex_file:1}"
+ local art_file="${art_file//\//@}"
+ local art_file=$ANDROID_DATA/dalvik-cache/$ISA/${art_file%.*}.art
DEX2OAT_FLAGS+=("--app-image-file=$art_file")
fi
@@ -558,7 +536,7 @@ if [ "$ANDROID_DATA" = "/data" ] || [ "$ANDROID_DATA" = "" ]; then
# by default.
ANDROID_DATA="$ANDROID_DATA/local/tmp/android-data$$"
fi
- mkdir -p "$ANDROID_DATA"
+ mkdir -p "$ANDROID_DATA/dalvik-cache/$ISA"
DELETE_ANDROID_DATA="yes"
fi
@@ -629,9 +607,6 @@ if [ "$ALLOW_DEFAULT_JDWP" = "no" ]; then
EXTRA_OPTIONS+=(-XjdwpProvider:none)
fi
-# First cleanup any left-over 'oat' files from the last time dalvikvm was run.
-cleanup_oat_directory_for_classpath "$@"
-
# Protect additional arguments in quotes to preserve whitespaces (used by
# run-jdwp-test.sh when running on device), '$' (may be used as part of
# classpath) and other special characters when evaluated.