Android 15 之如何快速适配 16K Page Size
在此之前,我们通过 《Android 15 上 16K Page Size 为什么是最坑》 介绍了:
- 什么是16K Page Size
- 为什么它对于 Android 很坑
- 如何测试
如果你还没了解,建议先去了解下前文,然后本篇主要是提供适配的思路,因为这类适配更多工作量在于实际的执行调整和编译跟踪,而非功能上的适配,本质不复杂,但可能量大且繁琐。
是的,想要适配你首选需要有 C/C++ 等 so 库的源码。
适配的开始,我们可以先粗暴的全局搜索 「4096」关键字,看看是否有将 4096 搭配 mmap
、sysconf
等相关的地方,因为 Android 上的 4K 这么多年已经「深入人心」,可以说不少代码都将 Android 默认为「4096」。
对于这些地方,我们可以通过类似 getpagesize()
等方式来进行调整,例如通过 ALOGV("####### %d", getpagesize());
可以看到在 Android15 上输出的是 16384 。
接着我们可以运行项目到 Android 15 的模拟器上(如果运行不起来看前文),看 so 是否能正常被加载执行,一般情况下你可能会看到类似:
java.lang.UnsatisfiedLinkError: dlopen failed: empty/missing DT_HASH ···· (new hash type from the future?)
这类问题基本都是 so 文件没有 16K 编译对齐的原因,此时,根据你的 CMakeList 版本,可以使用 target_link_options
或者 target_link_libraries
进行调整。
例如 3.13 之前:
target_link_libraries(a4ijkplayer "-Wl,-z,max-page-size=16384")
例如 3.13 之后:
target_link_options(a4ijkplayer PRIVATE "-Wl,-z,max-page-size=16384")
注意 CMakeList 的版本还需要 SDK Manager 里有下载安装。
如果是 Android.mk
, 则添加 LOCAL_LDFLAGS 也可以配置 16K Page :
LOCAL_LDFLAGS += -Wl,-z,max-page-size=16384
编译后,我们通过 readelf 工具,可以对比编译前后两个 so 的 elf 对齐情况,工具一般位于 /Users/guoshuyu/Library/Android/sdk/ndk/21.4.7075529/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin
,通过以下命令可以输出对应参数:
./aarch64-linux-android-readelf -l /Users/guoshuyu/workspace/android/******/libs/arm64-v8a/libijkffmpeg.so
如下两种图所示:
- 图 1 LOAD 段在 Align 栏目显示 1000 (16进制,即 4096) ,也就是还没增加 16K 对齐的状态
- 图 2 LOAD 段在 Align 栏目显示 4000 (16进制,即 16384) ,也就是修改编译后,已经增加 16K 对齐的状态
这里我们只关心 LOAD 段,因为一般只有 LOAD 段需要加载到内存中。
所以简单情况下,你也可以通过 readelf 工具查看 so 的对齐状态。
另外,如果你在低版本 NDK (低于 r27) 上使用动态链接到 C++ 标准库,那么可以也会遇到 1ibc++_shared.so
的相关报错,解决的思路还是:
- 升级到 NDK r27
- 将 C++ 标准库静态链接到 so 库里面,例如
-DANDROID_STL=c++_static
externalNativeBuild {cmake {abiFilters 'armeabi-v7a', 'arm64-v8a'arguments '-DANDROID_ARM_NEON=TRUE', '-DANDROID_STL=c++_static'}}
之后,如果 so 运行过程中还存在异常问题, 可以通过地址信息来进行代码定位,例如使用常见的:addr2line
。
而 addr2line
的可执行文件位置,一般位于以下位置:
/Users/guoshuyu/Library/Android/sdk/ndk/21.4.7075529/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin
注意 ndkVersion 的版本还需要 SDK Manager 里有下载安装。
其中 ndk 版本为项目 build.gradle
下配置的 ndk 版本,例如 ndkVersion '21.4.7075529'
,之后你只需要通过执行命令输出,即可看到出现问题的文件和行数:
./aarch64-linux-android-addr2line -e /Users/guoshuyu/workspace/android/··········/build/intermediates/merged_native_libs/debug/out/lib/arm64-v8a/????.so 000000000007e0a0
当然,也可以增加 -f,通过 ./aarch64-linux-android-addr2line -f -e
来查看出问题的函数是什么:
例如,对于 C++ 里静态存储区域分配,内存在程序编译的时候就已经分配好,而 static 这块内存变量上,如果 so 对齐和地址存在问题,也可能会导致访问地址异常。
如果上述在使用 addr2line
输出时看到都是 ?? ,那么你可能需要修改下编译的调试支持和优化级别,例如 Application.mk
上降低优化等级为 APP_CFLAGS := -O0
。
当然,很多时候存在许多「玄学」的问题,例如前段时间就遇到了一个神奇的 Bug ,甚至也不知道为什么,但是又能改好它。
举个不严谨的例子,通过地址定位,可以定位到报错的地方是这个 static
的全局变量报错,但是为什么会出现 Fatal signal 11(SIGSEGV),code 2(SEGV_ACCERR)
让人费解。
如果按照正常场景来看,C 和 C++ 中的静态变量通常存储在 “data” 区域,但是对于任何未初始化或初始化为零的全局数据,都是存放在 “bss” :
正常情况下,bss 段属于静态内存分配,通常是用来存放未初始化的全局变量和未初始化的局部静态变量,所以 bss 段只是给未初始化的全局变量和未初始化的局部静态变量预留位置而已。
我们可以通过前面的 readelf 工具看一下,如下命令所示 ,通过 -s | grep _errMsg
输出,我们可以看到 _errMsg
确实存在 [23] 的 bss 的 NOBITS 位置。
./aarch64-linux-android-readelf -S /Users/guoshuyu/workspace/*****.so -s | grep _errMsg
但是从输出看,貌似也没什么问题,如果从另外的 .text
和 .rodata
的 Address 上看, 165670 - 071fa0 = F36D0 ,也正好是 4000 的 3C 倍数 ,所以分页应该也没问题。
而通过 objdump 输出的结果看,也和没看出异常,所以问题就变得很玄学,根据猜测,可能是以下某个之一的问题:
./aarch64-linux-android-objdump -h /Users/guoshuyu/workspace/android/****.so
- 某个过程编译的对齐有问题
- NDK 的 gcc 优化存在一些奇怪问题, 例如 gcc 不仅观察变量如何定义,还观察了变量如何在代码中使用
- 赋值的寻址有问题没对齐
- 模拟器系统问题
在偶然之下,屏蔽掉某个使用
_errMsg
的 static function 的static
声明后,它居然就正常运行了,就是偶尔删掉了某个函数的 static 声明,它突然就好了···所以我也不知道是编译的问题还是系统的问题,也许后面有空再深入研究下,不过在适配过程中,真的是「运气好」的情况下,你只需要改一下配置,编译完就可以立即使用,运气不好的情况下,真的就很「玄学」。
最后,如果你需要升级到 NDK r27,你可能还需要对代码的编排方式做一些调整,例如类似 ISO C99 and later do not support implicit function declarations
等小细节问题,因为 NDK r27 目前是 clang-r522817 的版本:
根据 r27 目前的 clang_source_info.md
,其 clang 应该会是 18.1.0 ,也就是包含 C++ 20/23/2C 等的支持,如果升级跨度较大,其实可能会是改了旧坑来新坑的节奏。
例如腾讯目前的 MMKV,在 issue#1353 就提到了兼容的评估问题,虽然对于使用者来说,可能就是几个简单配置就可以重新编译支持,但是对于平台方来说,升级环境是一个“高风险”行为,所以还需要谨慎而行。
最后,这个适配的基础还是你有源码,如果你连源码都没有,那么基本就没希望了,对于 android 环境下,基于 linux 的 4k/16k 内核是不支持混用(详细原因见前文),所以如果你没做适配,很大可能 so 是无法正常运行,不过好消息是,OEM 厂商可以不启用,坏消息是,Google 表示明年在 Google Play 上会强制要求。
相关文章:

Android 15 之如何快速适配 16K Page Size
在此之前,我们通过 《Android 15 上 16K Page Size 为什么是最坑》 介绍了: 什么是16K Page Size为什么它对于 Android 很坑如何测试 如果你还没了解,建议先去了解下前文,然后本篇主要是提供适配的思路,因为这类适配…...
学习unity官方的网络插件Netcode【一】
对bool值的个人理解: using Unity.Netcode; using UnityEngine; //个人理解:通过Rpc完成了一次客户端给服务端发消息,服务端再向所有客户端广播消息 public class RpcTest : NetworkBehaviour {public override void OnNetworkSpawn(){if (!…...

QT写一个mainWindow
切换风格的写法: 先看看样式效果: mian_window.h文件 #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow>class MainWindow : public QMainWindow {Q_OBJECTpublic:MainWindow(QWidget *parent nullptr);~MainWindow();void Ini…...
Java查找算法练习(2024.7.23)
顺序查找 package SearchExercise20240723; import java.util.Scanner; public class SearchExercise {public static void main(String[] args) {Scanner sc new Scanner(System.in);System.out.println("需要多大的数组?");int size sc.nextInt();int[] array …...

洗地机哪个牌子好?四款口碑最好的洗地机排名推荐
随着“懒人经济”的出现,越来越多的人开始使用洗地机。洗地机哪个牌子好?为了帮助大家在这个琳琅满目的市场中做出明智决策,本文特别整理了四款口碑最好的洗地机排名推荐,它们凭借出色的清洁效果、智能化的操作体验以及用户的高度…...

如何提升短视频的曝光量和获客效能?云微客来解决
在流量至上的当下,短视频凭借其优势,迅速成为了众多企业获客引流的核心营销手段。进入短视频赛道后,如何提升短视频的曝光量和获客效能,就成为了众多企业亟待解决的焦点。 如果你不想投入大量的广告预算,还想在短视频平…...
SpringBoot开发中如何缓存数据, 减少数据库的访问频率?
一:自定义是否开启缓存 方法一: 在不同环境的配置文件中如application-dev.yml、application-test.yml、application-prod.yml,修改 spring.cache.type none; spring:cache:type: none 方法二: 自定义配置 application.yml&…...
PostgreSQL如何在windows/linux开启归档
linux开启归档: archive_mode onarchive_command test ! -f /mnt/pg12/archivedir/%f && cp %p /mnt/pg12/archivedir/%fwindows开启归档: archive_mode onarchive_command copy "%p" "C:\\server\\pg12\\archivedir\\%f&q…...

【启明智显分享】基于国产Model3芯片的7寸触摸屏助力智慧医疗,电子床头屏提升护理交互
未来医院必然是以信息化为基础,以物联网为特征,以医疗为核心的服务型医院。病房作为医院的重要服务场所,成为智慧医院建设的重要一环。 为提高医护人员与患者的互动交流,给医疗注入智慧元素,让患者享受智能服务&#…...

从理论到实践:如何用 TDengine 打造完美数据模型
在用 TDengine 进行数据建模之前,我们需要回答两个关键问题:建模的目标用户是谁?他们的具体需求是什么?在一个典型的时序数据管理方案中,数据采集和数据应用是两个主要环节。如下图所示: 对于数据采集工程师…...

可以免费合并pdf的软件 合并pdf文件的软件免费 合并pdf的软件免费
在数字化办公的今天,pdf格式因其稳定性和跨平台兼容性被广泛使用。然而,当我们需要将多个 pdf 文件合并为一个时,却往往感到力不从心。本文将为你介绍几款强大的pdf文件合并软件,让你轻松管理文档。 方法一、使用pdf转换器 步骤1…...

【排序 滑动窗口 】1498. 满足条件的子序列数目
本文涉及至知识点 排序 C算法:滑动窗口总结 LeetCode1498. 满足条件的子序列数目 给你一个整数数组 nums 和一个整数 target 。 请你统计并返回 nums 中能满足其最小元素与最大元素的 和 小于或等于 target 的 非空 子序列的数目。 由于答案可能很大,…...
RabbitMQ普通集群搭建指南
RabbitMQ普通集群搭建指南 本文已经完全迁移至,www.geekery.cn 后续不在此更新 目标架构 本次搭建的目标是构建一个由三个节点组成的RabbitMQ集群,节点信息如下: rabbit02: IP地址 192.168.10.132rabbit03: IP地址 192.168.10.133rabbit04:…...

AGV平面坐标系变换公式及实例
1、AGV坐标系简介 如上图,小车前后对角是有激光雷达的,其坐标系称为激光坐标系,采用极坐标系体现。中间为车体坐标系,激光坐标系相对于车体坐标系关系不变;左下角是地图坐标系,小车扫图后,建立的…...
es切片和集群
解决单点故障 支持高并发 解决海量数据 1.cluster 集群:包含多个节点,每个节点属于哪个集群是通过一个集群名称(集群名称,默认是elasticsearch)来决定的,对于中小型应用来说,刚开始一个集群就…...

IEEE官方列表会议 | 第三届能源与环境工程国际会议(CFEEE 2024)
会议简介 Brief Introduction 2024年第三届能源与环境工程国际会议(CFEEE 2024) 会议时间:2024年12月2日-4日 召开地点:澳大利亚凯恩斯 大会官网:CFEEE 2024-2024 International Conference on Frontiers of Energy and Environment Engineer…...

深度学习中的正则化技术 - Dropout篇
序言 在深度学习的浩瀚领域中,模型过拟合一直是研究者们面临的挑战之一。当模型在训练集上表现得近乎完美,却难以在未见过的数据(测试集)上保持同样优异的性能时,过拟合现象便悄然发生。为了有效缓解这一问题…...
《昇思 25 天学习打卡营第 18 天 | 扩散模型(Diffusion Models) 》
《昇思 25 天学习打卡营第 18 天 | 扩散模型(Diffusion Models) 》 活动地址:https://xihe.mindspore.cn/events/mindspore-training-camp 签名:Sam9029 扩散模型(Diffusion Models) 扩散模型概述 扩散模…...

【Django+Vue3 线上教育平台项目实战】Elasticsearch实战指南:从基础到构建课程搜索与数据同步接口
文章目录 前言一、Elasticsearch倒排索引 二、Docker 搭建 ESDocker 安装Docker 搭建 ES 三、ES基础语法创建索引查看索引删除索引添加数据查询数据修改数据删除数据条件查询分页查询排序 多条件查询andor 范围查询 四、ES在项目中的应用示例 前言 在数据驱动的时代,…...

libtins初探-抓包嗅探
libtin 一、概述1. 可移植性2. 特性 二、基础知识1. PDU2. 地址类3. 地址范围类4. 网络接口5. 写pcap文件 三、嗅探1.嗅探基础2. 嗅探器配置3. 循环嗅探4. 使用迭代器嗅探6. 包对象7. 读取pcap文件8. 包的解析 四、发送包1. 发送网络层pdu2. 发送链路层pdu3. 发送和接收响应校验…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...

循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别
UnsatisfiedLinkError 在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用,结果 dll 未实现 JNI 协…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业
6月9日,国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解,“超级…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...

相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...
leetcodeSQL解题:3564. 季节性销售分析
leetcodeSQL解题:3564. 季节性销售分析 题目: 表:sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...
C++八股 —— 单例模式
文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全(Thread Safety) 线程安全是指在多线程环境下,某个函数、类或代码片段能够被多个线程同时调用时,仍能保证数据的一致性和逻辑的正确性…...