平台

RK3288 + Android 9

问题

  • 官方原文:
    "从 Android 7.0 开始,系统将阻止应用动态链接非公开 NDK 库,这种库可能会导致您的应用崩溃。此行为变更旨在为跨平台更新和不同设备提供统一的应用体验。即使您的代码可能不会链接私有库,但您的应用中的第三方静态库可能会这么做。因此,所有开发者都应进行相应检查,确保他们的应用不会在运行 Android 7.0 的设备上崩溃。如果您的应用使用原生代码,则只能使用公开 NDK API。"
  • 这样会有什么问题?
    很多使用JNI的APP将无法像低版本SDK一样, 正常使用, 在使用7.1的时候, 系统会有相关的提示, 到使用9.0时, 直接崩溃报错.

        java.lang.UnsatisfiedLinkError: dlopen failed: library "/system/lib/libserial_port.so" needed or dlopened by "/system/lib/libnativeloader.so" is not accessible for the namespace "classloader-namespace"at java.lang.Runtime.loadLibrary0(Runtime.java:1016)at java.lang.System.loadLibrary(System.java:1669)
    
    • 1
    • 2
    • 3

    常见:UnsatisfiedLinkError

解决方案

方案 1修改APP端

见下文记录7.0加载so文件失败:java.lang.UnsatisfiedLinkError: dlopen failed: library “libsqlite.so” not found

方案 2 修改系统SDK

|-- 错误输出部分代码: bionic/linker/linker.cpp

