kk Blog —— 通用基础

date [-d @int|str] [+%s|"+%F %T"]

字符设备驱动和等待队列样例

前两篇的样例

字符设备驱动程序
Linux内核中的等待队列

waitqueue.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/wait.h>
#include <linux/semaphore.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>

#include <linux/socket.h>
#include <linux/tcp.h>
#include <linux/proc_fs.h>
#include <net/net_namespace.h>

#include <net/tcp.h>


static ssize_t globalvar_read(struct file *, char *, size_t, loff_t*);
static ssize_t globalvar_write(struct file *, const char *, size_t, loff_t*);

struct file_operations globalvar_fops =
{
	.owner     = THIS_MODULE,
	.read = globalvar_read,
	.write = globalvar_write,
};

#define LEN 1024
static char global_var[LEN];
static int read_index = 0;
static int write_index = 0;
static spinlock_t var_lock;
static wait_queue_head_t waitq;
static int flag = 0;
static int major;

static const char procname[] = "testvar";

static int __init globalvar_init(void)
{
	init_waitqueue_head(&waitq);
	spin_lock_init(&var_lock);
//    if (!proc_net_fops_create(&init_net, procname, S_IRUSR, &globalvar_fops)) {
	if (!(major = register_chrdev(0, "globalvar", &globalvar_fops))) {
		printk("globalvar register failure\n");
		return -1;
	}
	printk("major = %d\n", major);
	return 0;
}

static void __exit globalvar_exit(void)
{
//    proc_net_remove(&init_net, procname);
	unregister_chrdev(major, "globalvar");
}

static ssize_t globalvar_read(struct file *filp, char *buf, size_t len, loff_t *off)
{
	int read_len;
	//等待数据可获得
	if (wait_event_interruptible(waitq, flag != 0))
		return -ERESTARTSYS;

	spin_lock(&var_lock);
	read_len = write_index - read_index;
	if (copy_to_user(buf, global_var+read_index, read_len)) {
		spin_unlock(&var_lock);
		return -EFAULT;
	}
	read_index = write_index;
	flag = 0;
	spin_unlock(&var_lock);
	return read_len;
}

static ssize_t globalvar_write(struct file *filp, const char *buf, size_t len, loff_t *off)
{
	spin_lock(&var_lock);
	if (copy_from_user(global_var+write_index, buf, len)) {
		spin_unlock(&var_lock);
		return -EFAULT;
	}
	write_index += len;
	spin_unlock(&var_lock);

	flag = 1;
	//通知数据可获得
	wake_up_interruptible(&waitq);
	return len;
}

module_init(globalvar_init);
module_exit(globalvar_exit);
MODULE_LICENSE("GPL");

Makefile

1
2
3
4
5
6
7
obj-m += waitqueue.o

PWD = $(shell pwd)
KERNEL := /lib/modules/`uname -r`/build

all:
	make -C $(KERNEL) M=$(PWD) modules
安装模块
1
insmod ./waitqueue.ko
查看对应的设备号
1
2
$ cat /proc/devices | grep globalvar
$ 249 globalvar
建立文件
1
mknod /dev/globalvar c 249 0
终端1: cat文件
1
cat /dev/globalvar
终端2: echo数据到文件
1
2
3
echo 123 > /dev/globalvar
echo 1234567 > /dev/globalvar
echo 123 > /dev/globalvar

这时就能看见终端1读到了内容。

Linux内核中的等待队列

http://blog.sina.com.cn/s/blog_49d5604e010008bn.html

等待队列可以参考net/ipv4/tcp_probe.c的实现

简单样例

Linux内核中的等待队列

Linux内核的等待队列是以双循环链表为基础数据结构,与进程调度机制紧密结合,能够用于实现核心的异步事件通知机制。在Linux2.4.21中,等待队列在源代码树include/linux/wait.h中,这是一个通过list_head连接的典型双循环链表,

如下图所示。

在这个链表中,有两种数据结构:等待队列头(wait_queue_head_t)和等待队列项(wait_queue_t)。等待队列头和等待队列项中都包含一个list_head类型的域作为"连接件"。由于我们只需要对队列进行添加和删除操作,并不会修改其中的对象(等待队列项),因此,我们只需要提供一把保护整个基础设施和所有对象的锁,这把锁保存在等待队列头中,为wq_lock_t类型。在实现中,可以支持读写锁(rwlock)或自旋锁(spinlock)两种类型,通过一个宏定义来切换。如果使用读写锁,将wq_lock_t定义为rwlock_t类型;如果是自旋锁,将wq_lock_t定义为spinlock_t类型。无论哪种情况,分别相应设置wq_read_lock、wq_read_unlock、wq_read_lock_irqsave、wq_read_unlock_irqrestore、wq_write_lock_irq、wq_write_unlock、wq_write_lock_irqsave和wq_write_unlock_irqrestore等宏。

等待队列头
1
2
3
4
5
struct __wait_queue_head {
	wq_lock_t lock;
	struct list_head task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;

前面已经说过,等待队列的主体是进程,这反映在每个等待队列项中,是一个任务结构指针(struct task_struct * task)。flags为该进程的等待标志,当前只支持互斥。

等待队列项
1
2
3
4
5
6
7
struct __wait_queue {
	unsigned int flags;
#define WQ_FLAG_EXCLUSIVE 0x01
	struct task_struct * task;
	struct list_head task_list;
};
typedef struct __wait_queue wait_queue_t;
声明和初始化
1
2
3
4
5
6
#define DECLARE_WAITQUEUE(name, tsk)            \
	wait_queue_t name = __WAITQUEUE_INITIALIZER(name, tsk)
#define __WAITQUEUE_INITIALIZER(name, tsk) {    \
	task:  tsk,                                 \
	task_list: { NULL, NULL },                  \
	__WAITQUEUE_DEBUG_INIT(name)}

通过DECLARE_WAITQUEUE宏将等待队列项初始化成对应的任务结构,并且用于连接的相关指针均设置为空。其中加入了调试相关代码。

1
2
3
4
5
6
#define DECLARE_WAIT_QUEUE_HEAD(name)                    \
	wait_queue_head_t name = __WAIT_QUEUE_HEAD_INITIALIZER(name)
#define __WAIT_QUEUE_HEAD_INITIALIZER(name) {            \
	lock:  WAITQUEUE_RW_LOCK_UNLOCKED,                   \
	task_list: { &(name).task_list, &(name).task_list }, \
	__WAITQUEUE_HEAD_DEBUG_INIT(name)}

通过DECLARE_WAIT_QUEUE_HEAD宏初始化一个等待队列头,使得其所在链表为空,并设置链表为"未上锁"状态。其中加入了调试相关代码。

1
static inline void init_waitqueue_head(wait_queue_head_t *q)

该函数初始化一个已经存在的等待队列头,它将整个队列设置为"未上锁"状态,并将链表指针prev和next指向它自身。

1
2
3
4
5
{
	q->lock = WAITQUEUE_RW_LOCK_UNLOCKED;
	INIT_LIST_HEAD(&q->task_list);
}
static inline void init_waitqueue_entry(wait_queue_t *q, struct task_struct *p)

该函数初始化一个已经存在的等待队列项,它设置对应的任务结构,同时将标志位清0。

