searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

Android 系统新版本(7.0之后)预置库注意事项

2023-04-18 03:02:05
53
0

在早期的Android系统版本中,正常Android在预置本地共享库时,只需要把相应的库放入/system/lib/或者/system/lib64目录就可以了。
但在Android N(7.0)版本之后,推出了针对原生库的命名空间,旨在限制内部 API 的可见性,并解决应用意外地使用平台库(而非它们自己的库)这一问题。
这项更改会将系统库与应用库分离开来,从而很大程度上避免意外使用内部系统库(反之亦然)。


新版预制库feature设计架构:

添加其他原生库注意事项

除了标准的公共原生库之外,芯片供应商(从 Android 7.0 起)和设备制造商(从 Android 9 起)还可以选择提供可供应用访问的其他原生库,方法是将它们放在相应的库文件夹中,并在 .txt 文件中明确列出它们。


库文件夹是:
/vendor/lib(对于芯片供应商的 32 位库)和 /vendor/lib64(对于芯片供应商的 64 位库)
/system/lib(对于设备制造商的 32 位库)和 /system/lib64(对于设备制造商的 64 位库)

修改对应的.txt 文件是:
/vendor/etc/public.libraries.txt 或 /system/etc/public.libraries.txt(对于芯片供应商的库)
/system/etc/public.libraries-COMPANYNAME.txt(对于设备制造商的库),其中 COMPANYNAME 指的是制造商的名称(例如 aweson company等)。如果某些库来自外部解决方案提供商,则可以在设备中包含多个此类 .txt 文件。


必须将 system 分区内由设备制造商公开提供的原生库命名为 lib*companyName.so,例如 libFoo.awesome.company.so。换句话说,没有公司名称后缀的libFoo.so不得公开。库文件名中的 COMPANYNAME 必须与列出库名称的 txt 文件名称中的 COMPANYNAME 匹配。


举个遇到具体问题的例子:
应用在修改系统应用camera2时,需要新加入一个libHexin.so库,我们默认帮他预制到system/lib中,应用通过System.loadLibrary 方法加载这个库,一切看起来很美好。。


但是camera2应用在运行时,却弹出强制关闭,抓取log提示如下:
 

java.lang.UnsatisfiedLinkError: dlopen failed: library "/system/lib/libHexin.so" needed or dlopened by "/system/lib/libnativeloader.so" is not accessible for the namespace "classloader-namespace"

这个问题就是典型的内部库访问外部库命名空间被限制的问题,所以需要在对应的.txt文件中加入这个libHexin.so库就可以解决问题:

我们再来研究一下这个feature的具体代码实现:
/system/core/libnativeloader/native_loader.cpp

static constexpr const char* kPublicNativeLibrariesSystemConfigPathFromRoot =

"/etc/public.libraries.txt";

static constexpr const char* kPublicNativeLibrariesVendorConfig =


"/vendor/etc/public.libraries.txt";

static constexpr const char* kLlndkNativeLibrariesSystemConfigPathFromRoot =

"/etc/llndk.libraries.txt";

static constexpr const char* kVndkspNativeLibrariesSystemConfigPathFromRoot =

"/etc/vndksp.libraries.txt";

void Initialize() {

..................

std::vector<std::string> sonames;

system_public_libraries_ = base::Join(sonames, ':');

sonames.clear();

ReadConfig(kLlndkNativeLibrariesSystemConfigPathFromRoot, &sonames);

system_llndk_libraries_ = base::Join(sonames, ':');

sonames.clear();

ReadConfig(kVndkspNativeLibrariesSystemConfigPathFromRoot, &sonames);

system_vndksp_libraries_ = base::Join(sonames, ':');

sonames.clear();

// This file is optional, quietly ignore if the file does not exist.

ReadConfig(kPublicNativeLibrariesVendorConfig, &sonames);

vendor_public_libraries_ = base::Join(sonames, ':');

}

在LibraryNamespaces类的Initialize()会读取这个文件,将so库设置为公共so库,所谓公共so库,就是这个so库其他人都能用。


这个方法时什么时候调用的呢?大概看下具体实现流程
首先在创建一个虚拟机的时候,初始化NativeLoader,这个NativeLoader,顾名思义,就是用来装载so库的。

java_vm_ext.cc

android::InitializeNativeLoader();

然后进入刚才的native_loader.cpp 代码中 ,这样就回到了刚才公共库申明查询.txt文件的地方了。

然后进入刚才的native_loader.cpp 代码中 ,这样就回到了刚才公共库申明查询.txt文件的地方了。

