- 博客(310)
- 收藏
- 关注
原创 SElinux策略文件配置
上面导入的是build/make/target/board/emulator_x86_64/BoardConfig.mk,于是需要在这个文件中配置sepolicy所在的路径,这样系统可以将其加入编译到selinux_policy。因为切换进程域的时候,如果是由shell指令去切换,将切换成对应的sedemo_dt这个域,sedemo_dt_exec是类型。经过前面的一大堆理论的学习,我们知道,还需要编写相关的规则文件,才能通过 SElinux 的检测。切换,上下文标签已经是我们定义的了。
2025-12-13 01:17:12
395
原创 Selinux权限的检测
当主体要真正去访问客体资源的时候,会去触发安全的认证的检测过程,比如说它有对应的权限,放行,如果没对应的权限,就访问失败,问题是,由谁来监控权限的合法性工作?,这个监控是谁来做的,其实也是安全服务SecurityServer来处理,需要由linux内核LSM的支持, 翻译过来是Linux Secrity Module的简称, 它是内核的一个子系统,有一个概念前提大家要了解:所有定义的标签和规则,最终都会被写入到linux内核中。涉及策略规则的编译过程。
2025-12-12 22:47:23
227
原创 Selinux Context上下文
那么问题来了,现在所有的标签都已经准备好了,有file_contexts, genfs_contexts,service_contexts,seapp_contexts,property_contexts,也清楚 我们需要对每个客体所需要的标签是在对应的context_file文件中进行标签的定义,但这只是定义性的。在安卓系统中,一般是通过一些SecurityServer进程,如init进程(但不仅仅只有它), 它可以将上下文标签中的定义,给对应的文件打上标签(上图中也包含了打标签的过程)。
2025-12-12 22:43:06
355
原创 SELinux理论基础
APK->JNI->底层驱动(app操作设备驱点,read, write),可能会遇到权限问题,打开不了,不能读,不能写等问题, 但是在以前早期的版本,可能对节点chmod a+x /dev/xxx 进行权限的设置,就能访问了。但是:开机启动中,根据rc文件提供的启动信息, 会启动一些后台进程,可以在进程对应的rc文件中配置让进程开机启动,但是有可能跑不起来, 如果没有配置selinux相关的策略的话,这是因为app运行的时候,检测安全环境。SELinux (MAC) - 像严格管理的军事图书馆。
2025-12-12 22:39:20
602
原创 SELinux 介绍
SEAndroid 是 SELinux(Security-Enhanced Linux) 在 Android 系统中的实现,SELinux 是一个强制访问控制(MAC)系统,SEAndroid 将其引入以加强 Android 的安全性,主要通过限制应用和系统组件的权限范围,减少安全漏洞被利用的可能性。报错意思是:/vendor 分区在运行的 Android 系统中是只读的,重新挂载 /vendor 为可读写即可。这段代码,看起来应该是没啥难度,对 dev 文件下面的 sedemo_dev 进行写入一句话。
2025-12-12 22:26:56
203
原创 aosp系统中构建编译添加安卓app
通过 AOSP 构建的 APK 通常会被视为系统应用,具有系统应用的权限,甚至是特权。如果你在 AOSP 中使用 Android.mk 编译了 App 并将其放置在系统的分区中(如 /system/app 或 /system/priv-app),该 App 就会被当作系统应用。如果你不希望它成为系统应用,可以通过其他方式安装该 APK,例如通过 adb install 安装到用户空间。
2025-12-06 14:00:27
813
原创 Android 编译脚本 mk & bp
在android 的高版本,13,14,谷歌其实是比较推荐我们使用bp 文件来进行编译,但是旧版本的业务还是存在的,所以需要两者都掌握。Android.mk 中除了编译库文件外,还可以编译可执行文件。静态库使用 include $(BUILD_STATIC_LIBRARY),动态库使用 include $(BUILD_SHARED_LIBRARY)。Android.mk 文件是 Android 构建系统中定义编译规则的配置文件,主要用于描述哪些源文件需要编译,以及如何编译它们。定义可执行文件模块。
2025-12-06 12:36:53
854
原创 Android镜像、分区及其烧录
boot.img-> boot 分区:启动镜像,包含内核和启动引导程序。system.img -> system 分区:系统镜像,包含 Android 系统的核心组件和系统应用。vendor.img-> vendor 分区:供应商镜像,包含设备厂商提供的硬件相关库和驱动。recovery.img -> recovery 分区:恢复镜像,提供系统恢复功能,允许重置和更新系统。userdata.img-> userdata 分区:用户数据镜像,包含用户的应用和数据文件。
2025-12-05 23:33:40
1001
原创 android 有哪些常用的编译命令?
什么是模块的名称:android.mk或android.bp文件中要编译出来的对象的名称C++库:静态库libxxx.a 动态库libxxx.soJava库:***.jarC++可执行程序:JAVA app:编译模块的两种方式:make 模块名mmm 模块名所在的路径。
2025-12-05 22:39:57
246
原创 AOSP 源码阅读工具 ---vim (vim 也能很有趣)
建立索引 ctags -R查看某个文件 find . -name "PackageManagerService.java"跳转 ctrl + ]返回 ctrl + t查看文件 ctrl + f回到前一个文件 shift + : 输入bp列出当前文件所在的目录 F9当然啦,有人会说可以通过vscode 的ssh 连接到源码的服务器,但是vscode 本身建立索引就慢,再加上网络,那就更慢了,有时候搜索某个函数,需要等一小时以上(工作中深有体会)。。。。Android studio 同理。
2025-12-05 22:10:10
278
原创 电脑环境要求 && 源码下载 && 编译
总的来说,在 repo sync -c --no-tags --prune -j 4 命令中,使用 -c 和 --no-tags 选项可以减少需要同步的内容,从而减少要占用的本地代码空间,也可以减少一些同步时间。通俗理解是,Mem 消耗完之后,swap 能帮你硬抗,不至于终端闪退,没有调整之前,swap 是2G, 个人测试,发现,一共需要50G 左右才能满足 aosp 的编译。然后make -j12 进入编译,会进入较长时间的等待,我的电脑花了两个多小时,出现下面的输出代表编译成功了。
2025-11-30 18:34:32
975
原创 Android 系统常识 && 和Linux 的比较
本文对比了Android与Linux操作系统的异同。两者虽然基于相同的Linux内核,但在架构设计上存在显著差异:Linux采用模块化设计,强调通用性;Android则针对移动设备优化,增加了硬件抽象层和运行时环境。在应用层方面,Linux依赖系统调用和glibc,而Android基于Java/ART虚拟机运行应用。文件系统方面,Android采用分区挂载和沙盒机制,而Linux支持多种文件系统。安全机制上,Android在Linux基础上增加了应用沙盒和权限管理。应用场景方面,Linux适用于服务器/嵌入
2025-11-30 17:47:43
988
原创 第三章_布莱叶盲文与二进制
这里你可能会想:为什么不直接用三进制、十进制?电路简单:两种状态更容易识别和稳定。容错性高:噪声环境下,区分“有/无”比区分更多层次更可靠。组合能力强:别看只有 0 和 1,但一旦组合,就能表示几乎无限的内容。换句话说,二进制就是最低成本、最高效率的方案。第三章通过布莱叶盲文的故事,让我们直观理解了二进制编码的思想。两种状态就能表示信息。通过组合,可以无限扩展。这就是计算机的底层逻辑。**读完这章我的感受:**复杂的世界往往可以用最简单的方式来描述。
2025-08-30 17:21:13
180
原创 第二章_编码与组合
摘要: 莫尔斯电码用简单的“点”和“划”两个符号,通过组合与指数规律(如2个符号表达4种信息)实现复杂编码。分隔符号(停顿)赋予结构意义,解决信息混乱问题。本章揭示:1. 简单符号通过组合可表达无限信息;2. 数学是编码基础;3. 结构决定信息有效性。编码的本质是以有限表达无限,展现基础符号的强大潜力。(148字)
2025-08-30 17:14:12
357
原创 第一章_之亲密友
《编码》第一章从人类原始沟通方式入手,揭示信息传递的本质是"信号+约定"。通过手电筒闪灯等简单例子,说明复杂信息可由基本符号组合表达。关键在于状态区分和规则建立,这与计算机0/1状态的原理相通。本章虽未直接讨论二进制,却为理解计算机编码奠定了思维基础——简单规则能创造无限可能,这正是从原始沟通到数字世界的演化逻辑。
2025-08-26 22:03:48
208
原创 内核-mmap
ARM 架构支持一级页表映射,也就是说 MMU 根据 CPU 发来的虚拟地址可以找到第 1 个页表,从第 1 个页表里就可以知道这个虚拟地址对应的物理地址。一级页表里地址映射的最小单位是 1M。ARM 架构还支持二级页表映射,也就是说 MMU 根据 CPU 发来的虚拟地址先找到第 1 个页表,从第 1 个页表里就可以知道第 2 级页表在哪里;再取出第 2级页表,从第 2 个页表里才能确定这个虚拟地址对应的物理地址。二级页表地址映射的最小单位有 4K、 1K, Linux使用 4K。
2024-08-13 22:53:25
983
1
原创 中断的线程化处理
内核中有一个struct irq_desc结构体数组,有一个属性是struct irqaction* action,这个结构体中有一个属性irq_handler_t thread_fn,就对应的是request_threaded_irq函数中的thread_fn;内核线程被唤醒后,执行thread_fn函数可能有程序在等待thread_fn函数被执行,调用wake_threads_waitq(desc)来唤醒它。上半部用来处理紧急的事情,下半部用一个内核线程来处理,这个内核线程专用于这个中断。
2024-08-13 22:16:23
1168
原创 内核工作队列
参考内核头文件structstruct0第1个宏是用来定义一个结构体,要指定它的函数。第2个宏用来定义一个结构体,也要指定它的函数。所以delayed,意思就是说要让它运行时,可以指定:某段时间之后再执行。如果要在代码中初始化0。
2024-08-12 23:26:10
1106
原创 中断下半部 tasklet
当发生某一个硬件中断时,内核会调用对应的硬件中断处理函数,处理完之后,会去处理软件中断;从类似soft数组中取出action函数,对于lastlet这种软件中断,对应的函数是tasklet_action,这个函数会从某个队列/链表里取出每一个tasklet结构体,执行里面的函数。可以看到,发生 2 次硬件中断 A 时,它的上半部代码执行了 2 次,但是下半部代码只执行了一次。在第⑦步里,它会去执行中断 A 的下半部,也会去执行中断 B 的下半部。所以,同一个中断的上半部、下半部,在执行时是多对一的关系。
2024-08-12 22:31:18
1018
原创 定时器的使用
这表示内核每秒中会发生 100 次系统滴答中断(tick),这就像人类的心跳一样,这是 Linux 系统的心跳。所谓定时器,就是闹钟,时间到后你就要做某些事。核心在于:在 GPIO 中断中并不立刻记录按键值,而是修改定时器超时时间,10ms 后再处理。按下或松开一个按键,它的 GPIO 电平会反复变化,最后才稳定。如果不处理抖动的话,用户只操作一次按键,中断程序可能会上报多个数据。显然第 1 种方法太耗时,违背“中断要尽快处理”的原则,你的系统会很卡。在内核中使用定时器很简单,涉及这些函数(参考内核源码。
2024-08-11 23:00:19
1054
原创 阻塞与非阻塞
从驱动代码也可以看出来,当 APP 打开某个驱动时,在内核中会有一个struct file 结构体对应这个驱动,这个结构体中有 f_flags,就是打开文件时的标记位;也可以清除这个位表示阻塞。使用 poll 时,可以设置超时时间为 0,这样即使没有数据它也会立刻返回,这就是非阻塞方式。APP 调用open函数时,传入O_NONBLOCK,就表示要使用非阻塞方式;使用 poll 时,如果传入的超时时间不为 0,这种访问方法也是阻塞的。先输出-1,因为没有中断(此时是非阻塞),10次之后是阻塞的。
2024-08-11 18:05:51
526
原创 异步通知机制
写信号处理函数in val;注册信号处理函数// 3注册信号处理函数打开文件把APP的pid告诉驱动程序;读取驱动程序flag并设置FASYNC位为1。
2024-08-11 17:41:55
1110
原创 POLL机制的内核代码详解
即 table->pt->qproc = __pollwait, __pollwait 将在驱动的 poll 函数里用到。当执行完①之后,在⑥或⑦处, pt->_qproc 被设置为 NULL,所以第二次调用驱动程序的 poll 时,不会再次把线程放入某个队列里。是一个宏,它定义于 include/linux/syscalls.h,展开后就有 sys_poll 函数。沿着②③④⑤,你可以看到:驱动程序里的poll_wait会调用__pollwait 函数把线程放入某个队列。,他们对应的内核函数都是。
2024-08-11 12:25:05
868
原创 POLL机制
POLL方式:妈妈要干很多活,但是可以陪小孩睡一会,定个闹钟要浪费点时间,但是可以继续干活。使用休眠-唤醒的方式等待某个事件发生时,有一个缺点: 等待的时间可能很久。使用 poll 机制时,驱动程序的核心就是提供对应的 drv_poll 函数。⑦ 线程从休眠中被唤醒,继续执行 for 循环,再次调用 drv_poll: drv_poll 返回数据状态;什么都不做,5秒超时,调用两次drv_poll函数(打印两次)。⑥ 在休眠过程中,一直没有按下了按键,超时时间到:内核把这个线程唤醒;后,很有可能会休眠。
2024-08-11 12:17:50
1149
原创 休眠-唤醒
值得注意的是,上面 2个红线部分都属于 APP1 的“上下文”,或者这样说:红线所涉及的代码,都是 APP1调用的。但是按键的中断服务程序,不属于 APP1的“上下文”,这是突如其来的,当中断发生时, APP1正在休眠呢。当按下按键,驱动程序中的中断服务程序被调用,它会记录数据,并唤醒APP1。中剩下的代码,把数据复制回用户空间,返回用户空间。在 APP1的“上下文”,也就是在 APP1的执行过程中,它是可以休眠的。驱动中有数据时,图中红线就是APP1 的执行过程,设计用户态、内核态。
2024-08-10 23:39:04
746
原创 修改设备树及上机操作
哎呀,好像不对,需要的是,按下是1,松开是0,重新在驱动文件中设置。我们只需要指定GPIO信息,表示使用哪个GPIO即可。这里没问题,如果不是/boot分区,重新挂载。把编译出来的设备树文件拷贝到/boot目录下。安装驱动,按按键测试,按下是0,松开是1。使用前面编译出来的驱动。测试,按下1,松开0。
2024-08-10 22:20:16
732
原创 编写使用中断的按键驱动程序
而这些基础知识是更复杂的驱动程序的基础要素,以后的复杂驱动程序也就是对硬件操作的封装不同罢了,但是要用到的基础编程是一样的。还是建议从头写按键驱动,特别是如何使用中断。查看原理图确定按键使用的引脚,再在设备树中添加节点,在节点中指定中断信息。对于GPIO 按键,我们并不需要去写驱动程序,使用内核自带的驱动程序。休眠-唤醒、POLL机制、异步通知、定时器、中断的线程化处理。就可以了,然后你需要做的只是修改设备树指定引脚及按键值。
2024-08-10 16:46:08
235
原创 在设备树中指定中断_在代码中获得中断
对于SPI设备节点, SPI总线驱动在处理设备树里的 SPI 子节点时,也会处理其中的中断信息。假设GPIO1有32 个中断源,但是它把其中的16个汇聚起来向GIC发出一个中断,把另外16个汇聚起来向GIC发出另一个中断。如果中断控制器有级联关系,下级的中断控制器还需要表明它的“interrupt-parent”是谁,用了interrupt-parent ” 中的哪一个“ interrupts”。一个外设,它的中断信号接到哪个“中断控制器”的哪个“中断引脚”,这个中断的触发方式是怎样的?
2024-08-10 14:33:32
1018
原创 Linux 中断系统中的重要数据结构
比如GPIO控制器里有第1号中断,UART模块里也有第1号中断,这两个“第1号中断”是不一样的,它们属于不同的“域”──irq_domain。假设irq_desc[A].handle_irq是XXX_gpio_irq_handler(XXX 指厂家),这个函数需要读取芯片的 GPIO控制器,细分发生的是哪一个GPIO中断(假设是 B),再去调用irq_desc[B].handle_irq。对于共享中断,比如GPIO中断B,它的中断来源可能有多个,每个中断源对应一个中断处理函数。
2024-08-08 22:49:19
932
原创 Linux 系统对中断处理的演进
很耗时的中断处理,应该放到线程里去可以使用 work,work queue在中断上半部调用 schedule_work 函数,触发 work 的处理既然是在线程中运行,那对应的函数可以休眠。
2024-08-06 22:42:07
995
原创 Linux 系统对中断的处理
在 Linux 中:资源分配的单位是进程,调度的单位是线程, 也就是说,在一个进程里,可能有多个线程,这些线程共用打开的文件句柄、全局变量等等。而这些线程,之间是互相独立的,“同时运行”,也就是说:每一个线程,都有自己的栈。可以,但是开销太大:读按键的程序,要把按键通知播放音乐的程序,进程间通信的效率没那么高。从上图可知, CPU内部的寄存器很重要,如果要暂停一个程序,中断一个程序,就需要把这些寄存器的值保存下来:这就称为保存现场。这样,按键的读取及 GUI 显示、音乐的播放,可以分开来,不必混杂在一起。
2024-08-05 22:45:15
1048
原创 异常与中断的概念及处理流程
但是表中的各个异常向量的偏移地址,是固定的:复位向量偏移地址是 0,中断是 0x18。在主程序运行过程中,出现了特定的中断触发条件(中断源),使得CPU 暂停在当前正在运行的程序,转而去处理中断程序,处理完成后又返回原来被暂停的位置继续运行。当一个中断程序正在运行时,又有新的更高优先级的中断源申请中断,CPU 再次暂停当前中断程序,转而去处理新的中断程序,处理完成后以此进行返回。在向量表里,一般都是放置一条跳转指令,发生该异常时, CPU 就会执行向量表中的跳转指令,去调用更复杂的函数。
2024-08-05 22:07:19
1329
原创 GPIO 子系统LED驱动程序上机操作
就可以在 GUI 界面中选择引脚,配置它的功能,这就可以自动生成 Pinctrl 的子节点信息。100ASK_IMX6ULL 使用的 LED 原理图如下,可知引脚是。然后把设备树拷贝到开发板的/boot目录下,更新设备树,然后reboot,然后insmod就行了。原来的这个led被用来作为cpu的指示灯;要在设备树文件中搜索出来,然后disable一下。确定引脚并生成设备树节点,NXP 公司对于 IMX6ULL 芯片,有设备树生成工具,安装。对应的设备树代码生成,把自动生成的设备树信息,放到内核源码。
2024-08-02 23:08:40
360
原创 基于 GPIO 子系统的 LED 驱动程序
的地位跟其他模块,比如 I2C、 UART 的地方是一样的,要使用某个引脚,需要先把引脚配置为 GPIO 功能,这要使用 Pinctrl 子系统,只需要在设备树里指定就可以。下面,保存该厂家的文档,如果连文档都没有,那只能参考内核源码中的设备树文件,在内核源码目录。有些芯片提供了设备树生成工具,在GUI 界面中选择引脚功能和配置信息,就可以自动生成。本身需要确定引脚,这也需要在设备树里指定。核心代码是如下,它从该设备(对应设备树中的设备节点)获取名为。,对应的,驱动代码中要注册一个。
2024-08-01 23:08:51
590
原创 GPIO 子系统重要概念
几乎在所有的ARM 芯片中,GPIO 都分为几组,每组若干个引脚,所以在使用GPIO 子系统之前,我们就要确定它是哪组的,组里的哪一个的。的基地址是128,ngpio 是个数,GPIOH是第H 组GPIO ,有时候是一串别的字符串,根据字符在设备树中查找对应的GPIO 组。,这通常都由芯片厂家设置好,我们要做的是找到它的名字,比如gpio1,然后指定要用它里面的那个引脚,比如 。以前我们通过寄存器来操作 GPIO 引脚,即使LED 驱动程序,对于不同的板子它的代码也完全不同。
2024-07-30 22:26:51
1158
原创 GPIO && Pinctrl 子系统
大多数的芯片,没有单独的 IOMUX 模块,引脚的复用、配置等等,就是在GPIO 模块内部实现的。Pinctrl 系统的客户,那就是使用 Pinctrl 系统的设备,使用引脚的设备。现在的芯片动辄几百个引脚,在使用到 GPIO 功能时,让你一个引脚一个引脚去找对应的寄存器,这要疯掉。所以为了更方便驱动工程师的开发,要把引脚的复用、配置抽出来,做成 Pinctrl 子系统,给 GPIO、I2C 等模块使用。比如默认状态下, UART 设备是工作的,那么所用的引脚就要复用为 UART 功能。
2024-07-29 23:21:15
873
原创 查询方式的按键驱动程序_编写框架
对于 LED,APP 调用 open 函数导致驱动程序的 led_open 函数被调用。安装驱动程序后并不意味着会使用对应的硬件,而 APP 要使用对应的硬件,必须先调用 open 函数。APP 继续调用 write 函数传入数值,在驱动程序的 led_write 函数根据该数值去设置 GPIO的数据寄存器,从而控制 GPIO 的输出电平。按键没被按下时,上图中左边的 GPIO 电平为高,右边的 GPIO 电平为低。按键被按下后,上图中左边的 GPIO 电平为低,右边的 GPIO 电平为高。
2024-07-28 22:34:12
325
原创 APP 怎么读取按键值
APP 得到 poll/select 函数的返回结果后,如果确认是有数据的,则再调用 read 函数,这会导致驱动中的 read 函数被调用,这时驱动程序中含有数据,会直接返回数据。APP 调用 fcntl 函数,把驱动程序的 flag 改为 FASYNC,这会导致驱动程序的 fasync 函数被调用,它只是简单记录进程 PID。当用户按下按键时,GPIO 中断被触发,导致驱动程序之前注册的中断服务程序被执行。当用户按下按键时,GPIO 中断被触发,导致驱动程序之前注册的中断服务程序被执行。
2024-07-28 21:38:56
1128
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