Native so Library APK size 优化 以及chromium启动分析

对于使用了C++库的android应用来说, 通过在打包时使用7zip进行压缩, 当应用首次启动时解压so库后再进行加载, 可以达到50%上下的so文件大小优化.
这篇文章具体讲讲在实际项目中是如何实现的.

使用NativeLibCompression开源库

https://github.com/liyuming1978/NativeLibCompression
这个开源库还算比较简洁, 使用DecRawso提供的2个static方法就可以实现解压so库的工作.

DecRawso.NewInstance(mContext, null, false);
Log.d(TAG, "Native library uncompression started");
DecRawso.GetInstance().waitdecoding();
Log.d(TAG, "Native library uncompression finished");
DecRawso的实现分析

在构造对象时:

public static boolean NewInstance(Context cont,Handler hdl,boolean showProgress)
{
    DecRawsoSingleton = new DecRawso(cont,hdl,showProgress);
    return true;

}

--->

private DecRawso(Context cont,Handler hdl,boolean showProgress) {
    sAppFilePath = cont.getFilesDir().getAbsolutePath();
    sPathName  = sAppFilePath+"/../lib/";
    AssetFileDescriptor fd=null;
    AssetManager am = mAppContext.getAssets();
    try {
        fd = am.openFd("rawso"); //读取apk assets目录下的"rawso"文件
        fd.close();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

        File filex = new File(sAppFilePath+"/DecRawsoLib/decdone_"+localVersion+"_"+lasttime);
        File filedir = new File(sAppFilePath+"/DecRawsoLib/");
    if(!filex.exists())
    {
        if(!filedir.exists()){  
            filedir.mkdir();//empty so create dir
        } 
        
            sPathName  = sAppFilePath+"/DecRawsoLib/";
            Dec7zLib(showProgress,bClound,cont);
    }
}

--->

private void Dec7zLib(boolean showProgress,boolean bCloudDownload,Context cont)
{
    mDec7zLibThread = new Thread(new Dec7zLibThread(bCloudDownload));
    mDec7zLibThread.start();
}

--->

class Dec7zLibThread implements Runnable    
{
    private boolean bCloudDownload;
    public Dec7zLibThread(boolean CloudDownload)
    {
        bCloudDownload = CloudDownload;
    }

    
    @Override
    public void run() {   
        int res;
        res = Decode(mAppContext.getAssets(),null,sPathName,abi); //调用native方法进行解压缩
            
}

--->

private native int Decode(AssetManager  asset,String inpath, String outpath,String abi);

---->
7zMain.c file

JNIEXPORT int JNICALL Java_com_library_decrawso_DecRawso_Decode
(JNIEnv * env, jclass thiz,jobject assetManager,jstring jinpath,jstring joutpath,jstring jabi)
{
...
//在这里实现的用7zip进行的解压缩工作.
//7zip的底层实现:
./DecRawso/jni/7zMain.c
./DecRawso/jni/7zC/7zFile.c
./DecRawso/jni/7zC/LzmaDec.c
./DecRawso/jni/7zC/Bra86.c
./DecRawso/jni/7zC/Bcj2.c
./DecRawso/jni/7zC/Bra.c
./DecRawso/jni/7zC/7zAlloc.c
./DecRawso/jni/7zC/7zDec.c
./DecRawso/jni/7zC/Ppmd7.c
./DecRawso/jni/7zC/7zCrc.c
./DecRawso/jni/7zC/7zBuf.c
./DecRawso/jni/7zC/CpuArch.c
./DecRawso/jni/7zC/7zStream.c
./DecRawso/jni/7zC/Lzma2Dec.c
./DecRawso/jni/7zC/7zCrcOpt.c
./DecRawso/jni/7zC/Ppmd7Dec.c
./DecRawso/jni/7zC/7zIn.c

...

}
对apk size的试验结果

本身NativeLibCompression的7zip底层库占用46kb.

wangxin@wangxin:~/Downloads/temp/apk/360Browser_Chromium_116$ ll ./lib/armeabi-v7a/libDecRawso.so
-rw-r--r-- 1 wangxin wangxin 46260 Nov 15 17:10 ./lib/armeabi-v7a/libDecRawso.so

chromium内核压缩完占用12Mb.

wangxin@wangxin:~/Downloads/temp/apk/360Browser_Chromium_116$ ll ./assets/rawso
-rw-r--r-- 1 wangxin wangxin 12213535 Nov 15 17:10 ./assets/rawso

解压完的chromium内核占用29Mb.

root@android:/data/data/com.qihoo.browser/files/DecRawsoLib # ls -l
-rw------- u0_a89   u0_a89          0 2016-11-16 15:50 armmode
-rw------- u0_a89   u0_a89          0 2016-11-16 15:50 decdone_712_7.0.0.46_115
-rw------- u0_a89   u0_a89   29023944 2016-11-16 15:50 libchrome_public.so

综合起来, 减少了apk安装包12Mb, 实际效果还是不错的.

除了对so进行压缩, 还能进行扩展

既然能用7zip对so进行压缩, 也就可以对其他运行时才需要使用的文件进行压缩,例如html,js, json文件等.
只是NativeLibCompression的定制化并不好, 比如写死了assets目录下必须是文件名为"rawso"的so文件.
要实现对其他文件进行7zip解压的话, 需要重构它的源码,
还好NativeLibCompression的源码结构还是比较清晰的, 实现起来也不会太复杂.

chromium 加载 libchrome_public.so 的启动分析.
ChromeTabbedActivity extends ChromeActivity
ChromeActivity extends AsyncInitializationActivity

AsyncInitializationActivity onCreate()   ---->
ChromeBrowserInitializer.getInstance(this).handlePreNativeStartup(this);

ChromeBrowserInitializer handlePreNativeStartup() ---->

AsyncInitializationActivity setContentViewAndLoadLibrary() --->
mNativeInitializationController.startBackgroundTasks();

NativeInitializationController startBackgroundTasks(), new Thread() ---> 
2 steps:
1. DecRawso.NewInstance(mContext, null, false); 解压raw_so文件
2. libraryLoader.ensureInitialized()
catch ProcessInitException, if catch it, throw new RuntimeException(e), browser re-start().

LibraryLoader ensureInitialized() throws ProcessInitException--->

LibraryLoader loadAlreadyLocked() ---> System.load("libchrome_public.so");

----------DONE.---------------

你可能感兴趣的:(Native so Library APK size 优化 以及chromium启动分析)