月度归档:2020年02月

ActivityThead.mNewActivities导致的内存泄漏

昨天有测试报告说这个版本的应用在重复跑测试case的时候内存不断变大

由于测试case会重复启动activity首先就怀疑是不是activitty导致的内存泄漏

Adb shell dumpsys meminfo [packagename]

通过dump 信息,发现activity的实例确实在不断变多,但查阅代码并未发现任何持有引用的地方

android studio profile来 dump内存信息发现最短的引用路径来自android os. ActivityThead

开始有点不信,不觉得系统的引用的会导致内存不断增加,然后再次使用MAT分析

发现确实来自ActivityThead.mNewActivities

源码分析

通关简单分析发现mNewActivities 是一个链表

搜索关键字发现仅仅只在ActivityThead.Idler这个私有类里进行了引用释放,这个

MessageQueue.IdleHandler 这是一个接口,查阅注释发现这个接口仅仅只有当前线程 MessageQueue 空闲之后才会回调 查看更多

悬浮窗开发的总结

1、动画和点击区域问题

可以使用hide方法viewTreeObserver下的方法进行窗口裁剪实现局部透过点击事件,这样在动画的时候就不需要考虑进行window大小变化了

2、 启动慢的问题

1)由于悬浮窗启动一般使用的是service启动,通过分析ams可以发现,在进行activity启动的是有进行powehint操作的,而一般的service是没有的,如果系统是自家的可以考虑在启动自己的服务的时候加上powerhint操作

2)使用startforgroundService的方式提高进程的优先级

3) 考虑使用异步layoutinfler来实现在applictaion创建时候就着手准备view

3、偶现UI不刷新,但没有anr

这个问题,赶紧查查进程的OOM_ADJ,大概率是优先级过低,得不到系统的资源调度问题 查看更多

从最上层到驱动层看Android Conetext.getSystemService究竟做了什么

曾经好奇为什么同样是binder接口,Conetext.getService为什么可以直接获取,而不需要像bindeService一样异步回调,今天终于从能够从上层源码到binder驱动源码,彻底了解这一过程,同时分析binder接口在调用的时候,底层究竟是如何实现的。

1.从getSystemService 到native的getContextObject

ContextImpl.java

SystemServiceRegistry.java

SYSTEM_SERVICE_FETCHERS是一个hasmap,键值是一个抽象类,ServiceFetcher,它在初始化的时候实现,见如下代码

registerService 的作用就是把CachedServiceFetcher 放到 SYSTEM_SERVICE_FETCHERS 中,这样每次取服务时都可以从这个缓存获取,因此我们第二次getSystemService时性能是非常高的,时间复杂度位O(1),然后所有系统服务端最终都会调用到这一步 查看更多

Https、数字证书、SSL连接、中间人攻击

证书的签发原理

数字证书信息可以由申请者提供,包含域名等信息,CA机构签名后,这个证书就有效了,这个签名是数字签名,有效性来自RSA非对称加密

数字证书 = 域名数据(域名自己的公钥+域名等)+ 数据摘要(对域名的原始数据进行hash )+数字签名(对数据摘要使用CA机构自己的私钥加密的结果)

根证书:无条件信任的由系统内置的各大CA机构的证书,包含对应CA机构的公钥等

证书的验证原理

1.使用受信任的颁发者的公钥校验证书

使用本地的受信任的证书中的公钥(待验证的证书里指定了颁发者Issuer,因此可以快速找到它的公钥)来解密ssl链接中下发的的数字证书的数字签名,得到数据摘要S1,然后按相同的摘要算法对证书内容进行计算得到数据摘要S2,读取证书中的数据摘要S3,当S1=S2=S3说明证书确定是由正规机构颁发,并且内容完全正确 查看更多

总结一下各路绕过反射限制的方法

为了防止app调用系统的hide方法,android 9.0对反射的调用做了一个限制,每个方法或者变量在编译后在flag里表示了该方法是hide还是公开,通过回溯调用栈判断该调用者的类是否是BootstrapClassLoader 如果是则信任

应对方法

1,定义和系统相同类,骗过编译器,直接调用隐藏方法

2. jni修改 javaruntime里的 隐藏api策略, hidden_api_policy_

3.既然只检查调用类是否是是系统类,那么使用反射去调用反射方法,两次反射,第二次调用系统方法,在检查的时候会发现调用者反射工具类,而反射工具类是系统方法

4。 修改 javaruntime .里的豁免条件GetHiddenApiExemptions ,可以使用反射+反射 查看更多

MMKV代替 SharedPreferences

SharedPreferences 的缺点

1.SharedPreferences 写入性能低,在线上项目经常出现anr的情况,虽然 SharedPreferences 已经提供了异步写入apply方法,但由于为了保证数据的可靠性, SharedPreferences 会在一些特定的生命周期(如onDestory方法)直接执行还在pending过程的任务,导致app anr

2.对于多进程的使用, SharedPreferences 并不是很好,因为 SharedPreferences 有内存缓存,不能跨进程立即刷新,而使用contentprovider的话代码量更重

MMKV的优势

1.MMKV由于使用内存映射,使得每次写入只需写入到内存快即可,刷入操作由内核控制,不需要频繁的主动写入硬盘,即使进程意外挂掉,内核也会保存数据,写入速度极快 查看更多

TCP的连接和释放过程

TCP的报文格式

1) 源端口和目的端口       各占2个字节,分别写入源端口和目的端口。

2) 序号              占4字节。序号范围是【0,2^32 – 1】,共2^32(即4294967296)个序号。序号增加到2^32-1后,下一个序号就又回到0。也就是说,序号使用mod 2^32运算。TCP是面向字节流的。在一个TCP连接中传送的字节流中的每一个字节都按顺序编号。整个要传送的字节流的起始序号必须在连接建立时设置。首部中的序号字段值则是指的是本报文段所发送的数据的第一个字节的序号。例如,一报文段的序号是301,而接待的数据共有100字节。这就表明:本报文段的数据的第一个字节的序号是301,最后一个字节的序号是400。显然,下一个报文段(如果还有的话)的数据序号应当从401开始,即下一个报文段的序号字段值应为401。这个字段的序号也叫“报文段序号”。 查看更多