聊一聊binder传递文件fd原理及新版本性能优化

Android春招笔试复盘:Framework与性能优化高频考点深度解析 在Android开发者的技术成长路径中,深入理解系统底层机制与性能调优是突破进阶瓶颈的关键。无论是Zygote进程孵化、Handler消息驱动,还是Binder跨进程通信,这些核心原理共同构成了Android应用稳定运行的基石。在实际工程中,从APK体积瘦身到冷启动耗时优化,从线程池参数配置到内存泄漏治理,每一项技术决策都直接影响用户体验与线上质量。与此同时,掌握Systrace、Perfetto、LeakCanary等工具链,配合对AMS任务栈、LRU缓存并发设计的理解,能帮助开发者系统性地构建知识体系。 阅读详情

背景:

近期有vip学员朋友,问道了一个问题,那就是关于binder跨进程传递fd具体是怎么做到的呢?这块其实binder跨进程传递文件fd,本质的原理的实现在binder驱动中,所以给这个同学找一下相关的binder驱动中的代码,但是发现这块代码还和我以前看过的跨进程传递fd代码有较大的差别了,这个差别还不是简单改变一下方法,而是设计思路上就有变化,所以这里整理一下给大家分享出来。

老版本binder驱动代码传递fd

安卓kernel内核版本:

VERSION = 4
PATCHLEVEL = 4
SUBLEVEL = 302
EXTRAVERSION =

一般在client端调用调用了Parcel.writeFileDescriptor(fd)进行fd传递,接下来跨进程通信会一路调用到binder内核的binder_transaction代码:

