Shunix's Weblog

Everything I've done has made me who I am today.

Oct 1, 2020

深入应用冷启动优化

背景 为什么做冷启动优化 冷启动时间是用户对app的第一印象,线上AB实验表明,冷启动时间会直接影响用户的留存。 冷启动时间口径 起点:Application#attachBaseContext() 结束时间:第一个Activity的onWindowFocusChanged() 为什么是这两个点?Application#attachBaseContext()是应用代码被执行的最早节点,第一个Activity的onWindowFocusChanged()是第一帧完成绘制的时间。 这里有一个小坑,之前Launcher Activity还是SplashActivity的时候,我们发现SplashActivity的onWindowFocusChanged()永远不会被执行,因为还没执行到onWindowFocusChanged()时,SplashActivity就finish了,因此我们的冷启动上报做在了MainActivity的onWindowFocusChanged()里,这也导致了之前版本线上数据偏高。 区分冷启动 首先我们来定义一下冷启动,冷启动指的是系统不存在应用进程的情况下,启动应用。如果我们只在SplashActivity或者MainActivity第一次创建时上报,

Sep 24, 2020

关于SSL Pinning的一切

背景 HTTPS当下已经非常普遍,HTTPS全称是Hypertext Transfer Protocol Secure,在HTTP基础上增加了TLS加密,虽然名字里有个Secure,但HTTPS并不是绝对安全的,依然存在被中间人攻击( Man-in-the-middle attack)的风险,进而导致应用被抓包,HTTPS的加密流量被获取。 MITM中间人攻击 概念 这里举个简单的例子,帮助不了解MITM的读者理解:假如A和B需要通信,这个时候来了一个C,C告诉A自己是B,同时告诉B自己是A,A和B都以为自己在和对方通信,实际上看到的消息都是由C转发的,C就可以在这个过程中完成监听和篡改,这就是中间人攻击。 ARP欺骗 在真实的网络中,要完成上述的过程,需要借助ARP欺骗。ARP是局域网中用IP来查找MAC地址的协议,正常的ARP查找过程中,

Jan 9, 2020

Android Proxy实现分析(未完待续)

序章 最近在校招面试的时候顺手翻了一下TCP/IP详解卷一,然后就想起来VpnService刚出来的时候写过一个移动端抓包应用,写得非常累,还不少bug。其实proxy,sniffer之类的应用,在Android上实现都差不多,所以就趁着这个机会,看了一下圈内知名app shadowsocks Android端的实现。 proxy原理 proxy原理细节就不再赘述,简单地说,proxy其实就是起到了接收请求,返回响应的作用。Android上不是所有的应用都允许配置代理服务器的,所以我们必须实现一个透明代理(Transproxy)那么要在Android上实现一个Transproxy,我们需要做什么呢?首先我们需要实现一个client,负责和proxy server建立连接,转发流量,然后我们需要把整个系统的流量都拦截下来,转发到我们的client处理,最后再把处理完的响应交给系统,由系统分发到各个进程。 流量拦截 先说说流量转发,

Jun 25, 2019

海南之行

从去年年底开始,工作强度和压力巨大,神经一直紧绷,频繁北京上海两地跑,所以就想着出去散散心。我不太喜欢人很多的地方,于是就看一些冷门景点,选来选去,就选了海南文昌这个地方。选到这个地方还是比较凑巧的,之前买过几条星月菩提,发货地点都是海南文昌,顺手搜了一下,得知这是个靠海的地方,交通还算方便,就定下了,总行程4天。 往返机票每个人1600,从上海虹桥到海口的,中间经停井冈山,相对便宜一些,井冈山机场条件是真的艰苦,催促登记是人工喊的,从候机室到飞机是直接从地面走过去的,没有廊桥,没有摆渡车,这里贴一张图,可以脑补一下环境。 去文昌要先到海口中转,到海口也已经下午三点了,所以第一天就直接待在海口了,定了个海口东站附近的酒店,机场到东站打车半个小时左右,

May 2, 2018

Telegram网络层源码分析

最近看了一下Telegram网络层的源码,本来想网上找一下现成的结论,降低一点学习成本,但是并没有发现相关的资料。于是自己梳理了一下telegram是如何发送网络请求和响应回包的,这里做个总结。 连接的建立 先上一张图: 这张图描述了telegram客户端和server的连接时如何建立的。Java层的ConnectionsManager是一个线程安全的单例,其实只是个wrapper,真正的逻辑都是转交给C++层的ConnectionsManager类处理的。 C++层的ConnectionsManager对象,在TgNetWrapper.cpp中初始化,也同样是个单例。这里贴一下C++层ConnectionsManager类的init方法: 这里有两个关键的方法调用,一个是loadConfig(),一个是pthread_create()。顺着时间线往下看,loadConfig()调用了initDataCenter()方法,这个方法实现如下: 可以看到,主要是一些hardcode的IP和端口,其实在连接上第一个数据中心之后,客户端就会被分发到最优的数据中心接入,

Apr 9, 2018

Android N多窗口适配

前言 从Android 7.0开始,系统就开始支持多窗口模式,对于多窗口模式的适配,主要是两方面,UI适配和生命周期的调整,适配的工作量因App而异,下面就从几个方面来谈谈多窗口模式的适配。 多窗口模式规则 这里要注意,多窗口模式分为两种,split-screen模式和freeform模式,前者是单纯的屏幕一分为二,而后者允许用户自由调整两个activity的大小。根据官方文档的说法,所有Android N的设备都是支持split-screen模式的,而freeform模式由厂商决定是否开启,一般屏幕比较大的设备都支持这个模式。 AndroidManifest.xml中的android:resizeableActivity属性和应用的targetSDK共同影响着应用在分屏模式下的行为,这里先讨论应用没有指定orientation的情况。如果应用的targetSDK是24及以上,那么android:resizeableActivity属性默认为true,应用默认支持多窗口模式,当然应用可以手动覆盖掉这个默认值。如果应用的targetSDK是23及其以下,那么要分为三种情况。一是这个属性没有被指定,

