android 插件化atlas,Atlas插件化踩坑

博客探讨了在使用Android的Altas插件化框架时遇到的问题,即在4.x系统中,通过Bundle传递继承自Serializable的类对象时出现ClassNotFound异常。分析源码发现,ObjectInputStream在查找类时依赖于VM栈,这可能导致不可靠的结果。在5.0及以上系统中,该问题得到了解决,因为系统重写了resolveClass方法,允许指定ClassLoader。博客内容涉及Android插件化、Bundle序列化和ClassLoader机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在使用Altas插件化框架,遇到了一些问题,记录下

bundle传值报class not found

我们给bundle传了一个继承Serializable的对象,但是在4.x的系统里,报了class not found的异常

at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:53)

at java.lang.ClassLoader.loadClass(ClassLoader.java:501)

at java.lang.ClassLoader.loadClass(ClassLoader.java:461)

at java.lang.Class.classForName(Native Method)

at java.lang.Class.forName(Class.java:217)

at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:2304)

at java.io.ObjectInputStream.readNewClassDesc(ObjectInputStream.java:1663)

at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:683)

at java.io.ObjectInputStream.readNewObject(ObjectInputStream.java:1806)

at java.io.ObjectInputStream.readNonPrimitiveContent(ObjectInputStream.java:787)

at java.io.ObjectInputStream.readObject(ObjectInputStream.java:2006)

at java.io.ObjectInputStream.readObject(ObjectInputStream.java:1963)

at android.os.Parcel.readSerializable(Parcel.java:2142)

at android.os.Parcel.readValue(Parcel.java:2016)

at android.os.Parcel.readMapInternal(Parcel.java:2226)

at android.os.Bundle.unparcel(Bundle.java:223)

at android.os.Bundle.getString(Bundle.java:1055)

at android.content.Intent.getStringExtra(Intent.java:4488)

显然不是bundle的classloader,但是altas怎么控制解析时classloader的查找呢。根据研究altas源码发现,在查找bundle前,已经给intent设置了classloader

//InstrumentationHook.java

@Override

public void callActivityOnCreate(Activity activity, Bundle icicle) {

if(activity.getIntent()!=null){

activity.getIntent().setExtrasClassLoader(RuntimeVariables.delegateClassLoader);

}

}

但是这个代码居然没用,于是我们进一步分析,发现了关键问题。

因为ObjectInputStream的查找类的时候,是通过vmstack来查找最近的classloader的,这是不靠谱的。

protected Class> resolveClass(ObjectStreamClass desc)

throws IOException, ClassNotFoundException

{

String name = desc.getName();

try {

return Class.forName(name, false, latestUserDefinedLoader());

} catch (ClassNotFoundException ex) {

Class> cl = primClasses.get(name);

if (cl != null) {

return cl;

} else {

throw ex;

}

}

}

就是这里导致了bug,但是为啥5.0以上没问题呢。通过研究源码发现,5.0的代码,重写了resolveClass这个方法

// 19

2196 public final Serializable readSerializable() {

2197 String name = readString();

2198 if (name == null) {

2199 // For some reason we were unable to read the name of the Serializable (either there

2200 // is nothing left in the Parcel to read, or the next value wasn't a String), so

2201 // return null, which indicates that the name wasn't found in the parcel.

2202 return null;

2203 }

2204

2205 byte[] serializedData = createByteArray();

2206 ByteArrayInputStream bais = new ByteArrayInputStream(serializedData);

2207 try {

2208 ObjectInputStream ois = new ObjectInputStream(bais);

2209 return (Serializable) ois.readObject();

2210 } catch (IOException ioe) {

2211 throw new RuntimeException("Parcelable encountered " +

2212 "IOException reading a Serializable object (name = " + name +

2213 ")", ioe);

2214 } catch (ClassNotFoundException cnfe) {

2215 throw new RuntimeException("Parcelable encountered" +

2216 "ClassNotFoundException reading a Serializable object (name = "

2217 + name + ")", cnfe);

2218 }

2219 }

// 25

private final Serializable readSerializable(final ClassLoader loader) {

String name = readString();

if (name == null) {

// For some reason we were unable to read the name of the Serializable (either there

// is nothing left in the Parcel to read, or the next value wasn't a String), so

// return null, which indicates that the name wasn't found in the parcel.

return null;

}

byte[] serializedData = createByteArray();

ByteArrayInputStream bais = new ByteArrayInputStream(serializedData);

try {

ObjectInputStream ois = new ObjectInputStream(bais) {

@Override

protected Class> resolveClass(ObjectStreamClass osClass)

throws IOException, ClassNotFoundException {

// try the custom classloader if provided

if (loader != null) {

Class> c = Class.forName(osClass.getName(), false, loader);

if (c != null) {

return c;

}

}1

return super.resolveClass(osClass);

}

};

return (Serializable) ois.readObject();

} catch (IOException ioe) {

throw new RuntimeException("Parcelable encountered " +

"IOException reading a Serializable object (name = " + name +

")", ioe);

} catch (ClassNotFoundException cnfe) {

throw new RuntimeException("Parcelable encountered " +

"ClassNotFoundException reading a Serializable object (name = "

+ name + ")", cnfe);

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值