修改 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.javaString.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) 中使用

以编程方式访问 java 密钥库以创建 SSLSocketFactory

如何编写真正的跨平台 C++ 库以进行分发

在AWS S3上存储CakePHP库以用于多个应用程序

使用 AltBeacon 库以 CoreBluetooth 格式做广告