Android 系统源码项目加载预编好的so库

news2024/9/23 13:30:28

Android 系统源码项目加载预编好的so库

文章目录

  • Android 系统源码项目加载预编好的so库
    • 一、前言
    • 二、源码中加载so
      • 1、Android.mk加载so
        • 加载so的主要相关代码:
      • 2、Android.bp加载so
        • (1)Android.mk使用源码命令编译成Android.bp
        • (2)Android.bp
        • Android.bp 不用编译so并进行读取so解决方法:
    • 三、其他
      • 1、系统源码加载编译so小结
      • 2、Android.mk中可以执行 PRODUCT_COPY_FILES 吗?
      • 3、mk 添加编译androidx相关包报错解决
      • 4、Android.mk 在源码中执行执行转换成Android.bp

一、前言

Android 系统开发中会源代码有加载so库的情况,本文进行简单介绍。

Android Studio 项目加载so库,已经有介绍过:

https://blog.csdn.net/wenzhi20102321/article/details/137080360

Android Studio加载so和使用so还是比较方便的,环境OK的情况,几分钟就可以完成验证测试了。

但是如果要在系统源代码Java里面加载和使用so就比较麻烦了,

主要通过Android.mk或者Android.bp编译加载so,反正网上的代码写的mk/bp基本都是不行的。

本来以为只是介绍一下编译使用的Android.mk或者Android.bp就可以了,

但是事实有点出乎意料,总结下来发现收获了一些知识点;

所以这个很有必要进行总结一下。有兴趣的可以看看。

普通应用开发不一定用到这个知识,但是系统编译开发会用到这个知识,并且有的相关文件还不好解决。

本文最后还有一些源码编译apk相关知识的总结,还是比较有用的。可以点赞收藏。

二、源码中加载so

源码中加载so,首选是Android.mk,因为Android.bp 未完善,会有bug。

1、准备源码

这里准备的源码和Android Studio 加载so的源码是一模一样的,
只是在app同级目录下加一个Android.mk 或者Android.bp。

1、Android.mk加载so

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := JniLoadso

LOCAL_MODULE_TAGS := optional
LOCAL_CERTIFICATE := platform
LOCAL_PRIVATE_PLATFORM_APIS := true
#生成到system/priv-app目录
LOCAL_PRIVILEGED_MODULE := true

LOCAL_DEX_PREOPT := false

LOCAL_MANIFEST_FILE := \
   app/src/main/AndroidManifest.xml
        
LOCAL_SRC_FILES := \
            $(call all-java-files-under,app/src/main/java/) \

LOCAL_RESOURCE_DIR := \
    $(LOCAL_PATH)/app/src/main/res

LOCAL_PREBUILT_JNI_LIBS:= \
    app/jni/arm64-v8a/libnative-lib.so
#这样加没用!!不知为啥
#LOCAL_SHARED_LIBRARIES := libnative-lib

LOCAL_STATIC_ANDROID_LIBRARIES := \
    androidx.recyclerview_recyclerview \
    com.google.android.material_material

LOCAL_STATIC_JAVA_LIBRARIES := \
    androidx.appcompat_appcompat \
    androidx-constraintlayout_constraintlayout

include $(BUILD_PACKAGE)

include $(CLEAR_VARS)
LOCAL_MODULE := libnative-lib
LOCAL_SRC_FILES := app/jni/arm64-v8a/libnative-lib.so
include $(PREBUILT_SHARED_LIBRARY)

上面加了Androidx的包,需要在AndroidManifest.xml进行适配修改一下否则会编译报错。具体如何适配最后有说明;Android13或者Android14 源码编译会有这个问题。

这里的Android.mk 直接放在app同级目录下面就行,

我不喜欢放两个Android.mk的处理,实际上很多源码应用是这样处理的:
app同级目录下放一个声明链接的Android.mk,app/src/main/ 下面也放一个实际起作用的Android.mk;

加载so的主要相关代码:
LOCAL_PREBUILT_JNI_LIBS:= \
    app/jni/arm64-v8a/libnative-lib.so
