Framework.jar里的类无法通过Class.forName反射某个类的问题排查

1,背景

我们想要在system_server进程里扩展一些我们自己的功能。

考虑到解耦和编译依赖的问题,我们用PRODUCT_SYSTEM_SERVER_JARS预置我们的类,然后用反射jar里面的类的方式来实现代码引用。

2,遇到的问题

在SystemServer.java里用Class.forName可以反射到目标类。

在ParsingPackageUtils.java里用Class.forName 无法 反射到目标类。

log如下:

04-24 14:58:43.514 811 811 W PackageParsing: initSystemServerJarDemo, got exception.

04-24 14:58:43.514 811 811 W PackageParsing: at com.android.internal.pm.pkg.parsing.ParsingPackageUtils.initSystemServerJarDemo(ParsingPackageUtils.java:329)

04-24 14:58:46.120 811 811 D SystemServer: initSystemServerJarDemo, result:2

两个java里反射时,使用的是一样的方法:

java 复制代码
    private void initSystemServerJarDemo(){

        String classPath = "com.demo.systemserverdemo.SystemServerDemo";
        try {
            Class classObj = Class.forName(classPath);
            Object obj = classObj.getDeclaredConstructor().newInstance();
            Method method = obj.getClass().getDeclaredMethod("test");
            method.setAccessible(true);
            int result = (int) method.invoke(obj);
            Slog.d(TAG, "initSystemServerJarDemo, result:"+result);
        } catch (Throwable ex){
            Slog.d(TAG, "initSystemServerJarDemo, got exception.", ex);
        }
    }

3, 问题分析

3.1,原因猜测

可能是类加载器的双亲委派机制导致的。

ParsingPackageUtils.java在framework.jar里;SystemServer.java在service.jar里。

framework.jar属于bootJar,加载顺序在service.jar之前;

framework.jar的类加载器,有可能是services.jar的父加载器。

类加载器会向当前ClassLoader和父加载器ClassLoader查找目标class;

framework.jar里的ParsingPackageUtils.java不会向子加载器查询SYSTEM_SERVER_JARS里的类;

3.2,验证结论

我们可以打印出来SystemServer.java的ClassLoader及其父加载器。

并打印出来ParsingPackageUtils.java的ClassLoader及其父加载器。

来确认类加载器对象是否存在父子关系。

使用以下方法打印类加载器信息:

private void printClassLoader(){

boolean recycle = true;

ClassLoader loader = getClass().getClassLoader();

while (recycle){

if(loader == null){

recycle = false;

return;

}

Slog.d(TAG, "initSystemServerJarDemo, loader hash:"+loader.hashCode()+", loader class:"+loader.getClass().getName());

loader = loader.getParent();

}

}

输出如下:

04-24 15:21:27.443 806 806 D PackageParsing: initSystemServerJarDemo, loader hash:3047529, loader class:java.lang.BootClassLoader

04-24 15:21:30.883 806 806 D SystemServer: initSystemServerJarDemo, loader hash:179379372, loader class:dalvik.system.PathClassLoader

04-24 15:21:30.884 806 806 D SystemServer: initSystemServerJarDemo, loader hash:3047529, loader class:java.lang.BootClassLoader

3.3 结论

把类加载器打印出来,发现framework-PackageParsing的ClassLoader hash:3047529,

确实是SystemServer的类加载器(hash:179379372)的父类。

所以父加载器(hash:3047529)里的类,无法拿到子加载器里的东西。

因为Class.forName就是拿当前类加载器去查找类的。

libcore/ojluni/src/main/java/java/lang/Class.java

java 复制代码
    public static Class<?> forName(String className)
                throws ClassNotFoundException {
        Class<?> caller = Reflection.getCallerClass();//当前类
        return forName(className, true, ClassLoader.getClassLoader(caller));
    }

4,改善

我们无法在framework.jar里的java类里,通过当前类加载器拿到目标类。

我们可以创建一个新的类加载器,就可以加载jar里面的类。

java 复制代码
DexClassLoader classLoader = new DexClassLoader("/system/framework/**Demo.jar",
                    null, null,
                    this.class.getClassLoader());
Class classObj = classLoader.loadClass("com.demo.systemserverdemo.SystemServerDemo");
Constructor constructor = classObj.getDeclaredConstructor();
constructor.setAccessible(true);
constructor.newInstance();

--------------------------------end-----------------------------------

相关推荐
SharpCJ8 小时前
Android 开发者为什么必须掌握 AI 能力?端侧视角下的技术变革
android·ai·aigc
_李小白9 小时前
【OSG学习笔记】Day 38: TextureVisitor(纹理访问器)
android·笔记·学习
JJay.9 小时前
Kotlin 高阶函数学习指南
android·开发语言·kotlin
jinanwuhuaguo9 小时前
截止到4月8日,OpenClaw 2026年4月更新深度解读剖析:从“能力回归”到“信任内建”的范式跃迁
android·开发语言·人工智能·深度学习·kotlin
JJay.10 小时前
Android Kotlin 协程使用指南
android·开发语言·kotlin
BLUcoding10 小时前
Android 布局介绍
android
summerkissyou198710 小时前
android-蓝牙-状态和协议值总结及监听例子
android·蓝牙
徒 花10 小时前
数据库知识复习05
android·数据库
提子拌饭13313 小时前
番茄时间管理:鸿蒙Flutter 实现的高效时间管理工具
android·flutter·华为·架构·开源·harmonyos·鸿蒙
4311媒体网13 小时前
帝国CMS二次开发实战:精准实现“最新资讯”标识与高亮判断
android