当前位置: 首页 > news >正文

Android 15 适配之16K Page Size :为什么它会是最坑的一个适配点

首先什么是 Page Size ?一般意义上,页面(Page)指的就是 Linux 虚拟内存管理中使用的最小数据单位,页面大小(Page Size)就是虚拟地址空间中的页面大小, Linux 中进程的虚拟地址空间是由固定大小的页面组成。

Page Size

对于虚拟内存, CPU 的内存管理单元(MMU)会将虚拟地址转换为物理地址,所以虚拟内存最终也会映射到物理内存页面。

而为了实现虚拟内存到物理的映射,两个地址空间都会被划分为多个固定页面,而虚拟空间和物理空间中的页面需要大小相同,通常长度为 4K,为了区分虚拟页面和物理页面,后者一般会被称为页框(page frames )。

就是每个应用都有自己独特的虚拟地址空间,并且它永远也不要关心其他应用在做什么,占据了哪些真实地址,实际物理地址映射,是由 Linux 内核去管理和分配,虚拟内存也是为什么系统支持多应用同时运行的基础

剩下的就很简单了,因为 Android 用的是 Linux 内核,所以在这部分逻辑一直以来都是遵循 Linux 的实现,只是 Android 由于「历史因素」限制,一直只支持 4 KB 内存页面大小,而现在为了优化系统内存性能,提高内存密集型工作负载的性能,Android 15 开始将采用 16KB 页面大小的要求。

那前面说了那么多「无用的知识」,核心还是 Android 15 要启动 16K Page Size 了,对于我们来说有什么影响?

先说理论上的正面影响:

  • 系统面临内存压力时缩短应用启动时间:平均缩短 3.16%,某些应用的改进甚至高达 30%
  • 降低应用启动时的耗电量:平均减少 4.56%
  • 相机启动速度更快:热启动速度平均加快 4.48%,冷启动速度平均加快 6.60%
  • 改善系统启动时间:平均改善1.5%(约0.8秒)

那么负面影响是什么?你带有 .so 的 android 项目,很可能需要重新编译带有全新的动态库(.so) 才能正常运行对应功能,不然大概率会 crash

至于你的项目里有没有动态库,相信你应该很清楚,如果不清楚,直接把 apk 拖到 Android Studio ,看看 lib 下是否有 so 文件即可。

那为什么说用 Android 15 启动 16K Page Size 后,以往使用了 C/C++(native)代码的基本都会 crash 呢?这就是前面说到的 Linux 下 Page Size 的实现

可能大家会觉得,为什么不能有兼容层,将 4k 页面大小转换为 16k 页面大小?

理论上这是可行的,比如你可以使用虚拟化技术让 4K 的应用跑在 16K 主机上,但是想要系统直接混搭 Page Size 支持,是一个比较困难的事情。

前面我们知道,虚拟内存和物理内存之间存在映射,那么如果 CPU 处于 16K 模式,那么其实所有内容都会处于 16K 模式,简单不严谨的理解,这会是一个 CPU 全局寄存器设置的概念。

所以对于所有空间页面而言,在任意时刻要么是 4K,要么是 16K页表结构在 4K 模式和 16K 模式下完全不同(每级页面、级数、屏蔽)。

这里扯一段额外的东西, Apple Silicon 的 MacOS 其实是有混合 16K/4K 支持,事实上 macOS 本身始终以 16K 页面运行,只有 Rosetta 模式下应用会以 4K 模式运行:

我大概记得好像是,在 macOS 上,Rosetta 模式用户空间和内核空间的页面大小可以不同,不同的用户空间程序可以使用不同的页面大小运行。

因为 Linux 不支持混合 Page Size,默认上 android 也不支持,除非 Android OS 层后续也做类似 Rosetta 等处理

如何检测

前面讲了那么多废话,大家肯定还是很关系,如何知道我的 App 是否支持 16K Page Size 运行。

虽然带有陈年 .so 的很大概率不行,但是也许呢?

最简单且最实用的做法就是通过模拟器 VanillaIceCream 的 APIs Experimental 16k Page Size ARM 64 v8a System Image 进行测试。

根据自己的设备,如上图选择下载一个 VanillaIceCream 的 16k Page Size 的模拟器镜像,然后在 Other Images 选择下载的镜像创建模拟器。