static void binder_transaction(struct binder_proc *proc,
			       struct binder_thread *thread,
			       struct binder_transaction_data *tr, int reply,
			       binder_size_t extra_buffers_size)
{
	//省略

		hdr = (struct binder_object_header *)(t->buffer->data + *offp);
		off_min = *offp + object_size;
		switch (hdr->type) {
//省略

//针对binder传递的是fd类型
		case BINDER_TYPE_FD: {
			struct binder_fd_object *fp = to_binder_fd_object(hdr);
			int target_fd = binder_translate_fd(fp->fd, t, thread,
							    in_reply_to);

			fp->pad_binder = 0;
			fp->fd = target_fd;
		} break;

老版本内核处理fd转换:

static int binder_translate_fd(int fd,
			       struct binder_transaction *t,
			       struct binder_thread *thread,
			       struct binder_transaction *in_reply_to)
{
	struct binder_proc *proc = thread->proc;
	struct binder_proc *target_proc = t->to_proc;
	int target_fd;
	struct file *file;
	int ret;

//这个fd的是源进程的,通过fd获取到对应的file结构
	file = fget(fd);
//这里只是安全坚持,file是否可以传递过去
	ret = security_binder_transfer_file(proc->cred, target_proc->cred, file);

//这里会从目标进程中获取没有使用的fd,赋值给target_fd
	target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);
//直接把从目标进程获取的空闲target_fd与file进行绑定
	task_fd_install(target_proc, target_fd, file);
	return target_fd;

}

也看看fget和task_fd_install这两个核心方法:
fget其实是调用到__fget

static struct file *__fget(unsigned int fd, fmode_t mask, unsigned int refs)
{
	struct files_struct *files = current->files;
	struct file *file;

	rcu_read_lock();
loop:
	file = fcheck_files(files, fd);
//省略
	rcu_read_unlock();

	return file;
}

再看看task_fd_install方法:

void __fd_install(struct files_struct *files, unsigned int fd,
		struct file *file)
{
	struct fdtable *fdt;

	might_sleep();
	rcu_read_lock_sched();

	while (unlikely(files->resize_in_progress)) {
		rcu_read_unlock_sched();
		wait_event(files->resize_wait, !files->resize_in_progress);
		rcu_read_lock_sched();
	}
	/* coupled with smp_wmb() in expand_fdtable() */
	smp_rmb();
	fdt = rcu_dereference_sched(files->fdt);
	BUG_ON(fdt->fd[fd] != NULL);
	rcu_assign_pointer(fdt->fd[fd], file);//这里就是源进程file与新进程fd进行了绑定
	rcu_read_unlock_sched();
}

其实老版本的binder传递fd还是比较好理解的,主要就以下几个步骤:
1、根据源进程fd获取内核中对应的file
2、在目标进程中获取空闲没有使用的fd值
3、把第1步获取的file对象与第2步获取的fd值进行绑定既可以

老版本binder驱动的fd传递基本工作都直接在binder_translate_fd这个方法中完成,但是新版本binder驱动这块就有了较大的差异。
总结一个简单图给大家更容易理解:

在这里插入图片描述

新版本binder驱动代码传递fd

安卓kernel内核版本:

VERSION = 6
PATCHLEVEL = 1
SUBLEVEL = 90
EXTRAVERSION =
NAME = Curry Ramen

下面来看看这个6.1对应的源码是怎么传递fd的


static int binder_translate_fd(u32 fd, binder_size_t fd_offset,
			       struct binder_transaction *t,
			       struct binder_thread *thread,
			       struct binder_transaction *in_reply_to)
{
	struct binder_proc *proc = thread->proc;
	struct binder_proc *target_proc = t->to_proc;
	struct binder_txn_fd_fixup *fixup;
	struct file *file;

 //这里也是通过源进程fd获取对应的file结构
	file = fget(fd);
	//检验传递安全性
	ret = security_binder_transfer_file(proc->cred, target_proc->cred, file);
	

	/*
	 * Add fixup record for this transaction. The allocation
	 * of the fd in the target needs to be done from a
	 * target thread.
	 */
	 
	 //以下是差异部分
	//构造出一个binder_txn_fd_fixup结构
	fixup = kzalloc(sizeof(*fixup), GFP_KERNEL);
	//检验传递安全性
	fixup->file = file;//获取file
	fixup->offset = fd_offset;
	fixup->target_fd = -1;//注意这里开始构造时候没有值
	
	//该代码将 fixup 结构体(类型为 binder_txn_fd_fixup)的成员 fixup_entry 
	//添加到事务 t的 fd_fixups 链表尾部,用于‌延迟处理文件描述符(fd)的跨进程映射‌。
	list_add_tail(&fixup->fixup_entry, &t->fd_fixups);

	return ret;
}

上面可以看出与老版本巨大差别在于,新版本根本没有直接在binder_translate_fd中获取target_fd和install target_fd到file,只是构造了binder_txn_fd_fixup对象,赋值file后,然后加入到事物t的fd_fixups列表中。

下面来看看‌binder_txn_fd_fixup 结构体‌
表示一个待处理的 fd 映射修正项,包含以下关键字段:

struct binder_txn_fd_fixup {
    struct file *file;       // 源进程的 file 对象
    binder_size_t offset;    // fd 在事务数据缓冲区中的偏移
    int target_fd;           // 目标进程的 fd(初始为 -1)
    struct list_head fixup_entry; // 链表节点(通过 list_add_tail 链接)
};

上面看完后最大疑问肯定是:
1、没有看到有target_fd在目标进行进行获取啊?
2、也没有看到file与target_fd进行映射?

那么新版本到底是如何通过binder_txn_fd_fixup就可以实现的fd的跨进程传递呢?又为什么要这样做呢?

按照上面源码分析可以看到最后的binder_txn_fd_fixup被放到了传递事物binder_transaction中去了,那么什么时候执行处理这个呢?

目标进程处理事务‌,这里处理事物肯定在目标进程的binder_thread_read时候:

在 binder_thread_read 或事务处理函数中,遍历 t->fd_fixups 链表:

static int binder_thread_read(struct binder_proc *proc,
			      struct binder_thread *thread,
			      binder_uintptr_t binder_buffer, size_t size,
			      binder_size_t *consumed, int non_block)
{
		//省略
		//使用binder_apply_fd_fixups方法来专门处理fd相关
		ret = binder_apply_fd_fixups(proc, t);
		//省略
	return 0;
}

下面看看真正干活的binder_apply_fd_fixups

   /**
 * binder_apply_fd_fixups() - finish fd translation
 * @proc:         binder_proc associated @t->buffer
 * @t:	binder transaction with list of fd fixups
 *
 * Now that we are in the context of the transaction target
 * process, we can allocate and install fds. Process the
 * list of fds to translate and fixup the buffer with the
 * new fds first and only then install the files.
 *
 * If we fail to allocate an fd, skip the install and release
 * any fds that have already been allocated.
 */
static int binder_apply_fd_fixups(struct binder_proc *proc,
				  struct binder_transaction *t)
{
	struct binder_txn_fd_fixup *fixup, *tmp;
	int ret = 0;

	list_for_each_entry(fixup, &t->fd_fixups, fixup_entry) {
	//获取目标进程的空闲fd
		int fd = get_unused_fd_flags(O_CLOEXEC);
		fixup->target_fd = fd;//赋值给target_fd
		if (binder_alloc_copy_to_buffer(&proc->alloc, t->buffer,
						fixup->offset, &fd,
						sizeof(u32))) {
		}
	}
	list_for_each_entry_safe(fixup, tmp, &t->fd_fixups, fixup_entry) {
		//把源file与上面赋值的fixup->target_fd进行关联
		fd_install(fixup->target_fd, fixup->file);
		list_del(&fixup->fixup_entry);
		kfree(fixup);
	}

	return ret;
}

上面源码就很清楚看出来,fd的获取和关联file结构都是在目标进程进行read的时候才操作的,而不是和老版本那样在源进程进行binder_transaction时候做的,那么这样做是基于什么考虑呢?
个人认为有以下几个部分:

‌延迟处理设计‌

原因‌:目标进程的 fd 分配必须在其自身上下文中执行(涉及进程的 fd 表),避免竞态或权限问题。
‌流程‌:
‌收集阶段‌:在源进程的 Binder 线程中,通过 binder_translate_fd 收集所有待映射的 fd,形成 fd_fixups 链表。
‌处理阶段‌:当目标进程的线程处理该事务时,遍历 fd_fixups 链表,为每个 fixup 分配 target_fd,并修改事务数据缓冲区中的 fd 值。

有以下几个优势:
安全性‌
‌权限隔离‌:目标进程自行分配 fd,避免源进程直接操作目标资源。
‌策略检查‌:在 binder_translate_fd 阶段已通过 SELinux 检查(security_binder_transfer_file)。

原子性‌
所有 fd 修正项集中处理,确保事务数据的一致性。

性能优化‌
延迟分配减少上下文切换,结合 Binder 的 mmap 机制实现零拷贝。

文章参考来源:https://mp.weixin.qq.com/s/PabuIBgrX1EPcY0FLWSgGg

更多framework实战开发,关注下面“千里马学框架”

Android IPC 性能对比:ParcelFileDescriptor 与 AIDL Bundle 传输 10MB 数据实测 本文深入对比了Android进程间通信(IPC)中ParcelFileDescriptor与AIDL Bundle在传输10MB数据时的性能表现。实测数据显示,ParcelFileDescriptor通过文件描述符传递机制,成功实现了高效稳定的数据传输,平均耗时仅42.7ms,内存占用降低72%,而传统AIDL Bundle方式则全部失败。文章还提供了ParcelFileDescriptor的进阶应用技巧和优化建议,帮助开发者解决Android大数据传输的常见瓶颈问题。 阅读详情

相关推荐

Android HAL硬件抽象层:从原理到实战开发与调试指南

硬件抽象层(HAL)是操作系统与底层硬件之间的关键中间层,它通过定义标准接口,将硬件具体实现与上层软件解耦。其核心原理在于提供统一的访问接口,使上层应用无需关心底层硬件的具体差异。这一设计在Android系统中具有极高的技术价值,它极大地提升了系统的可移植性、稳定性和可维护性,使得同一套Android框架能够运行在由不同芯片和硬件组成的海量设备上。在应用场景上,HAL广泛应用于摄像头、传感器、音频、显示等所有需要直接操作硬件的模块。本文以Android HAL为例,深入剖析其**Binderized**架构

weixin_34245082的博客 345

Android Binder跨语言通信原理与Native调用Java实践

进程间通信(IPC)是Android系统开发的核心技术之一,其中Binder机制以其高效稳定的特性成为系统级通信的基石。从技术原理看,Binder通过内核驱动实现内存映射,配合独特的线程池模型,能够实现跨进程的远程方法调用(RPC)。在混合开发场景中,Native层通过JNI桥接调用Java服务时,需要特别注意线程附加、引用管理和参数编组等关键技术点。典型的应用场景包括系统服务调用、插件化架构和性能敏感模块开发。通过合理使用Parcel数据容器和Ashmem共享内存,开发者可以优化跨语言调用的性能表现,同时

weixin_33743661的博客 417

Android进程注入技术深度解析与实现

Android 权限系统是 Android 安全模型的重要组成部分,它通过权限机制控制应用对敏感资源的访问,确保系统的安全性与稳定性。Android 权限分为以下几类:权限类别说明正常权限(Normal Permissions)对用户隐私影响较小的权限,如访问网络、控制振动等,安装时自动授予。危险权限(Dangerous Permissions)涉及用户隐私或设备资源的权限,如读写联系人、位置信息等,需在运行时请求用户授权。

weixin_31591833的博客 873

binder传递fd的机制

进程获得的fd是进程fd table中的index, 在fd table中记录了file指针, file对象保留在kernel空间中. 因此不同进程间传递fd本身并没有什么意义. binder通过parcel传递fd的本质, 是将源进程的fd table中对应项指针, 记录到target进程的fd table中. client端add的fd和server端读出的是两个值.

vector03的专栏 3877

【大模型】大模型知识蒸馏 综述解读(Knowledge Distillation of Large Language Models)

知识蒸馏的(论文)方法总结。归纳了通过数据(如指令、对话、多模态)和训练方法(SFT、RL、数据增强),将复杂技能(如对齐、工具使用、多模态)蒸馏到开源模型的核心框架,附典型模型示例(如Alpaca、LLaVA)。

songxia928_928的博客 4339

dell r630 配置raid_DELL服务器RAID配置图文教程

名称解释:Disk Group:磁盘组,这里相当于是阵列,例如配置了一个RAID5,就是一个磁盘组VD(Virtual Disk): 虚拟磁盘,虚拟磁盘可以不使用阵列的全部容量,也就是说一个磁盘组可以分为多个VDPD(Physical Disk): 物理磁盘HS:Hot Spare 热备Mgmt:管理【一】创建逻辑磁盘1、按照屏幕下方的虚拟磁盘管理器提示,在VD Mgmt菜单(可以通过CTRL+P...

weixin_33253741的博客 3510

Android Binder传递文件描述符原理分析

Android Binder传递文件描述符原理分析前言问题描述问题原因 前言 Binder是Android中最常用,最重要的进程间通信机制。我们知道,Binder不仅可以传递普通的数据,还可以传递文件描述符。本文尝试分析Binder传递文件描述符的原理,切入点是工作中遇到一个和文件藐视符相关的问题。本文讲解分析和解决该问题的思路,在分析该问题的过程中,Binder传递文件描述符的原理也会呈现出来。...

昨夜星辰的博客 9368

AD21导出gerber文件

文件–>制造输出–>Gerber Files 文件–>制造输出–>Gerber Files 通用、光圈和高级跟第一步一样 3.文件–>制造输出–>NC Drill Files 这个默认就可以了 主要参考视频来自bilibili添加链接描述 此篇博客主要是写给自己好记的,无其他商业用途 ...

新手小杨 1万+

Android-全面理解Binder原理

一文打通你对Binder通信机制所有疑惑: - 如何理解Binder通信中的 binder实体、handle句柄? - Binder驱动如何维护binder实体和handle的映射? - Binder能够传递多大的数据? - Binder的“一次拷贝”是如何实现的? - client端如何接收到数据? - servicemanager的初始化和app、服务不同? - 进程隔离、IPC通信的介绍与思考。 - 为什么选择 Binder?

深海流浪汉 2175

4.7W防削顶单声道D类音频功率放大器HT6872介绍

HT6872是一款低EMI,防削顶失真,单声道免滤波D类音频功率放大器。在6.5V电源,10%THD+N,4Ω负载条件下,输出4.71W功率,在各类音频终端应用中维持高效率并提供AB类放大器的性能。

weichen_78的博客 4703

SOME/IP协议详解「1.0·概述」

主要讲解什么是someip,

雪云飞星的博客 5368

使用UNIX域套接字传递pipe管道fd进行跨进程读写的一个例子

server: #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/types.h> #include<sys/socket.h> #include<errno.h> #include<sys/un.h> #define SOCK_FILE "./chenxh" //通信的socket文件 int create_local_

qq_34999565的博客 1273

Atlas 300I Duo - vllm部署Qwen3-VL-8B-Instruct

本文介绍了在Ascend NPU环境下部署Qwen3-VL-8B大语言模型的步骤。主要包括:1)安装驱动、docker和vllm镜像;2)创建特权容器并挂载设备与目录;3)进入容器安装指定版本的transformers;4)设置环境变量和NPU卡配置;5)启动vllm服务;6)测试API接口。部署过程涉及多块NPU卡的使用,需注意内存碎片化问题,最终通过vllm框架提供模型推理服务。