void InitializeNativeLoader() {

#if defined(__ANDROID__)

std::lock_guard<std::mutex> guard(g_namespaces_mutex);

g_namespaces->Initialize();

#endif

0条评论
0 / 1000
朱****春
17文章数
3粉丝数
朱****春
17 文章 | 3 粉丝
原创

Android 系统新版本(7.0之后)预置库注意事项

2023-04-18 03:02:05
53
0

在早期的Android系统版本中,正常Android在预置本地共享库时,只需要把相应的库放入/system/lib/或者/system/lib64目录就可以了。
但在Android N(7.0)版本之后,推出了针对原生库的命名空间,旨在限制内部 API 的可见性,并解决应用意外地使用平台库(而非它们自己的库)这一问题。
这项更改会将系统库与应用库分离开来,从而很大程度上避免意外使用内部系统库(反之亦然)。


新版预制库feature设计架构:

添加其他原生库注意事项

除了标准的公共原生库之外,芯片供应商(从 Android 7.0 起)和设备制造商(从 Android 9 起)还可以选择提供可供应用访问的其他原生库,方法是将它们放在相应的库文件夹中,并在 .txt 文件中明确列出它们。


库文件夹是:
/vendor/lib(对于芯片供应商的 32 位库)和 /vendor/lib64(对于芯片供应商的 64 位库)
/system/lib(对于设备制造商的 32 位库)和 /system/lib64(对于设备制造商的 64 位库)

修改对应的.txt 文件是:
/vendor/etc/public.libraries.txt 或 /system/etc/public.libraries.txt(对于芯片供应商的库)
/system/etc/public.libraries-COMPANYNAME.txt(对于设备制造商的库),其中 COMPANYNAME 指的是制造商的名称(例如 aweson company等)。如果某些库来自外部解决方案提供商,则可以在设备中包含多个此类 .txt 文件。


必须将 system 分区内由设备制造商公开提供的原生库命名为 lib*companyName.so,例如 libFoo.awesome.company.so。换句话说,没有公司名称后缀的libFoo.so不得公开。库文件名中的 COMPANYNAME 必须与列出库名称的 txt 文件名称中的 COMPANYNAME 匹配。


举个遇到具体问题的例子:
应用在修改系统应用camera2时,需要新加入一个libHexin.so库,我们默认帮他预制到system/lib中,应用通过System.loadLibrary 方法加载这个库,一切看起来很美好。。


但是camera2应用在运行时,却弹出强制关闭,抓取log提示如下:
 

java.lang.UnsatisfiedLinkError: dlopen failed: library "/system/lib/libHexin.so" needed or dlopened by "/system/lib/libnativeloader.so" is not accessible for the namespace "classloader-namespace"

这个问题就是典型的内部库访问外部库命名空间被限制的问题,所以需要在对应的.txt文件中加入这个libHexin.so库就可以解决问题:

我们再来研究一下这个feature的具体代码实现:
/system/core/libnativeloader/native_loader.cpp

static constexpr const char* kPublicNativeLibrariesSystemConfigPathFromRoot =

"/etc/public.libraries.txt";

static constexpr const char* kPublicNativeLibrariesVendorConfig =


"/vendor/etc/public.libraries.txt";

static constexpr const char* kLlndkNativeLibrariesSystemConfigPathFromRoot =

"/etc/llndk.libraries.txt";

static constexpr const char* kVndkspNativeLibrariesSystemConfigPathFromRoot =

"/etc/vndksp.libraries.txt";

void Initialize() {

..................

std::vector<std::string> sonames;

system_public_libraries_ = base::Join(sonames, ':');

sonames.clear();

ReadConfig(kLlndkNativeLibrariesSystemConfigPathFromRoot, &sonames);

system_llndk_libraries_ = base::Join(sonames, ':');

sonames.clear();

ReadConfig(kVndkspNativeLibrariesSystemConfigPathFromRoot, &sonames);

system_vndksp_libraries_ = base::Join(sonames, ':');

sonames.clear();

// This file is optional, quietly ignore if the file does not exist.

ReadConfig(kPublicNativeLibrariesVendorConfig, &sonames);

vendor_public_libraries_ = base::Join(sonames, ':');

}

在LibraryNamespaces类的Initialize()会读取这个文件,将so库设置为公共so库,所谓公共so库,就是这个so库其他人都能用。


这个方法时什么时候调用的呢?大概看下具体实现流程
首先在创建一个虚拟机的时候,初始化NativeLoader,这个NativeLoader,顾名思义,就是用来装载so库的。

java_vm_ext.cc

android::InitializeNativeLoader();

然后进入刚才的native_loader.cpp 代码中 ,这样就回到了刚才公共库申明查询.txt文件的地方了。

然后进入刚才的native_loader.cpp 代码中 ,这样就回到了刚才公共库申明查询.txt文件的地方了。

void InitializeNativeLoader() {

#if defined(__ANDROID__)

std::lock_guard<std::mutex> guard(g_namespaces_mutex);

g_namespaces->Initialize();

#endif

文章来自个人专栏
Android系统开发
17 文章 | 1 订阅
0条评论
0 / 1000
请输入你的评论
0
0