static bool load_library(android_namespace_t* ns,LoadTask* task,LoadTaskList* load_tasks,int rtld_flags,const std::string& realpath,bool search_linked_namespaces) {off64_t file_offset = task->get_file_offset();const char* name = task->get_name();const android_dlextinfo* extinfo = task->get_extinfo();

if ((file_offset % PAGE_SIZE) != 0) {
DL_ERR(“file offset for the library “%s” is not page-aligned: %” PRId64, name, file_offset);
return false;
}
if (file_offset < 0) {
DL_ERR(“file offset for the library “%s” is negative: %” PRId64, name, file_offset);
return false;
}

struct stat file_stat;
if (TEMP_FAILURE_RETRY(fstat(task->get_fd(), &file_stat)) != 0) {
DL_ERR(“unable to stat file for the library “%s”: %s”, name, strerror(errno));
return false;
}
if (file_offset >= file_stat.st_size) {
DL_ERR(“file offset for the library “%s” >= file size: %” PRId64 " >= %" PRId64,
name, file_offset, file_stat.st_size);
return false;
}

// Check for symlink and other situations where
// file can have different names, unless ANDROID_DLEXT_FORCE_LOAD is set
if (extinfo nullptr || (extinfo->flags & ANDROID_DLEXT_FORCE_LOAD) 0) {
soinfo* si = nullptr;
if (find_loaded_library_by_inode(ns, file_stat, file_offset, search_linked_namespaces, &si)) {
TRACE("library “%s” is already loaded under different name/path “%s” - "
“will return existing soinfo”, name, si->get_realpath());
task->set_soinfo(si);
return true;
}
}

if ((rtld_flags & RTLD_NOLOAD) != 0) {
DL_ERR(“library “%s” wasn’t loaded and RTLD_NOLOAD prevented it”, name);
return false;
}

struct statfs fs_stat;
if (TEMP_FAILURE_RETRY(fstatfs(task->get_fd(), &fs_stat)) != 0) {
DL_ERR(“unable to fstatfs file for the library “%s”: %s”, name, strerror(errno));
return false;
}

// do not check accessibility using realpath if fd is located on tmpfs
// this enables use of memfd_create() for apps
if ((fs_stat.f_type != TMPFS_MAGIC) && (!ns->is_accessible(realpath))) {
// TODO(dimitry): workaround for http://b/26394120 - the grey-list

<span class="token comment">// TODO(dimitry) before O release: add a namespace attribute to have this enabled</span>
<span class="token comment">// only for classloader-namespaces</span>
<span class="token keyword">const</span> soinfo<span class="token operator">*</span> needed_by <span class="token operator">=</span> task<span class="token operator">-</span><span class="token operator">&gt;</span><span class="token function">is_dt_needed</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">?</span> task<span class="token operator">-</span><span class="token operator">&gt;</span><span class="token function">get_needed_by</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token keyword">nullptr</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">is_greylisted</span><span class="token punctuation">(</span>ns<span class="token punctuation">,</span> name<span class="token punctuation">,</span> needed_by<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token comment">// print warning only if needed by non-system library</span><span class="token keyword">if</span> <span class="token punctuation">(</span>needed_by <span class="token operator">==</span> <span class="token keyword">nullptr</span> <span class="token operator">||</span> <span class="token operator">!</span><span class="token function">is_system_library</span><span class="token punctuation">(</span>needed_by<span class="token operator">-</span><span class="token operator">&gt;</span><span class="token function">get_realpath</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token keyword">const</span> soinfo<span class="token operator">*</span> needed_or_dlopened_by <span class="token operator">=</span> task<span class="token operator">-</span><span class="token operator">&gt;</span><span class="token function">get_needed_by</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">const</span> <span class="token keyword">char</span><span class="token operator">*</span> sopath <span class="token operator">=</span> needed_or_dlopened_by <span class="token operator">==</span> <span class="token keyword">nullptr</span> <span class="token operator">?</span> <span class="token string">"(unknown)"</span> <span class="token operator">:</span>needed_or_dlopened_by<span class="token operator">-</span><span class="token operator">&gt;</span><span class="token function">get_realpath</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token function">DL_WARN_documented_change</span><span class="token punctuation">(</span>__ANDROID_API_N__<span class="token punctuation">,</span><span class="token string">"private-api-enforced-for-api-level-24"</span><span class="token punctuation">,</span><span class="token string">"library \"%s\" (\"%s\") needed or dlopened by \"%s\" "</span><span class="token string">"is not accessible by namespace \"%s\""</span><span class="token punctuation">,</span>name<span class="token punctuation">,</span> realpath<span class="token punctuation">.</span><span class="token function">c_str</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> sopath<span class="token punctuation">,</span> ns<span class="token operator">-</span><span class="token operator">&gt;</span><span class="token function">get_name</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token function">add_dlwarning</span><span class="token punctuation">(</span>sopath<span class="token punctuation">,</span> <span class="token string">"unauthorized access to"</span><span class="token punctuation">,</span>  name<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{<!-- --></span><span class="token comment">// do not load libraries if they are not accessible for the specified namespace.</span><span class="token keyword">const</span> <span class="token keyword">char</span><span class="token operator">*</span> needed_or_dlopened_by <span class="token operator">=</span> task<span class="token operator">-</span><span class="token operator">&gt;</span><span class="token function">get_needed_by</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token keyword">nullptr</span> <span class="token operator">?</span><span class="token string">"(unknown)"</span> <span class="token operator">:</span>task<span class="token operator">-</span><span class="token operator">&gt;</span><span class="token function">get_needed_by</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-</span><span class="token operator">&gt;</span><span class="token function">get_realpath</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token function">DL_ERR</span><span class="token punctuation">(</span><span class="token string">"library \"%s\" needed or dlopened by \"%s\" is not accessible for the namespace \"%s\""</span><span class="token punctuation">,</span>name<span class="token punctuation">,</span> needed_or_dlopened_by<span class="token punctuation">,</span> ns<span class="token operator">-</span><span class="token operator">&gt;</span><span class="token function">get_name</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// do not print this if a library is in the list of shared libraries for linked namespaces</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">maybe_accessible_via_namespace_links</span><span class="token punctuation">(</span>ns<span class="token punctuation">,</span> name<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token function">PRINT</span><span class="token punctuation">(</span><span class="token string">"library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the"</span><span class="token string">" namespace: [name=\"%s\", ld_library_paths=\"%s\", default_library_paths=\"%s\","</span><span class="token string">" permitted_paths=\"%s\"]"</span><span class="token punctuation">,</span>name<span class="token punctuation">,</span> realpath<span class="token punctuation">.</span><span class="token function">c_str</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>needed_or_dlopened_by<span class="token punctuation">,</span>ns<span class="token operator">-</span><span class="token operator">&gt;</span><span class="token function">get_name</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>android<span class="token operator">::</span>base<span class="token operator">::</span><span class="token function">Join</span><span class="token punctuation">(</span>ns<span class="token operator">-</span><span class="token operator">&gt;</span><span class="token function">get_ld_library_paths</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">':'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">c_str</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>android<span class="token operator">::</span>base<span class="token operator">::</span><span class="token function">Join</span><span class="token punctuation">(</span>ns<span class="token operator">-</span><span class="token operator">&gt;</span><span class="token function">get_default_library_paths</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">':'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">c_str</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>android<span class="token operator">::</span>base<span class="token operator">::</span><span class="token function">Join</span><span class="token punctuation">(</span>ns<span class="token operator">-</span><span class="token operator">&gt;</span><span class="token function">get_permitted_paths</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">':'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">c_str</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

}

soinfo* si = soinfo_alloc(ns, realpath.c_str(), &file_stat, file_offset, rtld_flags);
if (si == nullptr) {
return false;
}

task->set_soinfo(si);

// Read the ELF header and some of the segments.
if (!task->read(realpath.c_str(), file_stat.st_size)) {
soinfo_free(si);
task->set_soinfo(nullptr);
return false;
}

// find and set DT_RUNPATH and dt_soname
// Note that these field values are temporary and are
// going to be overwritten on soinfo::prelink_image
// with values from PT_LOAD segments.
const ElfReader& elf_reader = task->get_elf_reader();
for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
if (d->d_tag DT_RUNPATH) {
si->set_dt_runpath(elf_reader.get_string(d->d_un.d_val));
}
if (d->d_tag DT_SONAME) {
si->set_soname(elf_reader.get_string(d->d_un.d_val));
}
}