m0_50105717的博客 1563

Linux之进程(二)进程间通信

进程间通信(IPC,InterProcess Communication) 参考博客:https://blog.youkuaiyun.com/tangtang_yue/article/details/78296620? 是指在不同进程之间传播或交换信息。IPC的方式通常有管道(包括无名管道和命名管道)、消息队列、信号量、共享存储、Socket、Streams等。其中 Socket和Streams支持不同主机上的两个进程IPC。 一、管道(无名管道) 相当于水管,从上端流入,下端流出,内容被读取后管道就是空...

hello 663

【CT/电镜 重建教程 1.1】层析成像的精确实空间迭代重建算法(RESIRE)

在此,我们报告了RESIRE算法的发展用于准确的断层重建。与实空间迭代算法相比,RESIRE使用傅里叶切片定理或Radon变换作为正向投影,使用线性变换作为反向投影,两者都具有高精度。与EST和GENFIRE相比,RESIRE是一种实空间迭代算法,可以在并行计算中实现快速运行时间。

2401_87064292的博客 1062

【人工智能之深度学习】12. BERT微调实战:医疗文本分类的领域自适应技巧与工业级实现

摘要:医疗文本分类是自然语言处理在医疗健康领域的核心应用,可辅助疾病诊断、病历结构化和医疗质量监控。然而,医疗文本的专业术语密集、实体关系复杂及数据长尾分布等特性,导致通用BERT模型性能受限。本文系统阐述医疗文本分类的领域自适应技术,从理论原理到工业级实现展开全流程讲解。首先分析医疗文本的独特属性及技术挑战;随后详解领域继续预训练、适配器微调、对抗训练等核心技术的数学原理;构建包含数据预处理、模型优化、隐私保护的完整实战架构;通过疾病分类、情感分析、事件检测三大案例验证技术有效性。

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 1008

