技术文章

A collection of 23 posts

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查找过程中,

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及其以下,那么要分为三种情况。一是这个属性没有被指定,

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

Apr 9, 2017

Blog Migration Notes

My SSL certificate expired at the end of last month. And I lost the private key of my EC2 instance by chance. As I didn't want renew the SSL certificate and my amazon

Jan 17, 2017

Activity Leak Detection

Prior Knowledge Reference and ReferenceQueue Begin with Java 1.2, the java.lang.ref package give us limited degree of interaction with garbage collector. The subclasses of Reference and ReferenceQueue are quite useful

Dec 21, 2016

Efficient Thread-safe Singleton in Java

Single-threaded Version class Foo { private static Helper helper; public static Helper getHelper() { if (helper == null) { helper = new Helper(); } return helper; } } The code works fine in single thread case. If multiple threads access getHelper(