#这样加没用!!不知为啥
#LOCAL_SHARED_LIBRARIES := libnative-lib

include $(CLEAR_VARS)
LOCAL_MODULE := libnative-lib
LOCAL_SRC_FILES := app/jni/arm64-v8a/libnative-lib.so
include $(PREBUILT_SHARED_LIBRARY)

上面和so相关就就LOCAL_PREBUILT_JNI_LIBS这一行代码,其他的编译命令和编译普通Java代码项目是一样的。

加入这个后,系统会在apk的同级目录下生成so文件。

后续有尝试去除 PREBUILT_SHARED_LIBRARY ,其实也是可以生成so在lib目录的。

所以主要作用的文件就是:

LOCAL_PREBUILT_JNI_LIBS:= \
    app/jni/arm64-v8a/libnative-lib.so

out目录生成后的so文件,如下图所示:

在这里插入图片描述

整编整个大包,烧录到系统,这个so就会在运行的Android设备apk的lib目录下。具体情况:

rk3588_t:/system/priv-app/JniLoadso #
rk3588_t:/system/priv-app/JniLoadso # ls
JniLoadso.apk  lib  oat
rk3588_t:/system/priv-app/JniLoadso # ls lib/arm64/
libnative-lib.so
rk3588_t:/system/priv-app/JniLoadso #

app应用运行后是可以正常读取到so库的。

2、Android.bp加载so

Android.bp 如何编写?

其实系统源码中有个android.go 文件是写了Android.mk和Android.bp所有对于属性的转换关系的。

但是并不是所有的标签都能转换。估计是实现了比较常用的大部分功能。

(1)Android.mk使用源码命令编译成Android.bp

源码中如何实现转换的,最后有链接,有兴趣的可以看看。

通过转换后获取到Android.bp:

android_app {
    name: "JniLoadso",

    certificate: "platform",
    platform_apis: true,
    //生成到system/priv-app目录
    privileged: true,

    dex_preopt: {
        enabled: false,
    },

    manifest: "app/src/main/AndroidManifest.xml",

    srcs: ["app/src/main/java//**/*.java"],

    resource_dirs: ["app/src/main/res"],

    // ANDROIDMK TRANSLATION ERROR: unsupported assignment to LOCAL_PREBUILT_JNI_LIBS
    // LOCAL_PREBUILT_JNI_LIBS := app/jni/arm64-v8a/libnative-lib.so

    //这样加没用!!不知为啥
    //LOCAL_SHARED_LIBRARIES := libnative-lib

    static_libs: [
        "androidx.recyclerview_recyclerview",
        "com.google.android.material_material",
        "androidx.appcompat_appcompat",
        "androidx-constraintlayout_constraintlayout",
    ],

}

// ANDROIDMK TRANSLATION ERROR: unsupported include
// include $(PREBUILT_SHARED_LIBRARY)

虽然生成了Android.bp但是最后提示有ERROR,并且LOCAL_PREBUILT_JNI_LIBS指令是无法转换的。

所以Android使用源码命令转换Android.mk,在一些特殊的模块处理上是有问题的,比如so加载就有问题。

并且在mk和bp转换的关系源码android.go中也是未找到 LOCAL_PREBUILT_JNI_LIBS 的转换关系;

所以这个是目前Android14 也无法解决的问题;使用Android.bp就是无法编译加载so。

但是上面的Android.bp 是可以正常编译出apk的,只是编译出的out目录apk中未生成lib目录。

所以Android.bp 没法编译加载so项目吗,其实不是。

因为在源码中这样编译so项目是没问题的。但是要多做一些操作。往后看看吧。

(2)Android.bp

有用部分的源码:

