summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-01-10 18:43:21 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-01-10 18:43:21 +0000
commita358a1939c1300ea331e9ce9b87a7a869e8750e3 (patch)
treeef09510a48bde4a424c2427fc7eac3fb8e179336
parentb853df34583e3ad1deac3d56678714523605a8b0 (diff)
parent147f8bb89d7e785716275ef2c770f600376c81fa (diff)
downloadart-aml_tz5_341510010.tar.gz
Snap for 11296156 from 147f8bb89d7e785716275ef2c770f600376c81fa to mainline-tzdata5-releaseaml_tz5_341510070aml_tz5_341510050aml_tz5_341510010aml_tz5_341510010
Change-Id: I0631baca79cadbd2390cf64ce1e0331450d23a48
-rw-r--r--artd/Android.bp1
-rw-r--r--artd/artd.cc40
-rw-r--r--artd/artd.h7
-rw-r--r--artd/binder/com/android/server/art/IArtd.aidl13
-rw-r--r--artd/path_utils.cc48
-rw-r--r--artd/path_utils.h2
-rw-r--r--artd/path_utils_test.cc53
-rw-r--r--build/sdk/Android.bp5
-rw-r--r--dex2oat/Android.bp7
-rw-r--r--dex2oat/dex2oat_cts_test.cc238
-rw-r--r--libartbase/base/globals.h6
-rw-r--r--libartpalette/Android.bp22
-rw-r--r--libartpalette/apex/palette_test.cc34
-rw-r--r--libartservice/service/Android.bp11
-rw-r--r--libartservice/service/java/com/android/server/art/ArtJni.java63
-rw-r--r--libartservice/service/java/com/android/server/art/DexUseManagerLocal.java30
-rw-r--r--libartservice/service/javatests/com/android/server/art/DexUseManagerTest.java12
-rw-r--r--libartservice/service/native/service.cc97
-rw-r--r--libartservice/service/native/service.h12
-rw-r--r--libartservice/service/native/service_test.cc87
-rw-r--r--libdexfile/Android.bp7
-rw-r--r--libdexfile/dex/dex_file-inl.h9
-rw-r--r--libnativebridge/tests/Android.bp1
-rw-r--r--libnativeloader/Android.bp1
-rw-r--r--odrefresh/odr_config.h1
-rw-r--r--runtime/gc/collector/garbage_collector.cc50
-rw-r--r--runtime/image.cc80
-rw-r--r--runtime/jit/jit_code_cache.cc17
-rw-r--r--runtime/oat_file_assistant.cc14
-rw-r--r--runtime/oat_file_assistant.h6
-rw-r--r--runtime/trace.cc12
-rw-r--r--test/018-stack-overflow/Android.bp5
-rw-r--r--test/048-reflect-v8/Android.bp5
-rw-r--r--test/1911-get-local-var-table/src/art/Test1911.java175
-rw-r--r--test/913-heaps/src/art/Test913.java3
-rw-r--r--test/Android.bp37
-rw-r--r--test/art-gtests-target-standalone-cts-template.xml2
37 files changed, 847 insertions, 366 deletions
diff --git a/artd/Android.bp b/artd/Android.bp
index 1c964f489c..4862914839 100644
--- a/artd/Android.bp
+++ b/artd/Android.bp
@@ -35,6 +35,7 @@ cc_defaults {
"profman_headers",
],
shared_libs: [
+ "libartservice",
"libarttools", // Contains "libc++fs".
"libbase",
"libbinder_ndk",
diff --git a/artd/artd.cc b/artd/artd.cc
index 04a01a9ca4..8df6a70bc4 100644
--- a/artd/artd.cc
+++ b/artd/artd.cc
@@ -72,6 +72,7 @@
#include "path_utils.h"
#include "profman/profman_result.h"
#include "selinux/android.h"
+#include "service.h"
#include "tools/cmdline_builder.h"
#include "tools/tools.h"
@@ -107,6 +108,7 @@ using ::android::base::Split;
using ::android::base::StringReplace;
using ::android::base::WriteStringToFd;
using ::android::fs_mgr::FstabEntry;
+using ::art::service::ValidateDexPath;
using ::art::tools::CmdlineBuilder;
using ::ndk::ScopedAStatus;
@@ -1152,44 +1154,6 @@ ScopedAStatus Artd::isInDalvikCache(const std::string& in_dexFile, bool* _aidl_r
return NonFatal(ART_FORMAT("Fstab entries not found for '{}'", in_dexFile));
}
-ScopedAStatus Artd::validateDexPath(const std::string& in_dexPath,
- std::optional<std::string>* _aidl_return) {
- if (Result<void> result = ValidateDexPath(in_dexPath); !result.ok()) {
- *_aidl_return = result.error().message();
- } else {
- *_aidl_return = std::nullopt;
- }
- return ScopedAStatus::ok();
-}
-
-ScopedAStatus Artd::validateClassLoaderContext(const std::string& in_dexPath,
- const std::string& in_classLoaderContext,
- std::optional<std::string>* _aidl_return) {
- if (in_classLoaderContext == ClassLoaderContext::kUnsupportedClassLoaderContextEncoding) {
- *_aidl_return = std::nullopt;
- return ScopedAStatus::ok();
- }
-
- std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::Create(in_classLoaderContext);
- if (context == nullptr) {
- *_aidl_return = ART_FORMAT("Class loader context '{}' is invalid", in_classLoaderContext);
- return ScopedAStatus::ok();
- }
-
- std::vector<std::string> flattened_context = context->FlattenDexPaths();
- std::string dex_dir = Dirname(in_dexPath);
- for (const std::string& context_element : flattened_context) {
- std::string context_path = std::filesystem::path(dex_dir).append(context_element);
- if (Result<void> result = ValidateDexPath(context_path); !result.ok()) {
- *_aidl_return = result.error().message();
- return ScopedAStatus::ok();
- }
- }
-
- *_aidl_return = std::nullopt;
- return ScopedAStatus::ok();
-}
-
Result<void> Artd::Start() {
OR_RETURN(SetLogVerbosity());
diff --git a/artd/artd.h b/artd/artd.h
index 774f11a1d1..da85a035d9 100644
--- a/artd/artd.h
+++ b/artd/artd.h
@@ -166,13 +166,6 @@ class Artd : public aidl::com::android::server::art::BnArtd {
ndk::ScopedAStatus isInDalvikCache(const std::string& in_dexFile, bool* _aidl_return) override;
- ndk::ScopedAStatus validateDexPath(const std::string& in_dexPath,
- std::optional<std::string>* _aidl_return) override;
-
- ndk::ScopedAStatus validateClassLoaderContext(const std::string& in_dexPath,
- const std::string& in_classLoaderContext,
- std::optional<std::string>* _aidl_return) override;
-
android::base::Result<void> Start();
private:
diff --git a/artd/binder/com/android/server/art/IArtd.aidl b/artd/binder/com/android/server/art/IArtd.aidl
index 3b55297ab2..5465795010 100644
--- a/artd/binder/com/android/server/art/IArtd.aidl
+++ b/artd/binder/com/android/server/art/IArtd.aidl
@@ -178,17 +178,4 @@ interface IArtd {
* Throws fatal and non-fatal errors.
*/
boolean isInDalvikCache(@utf8InCpp String dexFile);
-
- /**
- * Returns an error message if the given dex path is invalid, or null if the validation
- * passes.
- */
- @nullable @utf8InCpp String validateDexPath(@utf8InCpp String dexPath);
-
- /**
- * Returns an error message if the given class loader context is invalid, or null if the
- * validation passes.
- */
- @nullable @utf8InCpp String validateClassLoaderContext(@utf8InCpp String dexPath,
- @utf8InCpp String classLoaderContext);
}
diff --git a/artd/path_utils.cc b/artd/path_utils.cc
index 6ff9b95bc1..95e4395a1c 100644
--- a/artd/path_utils.cc
+++ b/artd/path_utils.cc
@@ -30,6 +30,7 @@
#include "file_utils.h"
#include "fstab/fstab.h"
#include "oat_file_assistant.h"
+#include "service.h"
#include "tools/tools.h"
namespace art {
@@ -47,6 +48,9 @@ using ::android::base::StartsWith;
using ::android::fs_mgr::Fstab;
using ::android::fs_mgr::FstabEntry;
using ::android::fs_mgr::ReadFstabFromProcMounts;
+using ::art::service::ValidateDexPath;
+using ::art::service::ValidatePathElement;
+using ::art::service::ValidatePathElementSubstring;
using PrebuiltProfilePath = ProfilePath::PrebuiltProfilePath;
using PrimaryCurProfilePath = ProfilePath::PrimaryCurProfilePath;
@@ -56,45 +60,6 @@ using SecondaryRefProfilePath = ProfilePath::SecondaryRefProfilePath;
using TmpProfilePath = ProfilePath::TmpProfilePath;
using WritableProfilePath = ProfilePath::WritableProfilePath;
-Result<void> ValidateAbsoluteNormalPath(const std::string& path_str) {
- if (path_str.empty()) {
- return Errorf("Path is empty");
- }
- if (path_str.find('\0') != std::string::npos) {
- return Errorf("Path '{}' has invalid character '\\0'", path_str);
- }
- std::filesystem::path path(path_str);
- if (!path.is_absolute()) {
- return Errorf("Path '{}' is not an absolute path", path_str);
- }
- if (path.lexically_normal() != path_str) {
- return Errorf("Path '{}' is not in normal form", path_str);
- }
- return {};
-}
-
-Result<void> ValidatePathElementSubstring(const std::string& path_element_substring,
- const std::string& name) {
- if (path_element_substring.empty()) {
- return Errorf("{} is empty", name);
- }
- if (path_element_substring.find('/') != std::string::npos) {
- return Errorf("{} '{}' has invalid character '/'", name, path_element_substring);
- }
- if (path_element_substring.find('\0') != std::string::npos) {
- return Errorf("{} '{}' has invalid character '\\0'", name, path_element_substring);
- }
- return {};
-}
-
-Result<void> ValidatePathElement(const std::string& path_element, const std::string& name) {
- OR_RETURN(ValidatePathElementSubstring(path_element, name));
- if (path_element == "." || path_element == "..") {
- return Errorf("Invalid {} '{}'", name, path_element);
- }
- return {};
-}
-
Result<std::string> GetAndroidDataOrError() {
std::string error_msg;
std::string result = GetAndroidDataSafe(&error_msg);
@@ -155,11 +120,6 @@ Result<std::vector<std::string>> ListManagedFiles() {
return tools::Glob(patterns);
}
-Result<void> ValidateDexPath(const std::string& dex_path) {
- OR_RETURN(ValidateAbsoluteNormalPath(dex_path));
- return {};
-}
-
Result<std::string> BuildArtBinPath(const std::string& binary_name) {
return ART_FORMAT("{}/bin/{}", OR_RETURN(GetArtRootOrError()), binary_name);
}
diff --git a/artd/path_utils.h b/artd/path_utils.h
index a126118137..62d6005bf6 100644
--- a/artd/path_utils.h
+++ b/artd/path_utils.h
@@ -31,8 +31,6 @@ namespace artd {
// Returns all existing files that are managed by artd.
android::base::Result<std::vector<std::string>> ListManagedFiles();
-android::base::Result<void> ValidateDexPath(const std::string& dex_path);
-
android::base::Result<std::string> BuildArtBinPath(const std::string& binary_name);
// Returns the absolute path to the OAT file built from the `ArtifactsPath`.
diff --git a/artd/path_utils_test.cc b/artd/path_utils_test.cc
index c9fb809d03..626690787a 100644
--- a/artd/path_utils_test.cc
+++ b/artd/path_utils_test.cc
@@ -63,29 +63,12 @@ TEST_F(PathUtilsTest, BuildOatPathDalvikCache) {
HasValue(android_data_ + "/dalvik-cache/arm64/a@b.apk@classes.dex"));
}
-TEST_F(PathUtilsTest, BuildOatPathEmptyDexPath) {
- EXPECT_THAT(BuildOatPath(ArtifactsPath{.dexPath = "", .isa = "arm64", .isInDalvikCache = false}),
- HasError(WithMessage("Path is empty")));
-}
-
-TEST_F(PathUtilsTest, BuildOatPathRelativeDexPath) {
+TEST_F(PathUtilsTest, BuildOatPathInvalidDexPath) {
EXPECT_THAT(
BuildOatPath(ArtifactsPath{.dexPath = "a/b.apk", .isa = "arm64", .isInDalvikCache = false}),
HasError(WithMessage("Path 'a/b.apk' is not an absolute path")));
}
-TEST_F(PathUtilsTest, BuildOatPathNonNormalDexPath) {
- EXPECT_THAT(BuildOatPath(ArtifactsPath{
- .dexPath = "/a/c/../b.apk", .isa = "arm64", .isInDalvikCache = false}),
- HasError(WithMessage("Path '/a/c/../b.apk' is not in normal form")));
-}
-
-TEST_F(PathUtilsTest, BuildOatPathNul) {
- EXPECT_THAT(BuildOatPath(ArtifactsPath{
- .dexPath = "/a/\0/b.apk"s, .isa = "arm64", .isInDalvikCache = false}),
- HasError(WithMessage("Path '/a/\0/b.apk' has invalid character '\\0'"s)));
-}
-
TEST_F(PathUtilsTest, BuildOatPathInvalidIsa) {
EXPECT_THAT(BuildOatPath(
ArtifactsPath{.dexPath = "/a/b.apk", .isa = "invalid", .isInDalvikCache = false}),
@@ -110,51 +93,27 @@ TEST_F(PathUtilsTest, BuildPrimaryRefProfilePathPackageNameOk) {
EXPECT_THAT(BuildPrimaryRefProfilePath(
PrimaryRefProfilePath{.packageName = "...", .profileName = "primary"}),
HasValue(android_data_ + "/misc/profiles/ref/.../primary.prof"));
- EXPECT_THAT(BuildPrimaryRefProfilePath(
- PrimaryRefProfilePath{.packageName = "!@#$%^&*()_+-=", .profileName = "primary"}),
- HasValue(android_data_ + "/misc/profiles/ref/!@#$%^&*()_+-=/primary.prof"));
}
TEST_F(PathUtilsTest, BuildPrimaryRefProfilePathPackageNameWrong) {
EXPECT_THAT(BuildPrimaryRefProfilePath(
- PrimaryRefProfilePath{.packageName = "", .profileName = "primary"}),
- HasError(WithMessage("packageName is empty")));
- EXPECT_THAT(BuildPrimaryRefProfilePath(
- PrimaryRefProfilePath{.packageName = ".", .profileName = "primary"}),
- HasError(WithMessage("Invalid packageName '.'")));
- EXPECT_THAT(BuildPrimaryRefProfilePath(
PrimaryRefProfilePath{.packageName = "..", .profileName = "primary"}),
HasError(WithMessage("Invalid packageName '..'")));
EXPECT_THAT(BuildPrimaryRefProfilePath(
PrimaryRefProfilePath{.packageName = "a/b", .profileName = "primary"}),
HasError(WithMessage("packageName 'a/b' has invalid character '/'")));
- EXPECT_THAT(BuildPrimaryRefProfilePath(
- PrimaryRefProfilePath{.packageName = "a\0b"s, .profileName = "primary"}),
- HasError(WithMessage("packageName 'a\0b' has invalid character '\\0'"s)));
}
TEST_F(PathUtilsTest, BuildPrimaryRefProfilePathProfileNameOk) {
EXPECT_THAT(BuildPrimaryRefProfilePath(
- PrimaryRefProfilePath{.packageName = "com.android.foo", .profileName = "."}),
- HasValue(android_data_ + "/misc/profiles/ref/com.android.foo/..prof"));
- EXPECT_THAT(BuildPrimaryRefProfilePath(
PrimaryRefProfilePath{.packageName = "com.android.foo", .profileName = ".."}),
HasValue(android_data_ + "/misc/profiles/ref/com.android.foo/...prof"));
- EXPECT_THAT(BuildPrimaryRefProfilePath(PrimaryRefProfilePath{.packageName = "com.android.foo",
- .profileName = "!@#$%^&*()_+-="}),
- HasValue(android_data_ + "/misc/profiles/ref/com.android.foo/!@#$%^&*()_+-=.prof"));
}
TEST_F(PathUtilsTest, BuildPrimaryRefProfilePathProfileNameWrong) {
EXPECT_THAT(BuildPrimaryRefProfilePath(
- PrimaryRefProfilePath{.packageName = "com.android.foo", .profileName = ""}),
- HasError(WithMessage("profileName is empty")));
- EXPECT_THAT(BuildPrimaryRefProfilePath(
PrimaryRefProfilePath{.packageName = "com.android.foo", .profileName = "a/b"}),
HasError(WithMessage("profileName 'a/b' has invalid character '/'")));
- EXPECT_THAT(BuildPrimaryRefProfilePath(
- PrimaryRefProfilePath{.packageName = "com.android.foo", .profileName = "a\0b"s}),
- HasError(WithMessage("profileName 'a\0b' has invalid character '\\0'"s)));
}
TEST_F(PathUtilsTest, BuildFinalProfilePathForPrimary) {
@@ -194,18 +153,8 @@ TEST_F(PathUtilsTest, BuildTmpProfilePathIdWrong) {
EXPECT_THAT(BuildTmpProfilePath(TmpProfilePath{
.finalPath = PrimaryRefProfilePath{.packageName = "com.android.foo",
.profileName = "primary"},
- .id = ""}),
- HasError(WithMessage("id is empty")));
- EXPECT_THAT(BuildTmpProfilePath(TmpProfilePath{
- .finalPath = PrimaryRefProfilePath{.packageName = "com.android.foo",
- .profileName = "primary"},
.id = "123/45"}),
HasError(WithMessage("id '123/45' has invalid character '/'")));
- EXPECT_THAT(BuildTmpProfilePath(TmpProfilePath{
- .finalPath = PrimaryRefProfilePath{.packageName = "com.android.foo",
- .profileName = "primary"},
- .id = "123\0a"s}),
- HasError(WithMessage("id '123\0a' has invalid character '\\0'"s)));
}
TEST_F(PathUtilsTest, BuildPrebuiltProfilePath) {
diff --git a/build/sdk/Android.bp b/build/sdk/Android.bp
index b47bdc2fee..8723d20ff3 100644
--- a/build/sdk/Android.bp
+++ b/build/sdk/Android.bp
@@ -160,11 +160,6 @@ art_module_exports {
prebuilt_visibility: prebuilt_visibility,
- java_libs: [
- // Needed for grpc-grpc-java
- "okhttp-norepackage",
- ],
-
target: {
host: {
// Set in target.host because the top level compile_multilib
diff --git a/dex2oat/Android.bp b/dex2oat/Android.bp
index 7341774889..e37d18d148 100644
--- a/dex2oat/Android.bp
+++ b/dex2oat/Android.bp
@@ -620,7 +620,7 @@ art_cc_test {
// Counterpart to art_standalone_dex2oat_tests for tests that go into CTS.
art_cc_test {
name: "art_standalone_dex2oat_cts_tests",
- defaults: ["art_standalone_gtest_defaults"],
+ defaults: ["art_cts_gtest_defaults"],
srcs: ["dex2oat_cts_test.cc"],
data: [
":art-gtest-jars-Main",
@@ -638,5 +638,8 @@ art_cc_test {
"libziparchive",
],
test_config: "art_standalone_dex2oat_cts_tests.xml",
- test_suites: ["cts"],
+ test_suites: [
+ "cts",
+ "mcts-art",
+ ],
}
diff --git a/dex2oat/dex2oat_cts_test.cc b/dex2oat/dex2oat_cts_test.cc
index 254126446d..25cd94bb93 100644
--- a/dex2oat/dex2oat_cts_test.cc
+++ b/dex2oat/dex2oat_cts_test.cc
@@ -14,24 +14,252 @@
* limitations under the License.
*/
+#include <dirent.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <fstream>
+#include <functional>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "android-base/file.h"
+#include "android-base/unique_fd.h"
#include "base/file_utils.h"
-#include "dex2oat_environment_test.h"
+#include "base/os.h"
+#include "base/stl_util.h"
+#include "base/unix_file/fd_file.h"
+#include "gtest/gtest.h"
namespace art {
+namespace {
+
+void ClearDirectory(const char* dirpath, bool recursive = true) {
+ ASSERT_TRUE(dirpath != nullptr);
+ DIR* dir = opendir(dirpath);
+ ASSERT_TRUE(dir != nullptr);
+ dirent* e;
+ struct stat s;
+ while ((e = readdir(dir)) != nullptr) {
+ if ((strcmp(e->d_name, ".") == 0) || (strcmp(e->d_name, "..") == 0)) {
+ continue;
+ }
+ std::string filename(dirpath);
+ filename.push_back('/');
+ filename.append(e->d_name);
+ int stat_result = lstat(filename.c_str(), &s);
+ ASSERT_EQ(0, stat_result) << "unable to stat " << filename;
+ if (S_ISDIR(s.st_mode)) {
+ if (recursive) {
+ ClearDirectory(filename.c_str());
+ int rmdir_result = rmdir(filename.c_str());
+ ASSERT_EQ(0, rmdir_result) << filename;
+ }
+ } else {
+ int unlink_result = unlink(filename.c_str());
+ ASSERT_EQ(0, unlink_result) << filename;
+ }
+ }
+ closedir(dir);
+}
+
+class Dex2oatScratchDirs {
+ public:
+ void SetUp(const std::string& android_data) {
+ // Create a scratch directory to work from.
+
+ // Get the realpath of the android data. The oat dir should always point to real location
+ // when generating oat files in dalvik-cache. This avoids complicating the unit tests
+ // when matching the expected paths.
+ UniqueCPtr<const char[]> android_data_real(realpath(android_data.c_str(), nullptr));
+ ASSERT_TRUE(android_data_real != nullptr)
+ << "Could not get the realpath of the android data" << android_data << strerror(errno);
+
+ scratch_dir_.assign(android_data_real.get());
+ scratch_dir_ += "/Dex2oatEnvironmentTest";
+ ASSERT_EQ(0, mkdir(scratch_dir_.c_str(), 0700));
+
+ // Create a subdirectory in scratch for odex files.
+ odex_oat_dir_ = scratch_dir_ + "/oat";
+ ASSERT_EQ(0, mkdir(odex_oat_dir_.c_str(), 0700));
+
+ odex_dir_ = odex_oat_dir_ + "/" + std::string(GetInstructionSetString(kRuntimeISA));
+ ASSERT_EQ(0, mkdir(odex_dir_.c_str(), 0700));
+ }
+
+ void TearDown() {
+ ClearDirectory(odex_dir_.c_str());
+ ASSERT_EQ(0, rmdir(odex_dir_.c_str()));
-class Dex2oatCtsTest : public CommonArtTest, public Dex2oatScratchDirs {
+ ClearDirectory(odex_oat_dir_.c_str());
+ ASSERT_EQ(0, rmdir(odex_oat_dir_.c_str()));
+
+ ClearDirectory(scratch_dir_.c_str());
+ ASSERT_EQ(0, rmdir(scratch_dir_.c_str()));
+ }
+
+ // Scratch directory, for dex and odex files (oat files will go in the
+ // dalvik cache).
+ const std::string& GetScratchDir() const { return scratch_dir_; }
+
+ // Odex directory is the subdirectory in the scratch directory where odex
+ // files should be located.
+ const std::string& GetOdexDir() const { return odex_dir_; }
+
+ private:
+ std::string scratch_dir_;
+ std::string odex_oat_dir_;
+ std::string odex_dir_;
+};
+
+class Dex2oatCtsTest : public Dex2oatScratchDirs, public testing::Test {
public:
+ void SetUpAndroidDataDir(std::string& android_data) {
+ android_data = "/data/local/tmp";
+ android_data += "/art-data-XXXXXX";
+ if (mkdtemp(&android_data[0]) == nullptr) {
+ PLOG(FATAL) << "mkdtemp(\"" << &android_data[0] << "\") failed";
+ }
+ setenv("ANDROID_DATA", android_data.c_str(), 1);
+ }
+
+ void TearDownAndroidDataDir(const std::string& android_data,
+ bool fail_on_error) {
+ if (fail_on_error) {
+ ASSERT_EQ(rmdir(android_data.c_str()), 0);
+ } else {
+ rmdir(android_data.c_str());
+ }
+ }
+
+ std::string GetTestDexFileName(const char* name) const {
+ CHECK(name != nullptr);
+ // The needed jar files for gtest are located next to the gtest binary itself.
+ std::string executable_dir = android::base::GetExecutableDirectory();
+ for (auto ext : {".jar", ".dex"}) {
+ std::string path = executable_dir + "/art-gtest-jars-" + name + ext;
+ if (OS::FileExists(path.c_str())) {
+ return path;
+ }
+ }
+ LOG(FATAL) << "Test file " << name << " not found";
+ UNREACHABLE();
+ }
+
void SetUp() override {
- CommonArtTest::SetUp();
+ SetUpAndroidDataDir(android_data_);
Dex2oatScratchDirs::SetUp(android_data_);
}
void TearDown() override {
Dex2oatScratchDirs::TearDown();
- CommonArtTest::TearDown();
+ TearDownAndroidDataDir(android_data_, true);
+ }
+
+ struct ForkAndExecResult {
+ enum Stage {
+ kLink,
+ kFork,
+ kWaitpid,
+ kFinished,
+ };
+ Stage stage;
+ int status_code;
+
+ bool StandardSuccess() {
+ return stage == kFinished && WIFEXITED(status_code) && WEXITSTATUS(status_code) == 0;
+ }
+ };
+ using OutputHandlerFn = std::function<void(char*, size_t)>;
+ using PostForkFn = std::function<bool()>;
+
+ ForkAndExecResult ForkAndExec(
+ const std::vector<std::string>& argv,
+ const PostForkFn& post_fork,
+ const OutputHandlerFn& handler) {
+ ForkAndExecResult result;
+ result.status_code = 0;
+ result.stage = ForkAndExecResult::kLink;
+
+ std::vector<const char*> c_args;
+ c_args.reserve(argv.size() + 1);
+ for (const std::string& str : argv) {
+ c_args.push_back(str.c_str());
+ }
+ c_args.push_back(nullptr);
+
+ android::base::unique_fd link[2];
+ {
+ int link_fd[2];
+
+ if (pipe(link_fd) == -1) {
+ return result;
+ }
+ link[0].reset(link_fd[0]);
+ link[1].reset(link_fd[1]);
+ }
+
+ result.stage = ForkAndExecResult::kFork;
+
+ pid_t pid = fork();
+ if (pid == -1) {
+ return result;
+ }
+
+ if (pid == 0) {
+ if (!post_fork()) {
+ LOG(ERROR) << "Failed post-fork function";
+ exit(1);
+ UNREACHABLE();
+ }
+
+ // Redirect stdout and stderr.
+ dup2(link[1].get(), STDOUT_FILENO);
+ dup2(link[1].get(), STDERR_FILENO);
+
+ link[0].reset();
+ link[1].reset();
+
+ execv(c_args[0], const_cast<char* const*>(c_args.data()));
+ exit(1);
+ UNREACHABLE();
+ }
+
+ result.stage = ForkAndExecResult::kWaitpid;
+ link[1].reset();
+
+ char buffer[128] = { 0 };
+ ssize_t bytes_read = 0;
+ while (TEMP_FAILURE_RETRY(bytes_read = read(link[0].get(), buffer, 128)) > 0) {
+ handler(buffer, bytes_read);
+ }
+ handler(buffer, 0u); // End with a virtual write of zero length to simplify clients.
+
+ link[0].reset();
+
+ if (waitpid(pid, &result.status_code, 0) == -1) {
+ return result;
+ }
+
+ result.stage = ForkAndExecResult::kFinished;
+ return result;
+ }
+
+ ForkAndExecResult ForkAndExec(
+ const std::vector<std::string>& argv, const PostForkFn& post_fork, std::string* output) {
+ auto string_collect_fn = [output](char* buf, size_t len) {
+ *output += std::string(buf, len);
+ };
+ return ForkAndExec(argv, post_fork, string_collect_fn);
}
protected:
+ std::string android_data_;
+
// Stripped down counterpart to Dex2oatEnvironmentTest::Dex2Oat that only adds
// enough arguments for our purposes.
int Dex2Oat(const std::vector<std::string>& dex2oat_args,
@@ -63,6 +291,8 @@ class Dex2oatCtsTest : public CommonArtTest, public Dex2oatScratchDirs {
}
};
+} // namespace
+
// Run dex2oat with --enable-palette-compilation-hooks to force calls to
// PaletteNotify{Start,End}Dex2oatCompilation.
TEST_F(Dex2oatCtsTest, CompilationHooks) {
diff --git a/libartbase/base/globals.h b/libartbase/base/globals.h
index 4103154db1..14e056d8ad 100644
--- a/libartbase/base/globals.h
+++ b/libartbase/base/globals.h
@@ -118,12 +118,6 @@ static constexpr bool kHostStaticBuildEnabled = true;
static constexpr bool kHostStaticBuildEnabled = false;
#endif
-// System property for phenotype flag to test disabling compact dex and in
-// particular dexlayout.
-// TODO(b/256664509): Clean this up.
-static constexpr char kPhDisableCompactDex[] =
- "persist.device_config.runtime_native_boot.disable_compact_dex";
-
} // namespace art
#endif // ART_LIBARTBASE_BASE_GLOBALS_H_
diff --git a/libartpalette/Android.bp b/libartpalette/Android.bp
index 6e7415e7b1..60607097d8 100644
--- a/libartpalette/Android.bp
+++ b/libartpalette/Android.bp
@@ -114,10 +114,6 @@ art_cc_library {
art_cc_defaults {
name: "art_libartpalette_tests_defaults",
srcs: ["apex/palette_test.cc"],
- shared_libs: [
- "libartpalette",
- "libnativehelper",
- ],
target: {
android: {
static_libs: ["libmodules-utils-build"],
@@ -133,6 +129,10 @@ art_cc_test {
"art_gtest_defaults",
"art_libartpalette_tests_defaults",
],
+ shared_libs: [
+ "libartpalette",
+ "libnativehelper",
+ ],
host_supported: true,
}
@@ -141,9 +141,19 @@ art_cc_test {
art_cc_test {
name: "art_standalone_libartpalette_tests",
defaults: [
- "art_standalone_gtest_defaults",
+ "art_cts_gtest_defaults",
"art_libartpalette_tests_defaults",
],
+ static_libs: [
+ "libartpalette",
+ "libc++fs",
+ // libnativehelper_lazy has the glue we need to dlsym the platform-only
+ // APIs we need, like JniInvocationInit.
+ "libnativehelper_lazy",
+ ],
test_config_template: ":art-gtests-target-standalone-cts-template",
- test_suites: ["cts"],
+ test_suites: [
+ "cts",
+ "mcts-art",
+ ],
}
diff --git a/libartpalette/apex/palette_test.cc b/libartpalette/apex/palette_test.cc
index 63072c491b..f2b4858e66 100644
--- a/libartpalette/apex/palette_test.cc
+++ b/libartpalette/apex/palette_test.cc
@@ -28,8 +28,8 @@
#include "android/api-level.h"
#endif
-#include "base/common_art_test.h"
#include "gtest/gtest.h"
+#include "nativehelper/JniInvocation.h" \
namespace {
@@ -88,27 +88,28 @@ TEST_F(PaletteClientTest, Ashmem) {
#endif
}
-class PaletteClientJniTest : public art::CommonArtTest {};
-
-TEST_F(PaletteClientJniTest, JniInvocation) {
+TEST_F(PaletteClientTest, JniInvocation) {
+#ifndef ART_TARGET_ANDROID
+ // On host we need to set up a boot classpath and pass it in here. Let's not
+ // bother since this test is only for native API coverage on target.
+ GTEST_SKIP() << "Will only spin up a VM on Android";
+#else
bool enabled;
EXPECT_EQ(PALETTE_STATUS_OK, PaletteShouldReportJniInvocations(&enabled));
- std::string boot_class_path_string =
- GetClassPathOption("-Xbootclasspath:", GetLibCoreDexFileNames());
- std::string boot_class_path_locations_string =
- GetClassPathOption("-Xbootclasspath-locations:", GetLibCoreDexLocations());
+ // This calls JniInvocationInit, which is necessary to load the VM. It's not
+ // public but still stable.
+ JniInvocation jni_invocation;
+ ASSERT_TRUE(jni_invocation.Init(nullptr));
+ JavaVMInitArgs vm_args;
JavaVMOption options[] = {
- {.optionString = boot_class_path_string.c_str(), .extraInfo = nullptr},
- {.optionString = boot_class_path_locations_string.c_str(), .extraInfo = nullptr},
- };
- JavaVMInitArgs vm_args = {
- .version = JNI_VERSION_1_6,
- .nOptions = std::size(options),
- .options = options,
- .ignoreUnrecognized = JNI_TRUE,
+ {.optionString = "-verbose:jni", .extraInfo = nullptr},
};
+ vm_args.version = JNI_VERSION_1_6;
+ vm_args.nOptions = std::size(options);
+ vm_args.options = options;
+ vm_args.ignoreUnrecognized = JNI_TRUE;
JavaVM* jvm = nullptr;
JNIEnv* env = nullptr;
@@ -119,6 +120,7 @@ TEST_F(PaletteClientJniTest, JniInvocation) {
PaletteNotifyEndJniInvocation(env);
EXPECT_EQ(JNI_OK, jvm->DestroyJavaVM());
+#endif
}
TEST_F(PaletteClientTest, SetTaskProfiles) {
diff --git a/libartservice/service/Android.bp b/libartservice/service/Android.bp
index 7faa20d2fa..e013d688d7 100644
--- a/libartservice/service/Android.bp
+++ b/libartservice/service/Android.bp
@@ -30,8 +30,11 @@ cc_defaults {
srcs: [
"native/service.cc",
],
+ export_include_dirs: ["native"],
shared_libs: [
+ "libarttools", // Contains "libc++fs".
"libbase",
+ "libnativehelper",
],
}
@@ -43,6 +46,8 @@ cc_library {
"com.android.art.debug",
],
shared_libs: [
+ "libart",
+ "libartbase",
],
}
@@ -57,6 +62,8 @@ cc_library {
"com.android.art.debug",
],
shared_libs: [
+ "libartd",
+ "libartbased",
],
}
@@ -178,6 +185,9 @@ art_cc_defaults {
srcs: [
"native/service_test.cc",
],
+ static_libs: [
+ "libgmock",
+ ],
}
// Version of ART gtest `art_libartservice_tests` bundled with the ART APEX on target.
@@ -225,6 +235,7 @@ android_test {
],
jni_libs: [
+ "libartservice",
// The two libraries below are required by ExtendedMockito.
"libdexmakerjvmtiagent",
"libstaticjvmtiagent",
diff --git a/libartservice/service/java/com/android/server/art/ArtJni.java b/libartservice/service/java/com/android/server/art/ArtJni.java
new file mode 100644
index 0000000000..2cc9ea8911
--- /dev/null
+++ b/libartservice/service/java/com/android/server/art/ArtJni.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+package com.android.server.art;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import dalvik.system.VMRuntime;
+
+/**
+ * JNI methods for ART Service, with wrappers added for testability because Mockito cannot mock JNI
+ * methods.
+ *
+ * @hide
+ */
+public class ArtJni {
+ static {
+ if (VMRuntime.getRuntime().vmLibrary().equals("libartd.so")) {
+ System.loadLibrary("artserviced");
+ } else {
+ System.loadLibrary("artservice");
+ }
+ }
+
+ private ArtJni() {}
+
+ /**
+ * Returns an error message if the given dex path is invalid, or null if the validation passes.
+ */
+ @Nullable
+ public static String validateDexPath(@NonNull String dexPath) {
+ return validateDexPathNative(dexPath);
+ }
+
+ /**
+ * Returns an error message if the given class loader context is invalid, or null if the
+ * validation passes.
+ */
+ @Nullable
+ public static String validateClassLoaderContext(
+ @NonNull String dexPath, @NonNull String classLoaderContext) {
+ return validateClassLoaderContextNative(dexPath, classLoaderContext);
+ }
+
+ @Nullable private static native String validateDexPathNative(@NonNull String dexPath);
+ @Nullable
+ private static native String validateClassLoaderContextNative(
+ @NonNull String dexPath, @NonNull String classLoaderContext);
+}
diff --git a/libartservice/service/java/com/android/server/art/DexUseManagerLocal.java b/libartservice/service/java/com/android/server/art/DexUseManagerLocal.java
index 97b3c8a186..c73f71b9e3 100644
--- a/libartservice/service/java/com/android/server/art/DexUseManagerLocal.java
+++ b/libartservice/service/java/com/android/server/art/DexUseManagerLocal.java
@@ -566,7 +566,8 @@ public class DexUseManagerLocal {
}
mDexUse = new DexUse();
if (proto != null) {
- mDexUse.fromProto(proto, this::validateDexPath, this::validateClassLoaderContext);
+ mDexUse.fromProto(
+ proto, ArtJni::validateDexPath, ArtJni::validateClassLoaderContext);
}
}
}
@@ -600,12 +601,12 @@ public class DexUseManagerLocal {
for (var entry : classLoaderContextByDexContainerFile.entrySet()) {
Utils.assertNonEmpty(entry.getKey());
- String errorMsg = validateDexPath(entry.getKey());
+ String errorMsg = ArtJni.validateDexPath(entry.getKey());
if (errorMsg != null) {
throw new IllegalArgumentException(errorMsg);
}
Utils.assertNonEmpty(entry.getValue());
- errorMsg = validateClassLoaderContext(entry.getKey(), entry.getValue());
+ errorMsg = ArtJni.validateClassLoaderContext(entry.getKey(), entry.getValue());
if (errorMsg != null) {
throw new IllegalArgumentException(errorMsg);
}
@@ -623,29 +624,6 @@ public class DexUseManagerLocal {
}
}
- @Nullable
- private String validateDexPath(@NonNull String dexPath) {
- try {
- return mInjector.getArtd().validateDexPath(dexPath);
- } catch (RemoteException e) {
- String errorMsg = "Failed to validate dex path " + dexPath;
- Log.e(TAG, errorMsg, e);
- return errorMsg;
- }
- }
-
- @Nullable
- private String validateClassLoaderContext(
- @NonNull String dexPath, @NonNull String classLoaderContext) {
- try {
- return mInjector.getArtd().validateClassLoaderContext(dexPath, classLoaderContext);
- } catch (RemoteException e) {
- String errorMsg = "Failed to validate class loader context " + classLoaderContext;
- Log.e(TAG, errorMsg, e);
- return errorMsg;
- }
- }
-
/** @hide */
@Nullable
public String getSecondaryClassLoaderContext(
diff --git a/libartservice/service/javatests/com/android/server/art/DexUseManagerTest.java b/libartservice/service/javatests/com/android/server/art/DexUseManagerTest.java
index f34cd434ed..83cb81c1df 100644
--- a/libartservice/service/javatests/com/android/server/art/DexUseManagerTest.java
+++ b/libartservice/service/javatests/com/android/server/art/DexUseManagerTest.java
@@ -81,8 +81,8 @@ public class DexUseManagerTest {
private static final String SPLIT_APK = "/data/app/" + OWNING_PKG_NAME + "/split_0.apk";
@Rule
- public StaticMockitoRule mockitoRule =
- new StaticMockitoRule(SystemProperties.class, Constants.class, Process.class);
+ public StaticMockitoRule mockitoRule = new StaticMockitoRule(
+ SystemProperties.class, Constants.class, Process.class, ArtJni.class);
private final UserHandle mUserHandle = Binder.getCallingUserHandle();
@@ -155,8 +155,8 @@ public class DexUseManagerTest {
mTempFile = File.createTempFile("package-dex-usage", ".pb");
mTempFile.deleteOnExit();
- lenient().when(mArtd.validateDexPath(any())).thenReturn(null);
- lenient().when(mArtd.validateClassLoaderContext(any(), any())).thenReturn(null);
+ lenient().when(ArtJni.validateDexPath(any())).thenReturn(null);
+ lenient().when(ArtJni.validateClassLoaderContext(any(), any())).thenReturn(null);
lenient().when(mInjector.getArtd()).thenReturn(mArtd);
lenient().when(mInjector.getCurrentTimeMillis()).thenReturn(0l);
@@ -712,14 +712,14 @@ public class DexUseManagerTest {
@Test(expected = IllegalArgumentException.class)
public void testInvalidDexPath() throws Exception {
- lenient().when(mArtd.validateDexPath(any())).thenReturn("invalid");
+ lenient().when(ArtJni.validateDexPath(any())).thenReturn("invalid");
mDexUseManager.notifyDexContainersLoaded(
mSnapshot, OWNING_PKG_NAME, Map.of("/a/b.jar", "PCL[]"));
}
@Test(expected = IllegalArgumentException.class)
public void testInvalidClassLoaderContext() throws Exception {
- lenient().when(mArtd.validateClassLoaderContext(any(), any())).thenReturn("invalid");
+ lenient().when(ArtJni.validateClassLoaderContext(any(), any())).thenReturn("invalid");
mDexUseManager.notifyDexContainersLoaded(
mSnapshot, OWNING_PKG_NAME, Map.of("/a/b.jar", "PCL[]"));
}
diff --git a/libartservice/service/native/service.cc b/libartservice/service/native/service.cc
index d33cb59515..7d223e5c35 100644
--- a/libartservice/service/native/service.cc
+++ b/libartservice/service/native/service.cc
@@ -16,12 +16,105 @@
#include "service.h"
+#include <jni.h>
+
+#include <filesystem>
+
+#include "android-base/errors.h"
+#include "android-base/file.h"
+#include "android-base/result.h"
+#include "class_loader_context.h"
+#include "nativehelper/utils.h"
+
namespace art {
namespace service {
-std::string getMsg() {
- return "hello world!";
+using ::android::base::Dirname;
+using ::android::base::Result;
+
+Result<void> ValidateAbsoluteNormalPath(const std::string& path_str) {
+ if (path_str.empty()) {
+ return Errorf("Path is empty");
+ }
+ if (path_str.find('\0') != std::string::npos) {
+ return Errorf("Path '{}' has invalid character '\\0'", path_str);
+ }
+ std::filesystem::path path(path_str);
+ if (!path.is_absolute()) {
+ return Errorf("Path '{}' is not an absolute path", path_str);
+ }
+ if (path.lexically_normal() != path_str) {
+ return Errorf("Path '{}' is not in normal form", path_str);
+ }
+ return {};
}
+Result<void> ValidatePathElementSubstring(const std::string& path_element_substring,
+ const std::string& name) {
+ if (path_element_substring.empty()) {
+ return Errorf("{} is empty", name);
+ }
+ if (path_element_substring.find('/') != std::string::npos) {
+ return Errorf("{} '{}' has invalid character '/'", name, path_element_substring);
+ }
+ if (path_element_substring.find('\0') != std::string::npos) {
+ return Errorf("{} '{}' has invalid character '\\0'", name, path_element_substring);
+ }
+ return {};
}
+
+Result<void> ValidatePathElement(const std::string& path_element, const std::string& name) {
+ OR_RETURN(ValidatePathElementSubstring(path_element, name));
+ if (path_element == "." || path_element == "..") {
+ return Errorf("Invalid {} '{}'", name, path_element);
+ }
+ return {};
}
+
+Result<void> ValidateDexPath(const std::string& dex_path) {
+ OR_RETURN(ValidateAbsoluteNormalPath(dex_path));
+ return {};
+}
+
+extern "C" JNIEXPORT jstring JNICALL
+Java_com_android_server_art_ArtJni_validateDexPathNative(JNIEnv* env, jobject, jstring j_dex_path) {
+ std::string dex_path(GET_UTF_OR_RETURN(env, j_dex_path));
+
+ if (Result<void> result = ValidateDexPath(dex_path); !result.ok()) {
+ return CREATE_UTF_OR_RETURN(env, result.error().message()).release();
+ } else {
+ return nullptr;
+ }
+}
+
+extern "C" JNIEXPORT jstring JNICALL
+Java_com_android_server_art_ArtJni_validateClassLoaderContextNative(
+ JNIEnv* env, jobject, jstring j_dex_path, jstring j_class_loader_context) {
+ ScopedUtfChars dex_path = GET_UTF_OR_RETURN(env, j_dex_path);
+ std::string class_loader_context(GET_UTF_OR_RETURN(env, j_class_loader_context));
+
+ if (class_loader_context == ClassLoaderContext::kUnsupportedClassLoaderContextEncoding) {
+ return nullptr;
+ }
+
+ std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::Create(class_loader_context);
+ if (context == nullptr) {
+ return CREATE_UTF_OR_RETURN(
+ env, ART_FORMAT("Class loader context '{}' is invalid", class_loader_context))
+ .release();
+ }
+
+ std::vector<std::string> flattened_context = context->FlattenDexPaths();
+ std::string dex_dir = Dirname(dex_path);
+ for (const std::string& context_element : flattened_context) {
+ std::string context_path = std::filesystem::path(dex_dir).append(context_element);
+ if (Result<void> result = ValidateDexPath(context_path); !result.ok()) {
+ return CREATE_UTF_OR_RETURN(env, result.error().message()).release();
+ }
+ }
+
+ return nullptr;
+}
+
+} // namespace service
+} // namespace art
diff --git a/libartservice/service/native/service.h b/libartservice/service/native/service.h
index 2b680a28a4..7f43f17f0b 100644
--- a/libartservice/service/native/service.h
+++ b/libartservice/service/native/service.h
@@ -19,10 +19,20 @@
#include <string>
+#include "android-base/result.h"
+
namespace art {
namespace service {
-std::string getMsg();
+android::base::Result<void> ValidateAbsoluteNormalPath(const std::string& path_str);
+
+android::base::Result<void> ValidatePathElementSubstring(const std::string& path_element_substring,
+ const std::string& name);
+
+android::base::Result<void> ValidatePathElement(const std::string& path_element,
+ const std::string& name);
+
+android::base::Result<void> ValidateDexPath(const std::string& dex_path);
} // namespace service
} // namespace art
diff --git a/libartservice/service/native/service_test.cc b/libartservice/service/native/service_test.cc
index eb84b732c7..8300bf5e76 100644
--- a/libartservice/service/native/service_test.cc
+++ b/libartservice/service/native/service_test.cc
@@ -15,14 +15,97 @@
*/
#include "service.h"
+
+#include "android-base/result-gmock.h"
#include "gtest/gtest.h"
namespace art {
+namespace service {
+namespace {
+
+using ::android::base::testing::HasError;
+using ::android::base::testing::Ok;
+using ::android::base::testing::WithMessage;
+
+using std::literals::operator""s; // NOLINT
class ArtServiceTest : public testing::Test {};
-TEST_F(ArtServiceTest, Hello) {
- EXPECT_EQ("hello world!", art::service::getMsg());
+TEST_F(ArtServiceTest, ValidatePathElementOk) {
+ EXPECT_THAT(ValidatePathElement("com.android.foo", "packageName"), Ok());
+ EXPECT_THAT(ValidatePathElement("...", "packageName"), Ok());
+ EXPECT_THAT(ValidatePathElement("!@#$%^&*()_+-=", "packageName"), Ok());
+}
+
+TEST_F(ArtServiceTest, ValidatePathElementEmpty) {
+ EXPECT_THAT(ValidatePathElement("", "packageName"),
+ HasError(WithMessage("packageName is empty")));
+}
+
+TEST_F(ArtServiceTest, ValidatePathElementDot) {
+ EXPECT_THAT(ValidatePathElement(".", "packageName"),
+ HasError(WithMessage("Invalid packageName '.'")));
+}
+
+TEST_F(ArtServiceTest, ValidatePathElementDotDot) {
+ EXPECT_THAT(ValidatePathElement("..", "packageName"),
+ HasError(WithMessage("Invalid packageName '..'")));
+}
+
+TEST_F(ArtServiceTest, ValidatePathElementSlash) {
+ EXPECT_THAT(ValidatePathElement("a/b", "packageName"),
+ HasError(WithMessage("packageName 'a/b' has invalid character '/'")));
+}
+
+TEST_F(ArtServiceTest, ValidatePathElementNul) {
+ EXPECT_THAT(ValidatePathElement("a\0b"s, "packageName"),
+ HasError(WithMessage("packageName 'a\0b' has invalid character '\\0'"s)));
+}
+
+TEST_F(ArtServiceTest, ValidatePathElementSubstringOk) {
+ EXPECT_THAT(ValidatePathElementSubstring("com.android.foo", "packageName"), Ok());
+ EXPECT_THAT(ValidatePathElementSubstring(".", "packageName"), Ok());
+ EXPECT_THAT(ValidatePathElementSubstring("..", "packageName"), Ok());
+ EXPECT_THAT(ValidatePathElementSubstring("...", "packageName"), Ok());
+ EXPECT_THAT(ValidatePathElementSubstring("!@#$%^&*()_+-=", "packageName"), Ok());
+}
+
+TEST_F(ArtServiceTest, ValidatePathElementSubstringEmpty) {
+ EXPECT_THAT(ValidatePathElementSubstring("", "packageName"),
+ HasError(WithMessage("packageName is empty")));
+}
+
+TEST_F(ArtServiceTest, ValidatePathElementSubstringSlash) {
+ EXPECT_THAT(ValidatePathElementSubstring("a/b", "packageName"),
+ HasError(WithMessage("packageName 'a/b' has invalid character '/'")));
+}
+
+TEST_F(ArtServiceTest, ValidatePathElementSubstringNul) {
+ EXPECT_THAT(ValidatePathElementSubstring("a\0b"s, "packageName"),
+ HasError(WithMessage("packageName 'a\0b' has invalid character '\\0'"s)));
+}
+
+TEST_F(ArtServiceTest, ValidateDexPathOk) { EXPECT_THAT(ValidateDexPath("/a/b.apk"), Ok()); }
+
+TEST_F(ArtServiceTest, ValidateDexPathEmpty) {
+ EXPECT_THAT(ValidateDexPath(""), HasError(WithMessage("Path is empty")));
+}
+
+TEST_F(ArtServiceTest, ValidateDexPathRelative) {
+ EXPECT_THAT(ValidateDexPath("a/b.apk"),
+ HasError(WithMessage("Path 'a/b.apk' is not an absolute path")));
+}
+
+TEST_F(ArtServiceTest, ValidateDexPathNonNormal) {
+ EXPECT_THAT(ValidateDexPath("/a/c/../b.apk"),
+ HasError(WithMessage("Path '/a/c/../b.apk' is not in normal form")));
+}
+
+TEST_F(ArtServiceTest, ValidateDexPathNul) {
+ EXPECT_THAT(ValidateDexPath("/a/\0/b.apk"s),
+ HasError(WithMessage("Path '/a/\0/b.apk' has invalid character '\\0'"s)));
}
+} // namespace
+} // namespace service
} // namespace art
diff --git a/libdexfile/Android.bp b/libdexfile/Android.bp
index f0e010664c..73f93a6782 100644
--- a/libdexfile/Android.bp
+++ b/libdexfile/Android.bp
@@ -385,7 +385,6 @@ art_cc_defaults {
"external/dex_file_ext_test.cc",
],
shared_libs: [
- "libartbase",
"libdexfile",
],
header_libs: [
@@ -402,6 +401,9 @@ art_cc_test {
"art_test_defaults",
"art_libdexfile_external_tests_defaults",
],
+ shared_libs: [
+ "libartbase",
+ ],
}
// Standalone version of ART gtest `art_libdexfile_external_tests`, not bundled with the ART APEX on
@@ -412,6 +414,9 @@ art_cc_test {
"art_standalone_test_defaults",
"art_libdexfile_external_tests_defaults",
],
+ static_libs: [
+ "libartbase",
+ ],
test_config_template: ":art-gtests-target-standalone-cts-template",
test_suites: ["cts"], // For backed-by API coverage.
diff --git a/libdexfile/dex/dex_file-inl.h b/libdexfile/dex/dex_file-inl.h
index d9c5211cc8..cc2f641a38 100644
--- a/libdexfile/dex/dex_file-inl.h
+++ b/libdexfile/dex/dex_file-inl.h
@@ -319,7 +319,14 @@ bool DexFile::DecodeDebugLocalInfo(const uint8_t* stream,
// Emit what was previously there, if anything
if (local_in_reg[reg].is_live_) {
local_in_reg[reg].end_address_ = address;
- new_local_callback(local_in_reg[reg]);
+ // Parameters with generic types cannot be encoded in the debug_info_item header. So d8
+ // encodes it as null in the header with start and end address as 0. There will be a
+ // START_LOCAL_EXTENDED that will declare the parameter with correct signature
+ // Debuggers get confused when they see empty ranges. So don't emit them.
+ // See b/297843934 for more details.
+ if (local_in_reg[reg].end_address_ != 0) {
+ new_local_callback(local_in_reg[reg]);
+ }
}
local_in_reg[reg].name_ = index_to_string_data(name_idx);
diff --git a/libnativebridge/tests/Android.bp b/libnativebridge/tests/Android.bp
index f1725fc278..b2d29f10c7 100644
--- a/libnativebridge/tests/Android.bp
+++ b/libnativebridge/tests/Android.bp
@@ -188,6 +188,7 @@ cc_test {
"cts",
"general-tests",
"mts-art",
+ "mcts-art",
],
}
diff --git a/libnativeloader/Android.bp b/libnativeloader/Android.bp
index 96f56775f6..16449ac745 100644
--- a/libnativeloader/Android.bp
+++ b/libnativeloader/Android.bp
@@ -183,6 +183,7 @@ art_cc_test {
test_suites: [
"cts",
"mts-art",
+ "mcts-art",
],
}
diff --git a/odrefresh/odr_config.h b/odrefresh/odr_config.h
index 78af97c9a0..5aee588992 100644
--- a/odrefresh/odr_config.h
+++ b/odrefresh/odr_config.h
@@ -74,7 +74,6 @@ struct SystemPropertyConfig {
const android::base::NoDestructor<std::vector<SystemPropertyConfig>> kSystemProperties{
{SystemPropertyConfig{.name = "persist.device_config.runtime_native_boot.force_disable_uffd_gc",
.default_value = "false"},
- SystemPropertyConfig{.name = kPhDisableCompactDex, .default_value = "false"},
SystemPropertyConfig{.name = kSystemPropertySystemServerCompilerFilterOverride,
.default_value = ""},
// For testing only (cf. odsign_e2e_tests_full).
diff --git a/runtime/gc/collector/garbage_collector.cc b/runtime/gc/collector/garbage_collector.cc
index 03a432dbf4..b051bfb5c6 100644
--- a/runtime/gc/collector/garbage_collector.cc
+++ b/runtime/gc/collector/garbage_collector.cc
@@ -42,6 +42,50 @@ namespace art {
namespace gc {
namespace collector {
+namespace {
+
+// Report a GC metric via the ATrace interface.
+void TraceGCMetric(const char* name, int64_t value) {
+ // ART's interface with systrace (through libartpalette) only supports
+ // reporting 32-bit (signed) integer values at the moment. Upon
+ // underflows/overflows, clamp metric values at `int32_t` min/max limits and
+ // report these events via a corresponding underflow/overflow counter; also
+ // log a warning about the first underflow/overflow occurrence.
+ //
+ // TODO(b/300015145): Consider extending libarpalette to allow reporting this
+ // value as a 64-bit (signed) integer (instead of a 32-bit (signed) integer).
+ // Note that this is likely unnecessary at the moment (November 2023) for any
+ // size-related GC metric, given the maximum theoretical size of a managed
+ // heap (4 GiB).
+ if (UNLIKELY(value < std::numeric_limits<int32_t>::min())) {
+ ATraceIntegerValue(name, std::numeric_limits<int32_t>::min());
+ std::string underflow_counter_name = std::string(name) + " int32_t underflow";
+ ATraceIntegerValue(underflow_counter_name.c_str(), 1);
+ static bool int32_underflow_reported = false;
+ if (!int32_underflow_reported) {
+ LOG(WARNING) << "GC Metric \"" << name << "\" with value " << value
+ << " causing a 32-bit integer underflow";
+ int32_underflow_reported = true;
+ }
+ return;
+ }
+ if (UNLIKELY(value > std::numeric_limits<int32_t>::max())) {
+ ATraceIntegerValue(name, std::numeric_limits<int32_t>::max());
+ std::string overflow_counter_name = std::string(name) + " int32_t overflow";
+ ATraceIntegerValue(overflow_counter_name.c_str(), 1);
+ static bool int32_overflow_reported = false;
+ if (!int32_overflow_reported) {
+ LOG(WARNING) << "GC Metric \"" << name << "\" with value " << value
+ << " causing a 32-bit integer overflow";
+ int32_overflow_reported = true;
+ }
+ return;
+ }
+ ATraceIntegerValue(name, value);
+}
+
+} // namespace
+
Iteration::Iteration()
: duration_ns_(0), timings_("GC iteration timing logger", true, VLOG_IS_ON(heap)) {
Reset(kGcCauseBackground, false); // Reset to some place holder values.
@@ -238,6 +282,12 @@ void GarbageCollector::Run(GcCause gc_cause, bool clear_soft_references) {
gc_duration_->Add(NsToMs(current_iteration->GetDurationNs()));
gc_duration_delta_->Add(NsToMs(current_iteration->GetDurationNs()));
}
+
+ // Report some metrics via the ATrace interface, to surface them in Perfetto.
+ TraceGCMetric("freed_normal_object_bytes", current_iteration->GetFreedBytes());
+ TraceGCMetric("freed_large_object_bytes", current_iteration->GetFreedLargeObjectBytes());
+ TraceGCMetric("freed_bytes", freed_bytes);
+
is_transaction_active_ = false;
}
diff --git a/runtime/image.cc b/runtime/image.cc
index 37437b4b86..fda755353d 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -257,48 +257,36 @@ const char* ImageHeader::GetImageSectionName(ImageSections index) {
}
}
-// If `image_storage_mode` is compressed, compress data from `source`
-// into `storage`, and return an array pointing to the compressed.
-// If the mode is uncompressed, just return an array pointing to `source`.
-static ArrayRef<const uint8_t> MaybeCompressData(ArrayRef<const uint8_t> source,
- ImageHeader::StorageMode image_storage_mode,
- /*out*/ dchecked_vector<uint8_t>* storage) {
+// Compress data from `source` into `storage`.
+static bool CompressData(ArrayRef<const uint8_t> source,
+ ImageHeader::StorageMode image_storage_mode,
+ /*out*/ dchecked_vector<uint8_t>* storage) {
const uint64_t compress_start_time = NanoTime();
- switch (image_storage_mode) {
- case ImageHeader::kStorageModeLZ4: {
- storage->resize(LZ4_compressBound(source.size()));
- size_t data_size = LZ4_compress_default(
- reinterpret_cast<char*>(const_cast<uint8_t*>(source.data())),
- reinterpret_cast<char*>(storage->data()),
- source.size(),
- storage->size());
- storage->resize(data_size);
- break;
- }
- case ImageHeader::kStorageModeLZ4HC: {
- // Bound is same as non HC.
- storage->resize(LZ4_compressBound(source.size()));
- size_t data_size = LZ4_compress_HC(
- reinterpret_cast<const char*>(const_cast<uint8_t*>(source.data())),
- reinterpret_cast<char*>(storage->data()),
- source.size(),
- storage->size(),
- LZ4HC_CLEVEL_MAX);
- storage->resize(data_size);
- break;
- }
- case ImageHeader::kStorageModeUncompressed: {
- return source;
- }
- default: {
- LOG(FATAL) << "Unsupported";
- UNREACHABLE();
- }
+ // Bound is same for both LZ4 and LZ4HC.
+ storage->resize(LZ4_compressBound(source.size()));
+ size_t data_size = 0;
+ if (image_storage_mode == ImageHeader::kStorageModeLZ4) {
+ data_size = LZ4_compress_default(
+ reinterpret_cast<char*>(const_cast<uint8_t*>(source.data())),
+ reinterpret_cast<char*>(storage->data()),
+ source.size(),
+ storage->size());
+ } else {
+ DCHECK_EQ(image_storage_mode, ImageHeader::kStorageModeLZ4HC);
+ data_size = LZ4_compress_HC(
+ reinterpret_cast<const char*>(const_cast<uint8_t*>(source.data())),
+ reinterpret_cast<char*>(storage->data()),
+ source.size(),
+ storage->size(),
+ LZ4HC_CLEVEL_MAX);
+ }
+
+ if (data_size == 0) {
+ return false;
}
+ storage->resize(data_size);
- DCHECK(image_storage_mode == ImageHeader::kStorageModeLZ4 ||
- image_storage_mode == ImageHeader::kStorageModeLZ4HC);
VLOG(image) << "Compressed from " << source.size() << " to " << storage->size() << " in "
<< PrettyDuration(NanoTime() - compress_start_time);
if (kIsDebugBuild) {
@@ -319,7 +307,7 @@ static ArrayRef<const uint8_t> MaybeCompressData(ArrayRef<const uint8_t> source,
CHECK_EQ(decompressed_size, decompressed.size());
CHECK_EQ(memcmp(source.data(), decompressed.data(), source.size()), 0) << image_storage_mode;
}
- return ArrayRef<const uint8_t>(*storage);
+ return true;
}
bool ImageHeader::WriteData(const ImageFileGuard& image_file,
@@ -360,10 +348,16 @@ bool ImageHeader::WriteData(const ImageFileGuard& image_file,
for (const std::pair<uint32_t, uint32_t> block : block_sources) {
ArrayRef<const uint8_t> raw_image_data(data + block.first, block.second);
dchecked_vector<uint8_t> compressed_data;
- ArrayRef<const uint8_t> image_data =
- MaybeCompressData(raw_image_data, image_storage_mode, &compressed_data);
-
- if (!is_compressed) {
+ ArrayRef<const uint8_t> image_data;
+ if (is_compressed) {
+ if (!CompressData(raw_image_data, image_storage_mode, &compressed_data)) {
+ *error_msg = "Error compressing data for " +
+ image_file->GetPath() + ": " + std::string(strerror(errno));
+ return false;
+ }
+ image_data = ArrayRef<const uint8_t>(compressed_data);
+ } else {
+ image_data = raw_image_data;
// For uncompressed, preserve alignment since the image will be directly mapped.
out_offset = block.first;
}
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 34f9045a33..30631ac683 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -1537,16 +1537,21 @@ void* JitCodeCache::MoreCore(const void* mspace, intptr_t increment) {
void JitCodeCache::GetProfiledMethods(const std::set<std::string>& dex_base_locations,
std::vector<ProfileMethodInfo>& methods) {
+ ScopedTrace trace(__FUNCTION__);
Thread* self = Thread::Current();
WaitUntilInlineCacheAccessible(self);
+ std::vector<ProfilingInfo*> copies;
// TODO: Avoid read barriers for potentially dead methods.
// ScopedDebugDisallowReadBarriers sddrb(self);
- MutexLock mu(self, *Locks::jit_lock_);
- ScopedTrace trace(__FUNCTION__);
- for (const auto& entry : profiling_infos_) {
- ArtMethod* method = entry.first;
- ProfilingInfo* info = entry.second;
- DCHECK_EQ(method, info->GetMethod());
+ {
+ MutexLock mu(self, *Locks::jit_lock_);
+ copies.reserve(profiling_infos_.size());
+ for (const auto& entry : profiling_infos_) {
+ copies.push_back(entry.second);
+ }
+ }
+ for (ProfilingInfo* info : copies) {
+ ArtMethod* method = info->GetMethod();
const DexFile* dex_file = method->GetDexFile();
const std::string base_location = DexFileLoader::GetBaseLocation(dex_file->GetLocation());
if (!ContainsElement(dex_base_locations, base_location)) {
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index ce2b5609fc..7fed9f3827 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -310,7 +310,7 @@ int OatFileAssistant::GetDexOptNeeded(CompilerFilter::Filter target_compiler_fil
bool profile_changed,
bool downgrade) {
OatFileInfo& info = GetBestInfo();
- if (info.CheckDisableCompactDexExperiment()) { // TODO(b/256664509): Clean this up.
+ if (info.CheckDisableCompactDex()) { // TODO(b/256664509): Clean this up.
return kDex2OatFromScratch;
}
DexOptNeeded dexopt_needed = info.GetDexOptNeeded(
@@ -331,7 +331,7 @@ bool OatFileAssistant::GetDexOptNeeded(CompilerFilter::Filter target_compiler_fi
DexOptTrigger dexopt_trigger,
/*out*/ DexOptStatus* dexopt_status) {
OatFileInfo& info = GetBestInfo();
- if (info.CheckDisableCompactDexExperiment()) { // TODO(b/256664509): Clean this up.
+ if (info.CheckDisableCompactDex()) { // TODO(b/256664509): Clean this up.
dexopt_status->location_ = kLocationNoneOrError;
return true;
}
@@ -1275,14 +1275,10 @@ std::unique_ptr<OatFile> OatFileAssistant::OatFileInfo::ReleaseFileForUse() {
return std::unique_ptr<OatFile>();
}
-// Check if we should reject vdex containing cdex code as part of the
-// disable_cdex experiment.
+// Check if we should reject vdex containing cdex code as part of the cdex
+// deprecation.
// TODO(b/256664509): Clean this up.
-bool OatFileAssistant::OatFileInfo::CheckDisableCompactDexExperiment() {
- std::string ph_disable_compact_dex = android::base::GetProperty(kPhDisableCompactDex, "false");
- if (ph_disable_compact_dex != "true") {
- return false;
- }
+bool OatFileAssistant::OatFileInfo::CheckDisableCompactDex() {
const OatFile* oat_file = GetFile();
if (oat_file == nullptr) {
return false;
diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h
index 54287eb5f1..c81dea1210 100644
--- a/runtime/oat_file_assistant.h
+++ b/runtime/oat_file_assistant.h
@@ -434,10 +434,10 @@ class OatFileAssistant {
// the OatFileInfo object.
std::unique_ptr<OatFile> ReleaseFileForUse();
- // Check if we should reject vdex containing cdex code as part of the
- // disable_cdex experiment.
+ // Check if we should reject vdex containing cdex code as part of the cdex
+ // deprecation.
// TODO(b/256664509): Clean this up.
- bool CheckDisableCompactDexExperiment();
+ bool CheckDisableCompactDex();
private:
// Returns true if the oat file is usable but at least one dexopt trigger is matched. This
diff --git a/runtime/trace.cc b/runtime/trace.cc
index 74509ae0be..81c86f1923 100644
--- a/runtime/trace.cc
+++ b/runtime/trace.cc
@@ -113,7 +113,7 @@ uint64_t GetTimestamp() {
return t;
}
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
// Here we compute the scaling factor by sleeping for a millisecond. Alternatively, we could
// generate raw timestamp counter and also time using clock_gettime at the start and the end of the
// trace. We can compute the frequency of timestamp counter upadtes in the post processing step
@@ -130,7 +130,9 @@ double computeScalingFactor() {
DCHECK(scaling_factor > 0.0) << scaling_factor;
return scaling_factor;
}
+#endif
+#if defined(__i386__) || defined(__x86_64__)
double GetScalingFactorForX86() {
uint32_t eax, ebx, ecx;
asm volatile("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx) : "a"(0x0), "c"(0));
@@ -185,7 +187,13 @@ void InitializeTimestampCounters() {
uint64_t freq = 0;
// See Arm Architecture Registers Armv8 section System Registers
asm volatile("mrs %0, cntfrq_el0" : "=r"(freq));
- tsc_to_microsec_scaling_factor = seconds_to_microseconds / static_cast<double>(freq);
+ if (freq == 0) {
+ // It is expected that cntfrq_el0 is correctly setup during system initialization but some
+ // devices don't do this. In such cases fall back to computing the frequency. See b/315139000.
+ tsc_to_microsec_scaling_factor = computeScalingFactor();
+ } else {
+ tsc_to_microsec_scaling_factor = seconds_to_microseconds / static_cast<double>(freq);
+ }
#elif defined(__i386__) || defined(__x86_64__)
tsc_to_microsec_scaling_factor = GetScalingFactorForX86();
#else
diff --git a/test/018-stack-overflow/Android.bp b/test/018-stack-overflow/Android.bp
index ef817a8099..29ba5eafe3 100644
--- a/test/018-stack-overflow/Android.bp
+++ b/test/018-stack-overflow/Android.bp
@@ -21,7 +21,10 @@ java_test {
":art-run-test-018-stack-overflow-expected-stdout",
":art-run-test-018-stack-overflow-expected-stderr",
],
- test_suites: ["cts"],
+ test_suites: [
+ "cts",
+ "mcts-art",
+ ],
}
// Test's expected standard output.
diff --git a/test/048-reflect-v8/Android.bp b/test/048-reflect-v8/Android.bp
index f43f4b02d6..3b279bf0f8 100644
--- a/test/048-reflect-v8/Android.bp
+++ b/test/048-reflect-v8/Android.bp
@@ -21,7 +21,10 @@ java_test {
":art-run-test-048-reflect-v8-expected-stdout",
":art-run-test-048-reflect-v8-expected-stderr",
],
- test_suites: ["cts"],
+ test_suites: [
+ "cts",
+ "mcts-art",
+ ],
}
// Test's expected standard output.
diff --git a/test/1911-get-local-var-table/src/art/Test1911.java b/test/1911-get-local-var-table/src/art/Test1911.java
index 4dd9054bf0..3e2eec21b7 100644
--- a/test/1911-get-local-var-table/src/art/Test1911.java
+++ b/test/1911-get-local-var-table/src/art/Test1911.java
@@ -18,8 +18,10 @@ package art;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
+import java.lang.Integer;
import java.nio.ByteBuffer;
import java.util.Arrays;
+import java.util.ArrayList;
import java.util.Base64;
import java.util.HashSet;
import java.util.Set;
@@ -27,8 +29,8 @@ import java.util.Set;
public class Test1911 {
// Class/dex file containing the following class.
//
- // CLASS_BYTES generated with java version 1.8.0_45: javac -g art/Target.java
- // DEX_BYTES generated with dx version 1.14: dx --dex --output=./classes.dex art/Target.class
+ // CLASS_BYTES generated with java version 17.0.4.1: javac -g art/Target.java
+ // DEX_BYTES generated with d8 version 8.3.7-dev: d8 --debug art/Target.class
//
// package art;
// import java.util.ArrayList;
@@ -53,58 +55,76 @@ public class Test1911 {
// long q = 3 * p;
// doNothing(p, q, o, i);
// }
+ // public void testGenericParameters(ArrayList<Integer> array, int i, Integer val) {
+ // array.set(i, val);
+ // }
// }
public static byte[] CLASS_BYTES = Base64.getDecoder().decode(
- "yv66vgAAADQARgoABAAuCQANAC8KAA0AMAcAMQY/0zMzMzMzMwoAMgAzCgA0ADUHADYKAAkALgoA" +
- "NwA4CgA5ADoHADsBAAN6enoBAAFJAQAGPGluaXQ+AQAEKEkpVgEABENvZGUBAA9MaW5lTnVtYmVy" +
- "VGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAMTGFydC9UYXJnZXQ7AQADeHh4AQAB" +
- "cQEACWRvTm90aGluZwEAFihbTGphdmEvbGFuZy9PYmplY3Q7KVYBAARvYmpzAQATW0xqYXZhL2xh" +
- "bmcvT2JqZWN0OwEAC2RvU29tZXRoaW5nAQABRgEAAWkBAAFEAQABegEAAXgBAAF5AQABbwEAEkxq" +
- "YXZhL2xhbmcvT2JqZWN0OwEAFUxqYXZhL3V0aWwvQXJyYXlMaXN0OwEAAXABAAFKAQAWTG9jYWxW" +
- "YXJpYWJsZVR5cGVUYWJsZQEAKkxqYXZhL3V0aWwvQXJyYXlMaXN0PExqYXZhL2xhbmcvSW50ZWdl" +
- "cjs+OwEADVN0YWNrTWFwVGFibGUBAApTb3VyY2VGaWxlAQALVGFyZ2V0LmphdmEMABAAPAwADgAP" +
- "DAAZABoBABBqYXZhL2xhbmcvT2JqZWN0BwA9DAA+AD8HAEAMAD4AQQEAE2phdmEvdXRpbC9BcnJh" +
- "eUxpc3QHAEIMAD4AQwcARAwAPgBFAQAKYXJ0L1RhcmdldAEAAygpVgEAD2phdmEvbGFuZy9GbG9h" +
- "dAEAB3ZhbHVlT2YBABQoRilMamF2YS9sYW5nL0Zsb2F0OwEAEGphdmEvbGFuZy9Eb3VibGUBABUo" +
- "RClMamF2YS9sYW5nL0RvdWJsZTsBABFqYXZhL2xhbmcvSW50ZWdlcgEAFihJKUxqYXZhL2xhbmcv" +
- "SW50ZWdlcjsBAA5qYXZhL2xhbmcvTG9uZwEAEyhKKUxqYXZhL2xhbmcvTG9uZzsAIQANAAQAAAAB" +
- "AAEADgAPAAAAAwABABAAEQABABIAAABYAAIAAwAAAA4qtwABGwdoPSoctQACsQAAAAIAEwAAABIA" +
- "BAAAAAUABAAGAAgABwANAAgAFAAAACAAAwAAAA4AFQAWAAAAAAAOABcADwABAAgABgAYAA8AAgCJ" +
- "ABkAGgABABIAAAAvAAEAAQAAAAUquAADsQAAAAIAEwAAAAYAAQAAAAkAFAAAAAwAAQAAAAUAGwAc" +
- "AAAAAQAdABEAAQASAAABWAAFAAgAAACCBL0ABFkDKlO4AAMbBmA9Az4dHBtoogAvHB1khjgEFAAF" +
- "FwSNazkFBb0ABFkDFwS4AAdTWQQYBbgACFO4AAOEAwGn/9C7AARZtwABTrsACVm3AAo6BAcbgDYF" +
- "BhUFaIU3Bge9AARZAxUFuAALU1kEFga4AAxTWQUtU1kGGQRTuAADsQAAAAQAEwAAADYADQAAAAsA" +
- "CwAMAA8ADQAYAA4AHgAPACcAEAA+AA0ARAASAEwAEwBVABQAWgAVAGEAFgCBABcAFAAAAGYACgAe" +
- "ACAAGAAeAAQAJwAXAB8AIAAFABEAMwAhAA8AAwAAAIIAFQAWAAAAAACCACIADwABAA8AcwAjAA8A" +
- "AgBMADYAJAAlAAMAVQAtAB8AJgAEAFoAKAAnAA8ABQBhACEAGAAoAAYAKQAAAAwAAQBVAC0AHwAq" +
- "AAQAKwAAAAoAAv0AEQEB+gAyAAEALAAAAAIALQ==");
+ "yv66vgAAADcAUQoABAA2CQAOADcKAA4AOAcAOQY/0zMzMzMzMwoAOgA7CgA8AD0HAD4KAAkANgoA" +
+ "PwBACgBBAEIKAAkAQwcARAEAA3p6egEAAUkBAAY8aW5pdD4BAAQoSSlWAQAEQ29kZQEAD0xpbmVO" +
+ "dW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAAxMYXJ0L1RhcmdldDsBAAN4" +
+ "eHgBAAFxAQAJZG9Ob3RoaW5nAQAWKFtMamF2YS9sYW5nL09iamVjdDspVgEABG9ianMBABNbTGph" +
+ "dmEvbGFuZy9PYmplY3Q7AQALZG9Tb21ldGhpbmcBAAFGAQABaQEAAUQBAAF6AQABeAEAAXkBAAFv" +
+ "AQASTGphdmEvbGFuZy9PYmplY3Q7AQAVTGphdmEvdXRpbC9BcnJheUxpc3Q7AQABcAEAAUoBABZM" +
+ "b2NhbFZhcmlhYmxlVHlwZVRhYmxlAQAqTGphdmEvdXRpbC9BcnJheUxpc3Q8TGphdmEvbGFuZy9J" +
+ "bnRlZ2VyOz47AQANU3RhY2tNYXBUYWJsZQEAFXRlc3RHZW5lcmljUGFyYW1ldGVycwEALChMamF2" +
+ "YS91dGlsL0FycmF5TGlzdDtJTGphdmEvbGFuZy9JbnRlZ2VyOylWAQAFYXJyYXkBAAN2YWwBABNM" +
+ "amF2YS9sYW5nL0ludGVnZXI7AQAJU2lnbmF0dXJlAQBBKExqYXZhL3V0aWwvQXJyYXlMaXN0PExq" +
+ "YXZhL2xhbmcvSW50ZWdlcjs+O0lMamF2YS9sYW5nL0ludGVnZXI7KVYBAApTb3VyY2VGaWxlAQAL" +
+ "VGFyZ2V0LmphdmEMABEARQwADwAQDAAaABsBABBqYXZhL2xhbmcvT2JqZWN0BwBGDABHAEgHAEkM" +
+ "AEcASgEAE2phdmEvdXRpbC9BcnJheUxpc3QHAEsMAEcATAcATQwARwBODABPAFABAAphcnQvVGFy" +
+ "Z2V0AQADKClWAQAPamF2YS9sYW5nL0Zsb2F0AQAHdmFsdWVPZgEAFChGKUxqYXZhL2xhbmcvRmxv" +
+ "YXQ7AQAQamF2YS9sYW5nL0RvdWJsZQEAFShEKUxqYXZhL2xhbmcvRG91YmxlOwEAEWphdmEvbGFu" +
+ "Zy9JbnRlZ2VyAQAWKEkpTGphdmEvbGFuZy9JbnRlZ2VyOwEADmphdmEvbGFuZy9Mb25nAQATKEop" +
+ "TGphdmEvbGFuZy9Mb25nOwEAA3NldAEAJyhJTGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcv" +
+ "T2JqZWN0OwAhAA4ABAAAAAEAAQAPABAAAAAEAAEAEQASAAEAEwAAAFgAAgADAAAADiq3AAEbB2g9" +
+ "Khy1AAKxAAAAAgAUAAAAEgAEAAAACAAEAAkACAAKAA0ACwAVAAAAIAADAAAADgAWABcAAAAAAA4A" +
+ "GAAQAAEACAAGABkAEAACAIkAGgAbAAEAEwAAAC8AAQABAAAABSq4AAOxAAAAAgAUAAAABgABAAAA" +
+ "DQAVAAAADAABAAAABQAcAB0AAAABAB4AEgABABMAAAFYAAUACAAAAIIEvQAEWQMqU7gAAxsGYD0D" +
+ "Ph0cG2iiAC8cHWSGOAQUAAUXBI1rOQUFvQAEWQMXBLgAB1NZBBgFuAAIU7gAA4QDAaf/0LsABFm3" +
+ "AAFOuwAJWbcACjoEBxuANgUGFQVohTcGB70ABFkDFQW4AAtTWQQWBrgADFNZBS1TWQYZBFO4AAOx" +
+ "AAAABAAUAAAANgANAAAAEAALABEADwASABgAEwAeABQAJwAVAD4AEgBEABcATAAYAFUAGQBaABoA" +
+ "YQAbAIEAHAAVAAAAZgAKAB4AIAAZAB8ABAAnABcAIAAhAAUAEQAzACIAEAADAAAAggAWABcAAAAA" +
+ "AIIAIwAQAAEADwBzACQAEAACAEwANgAlACYAAwBVAC0AIAAnAAQAWgAoACgAEAAFAGEAIQAZACkA" +
+ "BgAqAAAADAABAFUALQAgACsABAAsAAAACgAC/QARAQH6ADIAAQAtAC4AAgATAAAAZgADAAQAAAAI" +
+ "KxwttgANV7EAAAADABQAAAAKAAIAAAAfAAcAIAAVAAAAKgAEAAAACAAWABcAAAAAAAgALwAnAAEA" +
+ "AAAIACAAEAACAAAACAAwADEAAwAqAAAADAABAAAACAAvACsAAQAyAAAAAgAzAAEANAAAAAIANQ==");
public static byte[] DEX_BYTES = Base64.getDecoder().decode(
- "ZGV4CjAzNQCQtgjEV631Ma/btYyIy2IzqHWNN+nZiwl0BQAAcAAAAHhWNBIAAAAAAAAAANQEAAAk" +
- "AAAAcAAAAA0AAAAAAQAABwAAADQBAAABAAAAiAEAAAkAAACQAQAAAQAAANgBAAB8AwAA+AEAAB4D" +
- "AAAmAwAAKQMAACwDAAAvAwAAMgMAADYDAAA6AwAAPgMAAEIDAABQAwAAZAMAAHcDAACMAwAAngMA" +
- "ALIDAADJAwAA9QMAAAIEAAAFBAAACQQAAA0EAAAiBAAALQQAADoEAAA9BAAAQAQAAEYEAABJBAAA" +
- "TAQAAFIEAABbBAAAXgQAAGMEAABmBAAAaQQAAAEAAAACAAAAAwAAAAQAAAAJAAAACgAAAAsAAAAM" +
- "AAAADQAAAA4AAAAPAAAAEgAAABUAAAAFAAAABQAAAPgCAAAGAAAABgAAAAADAAAHAAAABwAAAAgD" +
- "AAAIAAAACAAAABADAAASAAAACwAAAAAAAAATAAAACwAAAAgDAAAUAAAACwAAABgDAAAEAAIAIwAA" +
- "AAQABQAAAAAABAAGABYAAAAEAAUAFwAAAAUAAAAeAAAABgABAB4AAAAHAAIAHgAAAAgAAwAeAAAA" +
- "CQAEAAAAAAAKAAQAAAAAAAQAAAABAAAACQAAAAAAAAARAAAAAAAAAL4EAAAAAAAAAwACAAEAAABu" +
- "BAAACAAAAHAQBwABANoAAgRZEAAADgABAAEAAQAAAHsEAAAEAAAAcRABAAAADgAQAAIAAgAAAIEE" +
- "AABcAAAAEhkjmQwAEgpNDgkKcRABAAkA2AUPAxIIkgkFDzWYJACRCQUIgpYYCjMzMzMzM9M/iWyt" +
- "AAoMEikjmQwAEgpxEAQABgAMC00LCQoSGnEgAwAQAAwLTQsJCnEQAQAJANgICAEo2yIDCQBwEAcA" +
- "AwAiAgoAcBAIAAIA3gQPBNoJBAOBlhJJI5kMABIKcRAFAAQADAtNCwkKEhpxIAYAdgAMC00LCQoS" +
- "Kk0DCQoSOk0CCQpxEAEACQAOAAEAAAAAAAAAAQAAAAEAAAABAAAAAgAAAAEAAAADAAAAAQAAAAwA" +
- "Bjxpbml0PgABRAABRgABSQABSgACTEQAAkxGAAJMSQACTEoADExhcnQvVGFyZ2V0OwASTGphdmEv" +
- "bGFuZy9Eb3VibGU7ABFMamF2YS9sYW5nL0Zsb2F0OwATTGphdmEvbGFuZy9JbnRlZ2VyOwAQTGph" +
- "dmEvbGFuZy9Mb25nOwASTGphdmEvbGFuZy9PYmplY3Q7ABVMamF2YS91dGlsL0FycmF5TGlzdDsA" +
- "KkxqYXZhL3V0aWwvQXJyYXlMaXN0PExqYXZhL2xhbmcvSW50ZWdlcjs+OwALVGFyZ2V0LmphdmEA" +
- "AVYAAlZJAAJWTAATW0xqYXZhL2xhbmcvT2JqZWN0OwAJZG9Ob3RoaW5nAAtkb1NvbWV0aGluZwAB" +
- "aQABbwAEb2JqcwABcAABcQAEdGhpcwAHdmFsdWVPZgABeAADeHh4AAF5AAF6AAN6enoABQEhBw48" +
- "LQMAHQMtAAkBGwcOAAsBIAcOli0DBSIDAQEDCCMDSzwDBh0ChwMAGQEBFAtABQAFBloDAxoKWgQC" +
- "GQsRLQMEHAM8AwYdBAEaDwAAAQIBAAEAgYAE+AMBiQGYBAIBsAQADQAAAAAAAAABAAAAAAAAAAEA" +
- "AAAkAAAAcAAAAAIAAAANAAAAAAEAAAMAAAAHAAAANAEAAAQAAAABAAAAiAEAAAUAAAAJAAAAkAEA" +
- "AAYAAAABAAAA2AEAAAEgAAADAAAA+AEAAAEQAAAFAAAA+AIAAAIgAAAkAAAAHgMAAAMgAAADAAAA" +
- "bgQAAAAgAAABAAAAvgQAAAAQAAABAAAA1AQAAA==");
-
+ "ZGV4CjAzNQAALyjG3vy0POIlfGUh9Q7yf3NFwlp6VbWoBwAAcAAAAHhWNBIAAAAAAAAAAOQGAAAz" +
+ "AAAAcAAAAA8AAAA8AQAACgAAAHgBAAABAAAA8AEAAAwAAAD4AQAAAQAAAFgCAAAwBQAAeAIAACIE" +
+ "AAAlBAAAKQQAADEEAAA2BAAAOQQAADwEAAA/BAAAQgQAAEYEAABKBAAATgQAAFMEAABXBAAAZQQA" +
+ "AIQEAACYBAAAqwQAAMAEAADSBAAA5gQAAP0EAAAUBQAAQAUAAE0FAABQBQAAVAUAAFgFAABeBQAA" +
+ "YQUAAGUFAAB6BQAAgQUAAIwFAACZBQAAnAUAAKMFAACmBQAArAUAAK8FAACyBQAAtwUAAM4FAADT" +
+ "BQAA2gUAAOMFAADmBQAA6wUAAO4FAADxBQAA9gUAAAQAAAAFAAAABgAAAAcAAAANAAAADgAAAA8A" +
+ "AAAQAAAAEQAAABIAAAATAAAAFAAAABgAAAAcAAAAHgAAAAgAAAAGAAAA6AMAAAkAAAAHAAAA8AMA" +
+ "AAoAAAAIAAAA+AMAAAwAAAAJAAAAAAQAAAsAAAAKAAAACAQAABgAAAAMAAAAAAAAABkAAAAMAAAA" +
+ "+AMAABsAAAAMAAAAEAQAABoAAAAMAAAAHAQAAB0AAAANAAAA6AMAAAQAAgAxAAAABAAGAAIAAAAE" +
+ "AAgAIAAAAAQABgAhAAAABAAHACkAAAAGAAkAIwAAAAYAAAAsAAAABwABACwAAAAIAAIALAAAAAkA" +
+ "AwAsAAAACgAFAAIAAAALAAUAAgAAAAsABAAoAAAABAAAAAEAAAAKAAAAAAAAABcAAADMBgAApgYA" +
+ "AAAAAAADAAIAAQAAAIwDAAAIAAAAcBAJAAEA2gACBFkQAAAOAAEAAQABAAAAmAMAAAQAAABxEAEA" +
+ "AAAOAA4AAgACAAAAnQMAAFoAAAASECMBDgASAk0MAQJxEAEAAQDYAQ0DEgOSBAENEiU1QyQAkQQB" +
+ "A4JEGAYzMzMzMzPTP4lIcSAEAJgArQgIBnEQBgAEAAwGcSAFAJgADAcjVQ4ATQYFAk0HBQBxEAEA" +
+ "BQDYAwMBKNoiAwoAcBAJAAMAIgQLAHAQCgAEAN4GDQTaBwYDgXdxEAcABgAMCXEgCACHAAwKEksj" +
+ "uw4ATQkLAk0KCwBNAwsFEjBNBAsAcRABAAsADgAEAAQAAwAAANsDAAAEAAAAbjALACEDDgAIAS8O" +
+ "PC0DACgDLQANASYOABABLg6WLQMBMAMBAQMDMQNaPAMEKAK0AwgjAQERCwUEBQhABQNaAwMlC1oE" +
+ "BCMMFy0DBicDPAMHKAQBFw8AHwMAIysOBAEgDBc8AAEAAAAAAAAAAQAAAAEAAAABAAAAAgAAAAEA" +
+ "AAADAAAAAgAAAAIACgADAAAACwACAAgAAAABAAAADgABKAACKVYABjxpbml0PgADPjtJAAFEAAFG" +
+ "AAFJAAFKAAJMRAACTEYAAkxJAANMSUwAAkxKAAxMYXJ0L1RhcmdldDsAHUxkYWx2aWsvYW5ub3Rh" +
+ "dGlvbi9TaWduYXR1cmU7ABJMamF2YS9sYW5nL0RvdWJsZTsAEUxqYXZhL2xhbmcvRmxvYXQ7ABNM" +
+ "amF2YS9sYW5nL0ludGVnZXI7ABBMamF2YS9sYW5nL0xvbmc7ABJMamF2YS9sYW5nL09iamVjdDsA" +
+ "FUxqYXZhL3V0aWwvQXJyYXlMaXN0OwAVTGphdmEvdXRpbC9BcnJheUxpc3Q8ACpMamF2YS91dGls" +
+ "L0FycmF5TGlzdDxMamF2YS9sYW5nL0ludGVnZXI7PjsAC1RhcmdldC5qYXZhAAFWAAJWSQACVkwA" +
+ "BFZMSUwAAVoAAlpEABNbTGphdmEvbGFuZy9PYmplY3Q7AAVhcnJheQAJZG9Ob3RoaW5nAAtkb1Nv" +
+ "bWV0aGluZwABaQAFaXNOYU4AAW8ABG9ianMAAXAAAXEAA3NldAAVdGVzdEdlbmVyaWNQYXJhbWV0" +
+ "ZXJzAAN2YWwABXZhbHVlAAd2YWx1ZU9mAAF4AAN4eHgAAXkAAXoAA3p6egCbAX5+RDh7ImJhY2tl" +
+ "bmQiOiJkZXgiLCJjb21waWxhdGlvbi1tb2RlIjoiZGVidWciLCJoYXMtY2hlY2tzdW1zIjpmYWxz" +
+ "ZSwibWluLWFwaSI6MSwic2hhLTEiOiIzMTAxYWQ2Zjc0ZWUyMzI1MjhkZmM2NmEyNjE3YTkzODM4" +
+ "NGU2NmVhIiwidmVyc2lvbiI6IjguMy43LWRldiJ9AAIFASscBhcAFxUXERcDFxEXAQABAgIAAQCB" +
+ "gAT4BAGJAZgFAgGwBQEB9AYAAAAAAAEAAACUBgAAwAYAAAAAAAABAAAAAAAAAAMAAADEBgAAEAAA" +
+ "AAAAAAABAAAAAAAAAAEAAAAzAAAAcAAAAAIAAAAPAAAAPAEAAAMAAAAKAAAAeAEAAAQAAAABAAAA" +
+ "8AEAAAUAAAAMAAAA+AEAAAYAAAABAAAAWAIAAAEgAAAEAAAAeAIAAAMgAAAEAAAAjAMAAAEQAAAH" +
+ "AAAA6AMAAAIgAAAzAAAAIgQAAAQgAAABAAAAlAYAAAAgAAABAAAApgYAAAMQAAACAAAAwAYAAAYg" +
+ "AAABAAAAzAYAAAAQAAABAAAA5AYAAA==");
// The variables of the functions in the above Target class.
public static Set<Locals.VariableDescription>[] CONSTRUCTOR_VARIABLES = new Set[] {
@@ -149,23 +169,49 @@ public class Test1911 {
4))),
// ART Local variable table
new HashSet<>(Arrays.asList(
- new Locals.VariableDescription(19, 31, "q", "F", null, 6),
- new Locals.VariableDescription(55, 37, "o", "Ljava/lang/Object;", null, 3),
- new Locals.VariableDescription(0, 92, "this", "Lart/Target;", null, 14),
- new Locals.VariableDescription(12, 80, "z", "I", null, 8),
- new Locals.VariableDescription(11, 81, "y", "I", null, 5),
- new Locals.VariableDescription(62, 30, "p", "I", null, 4),
- new Locals.VariableDescription(0, 92, "x", "I", null, 15),
- new Locals.VariableDescription(27, 23, "i", "D", null, 0),
- new Locals.VariableDescription(65, 27, "q", "J", null, 6),
- new Locals.VariableDescription(60,
- 32,
+ new Locals.VariableDescription(20, 28, "q", "F", null, 4),
+ new Locals.VariableDescription(56, 34, "o", "Ljava/lang/Object;", null, 3),
+ new Locals.VariableDescription(0, 90, "this", "Lart/Target;", null, 12),
+ new Locals.VariableDescription(12, 39, "z", "I", null, 3),
+ new Locals.VariableDescription(11, 79, "y", "I", null, 1),
+ new Locals.VariableDescription(63, 27, "p", "I", null, 6),
+ new Locals.VariableDescription(0, 90, "x", "I", null, 13),
+ new Locals.VariableDescription(31, 17, "i", "D", null, 8),
+ new Locals.VariableDescription(66, 24, "q", "J", null, 7),
+ new Locals.VariableDescription(61,
+ 29,
"i",
"Ljava/util/ArrayList;",
"Ljava/util/ArrayList<Ljava/lang/Integer;>;",
- 2))),
+ 4))),
+ };
+
+ public static Set<Locals.VariableDescription>[] TEST_GENERIC_PARAMETERS_VARIABLES = new Set[] {
+ // RI Local variable table
+ new HashSet<>(Arrays.asList(
+ new Locals.VariableDescription(0, 8, "this", "Lart/Target;", null, 0),
+ new Locals.VariableDescription(0,
+ 8,
+ "array",
+ "Ljava/util/ArrayList;",
+ "Ljava/util/ArrayList<Ljava/lang/Integer;>;",
+ 1),
+ new Locals.VariableDescription(0, 8, "i", "I", null, 2),
+ new Locals.VariableDescription(0, 8, "val", "Ljava/lang/Integer;", null, 3))),
+ // ART Local variable table
+ new HashSet<>(Arrays.asList(
+ new Locals.VariableDescription(0, 4, "this", "Lart/Target;", null, 0),
+ new Locals.VariableDescription(0,
+ 4,
+ "array",
+ "Ljava/util/ArrayList;",
+ "Ljava/util/ArrayList<Ljava/lang/Integer;>;",
+ 1),
+ new Locals.VariableDescription(0, 4, "i", "I", null, 2),
+ new Locals.VariableDescription(0, 4, "val", "Ljava/lang/Integer;", null, 3))),
};
+
// Get a classloader that can load the Target class.
public static ClassLoader getClassLoader() throws Exception {
try {
@@ -213,6 +259,9 @@ public class Test1911 {
DO_NOTHING_VARIABLES);
CheckLocalVariableTable(target.getDeclaredMethod("doSomething", Integer.TYPE),
DO_SOMETHING_VARIABLES);
+ CheckLocalVariableTable(target.getDeclaredMethod("testGenericParameters",
+ (new ArrayList<Integer>(0)).getClass(), Integer.TYPE, (new Integer(0)).getClass()),
+ TEST_GENERIC_PARAMETERS_VARIABLES);
}
}
diff --git a/test/913-heaps/src/art/Test913.java b/test/913-heaps/src/art/Test913.java
index 4fffa88198..8bd7cf4710 100644
--- a/test/913-heaps/src/art/Test913.java
+++ b/test/913-heaps/src/art/Test913.java
@@ -317,7 +317,8 @@ public class Test913 {
BufferedReader reader = new BufferedReader(new FileReader("/proc/" + pid + "/maps"));
String line;
while ((line = reader.readLine()) != null) {
- if (line.endsWith(".art")) {
+ // On host the mappings end with .art and on device they end with .art]
+ if (line.endsWith(".art]") || line.endsWith(".art")) {
reader.close();
return true;
}
diff --git a/test/Android.bp b/test/Android.bp
index 6bc59904d0..5fc8cf96a3 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -343,6 +343,43 @@ art_cc_defaults {
],
}
+// Variant of art_standalone_gtest_defaults that doesn't link dynamically to any
+// internal ART libraries.
+art_cc_defaults {
+ name: "art_cts_gtest_defaults",
+ defaults: [
+ // Note: We don't include "art_debug_defaults" here, as standalone ART
+ // gtests link with the "non-d" versions of the libraries contained in
+ // the ART APEX, so that they can be used with all ART APEX flavors
+ // (including the Release ART APEX).
+ "art_standalone_test_defaults",
+ "art_gtest_common_defaults",
+ ],
+ gtest: true,
+
+ // Support multilib variants (using different suffix per sub-architecture), which is needed on
+ // build targets with secondary architectures, as the MTS test suite packaging logic flattens
+ // all test artifacts into a single `testcases` directory.
+ compile_multilib: "both",
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ suffix: "64",
+ },
+ },
+
+ static_libs: [
+ "libartbase",
+ ],
+
+ test_suites: [
+ "general-tests",
+ "mts-art",
+ ],
+}
+
// Properties common to `libart-gtest-defaults` and `libartd-gtest-defaults`.
art_cc_defaults {
name: "libart-gtest-common-defaults",
diff --git a/test/art-gtests-target-standalone-cts-template.xml b/test/art-gtests-target-standalone-cts-template.xml
index 3749c3e990..e862f171e2 100644
--- a/test/art-gtests-target-standalone-cts-template.xml
+++ b/test/art-gtests-target-standalone-cts-template.xml
@@ -30,8 +30,6 @@
<test class="com.android.tradefed.testtype.GTest" >
<option name="native-test-device-path" value="/data/local/tmp/{MODULE}" />
<option name="module-name" value="{MODULE}" />
- <option name="ld-library-path-32" value="/apex/com.android.art/lib" />
- <option name="ld-library-path-64" value="/apex/com.android.art/lib64" />
</test>
<!-- When this test is run in a Mainline context (e.g. with `mts-tradefed`), only enable it if