1
2
3
4
5
{
	q->flags = 0;
	q->task = p;
}
static inline int waitqueue_active(wait_queue_head_t *q)

该函数检查等待队列是否为空。

1
2
3
4
{
	return !list_empty(&q->task_list);
}
static inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_t *new)

将指定的等待队列项new添加到等待队列头head所在的链表头部,该函数假设已经获得锁。

1
2
3
4
{
	list_add(&new->task_list, &head->task_list);
}
static inline void __add_wait_queue_tail(wait_queue_head_t *head, wait_queue_t *new)

将指定的等待队列项new添加到等待队列头head所在的链表尾部,该函数假设已经获得锁。

1
2
3
4
{
	list_add_tail(&new->task_list, &head->task_list);
}
static inline void __remove_wait_queue(wait_queue_head_t *head, wait_queue_t *old)

将函数从等待队列头head所在的链表中删除指定等待队列项old,该函数假设已经获得锁,并且old在head所在链表中。

1
2
3
{
	list_del(&old->task_list);
}

睡眠和唤醒操作

对等待队列的操作包括睡眠和唤醒(相关函数保存在源代码树的/kernel/sched.c和include/linux/sched.h中)。思想是更改当前进程(CURRENT)的任务状态,并要求重新调度,因为这时这个进程的状态已经改变,不再在调度表的就绪队列中,因此无法再获得执行机会,进入"睡眠"状态,直至被"唤醒",即其任务状态重新被修改回就绪态。

常用的睡眠操作有interruptible_sleep_on和sleep_on。两个函数类似,只不过前者将进程的状态从就绪态(TASK_RUNNING)设置为TASK_INTERRUPTIBLE,允许通过发送signal唤醒它(即可中断的睡眠状态);而后者将进程的状态设置为TASK_UNINTERRUPTIBLE,在这种状态下,不接收任何singal。

以interruptible_sleep_on为例,其展开后的代码是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void interruptible_sleep_on(wait_queue_head_t *q)
{
	unsigned long flags;
	wait_queue_t wait;
	/* 构造当前进程对应的等待队列项 */
	init_waitqueue_entry(&wait, current);

	/* 将当前进程的状态从TASK_RUNNING改为TASK_INTERRUPTIBLE */
	current->state = TASK_INTERRUPTIBLE;

	/* 将等待队列项添加到指定链表中 */
	wq_write_lock_irqsave(&q->lock,flags);
	__add_wait_queue(q, &wait); 
	wq_write_unlock(&q->lock);

	/* 进程重新调度,放弃执行权 */
	schedule();

	/* 本进程被唤醒,重新获得执行权,首要之事是将等待队列项从链表中删除 */
	wq_write_lock_irq(&q->lock);
	__remove_wait_queue(q, &wait);
	wq_write_unlock_irqrestore(&q->lock,flags);
	/* 至此,等待过程结束,本进程可以正常执行下面的逻辑 */
}

对应的唤醒操作包括wake_up_interruptible和wake_up。wake_up函数不仅可以唤醒状态为TASK_UNINTERRUPTIBLE的进程,而且可以唤醒状态为TASK_INTERRUPTIBLE的进程。

wake_up_interruptible只负责唤醒状态为TASK_INTERRUPTIBLE的进程。这两个宏的定义如下:

1
2
#define wake_up(x)   __wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 1)
#define wake_up_interruptible(x) __wake_up((x),TASK_INTERRUPTIBLE, 1)

wake_up函数主要是获取队列操作的锁,具体工作是调用wake_up_common完成的。

1
2
3
4
5
6
7
8
9
void __wake_up(wait_queue_head_t *q, unsigned int mode, int nr)
{
	if (q) {
	    unsigned long flags;
	    wq_read_lock_irqsave(&q->lock, flags);
	    __wake_up_common(q, mode, nr, 0);
	    wq_read_unlock_irqrestore(&q->lock, flags);
	}
}

/ The core wakeup function. Non-exclusive wakeups (nr_exclusive == 0) just wake everything up. If it’s an exclusive wakeup (nr_exclusive == small +ve number) then we wake all the non-exclusive tasks and one exclusive task. There are circumstances in which we can try to wake a task which has already started to run but is not in state TASK_RUNNING. try_to_wake_up() returns zero in this (rare) case, and we handle it by contonuing to scan the queue. /

1
static inline void __wake_up_common (wait_queue_head_t *q, unsigned int mode, int nr_exclusive, const int sync)

参数q表示要操作的等待队列,mode表示要唤醒任务的状态,如TASK_UNINTERRUPTIBLE或TASK_INTERRUPTIBLE等。nr_exclusive是要唤醒的互斥进程数目,在这之前遇到的非互斥进程将被无条件唤醒。sync表示???

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{
	struct list_head *tmp;
	struct task_struct *p;

	CHECK_MAGIC_WQHEAD(q);
	WQ_CHECK_LIST_HEAD(&q->task_list);

	/* 遍历等待队列 */
	list_for_each(tmp,&q->task_list) {
	    unsigned int state;
	    /* 获得当前等待队列项 */
	    wait_queue_t *curr = list_entry(tmp, wait_queue_t, task_list);

	    CHECK_MAGIC(curr->__magic);
	    /* 获得对应的进程 */
	    p = curr->task;
	    state = p->state;

	    /* 如果我们需要处理这种状态的进程 */
	    if (state & mode) {
	        WQ_NOTE_WAKER(curr);
	        if (try_to_wake_up(p, sync) && (curr->flags&WQ_FLAG_EXCLUSIVE) && !--nr_exclusive)
	            break;
	    }
	}
}

/ 唤醒一个进程,将它放到运行队列中,如果它还不在运行队列的话。"当前"进程总是在运行队列中的(except when the actual re-schedule is in progress),and as such you’re allowed to do the simpler “current->state = TASK_RUNNING” to mark yourself runnable without the overhead of this. /

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
static inline int try_to_wake_up(struct task_struct * p, int synchronous)
{
	unsigned long flags;
	int success = 0;

	/* 由于我们需要操作运行队列,必须获得对应的锁 */
	spin_lock_irqsave(&runqueue_lock, flags);
	/* 将进程状态设置为TASK_RUNNING */
	p->state = TASK_RUNNING;
	/* 如果进程已经在运行队列中,释放锁退出 */
	if (task_on_runqueue(p))
	    goto out;
	/* 否则将进程添加到运行队列中 */
	add_to_runqueue(p);

	/* 如果设置了同步标志 */
	if (!synchronous || !(p->cpus_allowed & (1UL << smp_processor_id())))
	    reschedule_idle(p);
	/* 唤醒成功,释放锁退出 */
	success = 1;
out:
	spin_unlock_irqrestore(&runqueue_lock, flags);
	return success;
}

等待队列应用模式

等待队列的的应用涉及两个进程,假设为A和B。A是资源的消费者,B是资源的生产者。A在消费的时候必须确保资源已经生产出来,为此定义一个资源等待队列。这个队列同时要被进程A和进程B使用,我们可以将它定义为一个全局变量。

1
DECLARE_WAIT_QUEUE_HEAD(rsc_queue); /* 全局变量 */

在进程A中,执行逻辑如下:

1
2
3
4
while (resource is unavaiable) {
	interruptible_sleep_on( &wq );
}
consume_resource();