注意,这里干活来咯,因为老板本 AS 在 LLDB 调试 16 KB 模拟器系统映像会存在问题,所以至少需要下载一个和 Android Studio Koala Feature Drop | 2024.1.2 Canary 5 ,就是如下图所示这个,带 Drop 版本的才能成功运行 16K Page Size 模拟器。

什么是 Drop 版本?可以参考:https://juejin.cn/post/7379816515551723546

运行模拟器之后,通过 adb shell getconf PAGE_SIZE 可以获取到一个 16384 的值,说明系统现在已经是 16K 的模式。

那么,我把 GSYVideoPlayer 运行到 16K 模拟器后,不出所料 IJK 内核无法正常播放。

另外,官方提供了一个 16 KB ELF 对齐脚本来验证共享库的 ELF 段是否正确对齐,如下脚本针对 GSYVideoPlayer 里的动态库进行校验后,输出却是比较意外。

#!/bin/bash# usage: alignment.sh path to search for *.so filesdir="$1"RED="\e[31m"
GREEN="\e[32m"
ENDCOLOR="\e[0m"matches="$(find $dir -name "*.so" -type f)"
IFS=$'\n'
for match in $matches; dores="$(objdump -p ${match} | grep LOAD | awk '{ print $NF }' | head -1)"if [[ $res =~ "2**14" ]] || [[ $res =~ "2**16" ]]; thenecho -e "${match}: ${GREEN}ALIGNED${ENDCOLOR} ($res)"elseecho -e "${match}: ${RED}UNALIGNED${ENDCOLOR} ($res)"fi
done

可以看到此时动态库是 ALIGNED 的,并且是 2**16 ,也就是 armv68a 的动态库此时的 ELF 对齐。

另外,通过 sdk 的 build-tools/35.0.0 下的 zipalign 命令运行:

./zipalign -c -P 16 -v 4 /Users/guoshuyu/workspace/android/GSYVideoPlayer/app/build/outputs/apk/release/app-release.apk

可以看到此时的 apk 对齐也是没有问题的,所以此时的运行问题可能更多在于 C++ 代码里的 mmap 或者 sysconf 等代码存在问题,例如写死了 4096 等硬编码。

兼容

对于 LLDB 调试 16 KB 模拟器,需要 NDK r27 RC 1 的支持, 如果使用 r27 及以上的版本,那么只需要在 Application.mk 配置:

APP_SUPPORT_FLEXIBLE_PAGE_SIZES := true

如果是 Android NDK r26 及更低版本 ,则需要在 Android.mk 启用 16 KB ELF 对齐 :

LOCAL_LDFLAGS += "-Wl,-z,max-page-size=16384"

另外,构建支持 16 KB 设备的应用还需要 AGP 8.3 + 的支持,16 K 设备会要求附带未压缩共享库的应用将它们对齐到 16 KB 压缩对齐,为此升级到 Android Gradle 插件 (AGP) 版本 8.3+ 会是一个比较好的选择。

如果使用 AGP 版本 8.2或更低的版本,那么另一种选择是切换到使用压缩共享库

如果您无法将 AGP 升级到 8.3 或更高版本,那么另一种选择是切换到使用压缩共享库:

android {...packagingOptions {jniLibs {useLegacyPackaging true}}
}

也就是什么?适配的基础是重新编译 .so ,重新编译的基础是:

  • NDK r27 推荐,NDK r26 及更低版本可以修改 max-page-size ,当然太低是真不行,反正目前测试我的 NDK r10e 是有问额····
  • AGP 8.3 + 推荐,低版本可以用 useLegacyPackaging

当然,重新编译只是基础,代码里使用了例如 mmap 或者硬编码 4096 的地方,都需要修改适配

那么问题来了,老旧 .so 连源码都没有的情况下,是不是没救了? 答案是肯定的,确实没救了,更糟心的是:谷歌计划明年将对 16k 设备的支持作为 Google Play 应用程序提交的必要条件

本质上你的 .so 可能已经是 16K 对齐,但是还存在逻辑适配问题。

所以逃是逃不开了,好消息是目前这是一个实验性的阶段,另一个好消息,那就是 Flutter 本身已经支持了 16k ,在测试里 Flutter 3.22 是可以在 16K 模拟器上正常运行,这一定程度也算不幸中的万幸了。