for_each_dt_needed(task->get_elf_reader(), [&](const char* name) {
load_tasks->push_back(LoadTask::create(name, si, ns, task->get_readers_map()));
});

return true;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133

错误输出:

DL_ERR("library \"%s\" needed or dlopened by \"%s\" is not accessible for the namespace \"%s\"",name, needed_or_dlopened_by, ns->get_name());
  • 1
  • 2

修改的思路是, 不走报错这部分分支的代码, 切入点 is_greylisted

diff --git a/bionic/linker/linker.cpp b/bionic/linker/linker.cpp
old mode 100644
new mode 100755
index c78b9ab..0aa83bc
--- a/bionic/linker/linker.cpp
+++ b/bionic/linker/linker.cpp
@@ -200,12 +200,14 @@ static bool is_greylisted(android_namespace_t* ns, const char* name, const soinf"libui.so","libutils.so","libvorbisidec.so",
+       "libserial_port.so",nullptr};

// If you’re targeting N, you don’t get the greylist.
if (g_greylist_disabled || get_application_target_sdk_version() >= ANDROID_API_N) {
- return false;
+ //make system lib can be loaded.
+ //return false;
}

// if the library needed by a system library - implicitly assume it

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

修改点:

  • 将调用的SO加入灰名单列表, 这里加了一个libserial_port.so
  • 注释判断SDK和灰名单使能判断的返回, 当然, 也可以强制返回 true, 看需求办事

修改后有Warning提示, 忽略:

Warning: library "/system/lib/libserial_port.so" ("/system/lib/libserial_port.so") needed or dlopened by "/system/lib/libnativeloader.so" is not accessible by namespace "classloader-namespace" and will not work when the app moves to API level 24 or later (https://android.googlesource.com/platform/bionic/+/master/private-api-enforced-for-api-level-24) (allowing for now because this app's target API level is still 26)
  • 1

已上传资源: linker
使用:

adb root
adb remount
adb push linker /system/bin/
adb reboot
  • 1
  • 2
  • 3
  • 4

随着而来的第二个问题:

java.lang.UnsatisfiedLinkError: dlopen failed: library "libc++.so" not foundat java.lang.Runtime.loadLibrary0(Runtime.java:1016)at java.lang.System.loadLibrary(System.java:1669)
  • 1
  • 2
  • 3

|–bionic/linker/linker.cpp

@@ -2342,6 +2344,10 @@ android_namespace_t* create_namespace(const void* caller_addr,

parse_path(ld_library_path, “:”, &ld_library_paths);
parse_path(default_library_path, “:”, &default_library_paths);
+ if(strcmp(name, “classloader-namespace”) == 0){
+ parse_path("/system/lib", “:”, &default_library_paths);
+ }
parse_path(permitted_when_isolated_path, “:”, &permitted_paths);

android_namespace_t* ns = new (g_namespace_allocator.alloc()) android_namespace_t();

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

解决!!

完整补丁: linker_patch.tar.gz

相关

  • Android 7.0 NDK 行为变更
  • 记录7.0加载so文件失败:java.lang.UnsatisfiedLinkError: dlopen failed: library “libsqlite.so” not found

android第三方apk找不到/system/lib64/里面的系统库相关推荐

  1. android内置第三方APP为系统应用,第三方APP内置到/system/app目录下报错java.lang.UnsatisfiedLinkError,so文件不加载

    项目场景: 在无系统签名的情况下,将第三方APP内置到/system/app目录下,可以将第三方应用变为系统应用,用户无法直接卸载.不过前提是手机需要root. 问题描述 使用es文件管理工具将第三方 ...

  2. 【Android 12 AOSP学习】Android内置第三方apk到系统

    这篇文章将介绍如何在Android系统中内置第三方apk 一.准备工作 编译好的Android源码 Android apk文件:也就是安卓应用安装包 二.步骤 (1)在源码packages/apps目 ...

  3. android预置第三方apk,android 内置APK成系统应用

    一. 这种方法必须要自己编写Android.mk文件(关于Android.mk可以参考),在研发中,自己有源码时,可以将APK的源码包置于Android源码中(比如:alps/package/apps ...

  4. Android 系统预装添加第三方apk到data/app

    对于第三方apk预装入系统时如果将apk装入system/app目录下,由于第三方apk带有自己的.so文件,此时会出现apk无法打开的情况. 解决方法: 1:解压apk,将里面的.so文件放入dev ...

  5. Android O发生crash,提示/system/bin/linker64(备忘)

    错误提示: 2010-01-01 08:24:29.913 20251-20251/com.anwsdk.service W/linker: library "libsqlite.so&qu ...

  6. android打包apk时混淆遇到的问题

    android打包apk的时候一般会选择混淆,而在eclipse中常使用的是proguard来混淆.有很多时候引用了第三方包的时候会导致打包不成功,或者打包成功不能运行的情况. 首先看看正常的prog ...

  7. 第三方APK如何隐藏虚拟按键

    全面屏时代,android设备已经很少有键盘的存在了,为了便捷,虚拟按键应运而生,当然iphone的手势控制也有一部分厂商移植到了android系统中. 本文主要是关于底部的三个虚拟按键RECENT. ...

  8. Unity3D接入Android第三方SDK流程

    目录 一.SDK调用Unity3D 二.Unity3D调用SDK 1.在Unity中新建一个脚本,调用MySDkPlatform中的方法 四.打包 1.方式一:SDK打成plugins给Unity(u ...

  9. 【Android 安全】Android 应用 APK 加固总结 ( 加固原理 | 应用加固完整的实现方案 | 源码资源 )

    文章目录 一. APK 加固原理 1. Android 应用反编译 2. ProGuard 混淆 3. 多 dex 加载原理 4. 代理 Application 开发 5.Java 工具开发 6.Ap ...

  10. Android第三方QQ登录、获取个人信息、分享实现

    昨天调试了一下午终于成功 第三方QQ登录.获取个人信息,分享 QQ官方API文档写的太乱 并且很多地方没有更新 这里总结一下 方便记录和回看 实现结果图 首先进入腾讯开放平台 下载QQ的SDK 地址 ...

最新文章

  1. 自动化测试报告(ReportNG)手把手教你
  2. Windows 技术篇-cmd强制关闭端口、解除端口占用方法,cmd查询端口相关的进程pid并杀死进程实例演示
  3. C语言中变量的链接属性
  4. boost::make_connected用法的测试程序
  5. 最小步长移动word表格标尺
  6. php为什么要使用变量,为什么在PHP或其他语言中使用动态变量(变量变量)
  7. scp带密码后台传输
  8. 安装服务器选择什么系统盘,云服务器ecs选择什么系统盘
  9. vue-router如何参数传递
  10. 背包问题九讲笔记_01背包
  11. 电子计算机最早的应用,电子计算机的最早应用领域是什么?
  12. 函数信号发生器的功能介绍
  13. docker the input device is not a TTY. If you are using mintty, try prefixing the command with ‘winp
  14. 用spark统计50年美国最常见的20个名字
  15. Proteus,keil5仿真运行stm32程序,流水灯详细教程
  16. 你未必知的拼音打字快打十招
  17. 常见的中间件有哪些?
  18. Mybatis错误 Result Maps collection already contains value for xxx
  19. 线上nacos命名空间误删如何找回 实践笔记
  20. OpenX系列标准介绍(5):OpenDRIVE和OpenSCENARIO的中文版本

热门文章

  1. 基于面板数据的熵值法介绍与实现
  2. 情人节看IT男如何告白,IT男的告白攻略
  3. 如何使用计算机上合并计算方法,excel如何使用合并计算
  4. PC常见故障及解决思路汇总(网络方面)
  5. VS2022-更换背景壁纸
  6. 流量卡之家:5G从概念到落地,未来工厂触手可及
  7. 【测评】国外AR平台ENTITI测评-网页编辑器(1)
  8. Coding life,云栖社区的个性化首页上线
  9. Java总结IO之总集篇
  10. 【深入理解计算机系统】CSAPP-实验四:ArchLab全网最详细