在进程B中,执行逻辑如下:

1
2
produce_resource();
wake_up_interruptible( &wq );

字符设备驱动程序

http://techlife.blog.51cto.com/212583/39225

简单样例

实现如下的功能:
-字符设备驱动程序的结构及驱动程序需要实现的系统调用
-可以使用cat命令或者自编的readtest命令读出"设备"里的内容
-以8139网卡为例,演示了I/O端口和I/O内存的使用

本文中的大部分内容在Linux Device Driver这本书中都可以找到,这本书是Linux驱动开发者的唯一圣经。


先来看看整个驱动程序的入口,是char8139_init()这个函数,如果不指定MODULE_LICENSE(“GPL”), 在模块插入内核的时候会出错,因为将非"GPL"的模块插入内核就沾污了内核的"GPL"属性。

1
2
3
4
5
6
module_init(char8139_init);
module_exit(char8139_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("ypixunil");
MODULE_DESCRIPTION("Wierd char device driver for Realtek 8139 NIC");

接着往下看char8139_init()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
static int __init char8139_init(void)
{
	int result;

	PDBG("hello. init.\n");

	/* register our char device */
	result = register_chrdev(char8139_major, "char8139", &char8139_fops);
	if (result < 0) {
		PDBG("Cannot allocate major device number!\n");
		return result;
	}
	/* register_chrdev() will assign a major device number and return if it called
	 * with "major" parameter set to 0 */
	if(char8139_major == 0)
		char8139_major=result;

	/* allocate some kernel memory we need */
	buffer = (unsigned char*)(kmalloc(CHAR8139_BUFFER_SIZE, GFP_KERNEL));
	if (!buffer) {
		PDBG("Cannot allocate memory!\n");
		result = -ENOMEM;
		goto init_fail;
	}
	memset(buffer, 0, CHAR8139_BUFFER_SIZE);
	p_buf = buffer;

	return 0; /* everything's ok */

init_fail:
	char8139_exit();
	return result;
}

这个函数首先的工作就是使用register_chrdev()注册我们的设备的主设备号和系统调用。系统调用对于字符设备驱动程序来说就是file_operations接口。

我们先来看看char8139_major的定义,

1
2
3
4
#define DEFAULT_MAJOR 145         /* data structure used by our driver */
int char8139_major=DEFAULT_MAJOR; /* major device number. if initial value is 0,
				   * the kernel will dynamically assign a major device
				   * number in register_chrdev() */

这里我们指定我们的设备的主设备号是145,你必须找到一个系统中没有用的主设备号,可以通过"cat /proc/devices"命令来查看系统中已经使用的主设备号。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[michael@char8139]$ cat /proc/devices
Character devices:
1 mem
2 pty
3 ttyp
4 ttyS
5 cua
7 vcs
10 misc
14 sound
116 alsa
128 ptm
136 pts
162 raw
180 usb
195 nvidia
226 drm

Block devices:
2 fd
3 ide0
22 ide1
[michael@char8139]$

可见在我的系统中,145还没有被使用。

指定主设备号值得考虑。像上面这样指定一个主设备号显然缺乏灵活性,而且不能保证一个驱动程序在所有的机器上都能用。可以在调用register_chrdev()时将第一个参数,即主设备号指定为0,这样register_chrdev()会分配一个空闲的主设备号作为返回值。 但是这样也有问题,我们只有在将模块插入内核之后才能得到我们设备的主设备号(使用 “cat /proc/devices”),但是要操作设备需要在系统/dev目录下建立设备结点,而建立结点时要指定主设备号。当然,你可以写一个脚本来自动完成这些事情。

总之,作为一个演示,我们还是指定主设备号为145,这样我们可以在/dev/目录下建立几个设备节点。

1
2
3
4
[root@char8139]$ mknod /dev/char8139_0 c 145 0
[root@char8139]$ mknod /dev/char8139_0 c 145 17
[root@char8139]$ mknod /dev/char8139_0 c 145 36
[root@char8139]$ mknod /dev/char8139_0 c 145 145

看一下我们建立的节点

1
2
3
4
5
6
[michael@char8139]$ ll /dev/char8139*
crw-r--r-- 1 root root 145, 0 2004-12-26 20:33 /dev/char8139_0
crw-r--r-- 1 root root 145, 17 2004-12-26 20:34 /dev/char8139_1
crw-r--r-- 1 root root 145, 36 2004-12-26 20:34 /dev/char8139_2
crw-r--r-- 1 root root 145, 145 2004-12-26 20:34 /dev/char8139_3
[michael@char8139]$

我们建立了四个节点,使用了四个次设备号,后面我们会说明次设备号的作用。

再来看看我们的file_operations的定义。这里其实只实现了read(),open(),release()三个系统调用,ioctl()只是简单返回。更有write()等函数甚至根本没有声明,没有声明的函数系统可能会调用默认的操作。

1
2
3
4
5
6
7
8
struct file_operations char8139_fops =
{
	owner: THIS_MODULE,
	read: char8139_read,
	ioctl: char8139_ioctl,
	open: char8139_open,
	release: char8139_release,
};

file_operations是每个字符设备驱动程序必须实现的系统调用,当用户对/dev中我们的设备对应结点进行操作时,linux就会调用我们驱动程序中提供的系统调用。比如用户敲入"cat /dev/char8139_0"命令,想想cat这个应用程序的实现,首先它肯定调用C语言库里的open()函数去打开/dev/char8139_0这个文件,到了系统这一层,系统会看到/dev/char8139_0不是普通磁盘文件,而是一个代表字符设备的节点,所以系统会根据/dev/char8139_0的主设备号来查找是不是已经有驱动程序使用这个相同的主设备号进行了注册,如果有,就调用驱动程序的open()实现。

为什么要这样干?因为要提供抽象,提供统一的接口,别忘了操作系统的作用之一就是这个。因为我们的设备提供的统一的接口,所以cat这个应用程序使用一般的文件操作就能从我们的设备中读出数据, 而且more, less这些应用程序都能从我们的设备中读出数据。

现在来看看我们的设备

1
2
3
4
#define CHAR8139_BUFFER_SIZE 2000
unsigned char *buffer=NULL; /* driver data buffer */
unsigned char *p_buf;
unsigned int data_size=0;

我们的设备很简单,一个2000字节的缓冲区, data_size指定缓冲区中有效数据的字节数。我们的设备只支持读不支持写。我们在char8139_init()中为缓冲区分配空间。

char8139_exit()里面的操作就是char8139_init()里面操作的反向操作。

现在我们来看看,假如用户调用了"cat /dev/char8139_3"这个命令会发生什么事情。

根据前面的介绍,我们驱动程序中的open()函数会被调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int char8139_open(struct inode *node, struct file *flip)
{
	int type = MINOR(node->i_rdev)>>4;
	int num = MINOR(node->i_rdev) & 0x0F;

	/* put some char in buffer to reflect the minor device number */
	*buffer=(unsigned char)('0');
	*(buffer+1)=(unsigned char)('x');
	*(buffer+2)=(unsigned char)('0'+type);
	*(buffer+3)=(unsigned char)('0'+num);
	*(buffer+4)=(unsigned char)('\n');
	data_size+=5;

	PDBG("Ok. Find treasure! 8139 I/O port base: %x\n", detect_8139_io_port());
	PDBG("OK. Find treasure! 8139 I/O memory base address: %lx\n",
	detect_8139_io_mem());

	MOD_INC_USE_COUNT;

	return 0;
}

这里演示了次设备号的作用,它让我们知道用户操作的是哪一个"次设备",是/dev/char8139_0还是/dev/char8139_3,因为对不同的"次设备",具体的操作方法可能是不一样的,这样就为一个驱动程序控制多个类似的设备提供了可能。

我们根据次设备号的不同,在buffer中填入不同的字符(次设备号的16进制表示)。

接着驱动程序中的read()函数会被调用,因为cat程序的实现就是读取文件中的内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
ssize_t char8139_read (struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
	ssize_t ret=0;

	PDBG("copy to user. count=%d, f_pos=%ld\n", (int)count, (long)*f_pos);
	if (*f_pos>= data_size)
		return ret;
	if (*f_pos + count > data_size)
		count = data_size-*f_pos;
	if (copy_to_user(buf, p_buf, count))
	{
		PDBG("OOps, copy to user error.\n");
		return -EFAULT;
	}

	p_buf += count;
	*f_pos += count;
	ret = count;

	return ret;
}

要正确的实现一个read()调用,你得想一想一个应用程序是如何调用read()从文件中读取数据的。如果你想明白了就很简单,驱动程序所要做的就是把恰当的数据传递给应用程序,这是使用copy_to_user()函数完成的。

另外,我们必须得意识到,这里只是一个很简单的演示。还有很多复杂的问题有待考虑,比如两个应用程序可能同时打开我们设备,我们的设备应该怎样反应(这取决于具体的设备应有的行为),还有互斥的问题。

然后我们看看I/O端口和I/O内存的操作。这里使用8139网卡作为一个硬件实例来演示I/O端口和I/O内存的操作。没有什么特别的,都是标准的步骤。在使用时需要注意,如果你的系统中已经有8139网卡的驱动程序,必须先关掉网络设备,卸载驱动,然后再使用本驱动程序。

使用程序包的步骤:(在我的Debian系统上如此,你的可能不同)
1. 解压
2. 编译(/usr/src/linux处必须要有内核源代码)
3. ifconfig eth0 down 关掉网络设备
rmmod 8139too 卸载原来的8139网卡驱动
insmod char8139.o 插入我们的模块
(insmod会出错, 如果你现在运行的linux版本不是你编译本驱动程序时使用的内核源代码的版本,insmod时会报告模块版本与内核版本不一致。这时,你得看看内核源代码中/include/linux/version.h文件,这个文件中的UTS_RELEASE定义了内核的版本号,你可以在驱动程序中预先定义这个宏为当前运行的内核的版本号,这样就能避免上述错误。)
4. mknode(见本文前述)
5. 试试我们的设备
./readtest
或者
cat /dev/char8139_0或
cat /dev/char8139_1或
cat /dev/char8139_2或
cat /dev/char8139_3
6. 恢复系统
rmmod char8139
modprobe 8139too
ifconfig eth0 up
如果你使用dhcp可能还需要运行dhclient

编译android4.4.2源码

android4.4.2和jdk下载 http://pan.baidu.com/share/home?uk=3691037096&view=share#category/type=0

http://www.cnblogs.com/zhx831/p/3550688.html

这篇文章主要记录了我是如何搭建Android编译环境,以及搭建当中遇到的问题以及解决方法。搭建环境依照官网进行,整个搭建环境分为两步:
1. 安装JDK
2. 安装相对应的库以及软件

1、安装JDK

官网上给出的办法是使用apt进行jdk的安装

1
2
3
$ sudo add-apt-repository "deb http://archive.canonical.com/ lucid partner"
$ sudo apt-get update
$ sudo apt-get install sun-java6-jdk

但是我在按照这个方法进行安装是apt提示无法找到jdk安装包。 在更换了好几个source后都无法下载jdk。因此只能考虑手动安装。

1. 首先在Orecal官网下载JDK:

http://www.oracle.com/technetwork/java/javase/downloads/java-archive-downloads-javase6-419409.html

需要注意的是,现在官方网站上最新的版本的JDK7, 但是这个这个版本是不能用于Android的编译的,一定要去下载JDK6. 希望看到的朋友不要在走我的弯路。

2. 创建jvm文件夹
1
sudo mkdir /usr/lib/jvm
3. 安装JDK6
1
2
3
sudo cp jdk-6u45-linux-x64.bin /usr/lib/jvm/
sudo chmod +x jdk-6u45-linux-x64.bin
sudo ./jdk-6u45-linux-x64.bin
4. 设置环境变量
1
2
3
4
5
sudo mv jdk1.6.0_45/ jdk6
export JAVA_HOME=/usr/lib/jvm/jdk6
export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
export PATH=${JAVA_HOME}/bin:$PATH
5. 使能环境变量
1
source ~/.bashrc
6. 设置JDK6为系统默认JDK

因为在ubuntu中默认JDK可能是OpenJDK,这里我们设置JDK6为我们默认的JDK

1
2
3
4
5
sudo update-alternatives --install /usr/bin/java java /usr/lib/jvm/jdk6/bin/java 300
sudo update-alternatives --install /usr/bin/javac javac /usr/lib/jvm/jdk6/bin/javac 300
sudo update-alternatives --install /usr/bin/javaws javaws /usr/lib/jvm/jdk6/bin/javaws 300
sudo update-alternatives --install /usr/bin/jar jar /usr/lib/jvm/jdk6/bin/jar 300
sudo update-alternatives --config java
7. 至此JDK就安装好了,现在就可以在shell中查看Java版本
1
java -version

如果编译还提示java错误,就把java路径加到PATH中

1
PATH=$PATH:/usr/lib/jvm/jdk6/bin

2、安装相对应的库以及软件

根据官网上的指示我们需要安装如下软件包和lib

1
2
3
4
5
6
$ sudo apt-get install git gnupg flex bison gperf build-essential \
  zip curl libc6-dev libncurses5-dev:i386 x11proto-core-dev \
  libx11-dev:i386 libreadline6-dev:i386 libgl1-mesa-glx:i386 \
  libgl1-mesa-dev g++-multilib mingw32 tofrodos \
  python-markdown libxml2-utils xsltproc zlib1g-dev:i386
$ sudo ln -s /usr/lib/i386-linux-gnu/mesa/libGL.so.1 /usr/lib/i386-linux-gnu/libGL.so
  • 我安装libgl1-mesa-glx:i386的时候提示要卸掉很多软件,就没装这个,也是能正常编译。

但是在安装过程中遇到了如下错误:

1
2
3
4
Errors were encountered while processing:
libc6-dev:i386
 
E: Sub-process /usr/bin/dpkg returned an error code (1)

解决方法如下:

1
2
$ sudo apt-get install linux-libc-dev:i386
$ sudo apt-get install libc6-dev:i386

http://blog.csdn.net/yf210yf/article/details/9206269

http://www.cnblogs.com/qianxudetianxia/p/3681890.html

编译代码

进入源码根目录,编译初始化,在终端中执行:

1
source build/envsetup.sh

选择编译目标:

1
lunch 

选择第一个吧,或者直接

1
lunch aosp_arm-eng

开始编译

1
make -j4

3、5个小时左右吧

Android 完成编译的时候先执行 source build/envsetup.sh。 在这个shell 脚本中定义了 help, croot, m, mm, mmm 等 function

运行模拟器

在终端中执行:emulator

修改和编译系统应用代码

我们修改一下系统应用Mms的标题:

使用mm命令编译:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
xxx@ubuntu:~/Data/android/packages/apps/Mms$ mm
============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=4.4.3.2.1.000.000
TARGET_PRODUCT=aosp_arm
TARGET_BUILD_VARIANT=eng
TARGET_BUILD_TYPE=release
TARGET_BUILD_APPS=
TARGET_ARCH=arm
TARGET_2ND_ARCH=
TARGET_ARCH_VARIANT=armv7-a
TARGET_CPU_VARIANT=generic
HOST_ARCH=x86
HOST_OS=linux
HOST_OS_EXTRA=Linux-3.13.0-24-generic-x86_64-with-Ubuntu-14.04-trusty
HOST_BUILD_TYPE=release
BUILD_ID=OPENMASTER
OUT_DIR=out
============================================
make:进入目录'/home/xxx/Data/android'
target R.java/Manifest.java: Mms (out/target/common/obj/APPS/Mms_intermediates/src/R.stamp)
warning: string 'menu_insert_smiley' has no default translation.
target Java: Mms (out/target/common/obj/APPS/Mms_intermediates/classes)
注: 某些输入文件使用或覆盖了已过时的 API。
注: 有关详细信息, 请使用 -Xlint:deprecation 重新编译。
注: 某些输入文件使用了未经检查或不安全的操作。
注: 有关详细信息, 请使用 -Xlint:unchecked 重新编译。
Copying: out/target/common/obj/APPS/Mms_intermediates/classes-jarjar.jar
Copying: out/target/common/obj/APPS/Mms_intermediates/emma_out/lib/classes-jarjar.jar
Copying: out/target/common/obj/APPS/Mms_intermediates/classes.jar
Proguard: out/target/common/obj/APPS/Mms_intermediates/proguard.classes.jar
ProGuard, version 4.10
Reading program jar [/home/xxx/Data/android/out/target/common/obj/APPS/Mms_intermediates/classes.jar]
// ... ...
target Dex: Mms
Copying: out/target/common/obj/APPS/Mms_intermediates/classes.dex
target Package: Mms (out/target/product/generic/obj/APPS/Mms_intermediates/package.apk)
nothing matches overlay file ic_contact_picture.png, for flavor ,,,,,,,,,,,,mdpi,,,,,,,
libpng warning: iCCP: known incorrect sRGB profile
libpng warning: iCCP: known incorrect sRGB profile
warning: string 'menu_insert_smiley' has no default translation.
warning: string 'menu_insert_smiley' is missing 19 required localizations: az_AZ en_AU en_CA en_GB en_IN en_NZ en_SG en_US eo_EU hy_AM ka_GE km_KH lo_LA mn_MN ne_NP si_LK zh_CN zh_HK zh_TW
dex2oatd I 21424 21424 art/dex2oat/dex2oat.cc:1082] dex2oat: out/host/linux-x86/bin/dex2oatd --runtime-arg -Xms64m --runtime-arg -Xmx64m --boot-image=out/target/product/generic/dex_bootjars/system/framework/boot.art --dex-file=out/target/product/generic/obj/APPS/Mms_intermediates/package.apk --dex-location=/system/priv-app/Mms.apk --oat-file=out/target/product/generic/obj/APPS/Mms_intermediates/package.odex --android-root=out/target/product/generic/system --instruction-set=arm --instruction-set-features=default
dex2oatd I 21424 21424 art/dex2oat/dex2oat.cc:252] dex2oat took 1.189425041s (threads: 8)
Notice file: packages/apps/Mms/NOTICE -- out/target/product/generic/obj/NOTICE_FILES/src//system/priv-app/Mms.apk.txt
Install: out/target/product/generic/system/priv-app/Mms.apk
Install: out/target/product/generic/system/priv-app/Mms.odex
// ... ...
Install: out/target/product/generic/data/app/MmsTests.apk
Install: out/target/product/generic/data/app/MmsTests.odex
make:离开目录“/home/xxx/Data/android”