android_app {

    name: "JniLoadso",
    platform_apis: true,
    certificate: "platform",

    optimize: {
        proguard_flags_files: ["app/src/main/proguard.flags"],
    },

    privileged: true,

    static_libs: [
        "androidx.appcompat_appcompat",
        "androidx-constraintlayout_constraintlayout",
        "androidx.annotation_annotation",
        "com.google.android.material_material",
        "androidx-constraintlayout_constraintlayout",
        "androidx.recyclerview_recyclerview",
    ],

    manifest: "app/src/main/AndroidManifest.xml",

    srcs: ["app/src/main/java/**/*.java",
     ],

    resource_dirs: ["app/src/main/res"],

}

这样编译后运行的设备中未包含 JniLoadso 应用需要的so,那么点击运行应用肯定会报错的,怎么解决?

Android.bp 不用编译so并进行读取so解决方法:
1、Android 系统编译源码应用可以读取系统so;
如果apk应用是64位的(目前99%应用都是64位的),那么系统可以读取到system/lib64下面的so;
2、如果是限制单个应用使用,可以通过脚本把so放到运行环境的apk的lib/arm64/目录下;
3、apk优先是读取自己目录下的lib,如果没有就读取系统下的 system/lib64的so
这是亲自测试验证过的,两个地方只有一个地方有就可以正常读取到。

其实如何读取不用我们管,系统会实现;

具体要管的就是系统运行环境有没有放入so文件,有就可以读取到,没有就会报错。

系统编译的app应用代码中只要定义了加载so

    static {
        System.loadLibrary("native-lib");
    }

那如果运行环境中如果存在so就没有问题。

原因和思路找到了,源码里面怎么写这个脚本呢?

1、复制文件到system/lib64

PRODUCT_COPY_FILES += device/copyfile/libnative-lib.so:$(TARGET_COPY_OUT_SYSTEM)/lib64/libnative-lib.so

//PRODUCT_COPY_FILES 目录是以release目录为基准的;
//copyfile 这个文件夹是自己添加的,自定义的,可以根据自己情况设置。

2、复制文件到某个apk的目录下:
PRODUCT_COPY_FILES += device/copyfile/libnative-lib.so:$(TARGET_COPY_OUT_SYSTEM)/priv-app/JniLoadso/lib/arm64/libnative-lib.so

PRODUCT_COPY_FILES 指令,相信很多搞过系统源码都是知道的,这个就是复制文件的;

在device下的某个mk文件都有这个指令,在device目录其中一个起作用的写入上面的指令就可以。

正常情况下,写了上面指令,系统源码编译后就会在out目录下生成so文件,

比如写了第一条指令,就会在out/target/XXX…/system/lib64 看到 libnative-lib.so 文件。

三、其他

1、系统源码加载编译so小结

(1) Android.mk 中可以使用 LOCAL_PREBUILT_JNI_LIBS指令复制so到编译的XXXapk/lib/arm64/目录下;
(2) Android.bp 没有指令复制so到编译的apk目录下;
(3) Android 系统编译源码应用可以读取系统so和apk目录下的lib/arm64/的so文件
(4) 如果是使用Android.bp编译so项目,
必须要写脚本命令复制so到system/lib64 或者复制到apk的ib/arm64/
(5) 如果是使用Android.mk编译so项目,
即可使用LOCAL_PREBUILT_JNI_LIBS指令复制so,也可以在另外的mk文件使用脚本复制so文件到system/lib64 或者复制到apk的ib/arm64/
(6) 如果是单个应用使用的so,使用复制脚本命令把so文件复制到到apk的ib/arm64/就可以;
	 如果是多个应用使用到的so,使用复制脚本命令把so文件复制到到system/lib64/比较好。

其实那些编译apk的指令都是差不多的,很多网上搜索到不可用的指令,参考系统源码其他apk编译的就可以;

最重要的是学习到了系统中编译源码apk 会读取 apk的ib/arm64/或者system/lib64 下面的so;

加载so一定是以so文件名称作为唯一标识的,如果so文件名称不对是读取不到的;

Java代码中读取so:

    static {
        System.loadLibrary("native-lib");
    }

那么so的名称一定要设置成 libnative-lib.so(native-lib.so是不行的),也就是说前面加lib,后面加.so,就是so文件的命名。