最后

所以心凉了没?从目前看,基于 Linux 内核下的 16K Page Size 很大可能不支持 4K Page Size 的 C/C++ native 代码,所以可以遇见的情况有这么几种:

  • Android OS 最终落地了混合 Page Size 支持
  • 重新编译和修改 .so 支持 16K

所以大家觉得会是怎么样的一个结果?

相关文章:

Android 15 适配之16K Page Size :为什么它会是最坑的一个适配点

首先什么是 Page Size ?一般意义上,页面(Page)指的就是 Linux 虚拟内存管理中使用的最小数据单位,页面大小(Page Size)就是虚拟地址空间中的页面大小, Linux 中进程的虚拟地址空间是由固定大小的页面组成。 Page Size 对于虚拟内…...

下载linux的吐槽

本来这几天放假了,想下一个linux玩一玩 教程(我就是根据这个教程进行下载的,但是呢在进行修改BIOS 模式的 地方遇见了困难,也许是电脑修过的原因,我狂按F12 以及 FnF12都没有BIOS设置,只有一个让我选择用w…...

【HTML入门】第四课 - 换行、分割横线和html的注释

这一小节,我们继续说HTML的入门知识,包括换行、横线分割以及注释(html的注释)。 目录 1 换行 2 分割横线 3 html注释 1 换行 html中分为块元素和行内元素。这一小节呢,先不说这些元素们,我们先说一下换…...

基于Hadoop平台的电信客服数据的处理与分析④项目实现:任务15:数据生产

任务描述 电信数据生产是一个完整且严密的体系,这样可以保证数据的鲁棒性。在本项目的数据生产模块中,我们来模拟生产一些电信数据。同时,我们必须清楚电信数据的格式和数据结构,这样才能在后续的数据产生、存储、分析和展示环节…...

Kotlin中的数据类型

人不走空 🌈个人主页:人不走空 💖系列专栏:算法专题 ⏰诗词歌赋:斯是陋室,惟吾德馨 目录 🌈个人主页:人不走空 💖系列专栏:算法专题 ⏰诗词歌…...

提高交易决策质量,Anzo Capital昂首资本只需两个交易策略

要想提高交易决策质量,其实很简单,Anzo Capital昂首资本只需两个交易策略,结合价格行为和VSA(成交量与价格分析)就可以达成我们的目的。首先,理解这两个概念: 1. 价格行为:价格行为是市场价格变动的方式&a…...

Ubuntu TensorRT安装

什么是TensorRT 一般的深度学习项目,训练时为了加快速度,会使用多 GPU 分布式训练。但在部署推理时,为了降低成本,往往使用单个 GPU 机器甚至嵌入式平台(比如 NVIDIA Jetson)进行部署,部署端也…...

spring mvc学习

第四章 Spring MVC 第一节 Spring MVC 简介 1. Spring MVC SpringMVC是一个Java 开源框架, 是Spring Framework生态中的一个独立模块,它基于 Spring 实现了Web MVC(数据、业务与展现)设计模式的请求驱动类型的轻量级Web框架&am…...

第4集《修习止观坐禅法要》

请打开讲义第七面,四、悟道。 我们前面讲到智者大师出家以后,他除了持戒以外,一方面拜忏,一方面就是打坐,来调伏他过去的烦恼跟罪业,以为他未来圆顿止观的一个基础,这以下讲到他开悟的情况&…...

IPython 日志的开关:精通 %logoff 命令的实用指南

IPython 日志的开关:精通 %logoff 命令的实用指南 在 IPython 的强大功能中,日志记录是一个不可或缺的工具,它帮助用户记录会话历史,以便日后分析和重现。%logoff 命令作为日志记录功能的补充,允许用户在需要时停止日…...

Redis 分布式集群方案 Cluster

引言 相比于Codis,Redis Cluster是Redis官方提供的解决方案。相比于Codis的不同,他是去中心化的,如图所示,该集群有三个Redis节点组成,每个节点负责整个集群的一部分数据,每个节点负责的数据多少可能不一样…...

Redis的两种持久化方案

Redis 提供了多种持久化机制来保证数据在发生意外情况下(如断电或服务器崩溃)不丢失。以下是几种主要的 Redis 持久化方案及其特点: 1. RDB (Redis Database Backup) RDB 是 Redis 创建的数据库快照,它可以将数据集快照以二进制…...

Spring中常见知识点及使用

Spring Framework 是 Java 生态系统中最流行的开源框架之一,它提供了一系列强大的功能,用于构建企业级应用。以下是一些常见的 Spring 知识点及其使用方法: 1. 依赖注入(Dependency Injection) 依赖注入是 Spring 的…...

Excel 宏录制与VBA编程 ——VBA编程技巧篇二 (合并内容相同连续单元格、取消合并单元格并在每个单元格中保留内容)

1、合并内容相同的连续单元格 如果需要合并如图所示的工作表中B列中部门相同的连续单元格 VBA代码: Sub Mergerng()Dim IntRow As IntegerDim i As IntegerApplication.DisplayAlerts FalseWith Sheet1IntRow .Range("A65536").End(xlUp).RowFor i In…...

理解和应用工业设备字典文件:一篇详细指南

理解和应用工业设备字典文件:一篇详细指南 在工业自动化领域,设备和模块的配置和管理是一个复杂而重要的任务。为了简化这个过程,字典文件被广泛应用于描述离线对象字典。本文将详细解释字典文件的用途、格式,并举例说明如何引用…...

Python酷库之旅-第三方库Pandas(010)

目录 一、用法精讲 22、pandas.read_hdf函数 22-1、语法 22-2、参数 22-3、功能 22-4、返回值 22-5、说明 22-6、用法 22-6-1、数据准备 22-6-2、代码示例 22-6-3、结果输出 23、pandas.HDFStore.put方法 23-1、语法 23-2、参数 23-3、功能 23-4、返回值 23-5…...

海康威视监控web实时预览解决方案

海康威视摄像头都试rtsp流,web页面无法加载播放,所以就得转换成web页面可以播放的hls、rtmp等数据流来播放。 一:萤石云 使用萤石云平台,把rtsp转化成ezopen协议,然后使用组件UIKit 最佳实践 萤石开放平台API文档 …...

ubuntu运行qq音乐闪退

ubuntu运行qq音乐闪退 修改/usr/share/applications中的qqmusic.desktop,在Exec后加上 --no-sandbox,如下图所示: 该文件有可能是只读,权限不够的话用sudo vim qqmusic.desktop...

人脸检测(Python)

目录 环境: 初始化摄像头: 初始化FaceDetector对象: 获取摄像头帧: 获取数据: 绘制数据: 显示图像: 完整代码: 环境: cvzone库:cvzone是一个基于…...

Offer150-23:链表中环的入口节点

题目描述:如果一个链表中包含环,找了环的入口节点。例如,在下图所示的链表中,环的入口节点是节点4。 分析:第一步需要确定一个链表中是否包含环,可以用快慢指针来解决这个问题。定义两个指针,同时从链表的头…...

安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件

在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...

c++ 面试题(1)-----深度优先搜索(DFS)实现

操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现(两者等价),用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例: 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

多种风格导航菜单 HTML 实现(附源码)

下面我将为您展示 6 种不同风格的导航菜单实现&#xff0c;每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...

OpenLayers 分屏对比(地图联动)

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能&#xff0c;和卷帘图层不一样的是&#xff0c;分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习

禁止商业或二改转载&#xff0c;仅供自学使用&#xff0c;侵权必究&#xff0c;如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

Java线上CPU飙高问题排查全指南

一、引言 在Java应用的线上运行环境中&#xff0c;CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时&#xff0c;通常会导致应用响应缓慢&#xff0c;甚至服务不可用&#xff0c;严重影响用户体验和业务运行。因此&#xff0c;掌握一套科学有效的CPU飙高问题排查方法&…...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码

目录 一、&#x1f468;‍&#x1f393;网站题目 二、✍️网站描述 三、&#x1f4da;网站介绍 四、&#x1f310;网站效果 五、&#x1fa93; 代码实现 &#x1f9f1;HTML 六、&#x1f947; 如何让学习不再盲目 七、&#x1f381;更多干货 一、&#x1f468;‍&#x1f…...

uniapp 字符包含的相关方法

在uniapp中&#xff0c;如果你想检查一个字符串是否包含另一个子字符串&#xff0c;你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的&#xff0c;但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...