修改 Android 源代码的核心 java 库以在应用程序中使用
Posted
技术标签:
【中文标题】修改 Android 源代码的核心 java 库以在应用程序中使用【英文标题】:Modify core java libraries of Android source for use in apps 【发布时间】:2019-07-18 15:02:13 【问题描述】:我想对 android 源代码进行一些修改以满足我的要求。这是要求:
我想通过在java.lang.Object
类中再添加一个公共int
字段来索引Android 应用程序中的所有对象。因此,所有类都可以继承新添加的字段,因为它们都是Object
类的子类。
目前我所做的是修改<Android_source>/libcore/libart/src/main/java/java/lang
文件夹下的java.lang.Object
类并重新编译源代码。
我想问我是否做对了。我的 Android 应用能否识别此更改(例如,String
对象能否访问新添加的字段)?
编辑
经过大约 3 周的尝试和错误,我终于得到了完整的答案。如果有人想修改Android源码的核心java库(例如修改Object.java
和String.java
等),我想与其他人分享这个经验。同样,正如 Michael 所提到的,请注意此类修改可能仅适用于研究或测试目的。
成功修改的关键挑战(这里的“成功”是指修改后的 Android 源代码可以在模拟器或真实设备上毫无问题地构建和运行)是核心 java 库中的一些类具有它们的 C++ 镜像(位于<Android_source>/art/runtime/mirrors/
)。在修改这些 java 类时,您还应该对它们的 C++ 镜像进行相同的修改。否则,您可能会导致构建过程失败,因为您需要通过大量检查。由于我只是在Object.java
中添加了一个新字段,因此我将在下面列出我遇到的一些检查(或要求):
1.对象实例的大小=其C++镜像的大小。例如,如果我在Object.java
中添加一个long
字段,我还应该在其C++ 镜像中添加一个uint64_t
字段以使其大小相等。
2.尝试使对象实例的大小为 2 的幂(例如,2、4、8、16,...)。比如原来Object.java
的大小是8,所以我添加了一个long字段来将大小增加到16。如果我添加一个int字段,大小变成12,它可能会失败很多检查。我不知道确切的原因,但我想这与memory alignment 有关。
3.尽量将原始类型字段放在非原始类型字段之后,原始类型字段应按大小排序。这意味着您应该将引用类型字段放在前面,然后是 8 字节原始类型字段,然后是 4 字节原始类型字段,然后是 2 字节原始类型字段,然后是 1 字节原始类型字段-类型字段。再说一次,我猜原因是memory alignment
这就是我为满足我的要求所做的一切。如果您对这些检查的目的有任何想法(尤其是第 2 次和第 3 次),我愿意进行任何讨论
新编辑
更具体地说,我做了以下事情:
在Object.java
中添加一个新字段(例如public long tag;
)
在Object.h
中将static constexpr uint32_t kObjectHeaderSize = kUse***sReadBarrier ? 16 : 8;
更改为static constexpr uint32_t kObjectHeaderSize = kUse***sReadBarrier ? 24 : 16;
在Object.h
中添加如下方法
static MemberOffset TagOffset()
return OFFSET_OF_OBJECT_MEMBER(Object, tag);
在Object.h
中添加一个新的公共字段public: uint64_t tag;
改变
#define MIRROR_OBJECT_CLASS_OFFSET 0
ADD_TEST_EQ(MIRROR_OBJECT_CLASS_OFFSET, art::mirror::Object::ClassOffset().Int32Value())
#define MIRROR_OBJECT_LOCK_WORD_OFFSET 4
ADD_TEST_EQ(MIRROR_OBJECT_LOCK_WORD_OFFSET, art::mirror::Object::MonitorOffset().Int32Value())
#if defined(USE_***S_READ_BARRIER)
#define MIRROR_OBJECT_HEADER_SIZE 16
#else
#define MIRROR_OBJECT_HEADER_SIZE 8
到
#define MIRROR_OBJECT_CLASS_OFFSET 0
ADD_TEST_EQ(MIRROR_OBJECT_CLASS_OFFSET, art::mirror::Object::ClassOffset().Int32Value())
#define MIRROR_OBJECT_LOCK_WORD_OFFSET 4
ADD_TEST_EQ(MIRROR_OBJECT_LOCK_WORD_OFFSET, art::mirror::Object::MonitorOffset().Int32Value())
#define MIRROR_OBJECT_CLASS_TAG 8
ADD_TEST_EQ(MIRROR_OBJECT_CLASS_TAG, art::mirror::Object::TagOffset().Int32Value())
#if defined(USE_***S_READ_BARRIER)
#define MIRROR_OBJECT_HEADER_SIZE 24
#else
#define MIRROR_OBJECT_HEADER_SIZE 16
在asm_support.h
在class_linker_test.cc
中添加addOffset(OFFSETOF_MEMBER(mirror::Object, tag), "tag");
改变
static_assert(kObjectHeaderSize == sizeof(mirror::HeapReference<mirror::Class>) +
sizeof(LockWord),
到
static_assert(kObjectHeaderSize == sizeof(mirror::HeapReference<mirror::Class>) +
sizeof(LockWord) + 8,
在art/runtime/gc/collector/concurrent_copying.cc
8 在array.h
中将static constexpr size_t kFirstElementOffset = 12u;
更改为static constexpr size_t kFirstElementOffset = 20u;
9 将 runtime_globals.h
中的 static constexpr size_t kObjectAlignmentShift = 3;
更改为 static constexpr size_t kObjectAlignmentShift = 4;
(尚未完成)
10 改变
static_assert(kObjectAlignment == 8, "Alignment check");
class PACKED(8) ImageHeader
到
static_assert(kObjectAlignment == 16, "Alignment check");
class PACKED(16) ImageHeader
在image.h
(尚未完成)
11 将gc::space::BumpPointerSpace
中的static constexpr size_t kAlignment = 8;
更改为static constexpr size_t kAlignment = 16;
(尚未完成)
12 将device/generic/goldfish/tools/mk_combined_img.py
中的#!/usr/bin/python
更改为#!/usr/local/bin/python
(值取决于您的/bin/env python)
13 改变
#define DCHECK_ALIGNED_PARAM(value, alignment) \
DCHECK(::art::IsAlignedParam(value, alignment)) << reinterpret_cast<const void*>(value)
到
#define DCHECK_ALIGNED_PARAM(value, alignment) \
DCHECK(::art::IsAlignedParam(value, alignment)) << reinterpret_cast<const void*>(value) << "," << alignment
in art/libartbase/base/bit_utils.h
(用于调试目的)(仅适用于 Android 11)
14 改变
DCHECK_ALIGNED_PARAM(remaining_space, object_class->GetObjectSize());
Object* end = dst + remaining_space / object_class->GetObjectSize();
到
DCHECK_ALIGNED_PARAM(remaining_space, kObjectAlignment);
Object* end = dst + remaining_space / kObjectAlignment;
在art/dex2oat/linker/image_writer.cc
中(仅适用于 Android 11)
【问题讨论】:
这似乎是一种非常极端的处理方式,您的应用只能在运行您自定义构建的 AOSP 的设备上运行。在您的应用程序中使用int
方法创建接口并将其应用于所有相关类不是更容易吗?或者您是否也尝试通过继承来更改其他 Android SDK 类?
嗨迈克尔,谢谢您的回复!是的,我希望更改适用于每个类,包括核心 Java 库、Android SDK 类和我的应用程序类。我制作这个定制的 AOSP 仅用于研究目的,因此这实际上是我能找到的最简单的方法来满足我的要求。
您还需要创建一个自定义 Android SDK 并将其导入 Android Studio,否则您的新方法将不会显示在 Android Studio 中并且不会编译。这个链接应该是一个很好的起点:android.googlesource.com/platform/sdk/+/master/docs/…
嗨迈克尔,再次感谢!所以基本上我正在尝试做的是可行的,对吗?为什么不提出答案,我会将其标记为正确的。
【参考方案1】:
首先,我想声明,我认为这不是一个好主意,而且在研究目的之外可能是矫枉过正。如果您正在修改 AOSP,那么您编写的代码将取决于运行该自定义 AOSP 构建的目标设备。不过还是可以的。
我假设您已经知道如何编译自定义 AOSP 构建并将其闪存到设备。为了编写使用新功能的代码,您还需要编译自定义 SDK。这样 Android Studio 就会知道您的新方法存在于 Object
中,并且可以针对它正确编译。完整的文档可以在here 找到,但基本上可以归结为:
. build/envsetup.sh
lunch sdk-eng
make sdk
当您拥有 SDK zip 文件后,您需要将其解压缩到 SDK 的 platforms
目录 - 它现在应该会显示在您的 SDK 管理器中。如果您为 SDK 提供了自定义平台 ID,那么您应该可以在 build.gradle
文件中使用它。
免责声明:这个建议完全来自记忆,这是一个漫长的过程,所以我没有时间仔细检查,并且可能有一些我错过了的小事情.不过,这应该可以让您大部分时间到达您想要的位置。
【讨论】:
以上是关于修改 Android 源代码的核心 java 库以在应用程序中使用的主要内容,如果未能解决你的问题,请参考以下文章
如何更改 Android Leanback 库以支持背景视频而不是背景图像
使用 MinGW C++ 编译 64 位静态库以在 Java (JNI) 中使用