主要是生成了两个文件:
out/target/product/generic/system/priv-app/Mms.apk
out/target/product/generic/system/priv-app/Mms.odex

安装到手机

因为是系统应用,为了重启有效,使用push命令把两个文件push到模拟器中对应的位置:

1
2
3
4
5
6
// 注意现在一些核心的应用的位置由以前的system/app调整为了system/priv-app,不要push错了
/*
xxx@ubuntu:~/Data/android$ adb push out/target/product/generic/system/priv-app/Mms.odex /system/priv-app
2893 KB/s (2085348 bytes in 0.703s)
xxx@ubuntu:~/Data/android$ adb push out/target/product/generic/system/priv-app/Mms.apk /system/priv-app
3315 KB/s (1785258 bytes in 0.525s)

看模拟器的标题被替换了。类似了,你可以修改framework,替换内核

在 ~/.bashrc

添加环境变量:

1
2
export ANDROID_PRODUCT_OUT=~/code/android-4.2/out/target/product/generic
export ANDROID_SWT=~/code/android-4.2/out/host/linux-x86/framework/

备注:

执行emulator,出现如下错误:

1
2
3
4
5
6
emulator: ERROR: You did not specify a virtual device name, and the system
directory could not be found.

If you are an Android SDK user, please use '@<name>' or '-avd <name>'
to start a given virtual device (see -help-avd for details).
Otherwise, follow the instructions in -help-disk-images to start the emulator

解决:

1
2
source build/envsetup.sh 
lunch sdk-eng

然后再执行

1
emulator

可以启动模拟器


http://senrsl.blogspot.com/2015/03/s4shv-e300lkernelrom.html

三星S4韩版SHV-E300L源码编译(内核Kernel+ROM)

编译ROM

①准备工作

先看说明README_Platform.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
    How to build Module for Platform
    - It is only for modules are needed to using Android build system.
    - Please check its own install information under its folder for other module.
    [Step to build]
    1. Get android open source.
        : version info - Android 4.4
        ( Download site : http://source.android.com )
    2. Copy module that you want to build - to original android open source
       If same module exist in android open source, you should replace it. (no overwrite)
        # It is possible to build all modules at once.
    3. You should add module name to 'PRODUCT_PACKAGES' in 'build\target\product\core.mk' as following case.
        case 1) e2fsprog : should add 'e2fsck' to PRODUCT_PACKAGES
        case 2) blkid : should add 'libkeyutils' to PRODUCT_PACKAGES
        case 3) libhyphenation : should add 'libkeyutils' to PRODUCT_PACKAGES
        case 4) KeyUtils : should add 'libkeyutils' to PRODUCT_PACKAGES
        case 5) libexifa : should add 'libexifa' to PRODUCT_PACKAGES
        case 6) libjpega : should add 'libjpega' to PRODUCT_PACKAGES
        ex.) [build\target\product\core.mk] - add all module name for case 1 ~ 5 at once
            PRODUCT_PACKAGES += \
                e2fsck \
                blkid \
                libhyphenation \
                libkeyutils \
                libexifa \
                libjpega \
                ebtables
    4. excute build command
        ./build_platform.sh
    Note :
    to build SBrowser (vendor/samsung/packages/apps/SBrowser),
    please refer to Buildme.txt at the folder mentioned above.

意思就是说分4部走,后面加了个注释。

分别是下载4.4的源码,把包里的要编译的模块拷进去(替换,非覆盖),增加要编译的模块到core.mk进行注册,执行编译脚本。

查看当前源码版本

1
2
3
4
5
6
senrsl@senrsl-ubuntu:~$ cd android/source/WORKING_DIRECTORY/
senrsl@senrsl-ubuntu:~/android/source/WORKING_DIRECTORY$ repo branches
*  android-4.4.2_r2          | in all projects
    master                    | in:
                                      abi/cpp
                                      ....

所有的版本号里没有叫4.4的,只有4.4.*的。。。。

好吧,就用这个。

②替换模块

1)external目录,把这些目录剪出来

1
2
3
4
5
6
7
8
9
10
11
12
    senrsl@senrsl-ubuntu:~/android/source/test/三星替换 /external$ ll
    总用量 40
    drwxrwxr-x 10 senrsl senrsl 4096  3月 30 14:53 ./
    drwxrwxr-x  4 senrsl senrsl 4096  3月 30 15:02 ../
    drwxrwxr-x 17 senrsl senrsl 4096  3月 20 13:35 chromium/
    drwxrwxr-x  9 senrsl senrsl 4096  3月 20 13:36 dnsmasq/
    drwxrwxr-x 19 senrsl senrsl 4096  3月 20 13:36 e2fsprogs/
    drwxrwxr-x  3 senrsl senrsl 4096  3月 20 13:36 gcc-demangle/
    drwxrwxr-x  4 senrsl senrsl 4096  3月 20 13:36 hyphenation/
    drwxrwxr-x 15 senrsl senrsl 4096  3月 20 13:36 iproute2/
    drwxrwxr-x 11 senrsl senrsl 4096  3月 20 13:36 iptables/
    drwxrwxr-x  4 senrsl senrsl 4096  3月 20 13:36 junit/

把这些目录放进去

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    senrsl@senrsl-ubuntu:~$ cd android/source/SHV-E300L_KK_Opensource/Platform/external/
    senrsl@senrsl-ubuntu:~/android/source/SHV-E300L_KK_Opensource/Platform/external$ ll
    总用量 44
    drwxrwxr-x 11 senrsl senrsl 4096 10月 14 09:23 ./
    drwxrwxr-x  5 senrsl senrsl 4096  3月 30 13:10 ../
    drwxrwxr-x 17 senrsl senrsl 4096 10月  8 12:16 chromium/
    drwxrwxr-x  9 senrsl senrsl 4096 10月  8 09:07 dnsmasq/
    drwxrwxr-x 18 senrsl senrsl 4096 10月  8 09:07 e2fsprogs/
    drwxrwxr-x  2 senrsl senrsl 4096 10月  8 09:07 gcc-demangle/
    drwxrwxr-x  3 senrsl senrsl 4096 10月  8 09:07 hyphenation/
    drwxrwxr-x 14 senrsl senrsl 4096 10月  8 09:07 iproute2/
    drwxrwxr-x 10 senrsl senrsl 4096 10月  8 09:07 iptables/
    drwxrwxr-x  3 senrsl senrsl 4096 10月  8 09:07 junit/
    drwxrwxr-x 10 senrsl senrsl 4096 10月  8 12:23 webkit/

2)vendor目录,把vendor/samsung放进去

3)build目录,把这俩文件剪出来,把Platform里的放进去

1
2
3
4
5
6
7
8
9
    senrsl@senrsl-ubuntu:~/android/source/SHV-E300L_KK_Opensource/Platform/build$ tree
    .
    └── target
        ├── board
        │   └── generic
        │       └── BoardConfig.mk
        └── product
            └── core.mk
    4 directories, 2 files
③执行编译
1
    senrsl@senrsl-ubuntu:~/android/source/WORKING_DIRECTORY$ ./build_platform.sh

报错

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
    target Generated: libwebcore <= external/webkit/Source/WebCore/dom/make_names.pl
    target Generated: libwebcore <= external/webkit/Source/WebCore/dom/make_names.pl
    target Generated: libwebcore <= external/webkit/Source/WebCore/dom/make_names.pl
    target Generated: libwebcore <= external/webkit/Source/WebCore/dom/make_names.pl
    target Generated: libwebcore <= external/webkit/Source/WebCore/dom/make_names.pl
    target Generated: libwebcore <= external/webkit/Source/WebCore/dom/make_names.pl
    target Generated: libwebcore <= external/webkit/Source/WebCore/dom/make_names.pl
    target Generated: libwebcore <= external/webkit/Source/WebCore/dom/make_names.pl
    target Generated: libwebcore <= external/webkit/Source/WebCore/dom/make_names.pl
    Export includes file: frameworks/opt/emoji/Android.mk -- out/target/product/generic/obj/SHARED_LIBRARIES/libemoji_intermediates/export_includes
    Export includes file: external/harfbuzz/Android.mk -- out/target/product/generic/obj/SHARED_LIBRARIES/libharfbuzz_intermediates/export_includes
    Export includes file: external/webkit/Android.mk -- out/target/product/generic/obj/STATIC_LIBRARIES/libwebcore_intermediates/export_includes
    Export includes file: external/libxml2/Android.mk -- out/target/product/generic/obj/STATIC_LIBRARIES/libxml2_intermediates/export_includes
    Export includes file: external/libxslt/Android.mk -- out/target/product/generic/obj/STATIC_LIBRARIES/libxslt_intermediates/export_includes
    Export includes file: external/hyphenation/Android.mk -- out/target/product/generic/obj/STATIC_LIBRARIES/libhyphenation_intermediates/export_includes
    Import includes file: out/target/product/generic/obj/SHARED_LIBRARIES/libemoji_intermediates/import_includes
    Import includes file: out/target/product/generic/obj/SHARED_LIBRARIES/libharfbuzz_intermediates/import_includes
    target Generated: libwebcore <= external/webkit/Source/WebCore/html/DocTypeStrings.gperf
    Generating HTMLEntityTable.cpp
    target Generated: libwebcore <= external/webkit/Source/WebCore/platform/ColorData.gperf
    WebCore Yacc: libwebcore <= external/webkit/Source/WebCore/css/CSSGrammar.y
    target Generated: libwebcore <= external/webkit/Source/WebCore/dom/make_names.pl
    WebCore Yacc: libwebcore <= external/webkit/Source/WebCore/xml/XPathGrammar.y
    target Generated: libwebcore <= external/webkit/Source/WebCore/dom/make_names.pl
    Can't locate Switch.pm in @INC (you may need to install the Switch module) (@INC contains: /etc/perl /usr/local/lib/perl/5.18.2 /usr/local/share/perl/5.18.2 /usr/lib/perl5 /usr/share/perl5 /usr/lib/perl/5.18 /usr/share/perl/5.18 /usr/local/lib/site_perl .) at external/webkit/Source/WebCore/make-hash-tools.pl line 23.
    BEGIN failed--compilation aborted at external/webkit/Source/WebCore/make-hash-tools.pl line 23.
    Can't locate Switch.pm in @INC (you may need to install the Switch module) (@INC contains: /etc/perl /usr/local/lib/perl/5.18.2 /usr/local/share/perl/5.18.2 /usr/lib/perl5 /usr/share/perl5 /usr/lib/perl/5.18 /usr/share/perl/5.18 /usr/local/lib/site_perl .) at external/webkit/Source/WebCore/make-hash-tools.pl line 23.
    BEGIN failed--compilation aborted at external/webkit/Source/WebCore/make-hash-tools.pl line 23.
    make: *** [out/target/product/generic/obj/STATIC_LIBRARIES/libwebcore_intermediates/Source/WebCore/html/DocTypeStrings.cpp] 错误 2
    make: *** 正在等待未完成的任务....
    make: *** [out/target/product/generic/obj/STATIC_LIBRARIES/libwebcore_intermediates/Source/WebCore/platform/ColorData.cpp] 错误 2
    target Generated: libwebcore <= external/webkit/Source/WebCore/html/parser/HTMLEntityNames.in
    senrsl@senrsl-ubuntu:~/android/source/WORKING_DIRECTORY$ ./build_platform.sh

在core.mk里把 libwebcore \删掉,再build,报错

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    Install: out/target/product/generic/system/fonts/NotoSansKhmerUI-Bold.ttf
    Install: out/target/product/generic/system/fonts/NotoSansKhmerUI-Regular.ttf
    Install: out/target/product/generic/system/fonts/NotoSansLao-Bold.ttf
    Install: out/target/product/generic/system/fonts/NotoSansLao-Regular.ttf
    Install: out/target/product/generic/system/fonts/NotoSansLaoUI-Bold.ttf
    Install: out/target/product/generic/system/fonts/NotoSansLaoUI-Regular.ttf
    Install: out/target/product/generic/system/fonts/NotoSansMalayalam-Bold.ttf
    collect2: error: ld returned 1 exit status
    Install: out/target/product/generic/system/fonts/NotoSansMalayalam-Regular.ttf
    make: *** [out/target/product/generic/obj/EXECUTABLES/dnsmasq_intermediates/LINKED/dnsmasq] 错误 1
    make: *** 正在等待未完成的任务....
    Install: out/target/product/generic/system/fonts/NotoSansMalayalamUI-Bold.ttf
    external/e2fsprogs/lib/ext2fs/blkmap64_ba.c:339: error: undefined reference to 'ext2fs_test_bit64'
    external/e2fsprogs/lib/ext2fs/blkmap64_ba.c:390: error: undefined reference to 'ext2fs_test_bit64'
    external/e2fsprogs/lib/ext2fs/blkmap64_ba.c:186: error: undefined reference to 'ext2fs_test_bit64'
    external/e2fsprogs/lib/ext2fs/blkmap64_ba.c:281: error: undefined reference to 'ext2fs_mem_is_zero'
    external/e2fsprogs/lib/ext2fs/blkmap64_ba.c:178: error: undefined reference to 'ext2fs_clear_bit64'
    external/e2fsprogs/lib/ext2fs/blkmap64_ba.c:170: error: undefined reference to 'ext2fs_set_bit64'
    external/e2fsprogs/lib/ext2fs/blkmap64_ba.c:141: error: undefined reference to 'ext2fs_clear_bit64'
    external/e2fsprogs/lib/ext2fs/gen_bitmap64.c:735: error: undefined reference to 'ext2fs_get_bitmap_granularity'
    external/e2fsprogs/lib/ext2fs/gen_bitmap64.c:790: error: undefined reference to 'ext2fs_find_first_zero_generic_bitmap'
    external/e2fsprogs/lib/ext2fs/mmp.c:57: error: undefined reference to 'ext2fs_get_dio_alignment'
    external/e2fsprogs/lib/ext2fs/mmp.c:213: error: undefined reference to 'ext2fs_alloc_block2'
    collect2: error: ld returned 1 exit status
    make: *** [out/target/product/generic/obj/SHARED_LIBRARIES/libext2fs_intermediates/LINKED/libext2fs.so] 错误 1
    senrsl@senrsl-ubuntu:~/android/source/WORKING_DIRECTORY$

再把 libexifa \删掉,报错

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
    out/host/linux-x86/obj/SHARED_LIBRARIES/libext2fs_host_intermediates/blkmap64_ba.o: In function `ba_find_first_zero':
    /home/senrsl/android/source/WORKING_DIRECTORY/external/e2fsprogs/lib/ext2fs/blkmap64_ba.c:339: undefined reference to `ext2fs_test_bit64'
    /home/senrsl/android/source/WORKING_DIRECTORY/external/e2fsprogs/lib/ext2fs/blkmap64_ba.c:390: undefined reference to `ext2fs_test_bit64'
    out/host/linux-x86/obj/SHARED_LIBRARIES/libext2fs_host_intermediates/blkmap64_ba.o: In function `ba_test_bmap':
    /home/senrsl/android/source/WORKING_DIRECTORY/external/e2fsprogs/lib/ext2fs/blkmap64_ba.c:186: undefined reference to `ext2fs_test_bit64'
    out/host/linux-x86/obj/SHARED_LIBRARIES/libext2fs_host_intermediates/blkmap64_ba.o: In function `ba_test_clear_bmap_extent':
    /home/senrsl/android/source/WORKING_DIRECTORY/external/e2fsprogs/lib/ext2fs/blkmap64_ba.c:281: undefined reference to `ext2fs_mem_is_zero'
    out/host/linux-x86/obj/SHARED_LIBRARIES/libext2fs_host_intermediates/blkmap64_ba.o: In function `ba_unmark_bmap':
    /home/senrsl/android/source/WORKING_DIRECTORY/external/e2fsprogs/lib/ext2fs/blkmap64_ba.c:178: undefined reference to `ext2fs_clear_bit64'
    out/host/linux-x86/obj/SHARED_LIBRARIES/libext2fs_host_intermediates/blkmap64_ba.o: In function `ba_mark_bmap':
    /home/senrsl/android/source/WORKING_DIRECTORY/external/e2fsprogs/lib/ext2fs/blkmap64_ba.c:170: undefined reference to `ext2fs_set_bit64'
    out/host/linux-x86/obj/SHARED_LIBRARIES/libext2fs_host_intermediates/blkmap64_ba.o: In function `ba_resize_bmap':
    /home/senrsl/android/source/WORKING_DIRECTORY/external/e2fsprogs/lib/ext2fs/blkmap64_ba.c:141: undefined reference to `ext2fs_clear_bit64'
    out/host/linux-x86/obj/SHARED_LIBRARIES/libext2fs_host_intermediates/gen_bitmap64.o: In function `ext2fs_convert_subcluster_bitmap':
    /home/senrsl/android/source/WORKING_DIRECTORY/external/e2fsprogs/lib/ext2fs/gen_bitmap64.c:735: undefined reference to `ext2fs_get_bitmap_granularity'
    out/host/linux-x86/obj/SHARED_LIBRARIES/libext2fs_host_intermediates/gen_bitmap64.o: In function `ext2fs_find_first_zero_generic_bmap':
    /home/senrsl/android/source/WORKING_DIRECTORY/external/e2fsprogs/lib/ext2fs/gen_bitmap64.c:790: undefined reference to `ext2fs_find_first_zero_generic_bitmap'
    out/host/linux-x86/obj/SHARED_LIBRARIES/libext2fs_host_intermediates/mmp.o: In function `ext2fs_mmp_read':
    /home/senrsl/android/source/WORKING_DIRECTORY/external/e2fsprogs/lib/ext2fs/mmp.c:57: undefined reference to `ext2fs_get_dio_alignment'
    out/host/linux-x86/obj/SHARED_LIBRARIES/libext2fs_host_intermediates/mmp.o: In function `ext2fs_mmp_init':
    /home/senrsl/android/source/WORKING_DIRECTORY/external/e2fsprogs/lib/ext2fs/mmp.c:213: undefined reference to `ext2fs_alloc_block2'
    collect2: ld returned 1 exit status
    make: *** [out/host/linux-x86/obj/lib/libext2fs_host.so] 错误 1
    make: *** 正在等待未完成的任务....
    1 warning generated.
    external/openssl/ssl/s2_clnt.c:1027:38: warning: unused parameter 'type' [-Wunused-parameter]
    int ssl2_set_certificate(SSL *s, int type, int len, const unsigned char *data)
                                         ^
    1 warning generated.
    external/openssl/ssl/s2_lib.c:385:38: warning: unused parameter 'larg' [-Wunused-parameter]
    long ssl2_ctrl(SSL *s, int cmd, long larg, void *parg)
                                         ^
    external/openssl/ssl/s2_lib.c:385:50: warning: unused parameter 'parg' [-Wunused-parameter]
    long ssl2_ctrl(SSL *s, int cmd, long larg, void *parg)
                                                     ^
    external/openssl/ssl/s2_lib.c:400:30: warning: unused parameter 's' [-Wunused-parameter]
    long ssl2_callback_ctrl(SSL *s, int cmd, void (*fp)(void))
                                 ^
    external/openssl/ssl/s2_lib.c:400:37: warning: unused parameter 'cmd' [-Wunused-parameter]
    long ssl2_callback_ctrl(SSL *s, int cmd, void (*fp)(void))
                                        ^
    external/openssl/ssl/s2_lib.c:400:49: warning: unused parameter 'fp' [-Wunused-parameter]
    long ssl2_callback_ctrl(SSL *s, int cmd, void (*fp)(void))
                                                    ^
    external/openssl/ssl/s2_lib.c:405:29: warning: unused parameter 'ctx' [-Wunused-parameter]
    long ssl2_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
                                ^
    external/openssl/ssl/s2_lib.c:405:38: warning: unused parameter 'cmd' [-Wunused-parameter]
    long ssl2_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
                                         ^
    external/openssl/ssl/s2_lib.c:405:48: warning: unused parameter 'larg' [-Wunused-parameter]
    long ssl2_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
                                                   ^
    external/openssl/ssl/s2_lib.c:405:60: warning: unused parameter 'parg' [-Wunused-parameter]
    long ssl2_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
                                                               ^
    external/openssl/ssl/s2_lib.c:410:38: warning: unused parameter 'ctx' [-Wunused-parameter]
    long ssl2_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)(void))
                                         ^
    external/openssl/ssl/s2_lib.c:410:47: warning: unused parameter 'cmd' [-Wunused-parameter]
    long ssl2_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)(void))
                                                  ^
    external/openssl/ssl/s2_lib.c:410:59: warning: unused parameter 'fp' [-Wunused-parameter]
    long ssl2_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)(void))
                                                              ^
    12 warnings generated.
    1 warning generated.
    make: *** wait: 没有子进程。 停止。
    senrsl@senrsl-ubuntu:~/android/source/WORKING_DIRECTORY$

然后把之前的core.mk第二部分替换成README里的,报错

1
2
3
4
5
6
7
8
    /home/senrsl/android/source/WORKING_DIRECTORY/external/e2fsprogs/lib/ext2fs/mmp.c:57: undefined reference to `ext2fs_get_dio_alignment'
    out/host/linux-x86/obj/SHARED_LIBRARIES/libext2fs_host_intermediates/mmp.o: In function `ext2fs_mmp_init':
    /home/senrsl/android/source/WORKING_DIRECTORY/external/e2fsprogs/lib/ext2fs/mmp.c:213: undefined reference to `ext2fs_alloc_block2'
    collect2: ld returned 1 exit status
    make: *** [out/host/linux-x86/obj/lib/libext2fs_host.so] 错误 1
    make: *** 正在等待未完成的任务....
    Processing target/product/generic/dex_bootjars/system/framework/core.jar
    Done!

然后把core.mk里第二部分全都删掉,报的错还是上面那个。

恢复下core.mk重来,

报1:报错external/webkit/Source/WebCore/make-hash-tools.pl line 23.,core.mk砍掉 libwebcore \ 代码砍掉external/webkit.

报2:/home/senrsl/android/source/WORKING_DIRECTORY/external/e2fsprogs/lib/ext2fs/mmp.c:213: undefined reference to `ext2fs_alloc_block2',external/e2fsprogs 代码换回原版。

报3:/home/senrsl/android/source/WORKING_DIRECTORY/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7/bin/../lib/gcc/arm-linux-androideabi/4.7/../../../../arm-linux-androideabi/bin/ld: error: out/target/product/generic/obj/EXECUTABLES/dnsmasq_intermediates/dhcp-common.o: multiple definition of ‘option_string’ /home/senrsl/android/source/WORKING_DIRECTORY/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7/bin/../lib/gcc/arm-linux-androideabi/4.7/../../../../arm-linux-androideabi/bin/ld: out/target/product/generic/obj/EXECUTABLES/dnsmasq_intermediates/option.o: previous definition here,external/dnsmasq换回原版。

然后编译

这样竟编译成功

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    Creating filesystem with parameters:
        Size: 576716800
        Block size: 4096
        Blocks per group: 32768
        Inodes per group: 7040
        Inode size: 256
        Journal blocks: 2200
        Label:
        Blocks: 140800
        Block groups: 5
        Reserved block group size: 39
    Created filesystem with 892/35200 inodes and 65272/140800 blocks
    + '[' 0 -ne 0 ']'
    Install system fs image: out/target/product/generic/system.img
    out/target/product/generic/system.img+ maxsize=588791808 blocksize=2112 total=576716800 reserve=5947392

镜像文件输出到了/home/senrsl/android/source/WORKING_DIRECTORY/out/target /product/generic

4)封包

查看下官方提供的E300LKLUFNE4_E300LLGTFNE4_E300LKLUFNC1_HOME.tar

依次罗列了这几个img.

尝试封装

1
2
3
4
5
    senrsl@senrsl-ubuntu:~/android/source/WORKING_DIRECTORY/out/target/product/generic$ tar cvf p.tar cache.img ramdisk.img system.img userdata.img
    cache.img
    ramdisk.img
    system.img
    userdata.img

然后重启系统去烧。

//TODO 未成功,无法烧入


I9507V 的external/e2fsprogs,external/dnsmasq换回原版,就能编译成功,没试过烧进真机。