2、Android.mk中可以执行 PRODUCT_COPY_FILES 吗?

很多人可能没试过,不确定有没有作用。

我之前也么试过,今天特意试了一下,确实不行。

Android.mk中可以执行 PRODUCT_COPY_FILES 会报错:

FAILED: 
In file included from build/make/core/prebuilt.mk:53:
packages/SkgApps/JniLoadso/Android.mk:36: error: cannot assign to readonly variable: PRODUCT_COPY_FILES

其实想一下就知道了,Android.mk里面应该是执行有限的指令和标签的;

在android.go里面确实是没有这个 PRODUCT_COPY_FILES 指令的。

3、mk 添加编译androidx相关包报错解决

AndroidManifest.xml.fixed 的分析处理:

https://blog.csdn.net/wenzhi20102321/article/details/138334484

4、Android.mk 在源码中执行执行转换成Android.bp

Android.mk和Android.bp的区别和转换详解:

https://blog.csdn.net/wenzhi20102321/article/details/135704801

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2110899.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java灰度发布

有没有在北京面试java的小伙伴,每家公司面试问的问题都不一样,昨天面试官问到了灰度发布,一脸懵,好像在哪儿听说过,毕竟我都没发布过,之前都是项目组长在干这些事儿,所以聊聊,了解一…

驾驭Autofac,ASP.NET WebApi实现依赖注入详细步骤总结

前言 嘿,小伙伴们,今天我们来一场 Autofac 的学习之旅吧! Autofac 是一个轻量级的依赖注入框架,专门为 .NET 应用程序量身定做,它就像是你代码中的 “魔法师”,用它来管理对象的生命周期,让你…

828华为云征文|华为云Flexus X实例docker部署最新gitlab社区版,搭建自己的私人代码仓库

828华为云征文|华为云Flexus X实例docker部署最新gitlab社区版,搭建自己的私人代码仓库 华为云最近正在举办828 B2B企业节,Flexus X实例的促销力度非常大,特别适合那些对算力性能有高要求的小伙伴。如果你有自建MySQL、Redis、Ng…

大数据采集迁移工具

Flume Sqoop kafka框架 MQ:消息队列 broker相当于服务器 消息队列

栈和队列(1)

空栈先移动栈顶再加数据,满栈先插入数据再移 栈的基本概念栈是一种后进先出(LIFO,Last In First Out)的数据结构。栈支持两种主要的操作:•压栈(Push):向栈中添加一个元素。•弹栈&…

Kubernetes v1.28.0安装详解

Kubernetes v1.28.0安装详解 一.环境初始化 要在所有节点执行命令进行配置 1、检查操作系统的版本 此部署环境为CentOS 7.9 [rootCentOS7 ~]# cat /etc/redhat-release CentOS Linux release 7.9.2009 (Core) [rootCentOS7 ~]#2、主机名解析 为了方便集群节点间的互相调…

活动系统开发之采用设计模式与非设计模式的区别-数据库设计及代码设计

1、数据库ER图 2、应用框架选用 PHP语言对应的thinkphp6.1应用框架 3、功能代码设计(后端) a、父类Base.php i:控制登录,只能登录后管理员才能操作; ii:控制按钮权限,管理员不仅要登录,且必须要有对应菜单…

报错处理:超过Uobject最大数量

处理方式 一、打包时项目中设置游戏中UObject的最大数量为100000000 二、打包后的配置文件中设置 打包路径: 一厅统管\Windows\YZ_YTTG\Saved\Config\Windows\Engine.ini文件下添加配置文件 [/Script/Engine.GarbageCollectionSettings] gc.MaxObjectsInEditor1000…

API 网关 OpenID Connect 实战:单点登录(SSO)如此简单

