肥言肥语

肥肥鱼胡说八道的地方

0%

概述

zip 类型的压缩包文件中允许存在 ../ 类型的字符串,用于表示上一层级的目录。攻击者可以利用这一特性,通过精心构造 zip 文件,利用多个 ../ 从而改变 zip 包中某个文件的存放位置,达到替换掉原有文件的目的。

那么,如果被替换掉的文件是是 .so.dex.odex 类型文件,那么攻击者就可以轻易更改原有的代码逻辑,轻则产生本地拒绝服务漏洞,影响应用的可用性,重则可能造成任意代码执行漏洞,危害应用用户的设备安全和信息安全。比如寄生兽漏洞、海豚浏览器远程命令执行漏洞和三星默认输入法远程代码执行等著名的安全事件。

阅读全文 »

基于 64G 物理内存的 Android Studio 或者 IntelliJ IDEA 内存配置优化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# custom Android Studio VM options, see https://developer.android.com/studio/intro/studio-config.html
# 控制内存garbage方式
-server
# 初始化的内存大小
-Xms4096m
# 最大内存数
-Xmx16384m
# PermSize 永久区的大小
-XX:PermSize=2048m
-XX:MaxPermSize=4096m
# 代码内存容量
-XX:ReservedCodeCacheSize=2048m
-XX:+UseCompressedOops
-Dfile.encoding=UTF-8
#-XX:+UseConcMarkSweepGC
# 使用并行收集算法
-XX:+UseParNewGC
-XX:SoftRefLRUPolicyMSPerMB=512
-XX:CICompilerCount=8
-Dsun.io.useCanonCaches=false
-Dsun.io.useCanonPrefixCache=false
-Djava.net.preferIPv4Stack=true
-Djdk.http.auth.tunneling.disabledSchemes=""
-Djna.nosys=true
-Djna.boot.library.path=
-XX:+HeapDumpOnOutOfMemoryError
-XX:-OmitStackTraceInFastThrow
-Djdk.attach.allowAttachSelf
-Dkotlinx.coroutines.debug=off
-Djdk.module.illegalAccess.silent=true
-ea
-da

线上出现一些 OutOfMemoryError,经过分析崩溃数据,发现出现 OOM 时进程的可用空间还是非常大的。

从崩溃的堆栈信息中可以分析出引发该 OOM 的主要与 OkHttp 有关系,而业务场景中都是普通的数据请求(JSON),并没有使用 Bitmap 这一类的较大内存占用的资源。更何况,进程的可用内存空间还是很充足的。

虽然堆栈信息不尽相同,但是最终从大量堆栈 LOG 中分析出有价值的信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
java.lang.OutOfMemoryError: pthread_create (1040KB stack) failed: Try again
at java.lang.Thread.nativeCreate(Native Method)
at java.lang.Thread.start(Thread.java:733)
at tech.fiissh.base.utils.c.u(SourceFile:7)
at tech.fiissh.base.common.e.c.a(SourceFile:40)
at tech.fiissh.base.common.e.c.a(SourceFile:156)
at tech.fiissh.base.common.e.b.a(SourceFile:30)
at tech.fiissh.base.common.e.b.a$1.handleMessage(SourceFile:6)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6942)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)

java.lang.OutOfMemoryErrorat java.lang.String.<init>(String.java:255)
at libcore.io.IoUtils$FileReader.toString(IoUtils.java:272)
at libcore.io.IoUtils.readFileAsString(IoUtils.java:114)
at com.android.org.conscrypt.CertPinManager.readPinFile(CertPinManager.java:111)
at com.android.org.conscrypt.CertPinManager.rebuild(CertPinManager.java:85)
at com.android.org.conscrypt.CertPinManager.<init>(CertPinManager.java:49)
at com.android.org.conscrypt.TrustManagerImpl.<init>(TrustManagerImpl.java:137)
at com.android.org.conscrypt.TrustManagerImpl.<init>(TrustManagerImpl.java:97)
at com.android.org.conscrypt.TrustManagerFactoryImpl.engineGetTrustManagers(TrustManagerFactoryImpl.java:80)
at javax.net.ssl.TrustManagerFactory.getTrustManagers(TrustManagerFactory.java:219)
at tech.fiissh.thrid.okhttp.internal.Util.platformTrustManager(Util.java:670)
at tech.fiissh.thrid.okhttp.OkHttpClient.<init>(OkHttpClient.java:256)
at tech.fiissh.thrid.okhttp.OkHttpClient$Builder.build(OkHttpClient.java:1035)
at tech.fiissh.base.common.net.e.b.<init>(OkHttpStack.java:73)
at tech.fiissh.base.common.net.g.<init>(NetworkDispatcher.java:51)
at tech.fiissh.base.common.net.i$1.run(RequestQueue.java:110)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:841)

经过与源码文件进行比较,OkHttpStack 第73行的方法实际上是通过 OkHttpClient.Builder 来实例化一个 OkHttpClient 对象。

通常情况下我们所理解的 OOM 是由于进程的可用堆内存不够(即 Runtime.getRuntime().maxMemory() 小于需要申请的内存大小)的情况下系统会抛出 OutOfMemoryError。其报错信息中详细的记录了我们的内存分配需求和可用堆内存的大小信息:

1
java.lang.OutOfMemoryError: Failed to allocate a XXX byte allocation with XXX free bytes and XXXKB until OOM

通过对 pthread_create 关键字的搜索,最终在 thread.cc 中找到了抛出该异常的位置,并且通过对 Thread::CreateNativeThread 函数的分析发现,在创建线程时,系统会先判断当前线程数是否超过了系统对线程数的限制,如果超过该限制则抛出 java.lang.OutOfMemoryError:pthread_create (XXXXKB stack) failed 异常。

那么,问题的根源在哪里?通过对代码的分析,发现每次发起一个网络请求的时候都会创建一个 OkHttpClient,而每个 OkHttpClient 对象都会初始化一个线程池(线程的生命周期又较长),如果在短时间内发起多次请求,那么线程池会被创建多个,而线程数也会随之增加。解决的方案则是将 OkHttpClient 通过单例的方式对外提供。

针对上述线程创建的问题,可以参考 不可思议的OOM,作者针对出现类似问题的场景做了深入分析。

关于 HTTPClient 的问题,可以参考 OkHttp竟然玩出OOM?,作者针对为什么创建多个线程池的场景进行了深入的分析。

如何提高软件系统的可维护性和可复用性是面向对象程序设计思想需要解决的核心问题。在面向对象程序设计中,可维护性的复用是以设计原则为基础的。每一个设计原则都蕴含着面向对象程序设计的思想,可以从不同的角度提升一个软件系统的架构水平。

面向对象程序设计原则是为支撑可维护性的复用而诞生的,它们是从很多的设计方案中总结出来的指导性原则,通常体现在设计模式中。

阅读全文 »