Android Binder机制

是现代操作系统的核心安全机制,它确保了不同进程不能直接访问彼此的内存空间。Android系统中的Binder机制是进程间通信(IPC)的核心架构,它高效地连接了应用程序与系统服务,以及不同应用之间的交互。Binder作为Android系统架构的核心枢纽,通过创新的内存映射和C/S架构设计,在保证安全性的同时提供了高效的进程间通信能力。随着Android系统的演进,Binder机制仍在不断优化,如Android 8.0引入的Binder线程池优化、Android 10中的Binder调度改进等。

weixin_44078411的博客 808

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

‌多进程架构下Binder的性能优化:减少拷贝与延迟

Binder通过内核驱动实现进程间通信,其核心是将数据从用户空间传递到内核空间,再转发到目标进程。数据拷贝:发送方用户空间数据需复制到内核缓冲区(一次拷贝),然后目标进程从内核缓冲区复制到用户空间(二次拷贝)。总拷贝次数为$2$次。延迟来源:延迟包括内核处理时间$T_k$、数据传输时间$T_d$和上下文切换时间$T_c$,总延迟可建模为: $$ \text{总延迟} = T_k + T_d + T_c $$ 其中,$T_d$与数据大小成正比,$T_c$在高频通信时显著增加。拷贝开销。

