美文网首页frameworkAndroid知识Android开发
Framework基础:Android N 公共so库怎么定义呢

Framework基础:Android N 公共so库怎么定义呢

作者: 我在等你回复可你没回 | 来源:发表于2017-04-05 17:48 被阅读2335次
    邢菲.png

    Android N 版本有个新feature,就是普通应用不能直接引用系统的一些so库了,只能直接引用public.libraries.txt文件中过滤的so库。这个网址有介绍怎么处理。
    https://source.android.com/devices/tech/config/namespaces_libraries
    具体情况是这样的:我有一个系统权限的apk,这个apk会编译出一些so库放在system/lib目录下面,刚刷机这个apk是可以引用到这些so库的,但我调试的时候直接install这个apk,运行的时候居然直接挂了!!我也是醉了。没想到这个新feature居然影响到我的系统权限的apk。真蛋疼,我可不想每次push这个apk然后重启才生效,一般我都是直接install的,但现在好日子貌似到头了。

    一.看看报错信息罗

    具体报错的信息如下:

    01-01 02:17:24.222  7475  7475 E linker  : library "/system/lib64/libhaha_utils.so" ("/system/lib64/libhaha_utils.so") needed or dl
    opened by "/system/lib64/libnativeloader.so" is not accessible for the namespace: [name="classloader-namespace", ld_library_paths
    ="", default_library_paths="/system/fake-libs64:/data/app/com.example.haha-1/base.apk!/lib/arm64-v8a", permitted_paths="/dat
    a:/mnt/expand:/data/data/com.example.haha"]
    01-01 02:17:24.223  7475  7475 E System  : java.lang.UnsatisfiedLinkError: dlopen failed: library "/system/lib64/libhaha_utils.so"
     needed or dlopened by "/system/lib64/libnativeloader.so" is not accessible for the namespace "classloader-namespace"
    

    大概的意思就是应用nativeloader打不开libhaha_utils.so这个so库了,就崩溃了!!好残忍。libhaha_utils.so这个库是用我用Android.mk编译后放在system/lib64下面的。但现在打不开了。
    为啥呢?
    因为/system/lib64/不在APK查找so库的合法路径啊,合法路径有啥呢?
    上面log就有说明啦。下面三个路径都没有找到libhaha_utils.so库,所以就挂了。
    ld_library_paths="",
    default_library_paths="/system/fake-libs64:/data/app/com.example.haha-1/base.apk!/lib/arm64-v8a", permitted_paths="/data:/mnt/expand:/data/data/com.example.haha

    二.那为啥刚刷机时APK可以用,Install这个apk后就不能用了呢?

    这个apk可是系统权限的哟,就是apk的清单AndroidManifest中有下面一句
    android:sharedUserId="android.uid.system"

    正常来说,这种高端apk的permitted_paths是包含system/lib64的,从源码可以知道
    /frameworks/base/core/java/android/app/LoadedApk.java

            //如果是系统apk并且没有升级过
            final boolean isBundledApp = mApplicationInfo.isSystemApp()
                    && !mApplicationInfo.isUpdatedSystemApp();
    
            String libraryPermittedPath = mDataDir;
            if (isBundledApp) {   //permitted_paths就增加system/lib64
                // This is necessary to grant bundled apps access to
                // libraries located in subdirectories of /system/lib
                libraryPermittedPath += File.pathSeparator +
                                        System.getProperty("java.library.path");
            }
    

    看上面的注释就知道啦,如果是系统apk并且没有升级过的话,so库的搜索路径就会增加一个system/lib64。我去,google搞啥呢,为什么还要限定不能升级。
    因为install -r来安装apk就相当于升级,所以刷机时apk可以用,install升级后不能用。

    三.那如何解决这个鬼问题呢?

    我纯粹是为了调试方便,所以参考google的链接
    https://source.android.com/devices/tech/config/namespaces_libraries

    google.png
    应用可以调用/vendor/etc/public.libraries.txt和/system/etc/public.libraries.txt里面的所有so库,所以哥往这个文件写入libhaha_utils.so,这个库就变成共用的了,任意应用就可以找到这个so库了,终于可以欢快地使用install apk的方式调试啦!!再也不用重启了!!
    下面是原生google的图
    Paste_Image.png
    大概有这么些个so库是共用的。
    libandroid.so
    libc.so
    libdl.so
    libEGL.so
    libGLESv1_CM.so
    ......
    可以看看原生的这笔提交修改的。
    https://android-review.googlesource.com/#/c/209029/

    四.看看源码这个public.libraries.txt文件是咋玩的

    在这个源码里面用到这个txt文件
    /system/core/libnativeloader/native_loader.cpp
    在LibraryNamespaces类的Initialize()会读取这个文件,将so库设置为公共so库,所谓公共so库,就是这个so库谁都能用啦。

    static constexpr const char* kPublicNativeLibrariesSystemConfigPathFromRoot = "/etc/public.libraries.txt";
    static constexpr const char* kPublicNativeLibrariesVendorConfig = "/vendor/etc/public.libraries.txt";
      void Initialize() {
        ..................
        std::vector<std::string> sonames;
        ReadConfig(public_native_libraries_system_config, &sonames, &error_msg),
        ReadConfig(kPublicNativeLibrariesVendorConfig, &sonames);
        public_libraries_ = base::Join(sonames, ':');
        .............
      }
    

    这个方法时什么时候调用的呢?大概过下流程罗。
    首先在创建一个虚拟机的时候,初始化NativeLoader,这个NativeLoader,顾名思义,就是用来装载so库的。
    /art/runtime/java_vm_ext.cc

    extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
      ................
      // Initialize native loader. This step makes sure we have
      // everything set up before we start using JNI.
      android::InitializeNativeLoader();
      ..............
    }
    

    然后进入native_loader,进行初始化
    /system/core/libnativeloader/native_loader.cpp

    static LibraryNamespaces* g_namespaces = new LibraryNamespaces;
    
    void InitializeNativeLoader() {
      g_namespaces->Initialize();
    }
    

    初始化是调用LibraryNamespaces类的Initialize完成公共so库的赋值,哈哈哈,搞定!!

      void Initialize() {
        ..................
        std::vector<std::string> sonames;
        ReadConfig(public_native_libraries_system_config, &sonames, &error_msg),
        ReadConfig(kPublicNativeLibrariesVendorConfig, &sonames);
        public_libraries_ = base::Join(sonames, ':');
        .............
      }
    

    总结:
    1.Android N 不能直接调用系统的一些私有库了,公用的库都定义在public.libraries.txt里面。
    2.系统应用刚刷机是能够调用system/lib64下的库,但通过install升级该应用时,应用打开会挂。因为升级后permitted_paths就不再包含system/lib64了。所以我们可以将apk要用到的库名称写到public.libraries.txt中去解决快速调试问题。

    相关文章

      网友评论

      本文标题:Framework基础:Android N 公共so库怎么定义呢

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