summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libdexfile/dex/dex_file.cc3
-rw-r--r--libdexfile/dex/dex_file.h11
-rw-r--r--runtime/base/file_utils.cc7
-rw-r--r--runtime/base/file_utils.h3
-rw-r--r--runtime/class_linker.cc12
-rw-r--r--runtime/dex/art_dex_file_loader.cc36
-rw-r--r--runtime/dex/art_dex_file_loader.h13
-rw-r--r--runtime/dex/art_dex_file_loader_test.cc90
-rw-r--r--runtime/hidden_api.h43
-rw-r--r--runtime/interpreter/unstarted_runtime.cc1
-rw-r--r--runtime/jni_internal.cc9
-rw-r--r--runtime/native/java_lang_Class.cc10
12 files changed, 210 insertions, 28 deletions
diff --git a/libdexfile/dex/dex_file.cc b/libdexfile/dex/dex_file.cc
index 4613b40457..1f471106df 100644
--- a/libdexfile/dex/dex_file.cc
+++ b/libdexfile/dex/dex_file.cc
@@ -121,7 +121,8 @@ DexFile::DexFile(const uint8_t* base,
num_call_site_ids_(0),
oat_dex_file_(oat_dex_file),
container_(std::move(container)),
- is_compact_dex_(is_compact_dex) {
+ is_compact_dex_(is_compact_dex),
+ is_platform_dex_(false) {
CHECK(begin_ != nullptr) << GetLocation();
CHECK_GT(size_, 0U) << GetLocation();
// Check base (=header) alignment.
diff --git a/libdexfile/dex/dex_file.h b/libdexfile/dex/dex_file.h
index aeb49d2c25..683a8243ed 100644
--- a/libdexfile/dex/dex_file.h
+++ b/libdexfile/dex/dex_file.h
@@ -992,6 +992,14 @@ class DexFile {
ALWAYS_INLINE const StandardDexFile* AsStandardDexFile() const;
ALWAYS_INLINE const CompactDexFile* AsCompactDexFile() const;
+ ALWAYS_INLINE bool IsPlatformDexFile() const {
+ return is_platform_dex_;
+ }
+
+ ALWAYS_INLINE void SetIsPlatformDexFile() {
+ is_platform_dex_ = true;
+ }
+
bool IsInMainSection(const void* addr) const {
return Begin() <= addr && addr < Begin() + Size();
}
@@ -1094,6 +1102,9 @@ class DexFile {
// If the dex file is a compact dex file. If false then the dex file is a standard dex file.
const bool is_compact_dex_;
+ // If the dex file is located in /system/framework/.
+ bool is_platform_dex_;
+
friend class DexFileLoader;
friend class DexFileVerifierTest;
friend class OatWriter;
diff --git a/runtime/base/file_utils.cc b/runtime/base/file_utils.cc
index 1cb3b9c380..36caa7fcfb 100644
--- a/runtime/base/file_utils.cc
+++ b/runtime/base/file_utils.cc
@@ -319,4 +319,11 @@ bool LocationIsOnSystem(const char* location) {
return path != nullptr && android::base::StartsWith(path.get(), GetAndroidRoot().c_str());
}
+bool LocationIsOnSystemFramework(const char* location) {
+ UniqueCPtr<const char[]> path(realpath(location, nullptr));
+ std::string framework_path = GetAndroidRoot() + "/framework/";
+ return path != nullptr &&
+ android::base::StartsWith(path.get(), framework_path.c_str());
+}
+
} // namespace art
diff --git a/runtime/base/file_utils.h b/runtime/base/file_utils.h
index 7f691d546b..8adb4f7bf8 100644
--- a/runtime/base/file_utils.h
+++ b/runtime/base/file_utils.h
@@ -75,6 +75,9 @@ std::string ReplaceFileExtension(const std::string& filename, const std::string&
// Return whether the location is on system (i.e. android root).
bool LocationIsOnSystem(const char* location);
+// Return whether the location is on system/framework (i.e. android_root/framework).
+bool LocationIsOnSystemFramework(const char* location);
+
} // namespace art
#endif // ART_RUNTIME_BASE_FILE_UTILS_H_
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 1d72b46f6c..32cefbdfc5 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -7935,7 +7935,8 @@ ArtMethod* ClassLinker::FindResolvedMethod(ObjPtr<mirror::Class> klass,
}
DCHECK(resolved == nullptr || resolved->GetDeclaringClassUnchecked() != nullptr);
if (resolved != nullptr &&
- hiddenapi::ShouldBlockAccessToMember(resolved, class_loader, hiddenapi::kLinking)) {
+ hiddenapi::ShouldBlockAccessToMember(
+ resolved, class_loader, dex_cache, hiddenapi::kLinking)) {
resolved = nullptr;
}
if (resolved != nullptr) {
@@ -8077,7 +8078,8 @@ ArtMethod* ClassLinker::ResolveMethodWithoutInvokeType(uint32_t method_idx,
resolved = klass->FindClassMethod(dex_cache.Get(), method_idx, image_pointer_size_);
}
if (resolved != nullptr &&
- hiddenapi::ShouldBlockAccessToMember(resolved, class_loader.Get(), hiddenapi::kLinking)) {
+ hiddenapi::ShouldBlockAccessToMember(
+ resolved, class_loader.Get(), dex_cache.Get(), hiddenapi::kLinking)) {
resolved = nullptr;
}
return resolved;
@@ -8156,7 +8158,8 @@ ArtField* ClassLinker::ResolveField(uint32_t field_idx,
}
if (resolved == nullptr ||
- hiddenapi::ShouldBlockAccessToMember(resolved, class_loader.Get(), hiddenapi::kLinking)) {
+ hiddenapi::ShouldBlockAccessToMember(
+ resolved, class_loader.Get(), dex_cache.Get(), hiddenapi::kLinking)) {
const char* name = dex_file.GetFieldName(field_id);
const char* type = dex_file.GetFieldTypeDescriptor(field_id);
ThrowNoSuchFieldError(is_static ? "static " : "instance ", klass, type, name);
@@ -8189,7 +8192,8 @@ ArtField* ClassLinker::ResolveFieldJLS(uint32_t field_idx,
StringPiece type(dex_file.GetFieldTypeDescriptor(field_id));
resolved = mirror::Class::FindField(self, klass, name, type);
if (resolved != nullptr &&
- hiddenapi::ShouldBlockAccessToMember(resolved, class_loader.Get(), hiddenapi::kLinking)) {
+ hiddenapi::ShouldBlockAccessToMember(
+ resolved, class_loader.Get(), dex_cache.Get(), hiddenapi::kLinking)) {
resolved = nullptr;
}
if (resolved != nullptr) {
diff --git a/runtime/dex/art_dex_file_loader.cc b/runtime/dex/art_dex_file_loader.cc
index c456764834..cf9a814a6b 100644
--- a/runtime/dex/art_dex_file_loader.cc
+++ b/runtime/dex/art_dex_file_loader.cc
@@ -22,6 +22,7 @@
#include "android-base/stringprintf.h"
#include "base/file_magic.h"
+#include "base/file_utils.h"
#include "base/stl_util.h"
#include "base/systrace.h"
#include "base/unix_file/fd_file.h"
@@ -488,4 +489,39 @@ bool ArtDexFileLoader::OpenAllDexFilesFromZip(
}
}
+std::unique_ptr<DexFile> ArtDexFileLoader::OpenCommon(const uint8_t* base,
+ size_t size,
+ const uint8_t* data_base,
+ size_t data_size,
+ const std::string& location,
+ uint32_t location_checksum,
+ const OatDexFile* oat_dex_file,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg,
+ std::unique_ptr<DexFileContainer> container,
+ VerifyResult* verify_result) {
+ std::unique_ptr<DexFile> dex_file = DexFileLoader::OpenCommon(base,
+ size,
+ data_base,
+ data_size,
+ location,
+ location_checksum,
+ oat_dex_file,
+ verify,
+ verify_checksum,
+ error_msg,
+ std::move(container),
+ verify_result);
+
+ // Check if this dex file is located in the framework directory.
+ // If it is, set a flag on the dex file. This is used by hidden API
+ // policy decision logic.
+ if (dex_file != nullptr && LocationIsOnSystemFramework(location.c_str())) {
+ dex_file->SetIsPlatformDexFile();
+ }
+
+ return dex_file;
+}
+
} // namespace art
diff --git a/runtime/dex/art_dex_file_loader.h b/runtime/dex/art_dex_file_loader.h
index 7c7a59b37f..7577945632 100644
--- a/runtime/dex/art_dex_file_loader.h
+++ b/runtime/dex/art_dex_file_loader.h
@@ -120,6 +120,19 @@ class ArtDexFileLoader : public DexFileLoader {
bool verify_checksum,
std::string* error_msg,
ZipOpenErrorCode* error_code) const;
+
+ static std::unique_ptr<DexFile> OpenCommon(const uint8_t* base,
+ size_t size,
+ const uint8_t* data_base,
+ size_t data_size,
+ const std::string& location,
+ uint32_t location_checksum,
+ const OatDexFile* oat_dex_file,
+ bool verify,
+ bool verify_checksum,
+ std::string* error_msg,
+ std::unique_ptr<DexFileContainer> container,
+ VerifyResult* verify_result);
};
} // namespace art
diff --git a/runtime/dex/art_dex_file_loader_test.cc b/runtime/dex/art_dex_file_loader_test.cc
index 6e2cfec381..3e0d6662c7 100644
--- a/runtime/dex/art_dex_file_loader_test.cc
+++ b/runtime/dex/art_dex_file_loader_test.cc
@@ -16,9 +16,11 @@
#include <sys/mman.h>
+#include <fstream>
#include <memory>
#include "art_dex_file_loader.h"
+#include "base/file_utils.h"
#include "base/os.h"
#include "base/stl_util.h"
#include "base/unix_file/fd_file.h"
@@ -35,7 +37,40 @@
namespace art {
-class ArtDexFileLoaderTest : public CommonRuntimeTest {};
+static void Copy(const std::string& src, const std::string& dst) {
+ std::ifstream src_stream(src, std::ios::binary);
+ std::ofstream dst_stream(dst, std::ios::binary);
+ dst_stream << src_stream.rdbuf();
+}
+
+class ArtDexFileLoaderTest : public CommonRuntimeTest {
+ public:
+ virtual void SetUp() {
+ CommonRuntimeTest::SetUp();
+
+ std::string dex_location = GetTestDexFileName("Main");
+
+ data_location_path_ = android_data_ + "/foo.jar";
+ system_location_path_ = GetAndroidRoot() + "/foo.jar";
+ system_framework_location_path_ = GetAndroidRoot() + "/framework/foo.jar";
+
+ Copy(dex_location, data_location_path_);
+ Copy(dex_location, system_location_path_);
+ Copy(dex_location, system_framework_location_path_);
+ }
+
+ virtual void TearDown() {
+ remove(data_location_path_.c_str());
+ remove(system_location_path_.c_str());
+ remove(system_framework_location_path_.c_str());
+ CommonRuntimeTest::TearDown();
+ }
+
+ protected:
+ std::string data_location_path_;
+ std::string system_location_path_;
+ std::string system_framework_location_path_;
+};
// TODO: Port OpenTestDexFile(s) need to be ported to use non-ART utilities, and
// the tests that depend upon them should be moved to dex_file_loader_test.cc
@@ -304,4 +339,57 @@ TEST_F(ArtDexFileLoaderTest, GetDexCanonicalLocation) {
ASSERT_EQ(0, unlink(dex_location_sym.c_str()));
}
+TEST_F(ArtDexFileLoaderTest, IsPlatformDexFile) {
+ ArtDexFileLoader loader;
+ bool success;
+ std::string error_msg;
+ std::vector<std::unique_ptr<const DexFile>> dex_files;
+
+ // Load file from a non-system directory and check that it is not flagged as framework.
+ ASSERT_FALSE(LocationIsOnSystemFramework(data_location_path_.c_str()));
+ success = loader.Open(data_location_path_.c_str(),
+ data_location_path_,
+ /* verify */ false,
+ /* verify_checksum */ false,
+ &error_msg,
+ &dex_files);
+ ASSERT_TRUE(success);
+ ASSERT_GE(dex_files.size(), 1u);
+ for (std::unique_ptr<const DexFile>& dex_file : dex_files) {
+ ASSERT_FALSE(dex_file->IsPlatformDexFile());
+ }
+
+ dex_files.clear();
+
+ // Load file from a system, non-framework directory and check that it is not flagged as framework.
+ ASSERT_FALSE(LocationIsOnSystemFramework(system_location_path_.c_str()));
+ success = loader.Open(system_location_path_.c_str(),
+ system_location_path_,
+ /* verify */ false,
+ /* verify_checksum */ false,
+ &error_msg,
+ &dex_files);
+ ASSERT_TRUE(success);
+ ASSERT_GE(dex_files.size(), 1u);
+ for (std::unique_ptr<const DexFile>& dex_file : dex_files) {
+ ASSERT_FALSE(dex_file->IsPlatformDexFile());
+ }
+
+ dex_files.clear();
+
+ // Load file from a system/framework directory and check that it is flagged as a framework dex.
+ ASSERT_TRUE(LocationIsOnSystemFramework(system_framework_location_path_.c_str()));
+ success = loader.Open(system_framework_location_path_.c_str(),
+ system_framework_location_path_,
+ /* verify */ false,
+ /* verify_checksum */ false,
+ &error_msg,
+ &dex_files);
+ ASSERT_TRUE(success);
+ ASSERT_GE(dex_files.size(), 1u);
+ for (std::unique_ptr<const DexFile>& dex_file : dex_files) {
+ ASSERT_TRUE(dex_file->IsPlatformDexFile());
+ }
+}
+
} // namespace art
diff --git a/runtime/hidden_api.h b/runtime/hidden_api.h
index 5c6b4b56bc..dbe776e050 100644
--- a/runtime/hidden_api.h
+++ b/runtime/hidden_api.h
@@ -130,15 +130,15 @@ inline void WarnAboutMemberAccess(ArtMethod* method, AccessMethod access_method)
}
// Returns true if access to `member` should be denied to the caller of the
-// reflective query. The decision is based on whether the caller is in boot
-// class path or not. Because different users of this function determine this
-// in a different way, `fn_caller_in_boot(self)` is called and should return
-// true if the caller is in boot class path.
+// reflective query. The decision is based on whether the caller is in the
+// platform or not. Because different users of this function determine this
+// in a different way, `fn_caller_in_platform(self)` is called and should
+// return true if the caller is located in the platform.
// This function might print warnings into the log if the member is hidden.
template<typename T>
inline bool ShouldBlockAccessToMember(T* member,
Thread* self,
- std::function<bool(Thread*)> fn_caller_in_boot,
+ std::function<bool(Thread*)> fn_caller_in_platform,
AccessMethod access_method)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(member != nullptr);
@@ -149,14 +149,14 @@ inline bool ShouldBlockAccessToMember(T* member,
return false;
}
- // Member is hidden. Walk the stack to find the caller.
+ // Member is hidden. Invoke `fn_caller_in_platform` and find the origin of the access.
// This can be *very* expensive. Save it for last.
- if (fn_caller_in_boot(self)) {
- // Caller in boot class path. Exit.
+ if (fn_caller_in_platform(self)) {
+ // Caller in the platform. Exit.
return false;
}
- // Member is hidden and we are not in the boot class path.
+ // Member is hidden and caller is not in the platform.
// Print a log message with information about this class member access.
// We do this regardless of whether we block the access or not.
@@ -187,18 +187,39 @@ inline bool ShouldBlockAccessToMember(T* member,
return false;
}
+// Returns true if the caller is either loaded by the boot strap class loader or comes from
+// a dex file located in ${ANDROID_ROOT}/framework/.
+inline bool IsCallerInPlatformDex(ObjPtr<mirror::ClassLoader> caller_class_loader,
+ ObjPtr<mirror::DexCache> caller_dex_cache)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (caller_class_loader.IsNull()) {
+ return true;
+ } else if (caller_dex_cache.IsNull()) {
+ return false;
+ } else {
+ const DexFile* caller_dex_file = caller_dex_cache->GetDexFile();
+ return caller_dex_file != nullptr && caller_dex_file->IsPlatformDexFile();
+ }
+}
+
+inline bool IsCallerInPlatformDex(ObjPtr<mirror::Class> caller)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ return !caller.IsNull() && IsCallerInPlatformDex(caller->GetClassLoader(), caller->GetDexCache());
+}
+
// Returns true if access to `member` should be denied to a caller loaded with
// `caller_class_loader`.
// This function might print warnings into the log if the member is hidden.
template<typename T>
inline bool ShouldBlockAccessToMember(T* member,
ObjPtr<mirror::ClassLoader> caller_class_loader,
+ ObjPtr<mirror::DexCache> caller_dex_cache,
AccessMethod access_method)
REQUIRES_SHARED(Locks::mutator_lock_) {
- bool caller_in_boot = (caller_class_loader.IsNull());
+ bool caller_in_platform = IsCallerInPlatformDex(caller_class_loader, caller_dex_cache);
return ShouldBlockAccessToMember(member,
/* thread */ nullptr,
- [caller_in_boot] (Thread*) { return caller_in_boot; },
+ [caller_in_platform] (Thread*) { return caller_in_platform; },
access_method);
}
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index 76df65f730..4a2dd3bc3f 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -184,6 +184,7 @@ static ALWAYS_INLINE bool ShouldBlockAccessToMember(T* member, ShadowFrame* fram
return hiddenapi::ShouldBlockAccessToMember(
member,
frame->GetMethod()->GetDeclaringClass()->GetClassLoader(),
+ frame->GetMethod()->GetDeclaringClass()->GetDexCache(),
hiddenapi::kReflection); // all uses in this file are from reflection
}
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index b78fcacc08..f309581735 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -80,18 +80,15 @@ namespace art {
// things not rendering correctly. E.g. b/16858794
static constexpr bool kWarnJniAbort = false;
-static bool IsCallerInBootClassPath(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) {
- ObjPtr<mirror::Class> klass = GetCallingClass(self, /* num_frames */ 1);
- // If `klass` is null, it is an unattached native thread. Assume this is
- // *not* boot class path.
- return klass != nullptr && klass->IsBootStrapClassLoaded();
+static bool IsCallerInPlatformDex(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return hiddenapi::IsCallerInPlatformDex(GetCallingClass(self, /* num_frames */ 1));
}
template<typename T>
ALWAYS_INLINE static bool ShouldBlockAccessToMember(T* member, Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_) {
return hiddenapi::ShouldBlockAccessToMember(
- member, self, IsCallerInBootClassPath, hiddenapi::kJNI);
+ member, self, IsCallerInPlatformDex, hiddenapi::kJNI);
}
// Helpers to call instrumentation functions for fields. These take jobjects so we don't need to set
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index fc61c9597e..ad05856eaf 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -49,8 +49,8 @@
namespace art {
-// Returns true if the first non-ClassClass caller up the stack is in boot class path.
-static bool IsCallerInBootClassPath(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) {
+// Returns true if the first non-ClassClass caller up the stack is in a platform dex file.
+static bool IsCallerInPlatformDex(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) {
// Walk the stack and find the first frame not from java.lang.Class.
// This is very expensive. Save this till the last.
struct FirstNonClassClassCallerVisitor : public StackVisitor {
@@ -82,7 +82,7 @@ static bool IsCallerInBootClassPath(Thread* self) REQUIRES_SHARED(Locks::mutator
FirstNonClassClassCallerVisitor visitor(self);
visitor.WalkStack();
return visitor.caller != nullptr &&
- visitor.caller->GetDeclaringClass()->IsBootStrapClassLoaded();
+ hiddenapi::IsCallerInPlatformDex(visitor.caller->GetDeclaringClass());
}
// Returns true if the first non-ClassClass caller up the stack is not allowed to
@@ -90,7 +90,7 @@ static bool IsCallerInBootClassPath(Thread* self) REQUIRES_SHARED(Locks::mutator
ALWAYS_INLINE static bool ShouldEnforceHiddenApi(Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_) {
hiddenapi::EnforcementPolicy policy = Runtime::Current()->GetHiddenApiEnforcementPolicy();
- return policy != hiddenapi::EnforcementPolicy::kNoChecks && !IsCallerInBootClassPath(self);
+ return policy != hiddenapi::EnforcementPolicy::kNoChecks && !IsCallerInPlatformDex(self);
}
// Returns true if the first non-ClassClass caller up the stack should not be
@@ -99,7 +99,7 @@ template<typename T>
ALWAYS_INLINE static bool ShouldBlockAccessToMember(T* member, Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_) {
return hiddenapi::ShouldBlockAccessToMember(
- member, self, IsCallerInBootClassPath, hiddenapi::kReflection);
+ member, self, IsCallerInPlatformDex, hiddenapi::kReflection);
}
// Returns true if a class member should be discoverable with reflection given