2501_93895463的博客 626

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Android Binder服务端生命周期与架构深度解析

跨进程通信(IPC)是构建复杂分布式系统的核心技术,它解决了不同进程间数据交换与功能调用的难题。在Android系统中,Binder机制作为核心IPC方案,其设计基于面向对象思想,通过驱动层的内存映射实现高效的一次拷贝数据传输,在性能与安全性间取得了平衡。从技术价值看,Binder不仅支撑了Android系统服务的架构,更是应用间通信的基石,对系统稳定性与安全性至关重要。在应用场景上,无论是系统服务调用、应用组件绑定,还是自定义中间件开发,深入理解Binder服务端的工作机制都不可或缺。本文将聚焦Binde

weixin_34279184的博客 373

‌Binder驱动与ashmem:减少数据拷贝的跨进程通信技巧

在Android系统开发中,跨进程通信(IPC)是常见需求,但传统方法如管道或Socket可能导致多次数据拷贝,降低性能。Binder驱动和ashmem(Anonymous Shared Memory)是Android的核心IPC机制,它们通过共享内存和优化数据传输,显著减少数据拷贝次数。Binder和ashmem可以互补使用:Binder用于传递控制信息和小数据,ashmem用于大数据共享。Binder驱动是Android的默认IPC框架,它运行在内核层,充当进程间的“信使”。