作者:戴靖泽,阿里云 API 网关研发,Higress 开源社区 Member 前言 随着企业的发展,所使用的系统数量逐渐增多,用户在使用不同系统时需要频繁登录,导致用户体验较差。单点登录(Single Sign-On&a…

2024最新!Facebook手机版和网页版改名教程!

Facebook作为全球最大的社交平台之一,允许用户自定义名字和昵称。在Facebook更新姓名可以帮助您更好的展现账号形象。本文将为您提供详细的步骤指导,帮助您在手机APP和网页版上轻松完成Facebook改名操作。 Facebook手机版改名 打开Facebook APP并登录账号…

区块链ARC如何能让节点能够大规模处理交易数据

​​发表时间:2024年8月7日 TAAL技术主管Michael Bckli表示,TAAL公司一直在对ARC进行测试,并准备在今年年底全面发布。因TAAL在区块链交易处理方面具备深厚的专业知识,BSV区块链委托TAAL进行ARC开源参考落地方案的开发。 ARC是一个…

魔珐科技受邀参与外滩大会:以3D数字人AIGC产品赋能大资管行业,重塑金融服务边界

在人工智能浪潮的推动下,金融行业正经历着前所未有的场景革命。2024年Inclusion外滩大会作为行业交流的盛会,汇聚了众多学者、专家及企业领袖,共同探讨AI技术在多领域的深度应用,特别是其在金融行业中的革新潜力。 在外滩大会上&…

在桌面商业分析应用程序中启用高级 Web UI

挑战 Mercur Business Control 应用程序在企业界,尤其是金融领域,拥有悠久的应用历史。它帮助企业处理、可视化和分析海量数据,从而做出明智的商业决策。 随着产品的不断演进和现代化,Mercur Solutions AB 为该应用创建了 Web 客…

使用RestTemplate获取国内大盘股票数据的基本信息并存入数据库中

目录 使用RestTemplate获取国内大盘股票数据的基本信息并存入数据库中 第一步:导入RestTemplate依赖,并配置RestTemplate让其加入到SpringIoC容器中 第二步:在yml文件定义股票的相关参数 第三步:向新浪网发送请求,获…

FP7195:非同步升压恒流LED区动IC

前言:LED驱动芯片是什么? LED驱动芯片是一种能够将电源的电压和电流转换为适合LED(发光二极管)使用的电压和电流的芯片。这种芯片的主要作用是控制LED的亮度和电流,从而保证LED的正常工作和长寿命。简单来说&#xff…

【C++二分查找】1802. 有界数组中指定下标处的最大值

本文涉及的基础知识点 C二分查找 LeetCode 1802. 有界数组中指定下标处的最大值 给你三个正整数 n、index 和 maxSum 。你需要构造一个同时满足下述所有条件的数组 nums(下标 从 0 开始 计数): nums.length n nums[i] 是 正整数 &#xf…

Vue组件:使用$emit()方法监听子组件事件

1、监听自定义事件 父组件通过使用 Prop 为子组件传递数据,但如果子组件要把数据传递回去,就需要使用自定义事件来实现。父组件可以通过 v-on 指令(简写形式“”)监听子组件实例的自定义事件,而子组件可以通过调用内建…

Ollama Qwen2 支持 Function Calling

默认 Ollama 中的 Qwen2 模型不支持 Function Calling,使用默认 Qwen2,Ollama 会报错。本文将根据官方模板对 ChatTemplate 进行改进,使得Qwen2 支持 Tools,支持函数调用。 Ollama 会检查对话模板中是否存在 Tools,如…

wlanapi.dll丢失怎么办?有没有什么靠谱的修复wlanapi.dll方法

在遇到各种系统文件错误当中,其中之一就是“wlanapi.dll文件丢失”的问题。这种问题通常发生在Windows操作系统上,特别是当系统试图执行与无线网络相关的任务时。wlanapi.dll是一个重要的系统文件,它负责处理Windows无线网络服务的许多功能。…

一种非接触式智能垃圾桶设计(论文+源码+实物)

1系统方案设计 通过对需求展开分析,本设计非接触式智能垃圾桶采用STM32F103单片机作为控制器,通过红外传感器实现垃圾桶的满溢检测,通过三个SG90舵机分别控制可回收、不可回收、其他垃圾桶盖的开关,并通过WiFi通信模块将数据信息…