Skip to content

Commit

Permalink
[Samsung] Deal with core-libart.jar variants
Browse files Browse the repository at this point in the history
* java.lang.DexCache : some devices have two more fields named 'literals' and 'z_padding'
  -> Search for the fields in /system/framework/core-libart.jar when Android Runtime
     initialises then set up a flag whether to adjust offsets or not

* dalvik.system.PathClassLoader : some devices have one more native method named 'openNative'
  -> Try to register the method anyway and if it errors, ignore it
  • Loading branch information
Liliniser committed Sep 1, 2016
1 parent 860f3a3 commit 70fc6d9
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 7 deletions.
38 changes: 38 additions & 0 deletions runtime/class_linker.cc
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,28 @@ ClassLinker::ClassLinker(InternTable* intern_table)
std::fill_n(find_array_class_cache_, kFindArrayCacheSize, GcRoot<mirror::Class>(nullptr));
}

static void dexCacheExtraFieldsWorkaround(const DexFile* dex_file) {
const char* descriptor = "Ljava/lang/DexCache;";
const size_t hash = ComputeModifiedUtf8Hash(descriptor);
const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor, hash);
if (dex_class_def != nullptr) {
const uint8_t* class_data = dex_file->GetClassData(*dex_class_def);
if (class_data != nullptr) {
for (ClassDataItemIterator it(*dex_file, class_data); it.HasNextInstanceField(); it.Next()) {
const DexFile::FieldId& field_id = dex_file->GetFieldId(it.GetMemberIndex());
const char* name = dex_file->GetFieldName(field_id);
// Additional fields are normally 'literals' and 'z_padding'.
// Some devices have only 'literals' (without 'z_padding') but they work the same.
if (strcmp(name, "literals") == 0) {
mirror::sDexCacheJavaClassHasExtraFields = true;
LOG(INFO) << "java.lang.DexCache compatibility mode";
break;
}
}
}
}
}

void ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> boot_class_path) {
VLOG(startup) << "ClassLinker::Init";

Expand Down Expand Up @@ -432,8 +454,16 @@ void ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b
// DexCache instances. Needs to be after String, Field, Method arrays since AllocDexCache uses
// these roots.
CHECK_NE(0U, boot_class_path.size());
const char* core_libart_filename = "/system/framework/core-libart.jar";
for (auto& dex_file : boot_class_path) {
CHECK(dex_file.get() != nullptr);

// TODO: Workaround for DexCache extra fields. Could this be better?
if (dex_file->GetLocation() == core_libart_filename) {
dexCacheExtraFieldsWorkaround(dex_file.get());
java_lang_DexCache->SetObjectSize(mirror::DexCache::InstanceSize());
}

AppendToBootClassPath(self, *dex_file);
opened_dex_files_.push_back(std::move(dex_file));
}
Expand Down Expand Up @@ -1134,6 +1164,14 @@ void ClassLinker::InitFromImage() {

CHECK_EQ(oat_file.GetOatHeader().GetDexFileCount(),
static_cast<uint32_t>(dex_caches->GetLength()));

// TODO: Workaround for DexCache extra fields. Could this be better?
const OatFile::OatDexFile* oat_dex_file = oat_file.GetOatDexFile("/system/framework/core-libart.jar", nullptr);
std::string error_msg;
std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error_msg);
dexCacheExtraFieldsWorkaround(dex_file.get());
dex_file.reset();

for (int32_t i = 0; i < dex_caches->GetLength(); i++) {
StackHandleScope<1> hs2(self);
Handle<mirror::DexCache> dex_cache(hs2.NewHandle(dex_caches->Get(i)));
Expand Down
6 changes: 6 additions & 0 deletions runtime/jni_internal.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2170,6 +2170,12 @@ class JNI {
}

if (m == nullptr) {
if (PrettyDescriptor(c) == "dalvik.system.PathClassLoader" && strcmp(name, "openNative") == 0) {
LOG(INFO) << "Native method " << PrettyDescriptor(c) << "." << name << sig
<< " not found in " << c->GetDexCache()->GetLocation()->ToModifiedUtf8();
continue;
}

LOG(return_errors ? ERROR : INTERNAL_FATAL) << "Failed to register native method "
<< PrettyDescriptor(c) << "." << name << sig << " in "
<< c->GetDexCache()->GetLocation()->ToModifiedUtf8();
Expand Down
2 changes: 2 additions & 0 deletions runtime/mirror/dex_cache.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
namespace art {
namespace mirror {

bool sDexCacheJavaClassHasExtraFields = false;

void DexCache::Init(const DexFile* dex_file, String* location, ObjectArray<String>* strings,
ObjectArray<Class>* resolved_types, PointerArray* resolved_methods,
PointerArray* resolved_fields, size_t pointer_size) {
Expand Down
18 changes: 11 additions & 7 deletions runtime/mirror/dex_cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ namespace mirror {

class String;

// A flag for devices that have an additional 'String[] literals' field
// on the java class side. Mostly comes with 'Object z_padding' as well.
extern bool sDexCacheJavaClassHasExtraFields;

// C++ mirror of java.lang.DexCache.
class MANAGED DexCache FINAL : public Object {
public:
Expand All @@ -44,7 +48,7 @@ class MANAGED DexCache FINAL : public Object {

// Size of an instance of java.lang.DexCache not including referenced values.
static uint32_t InstanceSize() {
return sizeof(DexCache) + (IsSamsungROM() ? 8 : 0);
return sizeof(DexCache) + (sDexCacheJavaClassHasExtraFields ? 8 : 0);
}

void Init(const DexFile* dex_file, String* location, ObjectArray<String>* strings,
Expand All @@ -59,31 +63,31 @@ class MANAGED DexCache FINAL : public Object {
}

static MemberOffset LocationOffset() {
return MemberOffset(OFFSETOF_MEMBER(DexCache, location_) + (IsSamsungROM() ? 4 : 0));
return MemberOffset(OFFSETOF_MEMBER(DexCache, location_) + (sDexCacheJavaClassHasExtraFields ? 4 : 0));
}

static MemberOffset DexOffset() {
return OFFSET_OF_OBJECT_MEMBER(DexCache, dex_);
}

static MemberOffset StringsOffset() {
return MemberOffset(OFFSETOF_MEMBER(DexCache, strings_) + (IsSamsungROM() ? 4 : 0));
return MemberOffset(OFFSETOF_MEMBER(DexCache, strings_) + (sDexCacheJavaClassHasExtraFields ? 4 : 0));
}

static MemberOffset ResolvedFieldsOffset() {
return MemberOffset(OFFSETOF_MEMBER(DexCache, resolved_fields_) + (IsSamsungROM() ? 4 : 0));
return MemberOffset(OFFSETOF_MEMBER(DexCache, resolved_fields_) + (sDexCacheJavaClassHasExtraFields ? 4 : 0));
}

static MemberOffset ResolvedMethodsOffset() {
return MemberOffset(OFFSETOF_MEMBER(DexCache, resolved_methods_) + (IsSamsungROM() ? 4 : 0));
return MemberOffset(OFFSETOF_MEMBER(DexCache, resolved_methods_) + (sDexCacheJavaClassHasExtraFields ? 4 : 0));
}

static MemberOffset ResolvedTypesOffset() {
return MemberOffset(OFFSETOF_MEMBER(DexCache, resolved_types_) + (IsSamsungROM() ? 4 : 0));
return MemberOffset(OFFSETOF_MEMBER(DexCache, resolved_types_) + (sDexCacheJavaClassHasExtraFields ? 4 : 0));
}

static MemberOffset DexFileOffset() {
return MemberOffset(OFFSETOF_MEMBER(DexCache, dex_file_) + (IsSamsungROM() ? 8 : 0));
return MemberOffset(OFFSETOF_MEMBER(DexCache, dex_file_) + (sDexCacheJavaClassHasExtraFields ? 8 : 0));
}

size_t NumStrings() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Expand Down

0 comments on commit 70fc6d9

Please sign in to comment.