jsdhxfsdss的博客 708

从内存池到跨进程共享:深入剖析Camx ImageBuffer的Ion Buffer与文件描述符机制

本文深入剖析了高通Camx架构中ImageBuffer的内存池机制与跨进程共享实现。通过Ion Buffer与文件描述符(fd)的结合,Camx实现了高效的零拷贝数据共享和内存复用,解决了传统内存分配的性能瓶颈和碎片化问题,为嵌入式相机系统提供了稳定可靠的内存管理方案。

grape的博客 1040

DMA-BUF在相机系统中的内存流转与性能优化实践

本文深入探讨了DMA-BUF在相机系统中的内存流转机制与性能优化实践。通过分析DMA-BUF的核心概念、跨设备共享实现及内存池模型,提供了针对相机系统的高效内存管理方案。文章还分享了Perfetto性能分析工具的使用技巧和内存泄露排查方法,帮助开发者优化相机系统的性能与稳定性。

weixin_26897585的博客 369

超大文件跨进程传输,IPC 共享内存性能优化实战

共享内存是鸿蒙跨进程大数据传输的最优解,它的价值在于「用最小的代码改动,获得最大的性能提升」——不需要改业务逻辑,只需要把数据搬运的通道从 Binder 换成共享内存,就能获得数倍甚至数十倍的性能提升。对于百 KB 级的小数据,普通 IPC 足够用且更简单;但对于 MB 级甚至 GB 级的大文件、大图、音视频流,共享内存是必选方案。掌握这套机制,再配合合理的内存管理与同步控制,就能轻松应对各种复杂的跨进程大数据场景。

2502_93915572的博客 372

‌从数据拷贝到共享内存:Binder的性能提升策略

传统IPC涉及多次数据拷贝: $$ \text{发送进程} \xrightarrow{\text{拷贝1}} \text{内核缓冲区} \xrightarrow{\text{拷贝2}} \text{接收进程} $$ 每次拷贝消耗CPU周期,当数据量$N$增大时,时间复杂度达$O(N)$。通过减少数据移动次数、利用内存映射和批处理机制,Binder在保持安全性的同时,将IPC性能提升至传统机制的3-5倍。

2501_93895308的博客 331

Android IPC机制 Binder学习

目前学习binder已经一周了,一直想写一些东西来的,但发现不管是原理还是源代码自己都似懂非懂,还真写不出来,,,今天有幸遇到一篇大神博客,是binder机制系列博客,逐步解决了我的疑惑。当然有说的不对的地方,也请评论指正。           大神系列网址:http://gityuan.com/2015/11/01/binder-driver/           学习第一天,了解了下驱动这

仰视未来的专栏 475
上一篇: 看一看系统Task都为啥不显示的问题--学员作业
下一篇: 安卓黑屏,空白屏,不显示等系统疑难问题-千里马直播讲解带你解决
千里马学框架
博客等级 码龄6年 1万+粉丝 651原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值