美文网首页
Android so保护加载

Android so保护加载

作者: 柒黍 | 来源:发表于2017-11-24 14:15 被阅读0次

    背景

    在android开发中,经常需要使用别人提供的so库来开发功能,正常加载姿势是:

     static {
         System.loadLibrary("qrcode-engine");
     }
    

    以下是网友总结几种常见的错误:

    1、低级错误——根本木有SO,你加载个球啊!

    code System.loadLibrary(Bugly);
    libs 空
    运行设备 Android ARM设备
    运行结果

    Crash!java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file “/data/app/com.tencent.bugly.demo-1/base.apk”],nativeLibraryDirectories=[/vendor/lib, /systemb]]] couldn’t find “libBugly.so”
    

    原因分析 apk安装时,系统会把apk中libs目录下armeabi的SO拷贝到应用的私有目录下。所以libs里没有放入SO,运行时肯定找不到SO。

    2、进阶错误——根本木有X86的SO,在X86的设备上你加载个球啊!

    code System.loadLibrary(Bugly);
    libs libs\armeabi\libBugly.so
    运行设备 Android X86设备
    运行结果

    Crash!java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file “/data/app/com.tencent.bugly.demo-1/base.apk”],nativeLibraryDirectories=[/vendor/lib, /systemb]]] couldn’t find “libBugly.so”
    

    原因分析 apk安装时,x86设备上系统会把apk中libs目录下x86的SO,拷贝到应用的私有目录下。虽然libs下有armeabi的SO,但没有放入x86的SO,运行时还是找不到libbugly.so。

    3、大坑——尼玛,好难发现!

    libs libs\armeabi\libBugly.solibs\armeabi\libBugly2.solibs\armeabi-v7a\libBugly.so

    运行设备 Android ARMv7设备
    运行结果

     Crash!java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file “/data/app/com.tencent.bugly.demo-1/base.apk”],nativeLibraryDirectories=[/vendor/lib, /systemb]]] couldn’t find “libBugly2.so”
    

    原因分析 apk安装时,系统会把apk中libs目录下armeabi-v7a整个目录下的SO拷贝到应用的私有目录下。因为armeabi-v7a下没有放入libBugly2.so,运行时找不到libBugly2.so。不同的工具兼容的CPU架构不一致,就容易出这个错误了!例如:
    libBugly.so提供armeabi、armeabi-v7a、x86三种。
    但其它产品可能只提供了armeabi。
    如果把这些so都直接拷贝进apk,就会因为上述的原因直接crash,会误以为该Crash是因为不同产品的so不能兼容导致的!

    修复方式 添加SO:libs\armeabi-v7a\libBugly2.so或直接删除armeabi-v7a目录,arm设备上系统会自动选择armeabi

    4、天坑——尼玛,巨难发现!

    java.lang.UnsatisfiedLinkError中couldn’t find “XX.so”的占比非常高,上面提的三个场景都是这种错误!
    但你见过下面这种错误吗?

    java.lang.UnsatisfiedLinkError:dlopen failed: “**/*/arm/*.so” has unexpected e_machine: 3
    code     if(getArch().contain(“arm”)){//只在arm下加载System.loadLibrary(Bugly) ;}
    libs     libs\armeabi\libBugly.so 坑爹实习生放入了x86编译的libBugly.so(同名很容易出错)
    

    运行设备 Android ARM设备

    运行结果

    Crash!java.lang.UnsatisfiedLinkError: dlopen failed: “/data/app/com.tencent.bugly.crashreport.demo-2/lib/arm/libBugly.so” has unexpected e_machine: 3
    

    原因分析 apk安装时,系统把armeabi下的libBugly.so放入应用的私有目录中了!但这个libBugly.so不是arm的,而是x86编译的libBugly.so运行时,系统检察ELF文件中的e_machine字段的值,跟arm的不匹配,就会抛出这个异常了!

    5 java.lang.UnsatisfiedLinkError:No implementation found for XXX

    这种错误也是醉了,说是要建立跟c/cpp写的代码一样的包名和java文件

    一般情况下排除了以上几种情况后基本没有问题,但是(重点来了)根据真实数据有万分之几的几率,正常加载方式会加载失败,等到具体要调用so库中的方法时,那自然会崩溃,作为开发者的我们也是一样崩溃的...

    这里还是稍微吐槽一下,Android系统由于众所周知的开放性(手机厂商定制),稳定性得不到保证,所以使用以下方式再尝试一次.

    static {
            try {
                System.loadLibrary("engine");
            } catch (Throwable e) {
                LogUtil.e("load libengine.so error");
                //尝试重新加载一次
                try {
                    Context context = QRGlobal.getContext();
                    if (context != null) {
                        String desPath = context.getFilesDir().getPath() + "/libengine.so";
                        if (!(new File(desPath)).exists()) {
                            String apkPath = context.getPackageResourcePath();
                            ZipInputStream apkInput = new ZipInputStream(new FileInputStream(new File(apkPath)));
                            ZipEntry entry = apkInput.getNextEntry();
                            while (entry != null) {
                                if (entry.getName().equals("lib/armeabi/libengine.so")) {
                                    FileOutputStream out = new FileOutputStream(desPath, false);
                                    byte[] buffer = new byte[1024];
                                    int n = 0;
                                    while ((n = apkInput.read(buffer)) > 0)
                                        out.write(buffer, 0, n);
                                    out.flush();
                                    out.close();
                                    break;
                                }
                                entry = apkInput.getNextEntry();
                            }
                            apkInput.close();
                        }
                        System.load(desPath);
                    }
                } catch (Throwable t) {
    
                }
            }
        }
    

    相关文章

      网友评论

          本文标题:Android so保护加载

          本文链接:https://www.haomeiwen.com/subject/cjltbxtx.html