為什麼method數超過65535會build fail?

30
十萬個為什麼 #1 為什麼method數超過 65535build fail? System Architecture - Johnny 2015/7/24

Upload: chih-chung-lee

Post on 12-Apr-2017

377 views

Category:

Software


0 download

TRANSCRIPT

十萬個為什麼 #1

為什麼method數超過65535會build fail?

System Architecture - Johnny 2015/7/24

Why MultiDex?● Single Dex methods over 65535 will cause

“Conversion to Dalvik format failed” at build time○ Dalvik uses 16bits to index mehtods

● Single Dex file size >5MB will cause INSTALL_FAILED_DEXOPT before Android 2.3 at runtime○ Dalvik linearAlloc size is 5MB in Android 2.2 and 2.3

What is Dex file?Programs are commonly written in Java and compiled to bytecode for the Java virtual machine, which is then translated to Dalvik bytecode and stored in .dex (Dalvik EXecutable).

How to apply it?1. Change your Gradle build configuration to enable multidex

How to apply it? (Cont.)2. Modify your Application class to extend MultidexApplication

public class MobileDubaApplication extends MultiDexApplication {@Overrideprotected void attachBaseContext(final Context base) {

super.attachBaseContext(base);}

@Overridepublic void onCreate() {

} }

public class MultiDexApplication extends Application { @Override

protected void attachBaseContext(Context base) {super.attachBaseContext(base);MultiDex.install(this);

} }

Quiz - Application啟動順序?

A. Application.onCreate()

B. ActivityThread.installProviders()

C. Application.attachBaseContext()

1. __________________________

2. __________________________

3. __________________________

Application啟動順序

MultiDex.install()

What’s the secret?

1. How class loader works2. How to load class from dex file3. MultiDex Install load dex flow

How classloader works

How classloader works (Cont.)

BaseDexClassLoader load dex flow1. BaseDexClassLoader uses makeDexElement

to load dex2. dexElement is a list of dex/resource (class

path) elements

MultiDex install load dex flow1. Call DexPathList$makeDexElement() by

reflection to force Dalvik loads dex files2. Get dexElements by reflection and write back

extra elements by System.arraycopy()

Our Goal● Smaller → Lzma secondary dex and

concurrent decompress it before install to reduce APK size

● Faster → Concurrent install dex to reduce cold launch time

● Nicer → Show splash activity at the very first launch time and defer install dex process to worker thread

Lzma dex - Modify Gradle Build Configuration

1. Unpack Proguarded jar to get class files2. Split class files into main-dex and sub-dexs.3. Generate dex file from class file by “dx” build tool4. Lzma sub-dex file

5. Add lzma files into resocure file

Run lzma task

Everything looks Good!

8.64MB→ 7.79MB

代誌不是憨人想的那麼簡單

WTF…?

⇒ Looks like the class is either missing or broken when it was used

⇒ 我的觀察拉

⇒ But why? We have to trace into Dalvik native code to figure it out

<clinit> & <init>● <clinit> are the static initialization blocks for the class,

and static field initialization● <init> is the (or one of the) constructor(s) for the

instance, and non-static field initialization.

dvmInitClass● dvmInitClass will be called when the <clinit> code

resolves one of its fields, the field resolution will try to initialize the class.○ dvmInitClass is executing before <clinit>

● dvmInitClass tries to verify every methods in the class○ All classes in method’s parameter type, return type or

called by method will be resolved○ If the class can’t be resolved, Dalvik will throw

ClassNotFoundException or NoClassDefFoundError when the class was access

Remove dependencies from Application- Proxy Pattern● Move complex logic from Application to

ApplicationProxy○ Make sure all classes in subdex will not be resolved

when Dalvik initial Application class

Simplify import

Finally

疑難雜症 - 升級失敗

疑難雜症 - 系統空間不足

Thank You!