Mar 28, 2018

2017回顾与展望

引言 这个系列一般都是在每一年的11~12月写的,这一篇为什么推迟了这么久呢,因为这三个月发生了几件对我来说很重要的事情,我觉得等到一切尘埃落定之后再写会比较有意义。 回顾 先来看看2016年给自己定下的目标: 找个女朋友 ✅ 持续更新GitHub ✅ 坚持慢跑 ❓ 重新开始练书法 ❓ 拓展交际圈 ❎ 这里打勾的是完成了,叉是完全没做,问号是部分完成。女朋友是17年底找到的,算是赶上了末班车。持续更新GitHub这一条,完成度一般吧,去年一年,很大一部分时间是研究卡顿和内存泄漏监控,GitHub上主要更新的内容就是这个。坚持慢跑这一条,做了大概半年吧,后来因为天气转冷,就没有继续了。书法也差不多练了半年,重新拿起毛笔,有点生疏,后来因为搬家了,毛笔什么丢了,就暂时搁一边了。

Dec 28, 2017

CVE-2017-13156漏洞分析(中)

承接上篇,本篇主要介绍一下Android的签名机制,并从原理上分析一下为什么使用APK Signature Scheme v2签名的应用在Android 7.0以上不受漏洞影响。Android提供了两种签名方式,一种是v1的基于JAR签名的方式,另一种就是APK Signature Scheme v2。 签名验证时机 首先看一下PackageManagerService的代码,看看是什么时候进行签名验证的。 PMS的installPackageLI方法会构造一个PackageParser对象,并调用collectCertificates方法来验证签名。 这里可以看到,首先要对apk文件的entry做遍历,如果遇到entry是目录,或者是META-INF文件名,或者是AndroidManifest.xml则跳过,否则把entry加入一个List,这个List中的每一个entry将在下一步进行签名验证。验证签名的过程后面会说,这一节只是说明,在apk安装的时候,PMS会进行签名验证。 V1签名 Android官方文档有说,

Dec 18, 2017

CVE-2017-13156漏洞分析(上)

前言 CVE-2017-13156是今年Android爆出的最为严重的一个漏洞,这个漏洞允许攻击者绕过Android系统V1的签名,用篡改过的apk覆盖原有的应用,攻击者的代码可以访问原应用所有的数据。影响范围是Android 5.0+。这个漏洞的本质原因是ART允许直接运行一个dex,同时也允许运行一个里面包含dex的zip文件。而因为dex文件格式和zip文件格式的问题,一个文件可以同时是合法的zip文件和合法的dex文件。正是因为这种二义性,这个漏洞也被称作Janus漏洞,Janus是罗马神话中的双面神,具有前后两个面孔。对于特殊修改过的apk文件,PackageManagerService把它当作合法的apk安装,而ART把它视作合法的dex执行,这就是一个文件的两个视角。github上已经有人放出了这个漏洞的PoC,代码虽然很简单,但是看懂需要一点背景知识,下面就从zip和dex的文件结构上来解释这段代码。 Zip文件结构 Zip文件最重要的一个部分就是末尾的Central Directory,这个部分可以理解为Zip文件真正的文件头,解析zip文件都是从这里开始解析的,它包含了zip文件每一个entry的摘要信息。这个部分的结构如下: 这里很容易看出来,Central

Nov 14, 2017

SharedPreferences源码分析

前言 SharedPreferences作为Android应用配置项的存储,给上层提供了非常方便的接口,这篇Post将从源码层面分析SharedPreferences实现的细节。 获取SharedPreferences 获取SharedPreferences实例是通过ContextImpl.getSharedPreferences(String name, int mode)方法来完成的。 这里的sSharedPrefs是ContextImpl的静态成员,类型为ArrayMap<String, ArrayMap<String, SharedPreferencesImpl>>,从这个ArrayMap里,我们可以通过包名获取另一个ArrayMap packagePrefs,其中包含文件名到SharedPreferencesImpl的映射。这里我初看的时候不太理解,为什么要两级映射。后来想了一下,应该是针对sharedUserId的情况,这种情况下,同一个进程会有不同的Context和包名,个人见解,

Sep 13, 2017

TLS握手过程

最近和朋友吃饭的时候,聊到了HTTPS,HTTPS其实就是基于TLS建立了安全信道的HTTP协议。所以可以说,HTTPS最重要的就是TLS的握手过程。这篇post整理了一下TLS的握手过程。 前置知识 这里要先讲几个概念,在后面对于TLS握手过程的描述中会用到这几个概念。 HTTPS TLS和SSL的关系 SSL是90年代Netscape弄出来的一套东西,为的是解决HTTP协议明文传输数据的问题。后来SSL慢慢成了事实上的标准,于是IETF就把SSL标准化了,名字叫做TLS,TLS 1.0其实就是SSL 3.1。所以SSL和TLS经常被放在一起写成SSL/TLS,因为这两个名词在现在其实就是同一个东西。HTTPS是使用TLS的HTTP协议。 证书及信任链 我们知道,HTTPS的网站都有一个自己的证书,用于表明自己的身份。证书本质上是为了让公钥能可信的传输。公钥是放在证书里面的,如果证书可信,那么公钥就也是可信的。

Jul 7, 2017

Port leveldb to Android

As leveldb has already implemented platform-dependent interfaces, porting leveldb is pretty simple. Cross compile the source code on Linux or build with NDK are both OK. Here's my NDK build script. It compiles