从native层去startService(非原生系统7.1保活)

上篇文章我们谈到了在Android7.1原生系统上保活《从native层去startService(原生系统7.1保活)》但是我们发现在非原生系统的手机上使用时不能保活成功,主要是参数错误,导致startService没能成功,针对这个问题,又再进行了一点研究。

1.错误的原因:
会触发“calling Package is null”的问题或者其他字符串为空的问题,本质上属于同一个问题。这个问题的产生是这样的,我们把数据提交给远程系统服务后,AMS在解析Intent的数据的时候,读取到的calling Package为空,这种行为不合法,直接抛出异常,导致service起不来。这极有可能是因为数据顺序不对,少了或多了数据的问题,我之前写的这篇文章《关于android的Parcel》里提到过,parcel在读取和写入的顺序必须是完全一致的,不然肯定会有问题,这个异常是在解析Intent的时候抛出来的,那么很有可能是因为厂商修改了Intent的数据,而我们又是根据源码的顺序在写入数据的,这样修改过后的Intent调用readFromParcel的方法时,顺序不对或者多了少了一个数据,导致读出的数据错误,一些判断过不了。

根据这个猜想去试验,在探索中发现,在华为的手机上,去反射它的Intent的字段时,就找到几个多出来具有华为标识的String:
在这里插入图片描述
同样是下面几行代码:

Parcel data = Parcel.obtain();
Intent intent = new Intent(this , Service1.class);
intent.writeToParcel(data, 0);
int length = data.marshall().length;

在不同的手机版本,不同的手机厂商下,这个length的长度都是不一样的,也就是说,厂商其实多少都有在Intent这个类里面进行修改,但如果要去猜测它往Parcel里面写了哪些数据,又是以怎样的顺序去写的,这几乎无解,也会给适配带来非常大的困难。

2.问题的解决
既然不可能去猜厂商修改了什么东西,但是我们完全可以不用理会这个问题,让系统帮我们去写数据就行了。直接先写个模板Intent,拿到一个Parcel,把intent里面的数据写到Parcel里面去,再把Parcel的数据取出来,存到文件里,再在native层把数据读出来即可:

// java 层
Intent intent = new Intent(this , Service1.class);
intent.writeToParcel(data, 0);
byte[] marshall = data.marshall();
writeToFile(marshall);

// native 层,parcelDatas就是从上面那个文件取出来的数据
Parcel intentParcel , data;
intentParcel.setData((const uint8_t*)parcelDatas, length);

// 再把数据追加到data里面:
data.appendFrom(&intentParcel, 0, intentParcel.dataSize());

这样我们就可以绕过不同厂商的Intent,无视他们对里面的修改,还可以方便地添加Bundle数据,事实也证明如此,在7和8的不同厂商手机上,都能成功地启动service,这种方法也对原生系统适用。这样就可以在非原生系统上进行保活,在红米一个7.0的手机上进行测试:
在这里插入图片描述
我们在几台7.0和7.1的非原生系统的手机上都测试通过,保活成功,在8.0上进行尝试,原生的可以保活,非原生的还有问题,可能是后台限制的原因,还在进行研究。

3.疑问
可能有些人有疑问,如果厂商改了Parcel,一样会有问题,我个人认为,因为Parcel在java层和native层都会大量用于IPC,修改其的成本会非常大,相对来说修改Intent就比较容易了,在里面添加字段什么的,只需要保证 readFromParcel和writeToParcel 这两个方法读写数据的顺序是一样的就行了,目前还没在7的手机上失败过的,嗯,进行研究吧。

猜你喜欢

转载自blog.csdn.net/aa642531/article/details/83688365
今日推荐