<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Coding Guy</title>
	<atom:link href="http://www.codingguy.net/?feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://www.codingguy.net</link>
	<description>on my way...</description>
	<lastBuildDate>Mon, 25 Jun 2012 02:56:02 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>HTML5在路上——HTML5开发者日暨W3C中国6周年庆典</title>
		<link>http://www.codingguy.net/?p=208</link>
		<comments>http://www.codingguy.net/?p=208#comments</comments>
		<pubDate>Mon, 25 Jun 2012 02:56:00 +0000</pubDate>
		<dc:creator>codingguy</dc:creator>
				<category><![CDATA[MISC]]></category>

		<guid isPermaLink="false">http://www.codingguy.net/?p=208</guid>
		<description><![CDATA[<a href="http://2012.html5dw.com/" title="传送门" target="_blank">大会官网传送门</a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://2012.html5dw.com/" title="传送门" target="_blank">大会官网传送门</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.codingguy.net/?feed=rss2&#038;p=208</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Node.js代码阅读笔记之libeio</title>
		<link>http://www.codingguy.net/?p=195</link>
		<comments>http://www.codingguy.net/?p=195#comments</comments>
		<pubDate>Fri, 03 Feb 2012 09:37:10 +0000</pubDate>
		<dc:creator>codingguy</dc:creator>
				<category><![CDATA[Node.js]]></category>

		<guid isPermaLink="false">http://www.codingguy.net/?p=195</guid>
		<description><![CDATA[这个库全称貌似为enhanced IO或者evented IO，用多线程实现了异步IO操作，为什么不用libev实现？因为libev用epoll，不支持regular file。没错，eio就是给fs模块用的。
<h3>从demo.c看如何使用：</h3>
翻开代码，有个demo.c，操作很多，常用文件io都包括了。精简一下代码，得到一个minidemo.c:
[code lang="C" collapse="false"]
int respipe [2];
void
want_poll (void)
{
char dummy;
printf (&#34;want_poll ()\n&#34;);
write (respipe [1], &#38;amp;dummy, 1);
}

void
done_poll (void)
{
char dummy;
printf (&#34;done_poll ()\n&#34;);
read (respipe [0], &#38;amp;dummy, 1);
}

int
res_cb (eio_req *req)
{
printf (&#34;res_cb(%d&#124;%s) = %d\n&#34;, req-&#38;gt;type, req-&#38;gt;data ? req-&#38;gt;data : &#34;?&#34;, EIO_RESULT (req));
if (req-&#38;gt;result &#38;lt; 0)
abort ();
return 0;
}

void
event_loop (void)
{
// an event loop. yeah.
struct pollfd pfd;
pfd.fd     = respipe [0];
pfd.events = POLLIN;
printf (&#34;\nentering event loop\n&#34;);
while (eio_nreqs ())
{
poll (&#38;amp;pfd, 1, -1);
printf (&#34;eio_poll () = %d\n&#34;, eio_poll ());
}
printf (&#34;leaving event loop\n&#34;);
}

int
main (void)
{
printf (&#34;pipe ()\n&#34;);
if (pipe (respipe)) abort ();
printf (&#34;eio_init ()\n&#34;);
if (eio_init (want_poll, done_poll)) abort ();
eio_mkdir (&#34;eio-test-dir&#34;, 0777, 0, res_cb, &#34;mkdir&#34;);
event_loop ();
}
[/code]

这个demo很简单，大体流程如下：
<a href="http://www.codingguy.net/wp-content/uploads/2012/02/demo.png"><img class="aligncenter size-full wp-image-199" title="libeio_demo" src="http://www.codingguy.net/wp-content/uploads/2012/02/demo.png" alt="" width="773" height="364" /></a>
<ul>
	<li>创建pipe</li>
	<li>初始化eio，注册want_poll与done_poll</li>
	<li>发出异步操作：mkdir</li>
	<li>启动event loop</li>
</ul>
第一次看到这段代码，往往被pipe搞迷糊，为什么创建pipe呢？先不管为什么，我们先看是怎么用的。

创建匿名管道后，fd放在respipe数组中，respipe[0]用于读pipe，respipe[1]用于写pipe。在want_poll和done_poll函数中，分别对pipe进行写和读。而want_poll与done_poll则通过eio_init注册，即，赋值到全局变量中。

接着发出异步操作，创建一个目录eio_mkdir(……)，这里的res_cb是操作完成之后的回调函数。

最后启动event loop。在这个函数中，有个大循环，eio_nreqs()表明尚未完成的请求数量，如果有未完成的请求，则poll respipe[0]，即等待可读，若可读则调用eio_poll取回结果。eio_poll的执行也会回调res_cb函数。

关于前面提到的pipe的作用，这与want_poll与done_poll机制有关。want_poll在响应队列第一次装入请求包的时候被调用；done_poll在响应队列为空的时候被调用。want_poll向pipe写入数据、done_poll从pipe读出数据，读之前通过poll来等待数据可读，若可读，就说明有want_poll调用，有异步请求被处理。接下来就可以调用eio_poll去接收结果并做回调了。这样，起到了类似锁的作用，同步了生产者消费者类型的资源访问，避免了无意义的循环空转，节约处理器cycle。

<h3>小窥源代码</h3>

看过demo，我们了解了hello world般的流程。但为了清楚eio接口函数的细节，以及异步io的实现方式，我们要继续读eio.[ch]的代码。话说eio的代码文件并不多，简单介绍一下名字：
<ol>
	<li>ecb.h</li>
</ol>
这个头文件叫libecb（只有一个ecb.h的lib），全称为The e compiler builtins header/library。它把gcc相关的许多功能封装起来，并兼容不同的gcc版本。比如__attribute__(attrlist)这些编译器相关的属性，可以用ecb_attribute(attrlist)这个宏来写，且不用考虑编译器版本（3.1以上才支持这个玩意）。
<ol>
	<li>eio.[ch]</li>
</ol>
就这么一对儿c文件和h文件，先不解释了

下面翻开源代码，从demo中出现的几个接口函数开始，分析一下eio的工作流程。

<h3>一切的开始：eio_init</h3>
使用eio，第一步就是调用eio_init做一堆初始化。初始化mutex、队列、各种计数器，还有注册want_poll与done_poll回调函数，这两个函数是由用户提供的。

[code lang="C" collapse="false"]
X_MUTEX_CREATE (wrklock);
X_MUTEX_CREATE (reslock);
X_MUTEX_CREATE (reqlock);
X_COND_CREATE  (reqwait);
reqq_init (&#38;amp;req_queue);
reqq_init (&#38;amp;res_queue);
wrk_first.next =
wrk_first.prev = &#38;amp;wrk_first;
started  = 0;
idle     = 0;
nreqs    = 0;
nready   = 0;
npending = 0;
want_poll_cb = want_poll;
done_poll_cb = done_poll;
[/code]

<h3>业务逻辑的入口：eio_xxx</h3>
初始化之后，即可调用eio的异步io函数了。我们以前面demo中创建目录为例，调用eio_mkdir(…)函数。如其他异步io函数，函数体非常简洁，但是逻辑并不简洁：

[code lang="C" collapse="false"]
eio_req *eio_mkdir (const char *path, eio_mode_t mode, int pri, eio_cb cb, void *data)
{
REQ (EIO_MKDIR); PATH; req-&#38;gt;int2 = (long)mode; SEND;
}
[/code]

真是那各种宏啊，淡定一下，找找定义：
[code lang="C" collapse="false"]
#define REQ(rtype)                                              \
eio_req *req;                                                 \
req = (eio_req *)calloc (1, sizeof *req);                     \
if (!req)                                                     \
return 0;                                                   \
req-&#38;gt;type    = rtype;                                         \
req-&#38;gt;pri     = pri;                                                    \
req-&#38;gt;finish  = cb;                                                       \
req-&#38;gt;data    = data;                                               \
req-&#38;gt;destroy = eio_api_destroy;
[/code]

这个宏创建了一个eio_req变量，注意是堆空间哦。然后根据rtype，也就是io操作的类型，对其赋值。那些cb等参数都不是宏里面的，从使用场景可以看出是eio _mkdir的参数。接下来是PATH，同样找到定义如下：

[code lang="C" collapse="false"]
#define PATH                                                           \
req-&#38;gt;flags &#124;= EIO_FLAG_PTR1_FREE;                             \
req-&#38;gt;ptr1 = strdup (path);                                        \
if (!req-&#38;gt;ptr1)                                                      \
{                                                                         \
eio_api_destroy (req);                                               \
return 0;                                                               \
}
[/code]

文件io操作嘛，自然要有path。接下来又填写了mode。以上这些操作都是为了构建一个eio_req变量。这个eio_req的结构定义如下：

[code lang="C" collapse="false"]
struct eio_req
{
eio_req volatile *next; /* private ETP */
eio_ssize_t result;  /* result of syscall, e.g. result = read (... */
off_t offs;      /* read, write, truncate, readahead, sync_file_range, fallocate: file offset, mknod: dev_t */
size_t size;     /* read, write, readahead, sendfile, msync, mlock, sync_file_range, fallocate: length */
void *ptr1;      /* all applicable requests: pathname, old name; readdir: optional eio_dirents */
void *ptr2;      /* all applicable requests: new name or memory buffer; readdir: name strings */
eio_tstamp nv1;  /* utime, futime: atime; busy: sleep time */
eio_tstamp nv2;  /* utime, futime: mtime */
int type;        /* EIO_xxx constant ETP */
int int1;        /* all applicable requests: file descriptor; sendfile: output fd; open, msync, mlockall, readdir: flags */
long int2;       /* chown, fchown: uid; sendfile: input fd; open, chmod, mkdir, mknod: file mode, sync_file_range, fallocate: flags */
long int3;       /* chown, fchown: gid */
int errorno;     /* errno value on syscall return */
#if __i386 &#124;&#124; __amd64
unsigned char cancelled;
#else
sig_atomic_t cancelled;
#endif
unsigned char flags; /* private */
signed char pri;     /* the priority */
void *data;
eio_cb finish;
void (*destroy)(eio_req *req); /* called when request no longer needed */
void (*feed)(eio_req *req);    /* only used for group requests */
EIO_REQ_MEMBERS
eio_req *grp, *grp_prev, *grp_next, *grp_first; /* private */
};
[/code]

初始化了一个新的eio_req，接下只用了一个SEND完成其余工作，SEND定义很简单，只是调用了eio_submit函数：
[code lang="C" collapse="false"]
#define SEND eio_submit (req); return req
[/code]

<h3>异步IO的抽象：eio_submit</h3>
eio_submit只是etp_submit的一个封装：

[code lang="C" collapse="false"]
void
eio_submit (eio_req *req)
{
etp_submit (req);
}
[/code]

这个etp_submit几乎是所有io操作的入口，其中的关键代码如下：

[code lang="C" collapse="false"]
X_LOCK (reqlock);
++nreqs;
++nready;
reqq_push (&#38;amp;req_queue, req);
X_COND_SIGNAL (reqwait);
X_UNLOCK (reqlock);
etp_maybe_start_thread ();
[/code]

先做计数器累加，然后把刚刚初始化的eio_req放在req_queue，这是request队列，然后调动etp_maybe_start_thread()，在这个函数中会判断是否调用etp_start_thread()启动工作线程。判断逻辑如下：

[code lang="C" collapse="false"]
if (ecb_expect_true (etp_nthreads () &#38;gt;= wanted))
return;
if (ecb_expect_true (0 &#38;lt;= (int)etp_nthreads () + (int)etp_npending () - (int)etp_nreqs ()))
return;
[/code]

1．  先判断工作线程数量，如果已到达上限（wanted，默认是4），则直接返回，不做任何操作。

2．  如果<strong>当前的工作线程数量</strong>与<strong>已处理请求数量</strong>的和小于<strong>总的请求数量</strong>（包括完成与未完成的），则直接返回，不做任何操作

条件都满足了，接下来会调用etp_start_thread()函数，通过thread_create创建线程。
<h3>线程？！没错，就是线程：eio_proc</h3>
在etp_start_thread()中创建线程，线程函数etp_proc的代码大致如下：

[code lang="C" collapse="false"]
for (;;)
{
for (;;)
{
self-&#62;req = req = reqq_shift (&#38;amp;req_queue);
if (req)
break;
}

ETP_EXECUTE (self, req);

if (!reqq_push (&#38;amp;res_queue, req) &#38;amp;&#38;amp; want_poll_cb)
want_poll_cb ();
}
[/code]

流程概括如下：
<ol>
	<li>从req_queue队列（即，待处理队列）中取出一个eio请求</li>
	<li>调用ETP_EXECUTE完成io的实质操作，这会是一个阻塞过程。</li>
	<li>将eio请求插入res_queue队列（即，已处理队列）</li>
	<li>调用want_poll_cb回调函数</li>
</ol>
这里要注意want_poll_cb的回调条件，当且仅当入队前res_queue为空，才会调用。
<h3>执行同步IO：eio_execute</h3>
线程函数中有ETP_EXECUTE出现，这个宏指代了eio_execute函数。在这个函数里面，根据eio_req的type域进行switch case，调用相应的io函数完成实质操作，并把结果写到eio_req中。简单代码如下：

[code lang="C" collapse="false"]
// ...
switch (req-&#38;gt;type)
{
// ...
case EIO_MKDIR:     req-&#38;gt;result = mkdir     (req-&#38;gt;ptr1, (eio_mode_t)req-&#38;gt;int2); break;
// ...
}
// ...
[/code]

单纯从异步IO操作的执行看，前面介绍的流程已经能完成了，但是我们不仅要执行IO，还要获取执行的结果，并触发想要的回调。这是通过eio_poll来实现的：
<h3>接收报告：eio_poll</h3>
如同很多函数一样，eio_poll只是套了个壳儿，进而调用etp_poll。删减了一些代码，挑出重要逻辑如下：

[code lang="C" collapse="false"]
for (;;)
{
ETP_REQ *req;
etp_maybe_start_thread ();
req = reqq_shift (&#38;amp;res_queue);
if (req)
{
if (!res_queue.size &#38;amp;&#38;amp; done_poll_cb)
done_poll_cb ();
}
--nreqs;
}
[/code]

流程要点如下：
<ol>
	<li>调用etp_maybe_start_thread()，上面已经讲过，在满足条件的情况下会创建工作线程。</li>
	<li>从res_queue中取出一个eio_req</li>
	<li>如果res_queue为空，则触发done_poll_cb回调</li>
</ol>
<h3>总结</h3>
就这样吧，再给出一张图来整体贯穿一下：

<a href="http://www.codingguy.net/wp-content/uploads/2012/02/all.png"><img class="aligncenter size-full wp-image-198" title="libeio_all" src="http://www.codingguy.net/wp-content/uploads/2012/02/all.png" alt="" width="1062" height="691" /></a>]]></description>
			<content:encoded><![CDATA[<p>这个库全称貌似为enhanced IO或者evented IO，用多线程实现了异步IO操作，为什么不用libev实现？因为libev用epoll，不支持regular file。没错，eio就是给fs模块用的。</p>
<h3>从demo.c看如何使用：</h3>
<p>翻开代码，有个demo.c，操作很多，常用文件io都包括了。精简一下代码，得到一个minidemo.c:</p>
<pre class="brush: cpp; collapse: false; light: false; title: ; toolbar: true; notranslate">
int respipe [2];
void
want_poll (void)
{
char dummy;
printf (&quot;want_poll ()\n&quot;);
write (respipe [1], &amp;amp;dummy, 1);
}

void
done_poll (void)
{
char dummy;
printf (&quot;done_poll ()\n&quot;);
read (respipe [0], &amp;amp;dummy, 1);
}

int
res_cb (eio_req *req)
{
printf (&quot;res_cb(%d|%s) = %d\n&quot;, req-&amp;gt;type, req-&amp;gt;data ? req-&amp;gt;data : &quot;?&quot;, EIO_RESULT (req));
if (req-&amp;gt;result &amp;lt; 0)
abort ();
return 0;
}

void
event_loop (void)
{
// an event loop. yeah.
struct pollfd pfd;
pfd.fd     = respipe [0];
pfd.events = POLLIN;
printf (&quot;\nentering event loop\n&quot;);
while (eio_nreqs ())
{
poll (&amp;amp;pfd, 1, -1);
printf (&quot;eio_poll () = %d\n&quot;, eio_poll ());
}
printf (&quot;leaving event loop\n&quot;);
}

int
main (void)
{
printf (&quot;pipe ()\n&quot;);
if (pipe (respipe)) abort ();
printf (&quot;eio_init ()\n&quot;);
if (eio_init (want_poll, done_poll)) abort ();
eio_mkdir (&quot;eio-test-dir&quot;, 0777, 0, res_cb, &quot;mkdir&quot;);
event_loop ();
}
</pre>
<p>这个demo很简单，大体流程如下：<br />
<a href="http://www.codingguy.net/wp-content/uploads/2012/02/demo.png"><img class="aligncenter size-full wp-image-199" title="libeio_demo" src="http://www.codingguy.net/wp-content/uploads/2012/02/demo.png" alt="" width="773" height="364" /></a></p>
<ul>
<li>创建pipe</li>
<li>初始化eio，注册want_poll与done_poll</li>
<li>发出异步操作：mkdir</li>
<li>启动event loop</li>
</ul>
<p>第一次看到这段代码，往往被pipe搞迷糊，为什么创建pipe呢？先不管为什么，我们先看是怎么用的。</p>
<p>创建匿名管道后，fd放在respipe数组中，respipe[0]用于读pipe，respipe[1]用于写pipe。在want_poll和done_poll函数中，分别对pipe进行写和读。而want_poll与done_poll则通过eio_init注册，即，赋值到全局变量中。</p>
<p>接着发出异步操作，创建一个目录eio_mkdir(……)，这里的res_cb是操作完成之后的回调函数。</p>
<p>最后启动event loop。在这个函数中，有个大循环，eio_nreqs()表明尚未完成的请求数量，如果有未完成的请求，则poll respipe[0]，即等待可读，若可读则调用eio_poll取回结果。eio_poll的执行也会回调res_cb函数。</p>
<p>关于前面提到的pipe的作用，这与want_poll与done_poll机制有关。want_poll在响应队列第一次装入请求包的时候被调用；done_poll在响应队列为空的时候被调用。want_poll向pipe写入数据、done_poll从pipe读出数据，读之前通过poll来等待数据可读，若可读，就说明有want_poll调用，有异步请求被处理。接下来就可以调用eio_poll去接收结果并做回调了。这样，起到了类似锁的作用，同步了生产者消费者类型的资源访问，避免了无意义的循环空转，节约处理器cycle。</p>
<h3>小窥源代码</h3>
<p>看过demo，我们了解了hello world般的流程。但为了清楚eio接口函数的细节，以及异步io的实现方式，我们要继续读eio.[ch]的代码。话说eio的代码文件并不多，简单介绍一下名字：</p>
<ol>
<li>ecb.h</li>
</ol>
<p>这个头文件叫libecb（只有一个ecb.h的lib），全称为The e compiler builtins header/library。它把gcc相关的许多功能封装起来，并兼容不同的gcc版本。比如__attribute__(attrlist)这些编译器相关的属性，可以用ecb_attribute(attrlist)这个宏来写，且不用考虑编译器版本（3.1以上才支持这个玩意）。</p>
<ol>
<li>eio.[ch]</li>
</ol>
<p>就这么一对儿c文件和h文件，先不解释了</p>
<p>下面翻开源代码，从demo中出现的几个接口函数开始，分析一下eio的工作流程。</p>
<h3>一切的开始：eio_init</h3>
<p>使用eio，第一步就是调用eio_init做一堆初始化。初始化mutex、队列、各种计数器，还有注册want_poll与done_poll回调函数，这两个函数是由用户提供的。</p>
<pre class="brush: cpp; collapse: false; light: false; title: ; toolbar: true; notranslate">
X_MUTEX_CREATE (wrklock);
X_MUTEX_CREATE (reslock);
X_MUTEX_CREATE (reqlock);
X_COND_CREATE  (reqwait);
reqq_init (&amp;amp;req_queue);
reqq_init (&amp;amp;res_queue);
wrk_first.next =
wrk_first.prev = &amp;amp;wrk_first;
started  = 0;
idle     = 0;
nreqs    = 0;
nready   = 0;
npending = 0;
want_poll_cb = want_poll;
done_poll_cb = done_poll;
</pre>
<h3>业务逻辑的入口：eio_xxx</h3>
<p>初始化之后，即可调用eio的异步io函数了。我们以前面demo中创建目录为例，调用eio_mkdir(…)函数。如其他异步io函数，函数体非常简洁，但是逻辑并不简洁：</p>
<pre class="brush: cpp; collapse: false; light: false; title: ; toolbar: true; notranslate">
eio_req *eio_mkdir (const char *path, eio_mode_t mode, int pri, eio_cb cb, void *data)
{
REQ (EIO_MKDIR); PATH; req-&amp;gt;int2 = (long)mode; SEND;
}
</pre>
<p>真是那各种宏啊，淡定一下，找找定义：</p>
<pre class="brush: cpp; collapse: false; light: false; title: ; toolbar: true; notranslate">
#define REQ(rtype)                                              \
eio_req *req;                                                 \
req = (eio_req *)calloc (1, sizeof *req);                     \
if (!req)                                                     \
return 0;                                                   \
req-&amp;gt;type    = rtype;                                         \
req-&amp;gt;pri     = pri;                                                    \
req-&amp;gt;finish  = cb;                                                       \
req-&amp;gt;data    = data;                                               \
req-&amp;gt;destroy = eio_api_destroy;
</pre>
<p>这个宏创建了一个eio_req变量，注意是堆空间哦。然后根据rtype，也就是io操作的类型，对其赋值。那些cb等参数都不是宏里面的，从使用场景可以看出是eio _mkdir的参数。接下来是PATH，同样找到定义如下：</p>
<pre class="brush: cpp; collapse: false; light: false; title: ; toolbar: true; notranslate">
#define PATH                                                           \
req-&amp;gt;flags |= EIO_FLAG_PTR1_FREE;                             \
req-&amp;gt;ptr1 = strdup (path);                                        \
if (!req-&amp;gt;ptr1)                                                      \
{                                                                         \
eio_api_destroy (req);                                               \
return 0;                                                               \
}
</pre>
<p>文件io操作嘛，自然要有path。接下来又填写了mode。以上这些操作都是为了构建一个eio_req变量。这个eio_req的结构定义如下：</p>
<pre class="brush: cpp; collapse: false; light: false; title: ; toolbar: true; notranslate">
struct eio_req
{
eio_req volatile *next; /* private ETP */
eio_ssize_t result;  /* result of syscall, e.g. result = read (... */
off_t offs;      /* read, write, truncate, readahead, sync_file_range, fallocate: file offset, mknod: dev_t */
size_t size;     /* read, write, readahead, sendfile, msync, mlock, sync_file_range, fallocate: length */
void *ptr1;      /* all applicable requests: pathname, old name; readdir: optional eio_dirents */
void *ptr2;      /* all applicable requests: new name or memory buffer; readdir: name strings */
eio_tstamp nv1;  /* utime, futime: atime; busy: sleep time */
eio_tstamp nv2;  /* utime, futime: mtime */
int type;        /* EIO_xxx constant ETP */
int int1;        /* all applicable requests: file descriptor; sendfile: output fd; open, msync, mlockall, readdir: flags */
long int2;       /* chown, fchown: uid; sendfile: input fd; open, chmod, mkdir, mknod: file mode, sync_file_range, fallocate: flags */
long int3;       /* chown, fchown: gid */
int errorno;     /* errno value on syscall return */
#if __i386 || __amd64
unsigned char cancelled;
#else
sig_atomic_t cancelled;
#endif
unsigned char flags; /* private */
signed char pri;     /* the priority */
void *data;
eio_cb finish;
void (*destroy)(eio_req *req); /* called when request no longer needed */
void (*feed)(eio_req *req);    /* only used for group requests */
EIO_REQ_MEMBERS
eio_req *grp, *grp_prev, *grp_next, *grp_first; /* private */
};
</pre>
<p>初始化了一个新的eio_req，接下只用了一个SEND完成其余工作，SEND定义很简单，只是调用了eio_submit函数：</p>
<pre class="brush: cpp; collapse: false; light: false; title: ; toolbar: true; notranslate">
#define SEND eio_submit (req); return req
</pre>
<h3>异步IO的抽象：eio_submit</h3>
<p>eio_submit只是etp_submit的一个封装：</p>
<pre class="brush: cpp; collapse: false; light: false; title: ; toolbar: true; notranslate">
void
eio_submit (eio_req *req)
{
etp_submit (req);
}
</pre>
<p>这个etp_submit几乎是所有io操作的入口，其中的关键代码如下：</p>
<pre class="brush: cpp; collapse: false; light: false; title: ; toolbar: true; notranslate">
X_LOCK (reqlock);
++nreqs;
++nready;
reqq_push (&amp;amp;req_queue, req);
X_COND_SIGNAL (reqwait);
X_UNLOCK (reqlock);
etp_maybe_start_thread ();
</pre>
<p>先做计数器累加，然后把刚刚初始化的eio_req放在req_queue，这是request队列，然后调动etp_maybe_start_thread()，在这个函数中会判断是否调用etp_start_thread()启动工作线程。判断逻辑如下：</p>
<pre class="brush: cpp; collapse: false; light: false; title: ; toolbar: true; notranslate">
if (ecb_expect_true (etp_nthreads () &amp;gt;= wanted))
return;
if (ecb_expect_true (0 &amp;lt;= (int)etp_nthreads () + (int)etp_npending () - (int)etp_nreqs ()))
return;
</pre>
<p>1．  先判断工作线程数量，如果已到达上限（wanted，默认是4），则直接返回，不做任何操作。</p>
<p>2．  如果<strong>当前的工作线程数量</strong>与<strong>已处理请求数量</strong>的和小于<strong>总的请求数量</strong>（包括完成与未完成的），则直接返回，不做任何操作</p>
<p>条件都满足了，接下来会调用etp_start_thread()函数，通过thread_create创建线程。</p>
<h3>线程？！没错，就是线程：eio_proc</h3>
<p>在etp_start_thread()中创建线程，线程函数etp_proc的代码大致如下：</p>
<pre class="brush: cpp; collapse: false; light: false; title: ; toolbar: true; notranslate">
for (;;)
{
for (;;)
{
self-&gt;req = req = reqq_shift (&amp;amp;req_queue);
if (req)
break;
}

ETP_EXECUTE (self, req);

if (!reqq_push (&amp;amp;res_queue, req) &amp;amp;&amp;amp; want_poll_cb)
want_poll_cb ();
}
</pre>
<p>流程概括如下：</p>
<ol>
<li>从req_queue队列（即，待处理队列）中取出一个eio请求</li>
<li>调用ETP_EXECUTE完成io的实质操作，这会是一个阻塞过程。</li>
<li>将eio请求插入res_queue队列（即，已处理队列）</li>
<li>调用want_poll_cb回调函数</li>
</ol>
<p>这里要注意want_poll_cb的回调条件，当且仅当入队前res_queue为空，才会调用。</p>
<h3>执行同步IO：eio_execute</h3>
<p>线程函数中有ETP_EXECUTE出现，这个宏指代了eio_execute函数。在这个函数里面，根据eio_req的type域进行switch case，调用相应的io函数完成实质操作，并把结果写到eio_req中。简单代码如下：</p>
<pre class="brush: cpp; collapse: false; light: false; title: ; toolbar: true; notranslate">
// ...
switch (req-&amp;gt;type)
{
// ...
case EIO_MKDIR:     req-&amp;gt;result = mkdir     (req-&amp;gt;ptr1, (eio_mode_t)req-&amp;gt;int2); break;
// ...
}
// ...
</pre>
<p>单纯从异步IO操作的执行看，前面介绍的流程已经能完成了，但是我们不仅要执行IO，还要获取执行的结果，并触发想要的回调。这是通过eio_poll来实现的：</p>
<h3>接收报告：eio_poll</h3>
<p>如同很多函数一样，eio_poll只是套了个壳儿，进而调用etp_poll。删减了一些代码，挑出重要逻辑如下：</p>
<pre class="brush: cpp; collapse: false; light: false; title: ; toolbar: true; notranslate">
for (;;)
{
ETP_REQ *req;
etp_maybe_start_thread ();
req = reqq_shift (&amp;amp;res_queue);
if (req)
{
if (!res_queue.size &amp;amp;&amp;amp; done_poll_cb)
done_poll_cb ();
}
--nreqs;
}
</pre>
<p>流程要点如下：</p>
<ol>
<li>调用etp_maybe_start_thread()，上面已经讲过，在满足条件的情况下会创建工作线程。</li>
<li>从res_queue中取出一个eio_req</li>
<li>如果res_queue为空，则触发done_poll_cb回调</li>
</ol>
<h3>总结</h3>
<p>就这样吧，再给出一张图来整体贯穿一下：</p>
<p><a href="http://www.codingguy.net/wp-content/uploads/2012/02/all.png"><img class="aligncenter size-full wp-image-198" title="libeio_all" src="http://www.codingguy.net/wp-content/uploads/2012/02/all.png" alt="" width="1062" height="691" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.codingguy.net/?feed=rss2&#038;p=195</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Reading node.js&#8217;source code (2): uv overview</title>
		<link>http://www.codingguy.net/?p=183</link>
		<comments>http://www.codingguy.net/?p=183#comments</comments>
		<pubDate>Tue, 31 Jan 2012 09:19:42 +0000</pubDate>
		<dc:creator>codingguy</dc:creator>
				<category><![CDATA[Node.js]]></category>

		<guid isPermaLink="false">http://www.codingguy.net/?p=183</guid>
		<description><![CDATA[After peered the entry of Node.js, I think I have to read source code deeply in order to understand how does it working.

Beside the v8 engine, the most important is libuv. libuv as a platform layer for Node, its purpose is to abstract IOCP on Windows and libev on Unix systems. Of course, we pay attention to Unix system (maybe call *nix is better ?). Related libraries in libuv is as follow:
<ul>
	<li>ares</li>
</ul>
<p style="padding-left: 30px;">This is c-ares, an asynchronous resolver library.</p>

<ul>
	<li>libev</li>
</ul>
<p style="padding-left: 30px;">In a word: libev is an event loop</p>

<ul>
	<li>libeio</li>
</ul>
<p style="padding-left: 30px;">In a word: libeio is an asynchronous I/O library</p>

<pre></pre>]]></description>
			<content:encoded><![CDATA[<p>After peered the entry of Node.js, I think I have to read source code deeply in order to understand how does it working.</p>
<p>Beside the v8 engine, the most important is libuv. libuv as a platform layer for Node, its purpose is to abstract IOCP on Windows and libev on Unix systems. Of course, we pay attention to Unix system (maybe call *nix is better ?). Related libraries in libuv is as follow:</p>
<ul>
<li>ares</li>
</ul>
<p style="padding-left: 30px;">This is c-ares, an asynchronous resolver library.</p>
<ul>
<li>libev</li>
</ul>
<p style="padding-left: 30px;">In a word: libev is an event loop</p>
<ul>
<li>libeio</li>
</ul>
<p style="padding-left: 30px;">In a word: libeio is an asynchronous I/O library</p>
<pre></pre>
]]></content:encoded>
			<wfw:commentRss>http://www.codingguy.net/?feed=rss2&#038;p=183</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>HTML5 Tetris</title>
		<link>http://www.codingguy.net/?p=179</link>
		<comments>http://www.codingguy.net/?p=179#comments</comments>
		<pubDate>Thu, 05 Jan 2012 09:35:22 +0000</pubDate>
		<dc:creator>codingguy</dc:creator>
				<category><![CDATA[HTML5_JS]]></category>

		<guid isPermaLink="false">http://www.codingguy.net/?p=179</guid>
		<description><![CDATA[I wrote a classic tetris program just for touching the canvas component of HTML5.
Unfortunately, I have not run the javascript code by embedding into article successfully
so, Here is the link:
<a href="http://www.codingguy.net/tetris.html">http://www.codingguy.net/tetris.html</a>
notice: there are several bugs and the experience is so terrible :)]]></description>
			<content:encoded><![CDATA[<p>I wrote a classic tetris program just for touching the canvas component of HTML5.<br />
Unfortunately, I have not run the javascript code by embedding into article successfully<br />
so, Here is the link:<br />
<a href="http://www.codingguy.net/tetris.html">http://www.codingguy.net/tetris.html</a><br />
notice: there are several bugs and the experience is so terrible <img src='http://www.codingguy.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.codingguy.net/?feed=rss2&#038;p=179</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Reading node.js&#8217;source code (1)</title>
		<link>http://www.codingguy.net/?p=141</link>
		<comments>http://www.codingguy.net/?p=141#comments</comments>
		<pubDate>Thu, 22 Dec 2011 10:21:51 +0000</pubDate>
		<dc:creator>codingguy</dc:creator>
				<category><![CDATA[Node.js]]></category>

		<guid isPermaLink="false">http://www.codingguy.net/?p=141</guid>
		<description><![CDATA[Now we will read Init() which be called at first in Start()

Init(), as the name, is responsible for following work:
<ul>
	<li>Parse command line arguments</li>
	<li>Prepare v8 runtime</li>
<ul>
	<li>Set v8 flags (like stack size limit)</li>
	<li>Set fatal error handler</li>
</ul>
	<li>Prepare signal handler</li>
	<li>uv init</li>
</ul>]]></description>
			<content:encoded><![CDATA[<p>Now we will read Init() which be called at first in Start()</p>
<p>Init(), as the name, is responsible for following work:</p>
<ul>
<li>Parse command line arguments</li>
<li>Prepare v8 runtime</li>
<ul>
<li>Set v8 flags (like stack size limit)</li>
<li>Set fatal error handler</li>
</ul>
<li>Prepare signal handler</li>
<li>uv init</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.codingguy.net/?feed=rss2&#038;p=141</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Reading node.js&#8217;source code (0)</title>
		<link>http://www.codingguy.net/?p=118</link>
		<comments>http://www.codingguy.net/?p=118#comments</comments>
		<pubDate>Thu, 22 Dec 2011 08:46:44 +0000</pubDate>
		<dc:creator>codingguy</dc:creator>
				<category><![CDATA[Node.js]]></category>

		<guid isPermaLink="false">http://www.codingguy.net/?p=118</guid>
		<description><![CDATA[Node.js is not a single project as there are several components.
You can find them under NODEJS_SOURCE/deps:
<strong>http_parser</strong>, <strong>openssl</strong>, <strong>uv</strong>, <strong>v8</strong>, <strong>zlib</strong>

And of course, the source under NODEJS_SOURCE/src is the core of Node.js project. So I start to read the source code at this point. No matter whether it is the correct entry point... may be I will clear about this in future :)

Files in NODEJS_SOURCE/src:
36 .cc files, totally 18009 lines
26 .h files, totally 5420 lines
2 .py files, we don't care about these temporarily

The <span style="color: #ff0000;">node_main.cc</span> is the whole entry, you can find main function in this file. furthermore, there is only one function which has one line:

[code lang="C" collapse="false" highlight="4"]
#include

int main(int argc, char *argv[]) {
  return node::Start(argc, argv);
}
[/code]

The highlight function call node::Start defined in node.cc. Following is corresponding code:

[code lang="C" collapse="false" highlight="3,5,9,10,12,13,17,24,26"]
int Start(int argc, char *argv[]) {
  // This needs to run *before* V8::Initialize()
  argv = Init(argc, argv);

  v8::V8::Initialize();
  v8::HandleScope handle_scope;

  // Create the one and only Context.
  Persistent&#60;v8::Context&#62; context = v8::Context::New();
  v8::Context::Scope context_scope(context);

  Handle&#60;Object&#62; process = SetupProcessObject(argc, argv);
  v8_typed_array::AttachBindings(context-&#62;Global());

  // Create all the objects, load modules, do everything.
  // so your next reading stop should be node::Load()!
  Load(process);

  // All our arguments are loaded. We've evaluated all of the scripts. We
  // might even have created TCP servers. Now we enter the main eventloop. If
  // there are no watchers on the loop (except for the ones that were
  // uv_unref'd) then this function exits. As long as there are active
  // watchers, it blocks.
  uv_run(uv_default_loop());

  EmitExit(process);

#ifndef NDEBUG
  // Clean up.
  context.Dispose();
  V8::Dispose();
#endif  // NDEBUG

  return 0;
}
[/code]

We have to deep into each highlight function call.]]></description>
			<content:encoded><![CDATA[<p>Node.js is not a single project as there are several components.<br />
You can find them under NODEJS_SOURCE/deps:<br />
<strong>http_parser</strong>, <strong>openssl</strong>, <strong>uv</strong>, <strong>v8</strong>, <strong>zlib</strong></p>
<p>And of course, the source under NODEJS_SOURCE/src is the core of Node.js project. So I start to read the source code at this point. No matter whether it is the correct entry point&#8230; may be I will clear about this in future <img src='http://www.codingguy.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Files in NODEJS_SOURCE/src:<br />
36 .cc files, totally 18009 lines<br />
26 .h files, totally 5420 lines<br />
2 .py files, we don&#8217;t care about these temporarily</p>
<p>The <span style="color: #ff0000;">node_main.cc</span> is the whole entry, you can find main function in this file. furthermore, there is only one function which has one line:</p>
<pre class="brush: cpp; collapse: false; highlight: [4]; light: false; title: ; toolbar: true; notranslate">
#include

int main(int argc, char *argv[]) {
  return node::Start(argc, argv);
}
</pre>
<p>The highlight function call node::Start defined in node.cc. Following is corresponding code:</p>
<pre class="brush: cpp; collapse: false; highlight: [3,5,9,10,12,13,17,24,26]; light: false; title: ; toolbar: true; notranslate">
int Start(int argc, char *argv[]) {
  // This needs to run *before* V8::Initialize()
  argv = Init(argc, argv);

  v8::V8::Initialize();
  v8::HandleScope handle_scope;

  // Create the one and only Context.
  Persistent&lt;v8::Context&gt; context = v8::Context::New();
  v8::Context::Scope context_scope(context);

  Handle&lt;Object&gt; process = SetupProcessObject(argc, argv);
  v8_typed_array::AttachBindings(context-&gt;Global());

  // Create all the objects, load modules, do everything.
  // so your next reading stop should be node::Load()!
  Load(process);

  // All our arguments are loaded. We've evaluated all of the scripts. We
  // might even have created TCP servers. Now we enter the main eventloop. If
  // there are no watchers on the loop (except for the ones that were
  // uv_unref'd) then this function exits. As long as there are active
  // watchers, it blocks.
  uv_run(uv_default_loop());

  EmitExit(process);

#ifndef NDEBUG
  // Clean up.
  context.Dispose();
  V8::Dispose();
#endif  // NDEBUG

  return 0;
}
</pre>
<p>We have to deep into each highlight function call.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.codingguy.net/?feed=rss2&#038;p=118</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Example of Binder Device Access</title>
		<link>http://www.codingguy.net/?p=95</link>
		<comments>http://www.codingguy.net/?p=95#comments</comments>
		<pubDate>Thu, 22 Dec 2011 05:06:48 +0000</pubDate>
		<dc:creator>codingguy</dc:creator>
				<category><![CDATA[Android]]></category>

		<guid isPermaLink="false">http://www.codingguy.net/?p=95</guid>
		<description><![CDATA[As well-known, binder driver is the core component of Android IPC mechanism. Either client side or service side use binder lib to complete the communication as usual. But we can also access binder driver directly. Here is an example, we open binder device and get version number var ioctl():

[code lang="C" collapse="false"]
/*
 * Binder test, try to get binder version via ioctl()
 *
 */

#include &#60;stdio.h&#62;
#include &#60;stdlib.h&#62;
#include &#60;errno.h&#62;
#include &#60;unistd.h&#62;
#include &#60;fcntl.h&#62;

#include &#34;binder.h&#34;

struct binder_state
{
    int fd;
    void *mapped;
    unsigned mapsize;
};

signed long get_version(struct binder_state *bs)
{
	struct binder_version ver;

	int ret = ioctl(bs-&#62;fd, BINDER_VERSION, (unsigned long)&#38;ver);
	if (ret &#60; 0) {
		perror(&#34;binder_write: ioctl failed !&#34;);
		return -1;
	}

	return ver.protocol_version;
}

int main(int argc, char *argv[])
{
	struct binder_state *bs;
	signed long ver;

	bs = binder_open(128*1024);
	if (!bs) {
		perror(&#34;could not open binder device !&#34;);
		return -1;
	}

	ver = get_version(bs);

	printf(&#34;\nbinder version = 0x%08x (%d)\n\n&#34;, ver, ver);

	binder_close(bs);
	return 0;
}

[/code]]]></description>
			<content:encoded><![CDATA[<p>As well-known, binder driver is the core component of Android IPC mechanism. Either client side or service side use binder lib to complete the communication as usual. But we can also access binder driver directly. Here is an example, we open binder device and get version number var ioctl():</p>
<pre class="brush: cpp; collapse: false; light: false; title: ; toolbar: true; notranslate">
/*
 * Binder test, try to get binder version via ioctl()
 *
 */

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;errno.h&gt;
#include &lt;unistd.h&gt;
#include &lt;fcntl.h&gt;

#include &quot;binder.h&quot;

struct binder_state
{
    int fd;
    void *mapped;
    unsigned mapsize;
};

signed long get_version(struct binder_state *bs)
{
	struct binder_version ver;

	int ret = ioctl(bs-&gt;fd, BINDER_VERSION, (unsigned long)&amp;ver);
	if (ret &lt; 0) {
		perror(&quot;binder_write: ioctl failed !&quot;);
		return -1;
	}

	return ver.protocol_version;
}

int main(int argc, char *argv[])
{
	struct binder_state *bs;
	signed long ver;

	bs = binder_open(128*1024);
	if (!bs) {
		perror(&quot;could not open binder device !&quot;);
		return -1;
	}

	ver = get_version(bs);

	printf(&quot;\nbinder version = 0x%08x (%d)\n\n&quot;, ver, ver);

	binder_close(bs);
	return 0;
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.codingguy.net/?feed=rss2&#038;p=95</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>HOW-TO of Android NDK</title>
		<link>http://www.codingguy.net/?p=89</link>
		<comments>http://www.codingguy.net/?p=89#comments</comments>
		<pubDate>Sat, 17 Dec 2011 21:21:08 +0000</pubDate>
		<dc:creator>codingguy</dc:creator>
				<category><![CDATA[Android]]></category>

		<guid isPermaLink="false">http://www.codingguy.net/?p=89</guid>
		<description><![CDATA[<strong>How to force the display of build commands:</strong>
-------------------------------------------

Do "ndk-build V=1" and actual build commands will be displayed. This can be used to verify that things are compiled as you expect them to, and check for bugs in the NDK build system.

(The V=1 trick comes from the Linux kernel build system)

<strong>How to force a rebuild of all your sources:</strong>
-------------------------------------------

Use GNU Make's "-B" option, as in:

<span style="color: #0000ff;">ndk-build -B</span>

<strong>How to store your native sources in a location other than $PROJECT/jni:</strong>
-----------------------------------------------------------------------

First, you can simply tell your $PROJECT/jni/Android.mk to include another Android.mk that are located in different places. Alternatively, you can define APP_BUILD_SCRIPT in your Application.mk to point to an alternative Android.mk file.

<strong>How to build a project's native files without cd-ing to it:</strong>
-----------------------------------------------------------

Sometimes, you may need to rebuild a project's native file without being able to cd to its top-level path from the command-line. This is do-able by using the GNU-Make '-C &#60;path&#62;' option, as in:

<span style="color: #0000ff;">ndk-build -C &#60;project-path&#62;</span>

<strong>How to store your Application.mk in a location other than $PROJECT/jni:</strong>
-----------------------------------------------------------------------

Starting with NDK r4, you can simply place the file under $PROJECT/jni/ and launch the 'ndk-build' script from your project tree.

If you want to use 'ndk-build' but place the file to a different location, use a GNU Make variable override as:

<span style="color: #0000ff;">ndk-build NDK_APPLICATION_MK=/path/to/your/Application.mk</span>

If you're using the legacy $NDK/apps/&#60;name&#62; build method, you can create a symbolic link to your final Application.mk there. For example, imagine that you wrote: $PROJECT/foo/Application.mk You can create a symlink like with a command like:

<span style="color: #0000ff;">ln -s $PROJECT/foo $NDK/apps/&#60;name&#62;</span>

This will make $NDK/apps/&#60;name&#62;/Application.mk point directly to $PROJECT/jni/Application.mk

Note that generated files will still go under $NDK/out/apps/&#60;name&#62; though.

Windows users: The NDK is only supported on Cygwin, which implements symbolic links through the "ln -s" command, as in:

<span style="color: #0000ff;">ln -s &#60;target&#62; &#60;link&#62;</span>

<strong>How to properly add include directories to your module declaration:</strong>
-------------------------------------------------------------------

If you define several modules, it is common to need to include one module's header while compiling another one. For example, consider the following example:

<span style="color: #0000ff;">$PROJECT/jni/foo/</span>
<span style="color: #0000ff;"> Android.mk</span>
<span style="color: #0000ff;"> foo.h</span>
<span style="color: #0000ff;"> foo.c</span>

<span style="color: #0000ff;">$PROJECT/jni/bar/</span>
<span style="color: #0000ff;"> Android.mk</span>
<span style="color: #0000ff;"> bar.c</span>

Where the 'bar.c' uses '#include &#60;foo.h&#62;'. You will need to add the path to the 'foo' module in jni/bar/Android.mk to build it properly. One is tempted to use the following:

<span style="color: #0000ff;">LOCAL_C_INCLUDES := ../foo</span>

However this will not work because all compilation happens from the directory where 'ndk-build' is invoked, and include files must be relative to it.

The correct line is instead:

<span style="color: #0000ff;">LOCAL_C_INCLUDES := $(LOCAL_PATH)/../foo</span>

Which uses a path relative to $(LOCAL_PATH), in the case where you would need to move 'foo' and 'bar' to a deeper level in the 'sources' hierarchy.

In case you absolutely need it, you can also use NDK_APP_PROJECT_PATH to point to your project directory:

<span style="color: #0000ff;">LOCAL_C_INCLUDES := $(NDK_APP_PROJECT_PATH)/jni/foo</span>

However, we don't recommend using this, paths relative to $(LOCAL_PATH) being better.]]></description>
			<content:encoded><![CDATA[<p><strong>How to force the display of build commands:</strong><br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>Do “ndk-build V=1&#8243; and actual build commands will be displayed. This can be used to verify that things are compiled as you expect them to, and check for bugs in the NDK build system.</p>
<p>(The V=1 trick comes from the Linux kernel build system)</p>
<p><strong>How to force a rebuild of all your sources:</strong><br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>Use GNU Make&#8217;s “-B” option, as in:</p>
<p><span style="color: #0000ff;">ndk-build -B</span></p>
<p><strong>How to store your native sources in a location other than $PROJECT/jni:</strong><br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;</p>
<p>First, you can simply tell your $PROJECT/jni/Android.mk to include another Android.mk that are located in different places. Alternatively, you can define APP_BUILD_SCRIPT in your Application.mk to point to an alternative Android.mk file.</p>
<p><strong>How to build a project&#8217;s native files without cd-ing to it:</strong><br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;</p>
<p>Sometimes, you may need to rebuild a project&#8217;s native file without being able to cd to its top-level path from the command-line. This is do-able by using the GNU-Make &#8216;-C &lt;path&gt;&#8217; option, as in:</p>
<p><span style="color: #0000ff;">ndk-build -C &lt;project-path&gt;</span></p>
<p><strong>How to store your Application.mk in a location other than $PROJECT/jni:</strong><br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;</p>
<p>Starting with NDK r4, you can simply place the file under $PROJECT/jni/ and launch the &#8216;ndk-build&#8217; script from your project tree.</p>
<p>If you want to use &#8216;ndk-build&#8217; but place the file to a different location, use a GNU Make variable override as:</p>
<p><span style="color: #0000ff;">ndk-build NDK_APPLICATION_MK=/path/to/your/Application.mk</span></p>
<p>If you&#8217;re using the legacy $NDK/apps/&lt;name&gt; build method, you can create a symbolic link to your final Application.mk there. For example, imagine that you wrote: $PROJECT/foo/Application.mk You can create a symlink like with a command like:</p>
<p><span style="color: #0000ff;">ln -s $PROJECT/foo $NDK/apps/&lt;name&gt;</span></p>
<p>This will make $NDK/apps/&lt;name&gt;/Application.mk point directly to $PROJECT/jni/Application.mk</p>
<p>Note that generated files will still go under $NDK/out/apps/&lt;name&gt; though.</p>
<p>Windows users: The NDK is only supported on Cygwin, which implements symbolic links through the “ln -s” command, as in:</p>
<p><span style="color: #0000ff;">ln -s &lt;target&gt; &lt;link&gt;</span></p>
<p><strong>How to properly add include directories to your module declaration:</strong><br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>If you define several modules, it is common to need to include one module&#8217;s header while compiling another one. For example, consider the following example:</p>
<p><span style="color: #0000ff;">$PROJECT/jni/foo/</span><br />
<span style="color: #0000ff;"> Android.mk</span><br />
<span style="color: #0000ff;"> foo.h</span><br />
<span style="color: #0000ff;"> foo.c</span></p>
<p><span style="color: #0000ff;">$PROJECT/jni/bar/</span><br />
<span style="color: #0000ff;"> Android.mk</span><br />
<span style="color: #0000ff;"> bar.c</span></p>
<p>Where the &#8216;bar.c&#8217; uses &#8216;#include &lt;foo.h&gt;&#8217;. You will need to add the path to the &#8216;foo&#8217; module in jni/bar/Android.mk to build it properly. One is tempted to use the following:</p>
<p><span style="color: #0000ff;">LOCAL_C_INCLUDES := ../foo</span></p>
<p>However this will not work because all compilation happens from the directory where &#8216;ndk-build&#8217; is invoked, and include files must be relative to it.</p>
<p>The correct line is instead:</p>
<p><span style="color: #0000ff;">LOCAL_C_INCLUDES := $(LOCAL_PATH)/../foo</span></p>
<p>Which uses a path relative to $(LOCAL_PATH), in the case where you would need to move &#8216;foo&#8217; and &#8216;bar&#8217; to a deeper level in the &#8216;sources&#8217; hierarchy.</p>
<p>In case you absolutely need it, you can also use NDK_APP_PROJECT_PATH to point to your project directory:</p>
<p><span style="color: #0000ff;">LOCAL_C_INCLUDES := $(NDK_APP_PROJECT_PATH)/jni/foo</span></p>
<p>However, we don&#8217;t recommend using this, paths relative to $(LOCAL_PATH) being better.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.codingguy.net/?feed=rss2&#038;p=89</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>09年初写的Android Recovery</title>
		<link>http://www.codingguy.net/?p=49</link>
		<comments>http://www.codingguy.net/?p=49#comments</comments>
		<pubDate>Wed, 14 Dec 2011 17:04:45 +0000</pubDate>
		<dc:creator>codingguy</dc:creator>
				<category><![CDATA[Android]]></category>

		<guid isPermaLink="false">http://www.codingguy.net/?p=49</guid>
		<description><![CDATA[找到了以前写的老文档，09年初写的，不管内容怎样，贴出来晒晒~

----------------------------------------------------------------
<p align="center"><strong>Android</strong><strong> </strong><strong>Recovery</strong></p>
<strong>Android Recovery: </strong><strong>功能简介</strong><strong></strong>

Android支持Recovery模式。在某些操作之后，系统会自动重启并进入到Recovery模式，用户按组合键开机（HOME+POWER），也可进入Recovery模式。该模式提供如下功能：

1、擦除用户数据

<span class="Apple-style-span" style="line-height: 16px;">恢复系统到出厂模式，即擦除用户数据和缓存数据。</span>

2、系统升级

系统升级的概念比较广，包括系统文件的升级、恢复损害的系统数据、firmware的升级，以及应用软件的维护，甚至影音文件的下载。系统升级需要使用特定的升级包，Android使用OTA<a title="" href="file:///E:/document/android/Recovery/Android-Recover.doc#_ftn1">[1]</a>升级包，其初衷在于可以发挥广域无线通信链路的优势，如3G。

升级方式有两种：

1、在线升级

利用无线通信网络，系统自动连接更新源，查看有无升级包、下载OTA升级包，然后给出提示，发起升级过程，如下左图。感觉有点类似Windows XP的系统更新，只不过升级的时候，Android系统会重启系统进入Recovery模式。另外Android的升级内容很广泛，比如可以通过这种方式安装应用程序。T-Mobile已经提供了这种服务，如升级服务器以OTA无线方式向G1终端发送Android平台RC33升级包，传输媒介可以是3G网络、Wi-Fi或GPRS。

2、离线升级

可以将下载到的OTA包放在SD卡里，通过离线方式升级，如下右图所示。这种升级方式比较灵活，不用花费无线流量。这样一来，使用自己制作的OTA进行升级也成为可能。事实上，G1就是用这种方式进行刷机的，比如更新radio firmware以支持某个频段。

<strong>Android: </strong><strong>分区结构</strong><strong></strong>

在分析Recovery工作流程之前，我们先了解一下Android文件系统的分区结构。下表是android/bootable/recovery/root.c中提得到的结构：
<div align="center">
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top" width="83">Name</td>
<td valign="top" width="133">Device</td>
<td valign="top" width="92">Partition name</td>
<td valign="top" width="82">Mount point</td>
<td valign="top" width="103">File system</td>
</tr>
<tr>
<td valign="top" width="83">BOOT</td>
<td valign="top" width="133">g_mtd_device</td>
<td valign="top" width="92">Boot</td>
<td valign="top" width="82">NULL</td>
<td valign="top" width="103">g_raw</td>
</tr>
<tr>
<td valign="top" width="83">CACHE</td>
<td valign="top" width="133">g_mtd_device</td>
<td valign="top" width="92">Cache</td>
<td valign="top" width="82">/cache</td>
<td valign="top" width="103">yaffs2</td>
</tr>
<tr>
<td valign="top" width="83">DATA</td>
<td valign="top" width="133">g_mtd_device</td>
<td valign="top" width="92">Userdata</td>
<td valign="top" width="82">/data</td>
<td valign="top" width="103">yaffs2</td>
</tr>
<tr>
<td valign="top" width="83">MISC</td>
<td valign="top" width="133">g_mtd_device</td>
<td valign="top" width="92">Misc</td>
<td valign="top" width="82">NULL</td>
<td valign="top" width="103">g_raw</td>
</tr>
<tr>
<td valign="top" width="83">PACKAGE</td>
<td valign="top" width="133">NULL</td>
<td valign="top" width="92">NULL</td>
<td valign="top" width="82">NULL</td>
<td valign="top" width="103">g_package_file</td>
</tr>
<tr>
<td valign="top" width="83">RECOVERY</td>
<td valign="top" width="133">g_mtd_device</td>
<td valign="top" width="92">Recovery</td>
<td valign="top" width="82">/</td>
<td valign="top" width="103">g_raw</td>
</tr>
<tr>
<td valign="top" width="83">SDCARD</td>
<td valign="top" width="133">/dev/block/mmcblk0p1</td>
<td valign="top" width="92">NULL</td>
<td valign="top" width="82">/sdcard</td>
<td valign="top" width="103">Vfat</td>
</tr>
<tr>
<td valign="top" width="83">SYSTEM</td>
<td valign="top" width="133">g_mtd_device</td>
<td valign="top" width="92">System</td>
<td valign="top" width="82">/system</td>
<td valign="top" width="103">yaffs2</td>
</tr>
<tr>
<td valign="top" width="83">TMP</td>
<td valign="top" width="133">NULL</td>
<td valign="top" width="92">NULL</td>
<td valign="top" width="82">/tmp</td>
<td valign="top" width="103">NULL</td>
</tr>
</tbody>
</table>
</div>
<p align="center">Root file system layout</p>
模拟器环境下adb shell里的mount输出：

# mount

……

/dev/block/mtdblock0     /system                       yaffs2      ro                                0     0

/dev/block/mtdblock1     /data                            yaffs2      rw,nosuid,nodev            0     0

/dev/block/mtdblock2     /cache                         yaffs2      rw,nosuid,nodev            0     0

综上，MTD中有如下分区：

BOOT：                boot.img，Linux kernel (within normal ramdisk)

MISC：                 bootloader message struct

RECOVERY：       recovery.img，Linux kernel (within recovery ramdisk)

SYSTEM：            system.img

DATA：                 userdata.img

CACHE：              some cache files

有几点说明：

1、一般来讲，主板上还有用于存储bootloader的可擦写存储设备。若具备通信能力，还要存储radio firmware，这两部分的更新由Recovery协助Bootloader完成，没有代码证明一定存在NAND flash上。

2、RECOVERY分区无文件系统，存放二进制image。

3、SYSTEM中有recovery.img的备份：/system/recovery.img，initrc中有如下代码：

service flash_recovery /system/bin/flash_image recovery system/recovery.img

oneshot

每次启动，flash_image程序，会检查recovery分区中image的header，如果与备份的recovery.img不符，就会把备份写到RECOVERY分区。这样做是为了应对RECOVERY分区遭到破坏。当然，我们也可以更换这个备份，这样也会将其写到RECOVERY。事实上，处于安全及版权考虑，OTA是有签名的（其实就是JAR包），Recovery对签名有要求，所以只能进行被允许的升级，此时的破解思路就是更换一个不检查签名的Recovery程序，方法就是设法更换/system/recovery.img。

<strong>Android Recovery: </strong><strong>三个部分、两个接口</strong><strong></strong>

Recovery的工作需要整个软件平台的配合，从架构角度看，有三个部分：

1、Main system：用boot.img启动的Linux系统，Android的正常工作模式。

2、Recovery：用recovery.img启动的Linux系统，主要是运行Recovery程序。

3、Bootloader：除了加载、启动系统，还会通过读取flash的MISC分区获得来自Main system和Recovery的消息，并以此决定做何种操作。

在Recovery的工作流程中，上述三个实体的通信必不可少。通信的接口有以下两个：

l         CACHE分区中的三个文件：/cache/recovery/…

Recovery通过/cache/recovery里的文件与main system通信，有三个文件：
<ol>
	<li>/cache/recovery/command</li>
</ol>
Main system传给Recovery的命令行，每一行有一个命令，支持以下几种：

--send_intent=anystring               write the text out to recovery/intent

--update_package=root:path         verify install an OTA package file

--wipe_data                                 erase user data (and cache), then reboot

--wipe_cache                              wipe cache (but not user data), then reboot
<ol>
	<li>/cache/recovery/log</li>
</ol>
Recovery的log输出，在recovery运行过程中，stdout及stderr会重定位到/tmp/recovery.log文件，Recovery退出之前会将其转储到/cache/recovery/log中，也就是cache分区的recovery/log。
<ol>
	<li>/cache/recovery/intent</li>
</ol>
Recovery传给Main system的信息

l         BCB (bootloader control block)

struct bootloader_message {

char  command[32];

char  status[32];

char  recovery[1024];

};

BCB是Bootloader与Recovery的通信接口，也是Bootloader与Main system的通信接口，存储在flash中的MISC分区，占用三个page，各成员意义如下：

<strong>command</strong><strong>：</strong><strong></strong>

当想要重启进入recovery模式，或升级radio/bootloader firmware时，会更新这个域。当firmware更新完毕，为了启动后进入recovery做最终的清除，bootloader还会修改它。

<strong>status</strong><strong>：</strong><strong></strong>

update-radio或update-hboot完成后，bootloader会写入相应的信息，一般是一些状态或执行结果。

<strong>recovery</strong><strong>：</strong><strong></strong>

仅被Main system写入，用于向Recovery发送消息，必须以“recovery\n”开头，否则这个域的所有内容会被忽略。这一项的内容中“recovery/\n”以后的部分，是/cache/recovery/command支持的命令，可以认为这是在Recovery操作过程中，对命令操作的备份。Recovery也会更新这个域的信息，执行某操作前把该操作命令写到recovery域，并更新command域，操作完成后再清空recovery域及command域，这样在进入Main system之前，就能确保操作被执行。

如图所示，Main system、Recovery与Bootloader通过上述接口通信，通信逻辑依不同的目的而不同，在后面介绍具体工作流程中还会详细介绍。

<a href="http://www.codingguy.net/wp-content/uploads/2011/12/1.jpg"><img class="aligncenter size-full wp-image-52" title="1" src="http://www.codingguy.net/wp-content/uploads/2011/12/1.jpg" alt="" width="546" height="415" /></a>

<strong>从</strong><strong>Main system</strong><strong>进入</strong><strong>Recovery</strong><strong>的方法</strong><strong></strong>

我们提到，从Main system进入到Recovery，要修改MISC分区的数据并重启，从而告诉Bootloader是用boot.img还是用recovery.img启动。

init.c里的wait_for_one_process函数中有如下代码：

__reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,

LINUX_REBOOT_CMD_RESTART2, "recovery");

一些关键的进程运行异常，会重启进入recovery模式，这里用__reboot函数进入recovery。跟踪这个函数，由系统调用处理函数，到kernel_restart(char *cmd)，最终调用machine_restart使用体系结构相关的代码完成重启。

Android中没有给出如何处理“recovery”重启。不过可以断定，在重启之前会向BCB中写入信息，以告知bootloader如何启动，具体操作是这样的：

向command域中写入“boot-recovery”      // 此操作必做

向recovery域写入“recovery\n”         // 此操作也可不做

这些操作很可能在kernel_restart(char *cmd)中完成，因为这一部分与体系结构无关，如果要实现完整的Recovery，这部分工作是必须做的。

Bootloader得到进入Recovery模式的指示，用recovery.img启动，进入Recovery模式，init.rc (bootable/recovery/etc/init.rc)的内容比Main system的要短的多，最重要的是把recovery程序作为服务启动：

service recovery /sbin/recovery

<strong>Android Recovery: </strong><strong>总体流程</strong><strong></strong>

根据Recovery的initrc，kernel启动完成后，启动recovery服务，这是一个C程序，入口在/bootable/recovery/recovery.c中，main函数结构清晰，主要流程如图：

<a href="http://www.codingguy.net/wp-content/uploads/2011/12/21.jpg"><img class="aligncenter size-full wp-image-55" title="2" src="http://www.codingguy.net/wp-content/uploads/2011/12/21.jpg" alt="" width="552" height="557" /></a>

l         get_args：首先调用get_args获取参数，主要流程如下：

<a href="http://www.codingguy.net/wp-content/uploads/2011/12/3.jpg"><img class="aligncenter size-full wp-image-54" title="3" src="http://www.codingguy.net/wp-content/uploads/2011/12/3.jpg" alt="" width="455" height="332" /></a>

get_args不仅传回获取到的参数，还会将其写入BCB，这样，一旦升级或擦除数据的过程中出现错误，重启之后依然进入Recovery并做相同操作。

l         register_update_command，这是为update做准备工作，负责注册update用的command &#38; function，正是这些command &#38; function组成了update用到的update_script：

<a href="http://www.codingguy.net/wp-content/uploads/2011/12/4.jpg"><img class="aligncenter size-full wp-image-56" title="4" src="http://www.codingguy.net/wp-content/uploads/2011/12/4.jpg" alt="" width="414" height="266" /></a>

先用commandInit（android/bootable/recovery/amend/command.c）初始化command symbol table，然后多次调用registerCommand及registerFunction注册command及function。command相关的源代码都在amend目录中，语法的构建及解析使用Android已经包含的Bison（Yacc）。

这里的command有15个，见下表：
<div align="center">
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top" width="175">Command Name</td>
<td valign="top" width="175">Argument Type</td>
<td valign="top" width="175">Command Handler</td>
</tr>
<tr>
<td valign="top" width="175">assert</td>
<td valign="top" width="175">CMD_ARGS_BOOLEAN</td>
<td valign="top" width="175">cmd_assert</td>
</tr>
<tr>
<td valign="top" width="175">delete</td>
<td valign="top" width="175">CMD_ARGS_WORDS</td>
<td valign="top" width="175">cmd_delete</td>
</tr>
<tr>
<td valign="top" width="175">delete_recursive</td>
<td valign="top" width="175">CMD_ARGS_WORDS</td>
<td valign="top" width="175">cmd_delete</td>
</tr>
<tr>
<td valign="top" width="175">copy_dir</td>
<td valign="top" width="175">CMD_ARGS_WORDS</td>
<td valign="top" width="175">cmd_copy_dir</td>
</tr>
<tr>
<td valign="top" width="175">run_program</td>
<td valign="top" width="175">CMD_ARGS_WORDS</td>
<td valign="top" width="175">cmd_run_program</td>
</tr>
<tr>
<td valign="top" width="175">set_perm</td>
<td valign="top" width="175">CMD_ARGS_WORDS</td>
<td valign="top" width="175">cmd_set_perm</td>
</tr>
<tr>
<td valign="top" width="175">set_perm_recursive</td>
<td valign="top" width="175">CMD_ARGS_WORDS</td>
<td valign="top" width="175">cmd_set_perm</td>
</tr>
<tr>
<td valign="top" width="175">show_progress</td>
<td valign="top" width="175">CMD_ARGS_WORDS</td>
<td valign="top" width="175">cmd_show_progress</td>
</tr>
<tr>
<td valign="top" width="175">symlink</td>
<td valign="top" width="175">CMD_ARGS_WORDS</td>
<td valign="top" width="175">cmd_symlink</td>
</tr>
<tr>
<td valign="top" width="175">format</td>
<td valign="top" width="175">CMD_ARGS_WORDS</td>
<td valign="top" width="175">cmd_format</td>
</tr>
<tr>
<td valign="top" width="175">write_radio_image</td>
<td valign="top" width="175">CMD_ARGS_WORDS</td>
<td valign="top" width="175">cmd_write_firmware_image</td>
</tr>
<tr>
<td valign="top" width="175">write_hboot_image</td>
<td valign="top" width="175">CMD_ARGS_WORDS</td>
<td valign="top" width="175">cmd_write_firmware_image</td>
</tr>
<tr>
<td valign="top" width="175">write_raw_image</td>
<td valign="top" width="175">CMD_ARGS_WORDS</td>
<td valign="top" width="175">cmd_write_raw_image</td>
</tr>
<tr>
<td valign="top" width="175">mark</td>
<td valign="top" width="175">CMD_ARGS_WORDS</td>
<td valign="top" width="175">cmd_mark</td>
</tr>
<tr>
<td valign="top" width="175">done</td>
<td valign="top" width="175">CMD_ARGS_WORDS</td>
<td valign="top" width="175">cmd_done</td>
</tr>
</tbody>
</table>
</div>
CMD_ARGS_BOOLEAN表示该command后面接的参数是boolean值，即true或false，解析脚本时计算参数的逻辑值，然后传给command handler，目前只有“assert”这个command用此类型的参数。

CMD_ARGS_WORDS表示该command后面接的参数是字符，形如C程序启动时加的参数，解析脚本时把参数直接传递给command handler，比如“format BOOT:”，“BOOT:”会传给cmd_format。
<div align="center">
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top" width="175">Function Name</td>
<td valign="top" width="175">Function Handler</td>
</tr>
<tr>
<td valign="top" width="175">compatible_with</td>
<td valign="top" width="175">fn_compatible_with</td>
</tr>
<tr>
<td valign="top" width="175">update_forced</td>
<td valign="top" width="175">fn_update_forced</td>
</tr>
<tr>
<td valign="top" width="175">get_mark</td>
<td valign="top" width="175">fn_get_mark</td>
</tr>
<tr>
<td valign="top" width="175">hash_dir</td>
<td valign="top" width="175">fn_hash_dir</td>
</tr>
<tr>
<td valign="top" width="175">matches</td>
<td valign="top" width="175">fn_matches</td>
</tr>
<tr>
<td valign="top" width="175">concat</td>
<td valign="top" width="175">fn_concat</td>
</tr>
<tr>
<td valign="top" width="175">getprop</td>
<td valign="top" width="175">fn_getprop</td>
</tr>
<tr>
<td valign="top" width="175">file_contains</td>
<td valign="top" width="175">fn_file_contains</td>
</tr>
</tbody>
</table>
</div>
function与command用同样的处理框架，只不过function会产生返回值，目前见到的用法一般都是与assert一起使用，例如下面脚本：

assert  getprop("ro.bootloader") == "0.95.0000"

先用getprop从properties中取得bootloader版本，然后再将比较后的boolean值传给assert。

l         prompt_and_wait：等待用户输入

<a href="http://www.codingguy.net/wp-content/uploads/2011/12/5.jpg"><img class="aligncenter size-full wp-image-57" title="5" src="http://www.codingguy.net/wp-content/uploads/2011/12/5.jpg" alt="" width="434" height="322" /></a>

首先打印文本信息。然后执行finish_recovery(NULL)，这个函数后面介绍。然后进入ui_wait_key等待用户输入，按下不同的组合键会有不同的动作。对于键盘输入，先到达input_thread函数(android/bootable/recovery/ui.c)，在那里处理两种组合键，其余才交给ui_wait_key处理：
<div align="center">
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top" width="171">KEY</td>
<td valign="top" width="171">Funcion</td>
<td valign="top" width="171">Handler</td>
</tr>
<tr>
<td valign="top" width="171">Home + Back</td>
<td valign="top" width="171">reboot system now</td>
<td valign="top" width="171">ui_wait_key</td>
</tr>
<tr>
<td valign="top" width="171">Alt + S</td>
<td valign="top" width="171">apply sdcard:update.zip</td>
<td valign="top" width="171">ui_wait_key</td>
</tr>
<tr>
<td valign="top" width="171">Alt + W</td>
<td valign="top" width="171">wipe data/factory reset</td>
<td valign="top" width="171">ui_wait_key</td>
</tr>
<tr>
<td valign="top" width="171">Alt + L</td>
<td valign="top" width="171">toggle log text display</td>
<td valign="top" width="171">input_thread</td>
</tr>
<tr>
<td valign="top" width="171">Green + Menu + Red</td>
<td valign="top" width="171">reboot immediately</td>
<td valign="top" width="171">input_thread</td>
</tr>
</tbody>
</table>
</div>
Home + Back：退出prompt_and_wait。

Alt + W或Alt + S，执行完install_package或erase_root后，若没有激活log text display，那么，就会退出prompt_and_wait，否则继续等待输入。

Green + Menu + Red：立刻重启，一般这样还会进入Recovery，因为BCB还没有来得及清空。

l         finish_recovery：离开Recovery进入Main system的必经之路，流程如下：

<a href="http://www.codingguy.net/wp-content/uploads/2011/12/6.jpg"><img class="aligncenter size-full wp-image-58" title="6" src="http://www.codingguy.net/wp-content/uploads/2011/12/6.jpg" alt="" width="248" height="322" /></a>

intent内容作为参数传进来，如果有intent需要告知Main system，将其写入/cache/recovery/intent；

将所有log信息转储到/cache/recovery/log文件，以供Main system读取；

清除BCB，也就是告知Bootloader启动进入Main system；

删除/cache/recovery/command；

以上是整体流程中的几个函数，关于安装升级包、升级firmware等操作将在具体流程中介绍。

<strong>Android Recovery: Factory data reset</strong><strong>流程</strong><strong></strong>

如果系统不稳定，可以尝试恢复出厂设置，该操作会擦除DATA分区及CACHE分区，有两种恢复方式，下面分别介绍：

l         通过Setting程序发起Facory data reset：

<a href="http://www.codingguy.net/wp-content/uploads/2011/12/7.jpg"><img class="aligncenter size-full wp-image-59" title="7" src="http://www.codingguy.net/wp-content/uploads/2011/12/7.jpg" alt="" width="352" height="249" /></a>

屏幕显示如上图，结合着下面的通信图，列出工作流程：

<a href="http://www.codingguy.net/wp-content/uploads/2011/12/8.jpg"><img class="aligncenter size-full wp-image-60" title="8" src="http://www.codingguy.net/wp-content/uploads/2011/12/8.jpg" alt="" width="598" height="423" /></a>

1、在应用程序Setting中选择factory data reset

2、Main system向/cache/recovery/command写入"--wipe_data"

3、Main system重启进入recovery模式（方法：修改BCB）

4、Recovery向BCB写入"boot-recevory"和"recovery\n--wipe_data\n"

5、擦除DATA分区，里面是用户数据，擦除CACHE分区

6、finish_recovery函数

7、重启，回到Main system

第四个步骤，Recovery向BCB写入boot-recovery和--wipe_data，这是为了保证后面几个步骤的完整执行。如，在擦除DATA分区或CACHE分区过程中，如果发生了重启、关机等操作，导致没有擦除成功，那么再次用常规方式开机后，Bootloader会依据BCB的指示，引导进入Recovery，并重新擦除这两个分区。擦完DATA分区与CACHE分区后，调用finish_recovery，做返回Main system前最后的工作，最终要的是擦除BCB，即MISC分区。此后，用常规方式重新开机，系统会进入Main system。

阅读Android的代码，发现Setting通过RPC调用Checkin Service的masterClear()启动这个过程，然而在Android中并没有找到masterClear()的实现，相关代码需要在产品化的过程中加入。从ICheckinService.aidl的注释可以了解到这个函数的作用：

/** Reboot into the recovery system and wipe all user data. */

代码位置：

/packages/apps/Settings/src/com/android/settings/MasterClear.java

/frameworks/base/core/java/android/os/ICheckinService.aidl

l         通过HOME+POWER组合键进入Recovery，再按ALT+W启动Factory data reset

过程比较简单，而且与上一种方式类似，结合总体流程，步骤如下：

1、捕获按键Alt + W。

2、擦除DATA分区、擦除CACHE分区。

3a、若激活了log显示（ALT+L：toggle log text display），调用finish_recovery函数重启，回到Main system。

3b、若没有激活log显示，继续接收按键，可用HOME+BACK重启回到Main system。

<strong>Android Recovery Update: </strong><strong>流程</strong><strong></strong>

l         update.zip

update操作需要升级包，该升级包是文件名是*.zip，但观察包内结构会发现其实就是JAR包，JAR包是具有特定目录和文件结构的ZIP压缩包，因此可以作为ZIP包解开：

<a href="http://www.codingguy.net/wp-content/uploads/2011/12/9.jpg"><img class="aligncenter size-full wp-image-61" title="9" src="http://www.codingguy.net/wp-content/uploads/2011/12/9.jpg" alt="" width="458" height="127" /></a>

MANIFEST.MF：这个manifest文件定义了与包相关数据。

XXX.SF：这是JAR文件的签名文件，占位符xxx标识签名者，如CERT。

XXX.DSA：与签名文件相关联的签名程序块文件，它存储了用于签名JAR文件的公共签名。

在META-INF/com/google/android目录下有update_script文件，内容就是update要做的操作，也就是前面提到过的command序列。

出于安全性及版本控制的考虑，JAR包要求必须有完整性以及合法性签名。可以看出这是Android确保安全的策略。JAR相关内容参见<a href="http://www.ibm.com/developerworks/cn/java/j-jar/">http://www.ibm.com/developerworks/cn/java/j-jar/</a>，这里就不再详细介绍。

l         Main system部分

通过Android系统下载升级包并启动升级操作，需要上层应用Updater的支持，它是Java程序，代码位置android/packages/apps/Updater。大致流程：

系统启动后，如果存在网络连接，则检查是否存在升级包；

如果存在升级包，则下载至/cache目录；

调用Updater程序来提示是否升级；

如果Updater程序进程不存在,则自动启动此程序；

没有在代码中找到开始升级后执行哪些操作。不过由recovery.c的注释部分可以肯定一定需要重启进入Recovery，重启前要更新/cache/recovery/command，以告知Recovery进行升级：

--update_package=root:path

l         update流程

update有两种方式，第一种是上面提到的由Android启动的自动update过程，升级包在cache/下，升级包的名字在/cache/recovery/command文件中指定。第二种是手动进入Recovery模式，然后输入Alt + S，安装/sdcard/update.zip升级包。两种方式不同的只是安装包的位置以及传递参数给Recovery的方法，update过程都是一样的，工作流程如下图所示：

<a href="http://www.codingguy.net/wp-content/uploads/2011/12/10.jpg"><img class="aligncenter size-full wp-image-62" title="10" src="http://www.codingguy.net/wp-content/uploads/2011/12/10.jpg" alt="" width="365" height="287" /></a>
<ul>
	<li>install_package @ android/bootable/recovery/install.c</li>
</ul>
得到安装包信息，如“--update_package=CACHE:update.zip”，进入install_package函数，流程如下左图。mount安装包所在的分区，然后打开zip压缩包，进入handle_update_package开始升级：

<a href="http://www.codingguy.net/wp-content/uploads/2011/12/11.jpg"><img class="aligncenter size-full wp-image-63" title="11" src="http://www.codingguy.net/wp-content/uploads/2011/12/11.jpg" alt="" width="563" height="314" /></a>

handle_update_package中，先对包进行校验，校验过程分三步：

verifySignature：    检验SF文件与RSA文件的匹配

verifyManifest：      检验/META-INF/MANIFEST.MF与签名文件中的digest是否一致

verifyArchive：       检验包中的文件与MANIFEST是否一致

接着find_update_script从MANIFEST.MF找到update_script的位置，然后handle_update_script，如下图，把内容读到buffer后，对其进行解析，分解成各个command（包括function）放在一个list中依次执行。

<a href="http://www.codingguy.net/wp-content/uploads/2011/12/12.jpg"><img class="aligncenter size-full wp-image-64" title="12" src="http://www.codingguy.net/wp-content/uploads/2011/12/12.jpg" alt="" width="523" height="171" /></a>
<ul>
	<li>maybe_install_firmware_update @ android/bootable/recovery/firmware.c</li>
</ul>
install_package成功后，调用maybe_install_firmware_update，这个函数处理firmware的更新。update firmware脚本是这样的：

write_radio_image PACKAGE:radio.img

cmd_write_firmware_image处理write_radio_image这个命令，将image从压缩包加载到RAM中，并调用remember_firmware_update更新update_type、update_data及update_length。这三个变量对于maybe_install_firmware_update是可见的，并由它们来判断是否要安装firmware。下面是主要流程：

<a href="http://www.codingguy.net/wp-content/uploads/2011/12/13.jpg"><img class="aligncenter size-full wp-image-65" title="13" src="http://www.codingguy.net/wp-content/uploads/2011/12/13.jpg" alt="" width="621" height="445" /></a>

如果升级涉及radio / hboot firmware （radio：基带处理相关，hboot：bootloader）

1、向BCB写入"boot-recovery"和"--wipe_cache"

……此后重启系统，将进入recovery并擦除CACHE分区

2、write_update_for_bootloader向raw CACHE分区写入image，CACHE分区的内容将被破坏。

3、向BCB写入"update-radio/hboot"和"--wipe_cache"

4、重启，由Bootloader更新firmware

5、Bootloader向BCB写入"boot-recovery"，并保留BCB中recovery里的"--wipe_cache"

6、重启，再次进入Recovery，调用erase_root()擦除CACHE分区

7、finish_recovery()清除BCB

8、重启，进入main system

l         Bootloader

每次启动，Bootloader都会读取位于MISC分区的bootloader_message，并检查command区域以\0结尾，还要考虑flash存在坏块的情况。然后根据读取的命令，启动系统或者更新firmware。工作流程如下：

<a href="http://www.codingguy.net/wp-content/uploads/2011/12/14.jpg"><img class="aligncenter size-full wp-image-66" title="14" src="http://www.codingguy.net/wp-content/uploads/2011/12/14.jpg" alt="" width="611" height="635" /></a>

升级之后，无论升级成功是否，Bootloader都会进入recovery完成最后的收尾工作，并带着status以告知是否成功。如果更新hboot（尚不知道为什么叫这个名字，不过可以确定它就是bootloader firmware），一旦失败，若原有的bootloader遭到破坏，那么系统将不能boot。

<strong>为实现</strong><strong>Android Recovery</strong><strong>，还需要做什么？</strong><strong></strong>

实现Setting中Factory data reset

查看Updater工作流程，找到发起update的方法

实现__reboot(….."recovery")函数，连接Main system与Recovery

升级包的打包方法，以及JAR包签名机制

实现Bootloader与Recovery及Main System的通信；

实现Bootloader的启动逻辑、firmware升级；

<hr align="left" size="1" width="33%" />

<div>

<a title="" href="file:///E:/document/android/Recovery/Android-Recover.doc#_ftnref1">[1]</a> OTA：Over The Air，一种手机等终端应用的“空中下载”技术，利用这种技术用户可以通过下载来修补终端的漏洞或升级某些功能。

</div>]]></description>
			<content:encoded><![CDATA[<p>找到了以前写的老文档，09年初写的，不管内容怎样，贴出来晒晒~</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p align="center"><strong>Android</strong><strong> </strong><strong>Recovery</strong></p>
<p><strong>Android Recovery: </strong><strong>功能简介</strong><strong></strong></p>
<p>Android支持Recovery模式。在某些操作之后，系统会自动重启并进入到Recovery模式，用户按组合键开机（HOME+POWER），也可进入Recovery模式。该模式提供如下功能：</p>
<p>1、擦除用户数据</p>
<p><span class="Apple-style-span" style="line-height: 16px;">恢复系统到出厂模式，即擦除用户数据和缓存数据。</span></p>
<p>2、系统升级</p>
<p>系统升级的概念比较广，包括系统文件的升级、恢复损害的系统数据、firmware的升级，以及应用软件的维护，甚至影音文件的下载。系统升级需要使用特定的升级包，Android使用OTA<a title="" href="file:///E:/document/android/Recovery/Android-Recover.doc#_ftn1">[1]</a>升级包，其初衷在于可以发挥广域无线通信链路的优势，如3G。</p>
<p>升级方式有两种：</p>
<p>1、在线升级</p>
<p>利用无线通信网络，系统自动连接更新源，查看有无升级包、下载OTA升级包，然后给出提示，发起升级过程，如下左图。感觉有点类似Windows XP的系统更新，只不过升级的时候，Android系统会重启系统进入Recovery模式。另外Android的升级内容很广泛，比如可以通过这种方式安装应用程序。T-Mobile已经提供了这种服务，如升级服务器以OTA无线方式向G1终端发送Android平台RC33升级包，传输媒介可以是3G网络、Wi-Fi或GPRS。</p>
<p>2、离线升级</p>
<p>可以将下载到的OTA包放在SD卡里，通过离线方式升级，如下右图所示。这种升级方式比较灵活，不用花费无线流量。这样一来，使用自己制作的OTA进行升级也成为可能。事实上，G1就是用这种方式进行刷机的，比如更新radio firmware以支持某个频段。</p>
<p><strong>Android: </strong><strong>分区结构</strong><strong></strong></p>
<p>在分析Recovery工作流程之前，我们先了解一下Android文件系统的分区结构。下表是android/bootable/recovery/root.c中提得到的结构：</p>
<div align="center">
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top" width="83">Name</td>
<td valign="top" width="133">Device</td>
<td valign="top" width="92">Partition name</td>
<td valign="top" width="82">Mount point</td>
<td valign="top" width="103">File system</td>
</tr>
<tr>
<td valign="top" width="83">BOOT</td>
<td valign="top" width="133">g_mtd_device</td>
<td valign="top" width="92">Boot</td>
<td valign="top" width="82">NULL</td>
<td valign="top" width="103">g_raw</td>
</tr>
<tr>
<td valign="top" width="83">CACHE</td>
<td valign="top" width="133">g_mtd_device</td>
<td valign="top" width="92">Cache</td>
<td valign="top" width="82">/cache</td>
<td valign="top" width="103">yaffs2</td>
</tr>
<tr>
<td valign="top" width="83">DATA</td>
<td valign="top" width="133">g_mtd_device</td>
<td valign="top" width="92">Userdata</td>
<td valign="top" width="82">/data</td>
<td valign="top" width="103">yaffs2</td>
</tr>
<tr>
<td valign="top" width="83">MISC</td>
<td valign="top" width="133">g_mtd_device</td>
<td valign="top" width="92">Misc</td>
<td valign="top" width="82">NULL</td>
<td valign="top" width="103">g_raw</td>
</tr>
<tr>
<td valign="top" width="83">PACKAGE</td>
<td valign="top" width="133">NULL</td>
<td valign="top" width="92">NULL</td>
<td valign="top" width="82">NULL</td>
<td valign="top" width="103">g_package_file</td>
</tr>
<tr>
<td valign="top" width="83">RECOVERY</td>
<td valign="top" width="133">g_mtd_device</td>
<td valign="top" width="92">Recovery</td>
<td valign="top" width="82">/</td>
<td valign="top" width="103">g_raw</td>
</tr>
<tr>
<td valign="top" width="83">SDCARD</td>
<td valign="top" width="133">/dev/block/mmcblk0p1</td>
<td valign="top" width="92">NULL</td>
<td valign="top" width="82">/sdcard</td>
<td valign="top" width="103">Vfat</td>
</tr>
<tr>
<td valign="top" width="83">SYSTEM</td>
<td valign="top" width="133">g_mtd_device</td>
<td valign="top" width="92">System</td>
<td valign="top" width="82">/system</td>
<td valign="top" width="103">yaffs2</td>
</tr>
<tr>
<td valign="top" width="83">TMP</td>
<td valign="top" width="133">NULL</td>
<td valign="top" width="92">NULL</td>
<td valign="top" width="82">/tmp</td>
<td valign="top" width="103">NULL</td>
</tr>
</tbody>
</table>
</div>
<p align="center">Root file system layout</p>
<p>模拟器环境下adb shell里的mount输出：</p>
<p># mount</p>
<p>……</p>
<p>/dev/block/mtdblock0     /system                       yaffs2      ro                                0     0</p>
<p>/dev/block/mtdblock1     /data                            yaffs2      rw,nosuid,nodev            0     0</p>
<p>/dev/block/mtdblock2     /cache                         yaffs2      rw,nosuid,nodev            0     0</p>
<p>综上，MTD中有如下分区：</p>
<p>BOOT：                boot.img，Linux kernel (within normal ramdisk)</p>
<p>MISC：                 bootloader message struct</p>
<p>RECOVERY：       recovery.img，Linux kernel (within recovery ramdisk)</p>
<p>SYSTEM：            system.img</p>
<p>DATA：                 userdata.img</p>
<p>CACHE：              some cache files</p>
<p>有几点说明：</p>
<p>1、一般来讲，主板上还有用于存储bootloader的可擦写存储设备。若具备通信能力，还要存储radio firmware，这两部分的更新由Recovery协助Bootloader完成，没有代码证明一定存在NAND flash上。</p>
<p>2、RECOVERY分区无文件系统，存放二进制image。</p>
<p>3、SYSTEM中有recovery.img的备份：/system/recovery.img，initrc中有如下代码：</p>
<p>service flash_recovery /system/bin/flash_image recovery system/recovery.img</p>
<p>oneshot</p>
<p>每次启动，flash_image程序，会检查recovery分区中image的header，如果与备份的recovery.img不符，就会把备份写到RECOVERY分区。这样做是为了应对RECOVERY分区遭到破坏。当然，我们也可以更换这个备份，这样也会将其写到RECOVERY。事实上，处于安全及版权考虑，OTA是有签名的（其实就是JAR包），Recovery对签名有要求，所以只能进行被允许的升级，此时的破解思路就是更换一个不检查签名的Recovery程序，方法就是设法更换/system/recovery.img。</p>
<p><strong>Android Recovery: </strong><strong>三个部分、两个接口</strong><strong></strong></p>
<p>Recovery的工作需要整个软件平台的配合，从架构角度看，有三个部分：</p>
<p>1、Main system：用boot.img启动的Linux系统，Android的正常工作模式。</p>
<p>2、Recovery：用recovery.img启动的Linux系统，主要是运行Recovery程序。</p>
<p>3、Bootloader：除了加载、启动系统，还会通过读取flash的MISC分区获得来自Main system和Recovery的消息，并以此决定做何种操作。</p>
<p>在Recovery的工作流程中，上述三个实体的通信必不可少。通信的接口有以下两个：</p>
<p>l         CACHE分区中的三个文件：/cache/recovery/…</p>
<p>Recovery通过/cache/recovery里的文件与main system通信，有三个文件：</p>
<ol>
<li>/cache/recovery/command</li>
</ol>
<p>Main system传给Recovery的命令行，每一行有一个命令，支持以下几种：</p>
<p>&#8211;send_intent=anystring               write the text out to recovery/intent</p>
<p>&#8211;update_package=root:path         verify install an OTA package file</p>
<p>&#8211;wipe_data                                 erase user data (and cache), then reboot</p>
<p>&#8211;wipe_cache                              wipe cache (but not user data), then reboot</p>
<ol>
<li>/cache/recovery/log</li>
</ol>
<p>Recovery的log输出，在recovery运行过程中，stdout及stderr会重定位到/tmp/recovery.log文件，Recovery退出之前会将其转储到/cache/recovery/log中，也就是cache分区的recovery/log。</p>
<ol>
<li>/cache/recovery/intent</li>
</ol>
<p>Recovery传给Main system的信息</p>
<p>l         BCB (bootloader control block)</p>
<p>struct bootloader_message {</p>
<p>char  command[32];</p>
<p>char  status[32];</p>
<p>char  recovery[1024];</p>
<p>};</p>
<p>BCB是Bootloader与Recovery的通信接口，也是Bootloader与Main system的通信接口，存储在flash中的MISC分区，占用三个page，各成员意义如下：</p>
<p><strong>command</strong><strong>：</strong><strong></strong></p>
<p>当想要重启进入recovery模式，或升级radio/bootloader firmware时，会更新这个域。当firmware更新完毕，为了启动后进入recovery做最终的清除，bootloader还会修改它。</p>
<p><strong>status</strong><strong>：</strong><strong></strong></p>
<p>update-radio或update-hboot完成后，bootloader会写入相应的信息，一般是一些状态或执行结果。</p>
<p><strong>recovery</strong><strong>：</strong><strong></strong></p>
<p>仅被Main system写入，用于向Recovery发送消息，必须以“recovery\n”开头，否则这个域的所有内容会被忽略。这一项的内容中“recovery/\n”以后的部分，是/cache/recovery/command支持的命令，可以认为这是在Recovery操作过程中，对命令操作的备份。Recovery也会更新这个域的信息，执行某操作前把该操作命令写到recovery域，并更新command域，操作完成后再清空recovery域及command域，这样在进入Main system之前，就能确保操作被执行。</p>
<p>如图所示，Main system、Recovery与Bootloader通过上述接口通信，通信逻辑依不同的目的而不同，在后面介绍具体工作流程中还会详细介绍。</p>
<p><a href="http://www.codingguy.net/wp-content/uploads/2011/12/1.jpg"><img class="aligncenter size-full wp-image-52" title="1" src="http://www.codingguy.net/wp-content/uploads/2011/12/1.jpg" alt="" width="546" height="415" /></a></p>
<p><strong>从</strong><strong>Main system</strong><strong>进入</strong><strong>Recovery</strong><strong>的方法</strong><strong></strong></p>
<p>我们提到，从Main system进入到Recovery，要修改MISC分区的数据并重启，从而告诉Bootloader是用boot.img还是用recovery.img启动。</p>
<p>init.c里的wait_for_one_process函数中有如下代码：</p>
<p>__reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,</p>
<p>LINUX_REBOOT_CMD_RESTART2, “recovery”);</p>
<p>一些关键的进程运行异常，会重启进入recovery模式，这里用__reboot函数进入recovery。跟踪这个函数，由系统调用处理函数，到kernel_restart(char *cmd)，最终调用machine_restart使用体系结构相关的代码完成重启。</p>
<p>Android中没有给出如何处理“recovery”重启。不过可以断定，在重启之前会向BCB中写入信息，以告知bootloader如何启动，具体操作是这样的：</p>
<p>向command域中写入“boot-recovery”      // 此操作必做</p>
<p>向recovery域写入“recovery\n”         // 此操作也可不做</p>
<p>这些操作很可能在kernel_restart(char *cmd)中完成，因为这一部分与体系结构无关，如果要实现完整的Recovery，这部分工作是必须做的。</p>
<p>Bootloader得到进入Recovery模式的指示，用recovery.img启动，进入Recovery模式，init.rc (bootable/recovery/etc/init.rc)的内容比Main system的要短的多，最重要的是把recovery程序作为服务启动：</p>
<p>service recovery /sbin/recovery</p>
<p><strong>Android Recovery: </strong><strong>总体流程</strong><strong></strong></p>
<p>根据Recovery的initrc，kernel启动完成后，启动recovery服务，这是一个C程序，入口在/bootable/recovery/recovery.c中，main函数结构清晰，主要流程如图：</p>
<p><a href="http://www.codingguy.net/wp-content/uploads/2011/12/21.jpg"><img class="aligncenter size-full wp-image-55" title="2" src="http://www.codingguy.net/wp-content/uploads/2011/12/21.jpg" alt="" width="552" height="557" /></a></p>
<p>l         get_args：首先调用get_args获取参数，主要流程如下：</p>
<p><a href="http://www.codingguy.net/wp-content/uploads/2011/12/3.jpg"><img class="aligncenter size-full wp-image-54" title="3" src="http://www.codingguy.net/wp-content/uploads/2011/12/3.jpg" alt="" width="455" height="332" /></a></p>
<p>get_args不仅传回获取到的参数，还会将其写入BCB，这样，一旦升级或擦除数据的过程中出现错误，重启之后依然进入Recovery并做相同操作。</p>
<p>l         register_update_command，这是为update做准备工作，负责注册update用的command &amp; function，正是这些command &amp; function组成了update用到的update_script：</p>
<p><a href="http://www.codingguy.net/wp-content/uploads/2011/12/4.jpg"><img class="aligncenter size-full wp-image-56" title="4" src="http://www.codingguy.net/wp-content/uploads/2011/12/4.jpg" alt="" width="414" height="266" /></a></p>
<p>先用commandInit（android/bootable/recovery/amend/command.c）初始化command symbol table，然后多次调用registerCommand及registerFunction注册command及function。command相关的源代码都在amend目录中，语法的构建及解析使用Android已经包含的Bison（Yacc）。</p>
<p>这里的command有15个，见下表：</p>
<div align="center">
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top" width="175">Command Name</td>
<td valign="top" width="175">Argument Type</td>
<td valign="top" width="175">Command Handler</td>
</tr>
<tr>
<td valign="top" width="175">assert</td>
<td valign="top" width="175">CMD_ARGS_BOOLEAN</td>
<td valign="top" width="175">cmd_assert</td>
</tr>
<tr>
<td valign="top" width="175">delete</td>
<td valign="top" width="175">CMD_ARGS_WORDS</td>
<td valign="top" width="175">cmd_delete</td>
</tr>
<tr>
<td valign="top" width="175">delete_recursive</td>
<td valign="top" width="175">CMD_ARGS_WORDS</td>
<td valign="top" width="175">cmd_delete</td>
</tr>
<tr>
<td valign="top" width="175">copy_dir</td>
<td valign="top" width="175">CMD_ARGS_WORDS</td>
<td valign="top" width="175">cmd_copy_dir</td>
</tr>
<tr>
<td valign="top" width="175">run_program</td>
<td valign="top" width="175">CMD_ARGS_WORDS</td>
<td valign="top" width="175">cmd_run_program</td>
</tr>
<tr>
<td valign="top" width="175">set_perm</td>
<td valign="top" width="175">CMD_ARGS_WORDS</td>
<td valign="top" width="175">cmd_set_perm</td>
</tr>
<tr>
<td valign="top" width="175">set_perm_recursive</td>
<td valign="top" width="175">CMD_ARGS_WORDS</td>
<td valign="top" width="175">cmd_set_perm</td>
</tr>
<tr>
<td valign="top" width="175">show_progress</td>
<td valign="top" width="175">CMD_ARGS_WORDS</td>
<td valign="top" width="175">cmd_show_progress</td>
</tr>
<tr>
<td valign="top" width="175">symlink</td>
<td valign="top" width="175">CMD_ARGS_WORDS</td>
<td valign="top" width="175">cmd_symlink</td>
</tr>
<tr>
<td valign="top" width="175">format</td>
<td valign="top" width="175">CMD_ARGS_WORDS</td>
<td valign="top" width="175">cmd_format</td>
</tr>
<tr>
<td valign="top" width="175">write_radio_image</td>
<td valign="top" width="175">CMD_ARGS_WORDS</td>
<td valign="top" width="175">cmd_write_firmware_image</td>
</tr>
<tr>
<td valign="top" width="175">write_hboot_image</td>
<td valign="top" width="175">CMD_ARGS_WORDS</td>
<td valign="top" width="175">cmd_write_firmware_image</td>
</tr>
<tr>
<td valign="top" width="175">write_raw_image</td>
<td valign="top" width="175">CMD_ARGS_WORDS</td>
<td valign="top" width="175">cmd_write_raw_image</td>
</tr>
<tr>
<td valign="top" width="175">mark</td>
<td valign="top" width="175">CMD_ARGS_WORDS</td>
<td valign="top" width="175">cmd_mark</td>
</tr>
<tr>
<td valign="top" width="175">done</td>
<td valign="top" width="175">CMD_ARGS_WORDS</td>
<td valign="top" width="175">cmd_done</td>
</tr>
</tbody>
</table>
</div>
<p>CMD_ARGS_BOOLEAN表示该command后面接的参数是boolean值，即true或false，解析脚本时计算参数的逻辑值，然后传给command handler，目前只有“assert”这个command用此类型的参数。</p>
<p>CMD_ARGS_WORDS表示该command后面接的参数是字符，形如C程序启动时加的参数，解析脚本时把参数直接传递给command handler，比如“format BOOT:”，“BOOT:”会传给cmd_format。</p>
<div align="center">
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top" width="175">Function Name</td>
<td valign="top" width="175">Function Handler</td>
</tr>
<tr>
<td valign="top" width="175">compatible_with</td>
<td valign="top" width="175">fn_compatible_with</td>
</tr>
<tr>
<td valign="top" width="175">update_forced</td>
<td valign="top" width="175">fn_update_forced</td>
</tr>
<tr>
<td valign="top" width="175">get_mark</td>
<td valign="top" width="175">fn_get_mark</td>
</tr>
<tr>
<td valign="top" width="175">hash_dir</td>
<td valign="top" width="175">fn_hash_dir</td>
</tr>
<tr>
<td valign="top" width="175">matches</td>
<td valign="top" width="175">fn_matches</td>
</tr>
<tr>
<td valign="top" width="175">concat</td>
<td valign="top" width="175">fn_concat</td>
</tr>
<tr>
<td valign="top" width="175">getprop</td>
<td valign="top" width="175">fn_getprop</td>
</tr>
<tr>
<td valign="top" width="175">file_contains</td>
<td valign="top" width="175">fn_file_contains</td>
</tr>
</tbody>
</table>
</div>
<p>function与command用同样的处理框架，只不过function会产生返回值，目前见到的用法一般都是与assert一起使用，例如下面脚本：</p>
<p>assert  getprop(“ro.bootloader”) == “0.95.0000&#8243;</p>
<p>先用getprop从properties中取得bootloader版本，然后再将比较后的boolean值传给assert。</p>
<p>l         prompt_and_wait：等待用户输入</p>
<p><a href="http://www.codingguy.net/wp-content/uploads/2011/12/5.jpg"><img class="aligncenter size-full wp-image-57" title="5" src="http://www.codingguy.net/wp-content/uploads/2011/12/5.jpg" alt="" width="434" height="322" /></a></p>
<p>首先打印文本信息。然后执行finish_recovery(NULL)，这个函数后面介绍。然后进入ui_wait_key等待用户输入，按下不同的组合键会有不同的动作。对于键盘输入，先到达input_thread函数(android/bootable/recovery/ui.c)，在那里处理两种组合键，其余才交给ui_wait_key处理：</p>
<div align="center">
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top" width="171">KEY</td>
<td valign="top" width="171">Funcion</td>
<td valign="top" width="171">Handler</td>
</tr>
<tr>
<td valign="top" width="171">Home + Back</td>
<td valign="top" width="171">reboot system now</td>
<td valign="top" width="171">ui_wait_key</td>
</tr>
<tr>
<td valign="top" width="171">Alt + S</td>
<td valign="top" width="171">apply sdcard:update.zip</td>
<td valign="top" width="171">ui_wait_key</td>
</tr>
<tr>
<td valign="top" width="171">Alt + W</td>
<td valign="top" width="171">wipe data/factory reset</td>
<td valign="top" width="171">ui_wait_key</td>
</tr>
<tr>
<td valign="top" width="171">Alt + L</td>
<td valign="top" width="171">toggle log text display</td>
<td valign="top" width="171">input_thread</td>
</tr>
<tr>
<td valign="top" width="171">Green + Menu + Red</td>
<td valign="top" width="171">reboot immediately</td>
<td valign="top" width="171">input_thread</td>
</tr>
</tbody>
</table>
</div>
<p>Home + Back：退出prompt_and_wait。</p>
<p>Alt + W或Alt + S，执行完install_package或erase_root后，若没有激活log text display，那么，就会退出prompt_and_wait，否则继续等待输入。</p>
<p>Green + Menu + Red：立刻重启，一般这样还会进入Recovery，因为BCB还没有来得及清空。</p>
<p>l         finish_recovery：离开Recovery进入Main system的必经之路，流程如下：</p>
<p><a href="http://www.codingguy.net/wp-content/uploads/2011/12/6.jpg"><img class="aligncenter size-full wp-image-58" title="6" src="http://www.codingguy.net/wp-content/uploads/2011/12/6.jpg" alt="" width="248" height="322" /></a></p>
<p>intent内容作为参数传进来，如果有intent需要告知Main system，将其写入/cache/recovery/intent；</p>
<p>将所有log信息转储到/cache/recovery/log文件，以供Main system读取；</p>
<p>清除BCB，也就是告知Bootloader启动进入Main system；</p>
<p>删除/cache/recovery/command；</p>
<p>以上是整体流程中的几个函数，关于安装升级包、升级firmware等操作将在具体流程中介绍。</p>
<p><strong>Android Recovery: Factory data reset</strong><strong>流程</strong><strong></strong></p>
<p>如果系统不稳定，可以尝试恢复出厂设置，该操作会擦除DATA分区及CACHE分区，有两种恢复方式，下面分别介绍：</p>
<p>l         通过Setting程序发起Facory data reset：</p>
<p><a href="http://www.codingguy.net/wp-content/uploads/2011/12/7.jpg"><img class="aligncenter size-full wp-image-59" title="7" src="http://www.codingguy.net/wp-content/uploads/2011/12/7.jpg" alt="" width="352" height="249" /></a></p>
<p>屏幕显示如上图，结合着下面的通信图，列出工作流程：</p>
<p><a href="http://www.codingguy.net/wp-content/uploads/2011/12/8.jpg"><img class="aligncenter size-full wp-image-60" title="8" src="http://www.codingguy.net/wp-content/uploads/2011/12/8.jpg" alt="" width="598" height="423" /></a></p>
<p>1、在应用程序Setting中选择factory data reset</p>
<p>2、Main system向/cache/recovery/command写入”&#8211;wipe_data”</p>
<p>3、Main system重启进入recovery模式（方法：修改BCB）</p>
<p>4、Recovery向BCB写入”boot-recevory”和”recovery\n&#8211;wipe_data\n”</p>
<p>5、擦除DATA分区，里面是用户数据，擦除CACHE分区</p>
<p>6、finish_recovery函数</p>
<p>7、重启，回到Main system</p>
<p>第四个步骤，Recovery向BCB写入boot-recovery和&#8211;wipe_data，这是为了保证后面几个步骤的完整执行。如，在擦除DATA分区或CACHE分区过程中，如果发生了重启、关机等操作，导致没有擦除成功，那么再次用常规方式开机后，Bootloader会依据BCB的指示，引导进入Recovery，并重新擦除这两个分区。擦完DATA分区与CACHE分区后，调用finish_recovery，做返回Main system前最后的工作，最终要的是擦除BCB，即MISC分区。此后，用常规方式重新开机，系统会进入Main system。</p>
<p>阅读Android的代码，发现Setting通过RPC调用Checkin Service的masterClear()启动这个过程，然而在Android中并没有找到masterClear()的实现，相关代码需要在产品化的过程中加入。从ICheckinService.aidl的注释可以了解到这个函数的作用：</p>
<p>/** Reboot into the recovery system and wipe all user data. */</p>
<p>代码位置：</p>
<p>/packages/apps/Settings/src/com/android/settings/MasterClear.java</p>
<p>/frameworks/base/core/java/android/os/ICheckinService.aidl</p>
<p>l         通过HOME+POWER组合键进入Recovery，再按ALT+W启动Factory data reset</p>
<p>过程比较简单，而且与上一种方式类似，结合总体流程，步骤如下：</p>
<p>1、捕获按键Alt + W。</p>
<p>2、擦除DATA分区、擦除CACHE分区。</p>
<p>3a、若激活了log显示（ALT+L：toggle log text display），调用finish_recovery函数重启，回到Main system。</p>
<p>3b、若没有激活log显示，继续接收按键，可用HOME+BACK重启回到Main system。</p>
<p><strong>Android Recovery Update: </strong><strong>流程</strong><strong></strong></p>
<p>l         update.zip</p>
<p>update操作需要升级包，该升级包是文件名是*.zip，但观察包内结构会发现其实就是JAR包，JAR包是具有特定目录和文件结构的ZIP压缩包，因此可以作为ZIP包解开：</p>
<p><a href="http://www.codingguy.net/wp-content/uploads/2011/12/9.jpg"><img class="aligncenter size-full wp-image-61" title="9" src="http://www.codingguy.net/wp-content/uploads/2011/12/9.jpg" alt="" width="458" height="127" /></a></p>
<p>MANIFEST.MF：这个manifest文件定义了与包相关数据。</p>
<p>XXX.SF：这是JAR文件的签名文件，占位符xxx标识签名者，如CERT。</p>
<p>XXX.DSA：与签名文件相关联的签名程序块文件，它存储了用于签名JAR文件的公共签名。</p>
<p>在META-INF/com/google/android目录下有update_script文件，内容就是update要做的操作，也就是前面提到过的command序列。</p>
<p>出于安全性及版本控制的考虑，JAR包要求必须有完整性以及合法性签名。可以看出这是Android确保安全的策略。JAR相关内容参见<a href="http://www.ibm.com/developerworks/cn/java/j-jar/">http://www.ibm.com/developerworks/cn/java/j-jar/</a>，这里就不再详细介绍。</p>
<p>l         Main system部分</p>
<p>通过Android系统下载升级包并启动升级操作，需要上层应用Updater的支持，它是Java程序，代码位置android/packages/apps/Updater。大致流程：</p>
<p>系统启动后，如果存在网络连接，则检查是否存在升级包；</p>
<p>如果存在升级包，则下载至/cache目录；</p>
<p>调用Updater程序来提示是否升级；</p>
<p>如果Updater程序进程不存在,则自动启动此程序；</p>
<p>没有在代码中找到开始升级后执行哪些操作。不过由recovery.c的注释部分可以肯定一定需要重启进入Recovery，重启前要更新/cache/recovery/command，以告知Recovery进行升级：</p>
<p>&#8211;update_package=root:path</p>
<p>l         update流程</p>
<p>update有两种方式，第一种是上面提到的由Android启动的自动update过程，升级包在cache/下，升级包的名字在/cache/recovery/command文件中指定。第二种是手动进入Recovery模式，然后输入Alt + S，安装/sdcard/update.zip升级包。两种方式不同的只是安装包的位置以及传递参数给Recovery的方法，update过程都是一样的，工作流程如下图所示：</p>
<p><a href="http://www.codingguy.net/wp-content/uploads/2011/12/10.jpg"><img class="aligncenter size-full wp-image-62" title="10" src="http://www.codingguy.net/wp-content/uploads/2011/12/10.jpg" alt="" width="365" height="287" /></a></p>
<ul>
<li>install_package @ android/bootable/recovery/install.c</li>
</ul>
<p>得到安装包信息，如“&#8211;update_package=CACHE:update.zip”，进入install_package函数，流程如下左图。mount安装包所在的分区，然后打开zip压缩包，进入handle_update_package开始升级：</p>
<p><a href="http://www.codingguy.net/wp-content/uploads/2011/12/11.jpg"><img class="aligncenter size-full wp-image-63" title="11" src="http://www.codingguy.net/wp-content/uploads/2011/12/11.jpg" alt="" width="563" height="314" /></a></p>
<p>handle_update_package中，先对包进行校验，校验过程分三步：</p>
<p>verifySignature：    检验SF文件与RSA文件的匹配</p>
<p>verifyManifest：      检验/META-INF/MANIFEST.MF与签名文件中的digest是否一致</p>
<p>verifyArchive：       检验包中的文件与MANIFEST是否一致</p>
<p>接着find_update_script从MANIFEST.MF找到update_script的位置，然后handle_update_script，如下图，把内容读到buffer后，对其进行解析，分解成各个command（包括function）放在一个list中依次执行。</p>
<p><a href="http://www.codingguy.net/wp-content/uploads/2011/12/12.jpg"><img class="aligncenter size-full wp-image-64" title="12" src="http://www.codingguy.net/wp-content/uploads/2011/12/12.jpg" alt="" width="523" height="171" /></a></p>
<ul>
<li>maybe_install_firmware_update @ android/bootable/recovery/firmware.c</li>
</ul>
<p>install_package成功后，调用maybe_install_firmware_update，这个函数处理firmware的更新。update firmware脚本是这样的：</p>
<p>write_radio_image PACKAGE:radio.img</p>
<p>cmd_write_firmware_image处理write_radio_image这个命令，将image从压缩包加载到RAM中，并调用remember_firmware_update更新update_type、update_data及update_length。这三个变量对于maybe_install_firmware_update是可见的，并由它们来判断是否要安装firmware。下面是主要流程：</p>
<p><a href="http://www.codingguy.net/wp-content/uploads/2011/12/13.jpg"><img class="aligncenter size-full wp-image-65" title="13" src="http://www.codingguy.net/wp-content/uploads/2011/12/13.jpg" alt="" width="621" height="445" /></a></p>
<p>如果升级涉及radio / hboot firmware （radio：基带处理相关，hboot：bootloader）</p>
<p>1、向BCB写入”boot-recovery”和”&#8211;wipe_cache”</p>
<p>……此后重启系统，将进入recovery并擦除CACHE分区</p>
<p>2、write_update_for_bootloader向raw CACHE分区写入image，CACHE分区的内容将被破坏。</p>
<p>3、向BCB写入”update-radio/hboot”和”&#8211;wipe_cache”</p>
<p>4、重启，由Bootloader更新firmware</p>
<p>5、Bootloader向BCB写入”boot-recovery”，并保留BCB中recovery里的”&#8211;wipe_cache”</p>
<p>6、重启，再次进入Recovery，调用erase_root()擦除CACHE分区</p>
<p>7、finish_recovery()清除BCB</p>
<p>8、重启，进入main system</p>
<p>l         Bootloader</p>
<p>每次启动，Bootloader都会读取位于MISC分区的bootloader_message，并检查command区域以\0结尾，还要考虑flash存在坏块的情况。然后根据读取的命令，启动系统或者更新firmware。工作流程如下：</p>
<p><a href="http://www.codingguy.net/wp-content/uploads/2011/12/14.jpg"><img class="aligncenter size-full wp-image-66" title="14" src="http://www.codingguy.net/wp-content/uploads/2011/12/14.jpg" alt="" width="611" height="635" /></a></p>
<p>升级之后，无论升级成功是否，Bootloader都会进入recovery完成最后的收尾工作，并带着status以告知是否成功。如果更新hboot（尚不知道为什么叫这个名字，不过可以确定它就是bootloader firmware），一旦失败，若原有的bootloader遭到破坏，那么系统将不能boot。</p>
<p><strong>为实现</strong><strong>Android Recovery</strong><strong>，还需要做什么？</strong><strong></strong></p>
<p>实现Setting中Factory data reset</p>
<p>查看Updater工作流程，找到发起update的方法</p>
<p>实现__reboot(…..”recovery”)函数，连接Main system与Recovery</p>
<p>升级包的打包方法，以及JAR包签名机制</p>
<p>实现Bootloader与Recovery及Main System的通信；</p>
<p>实现Bootloader的启动逻辑、firmware升级；</p>
<hr align="left" size="1" width="33%" />
<div>
<p><a title="" href="file:///E:/document/android/Recovery/Android-Recover.doc#_ftnref1">[1]</a> OTA：Over The Air，一种手机等终端应用的“空中下载”技术，利用这种技术用户可以通过下载来修补终端的漏洞或升级某些功能。</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.codingguy.net/?feed=rss2&#038;p=49</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>[转] Execution in the Kingdom of Nouns</title>
		<link>http://www.codingguy.net/?p=32</link>
		<comments>http://www.codingguy.net/?p=32#comments</comments>
		<pubDate>Mon, 12 Dec 2011 07:12:38 +0000</pubDate>
		<dc:creator>codingguy</dc:creator>
				<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://www.codingguy.net/?p=32</guid>
		<description><![CDATA[<h3><span class="Apple-style-span" style="font-size: 13px; font-weight: normal;">Forward from: </span><a style="font-size: 13px; font-weight: normal;" href="http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html">http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html</a></h3>
<h3><span class="Apple-style-span" style="font-size: 13px; font-weight: normal;">They've a temper, some of them—particularly verbs: they're the proudest—adjectives you can do anything with, but not verbs—however, <em>I</em> can manage the whole lot of them! Impenetrability! That's what <em>I</em> say!
— Humpty Dumpty
</span></h3>
<h3><span class="Apple-style-span" style="font-size: 13px; font-weight: normal;">Hello, world! Today we're going to hear the story of Evil King Java and his quest for worldwide verb stamp-outage.</span><sup><a href="http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html#note1">1</a></sup></h3>
<div id="post-body-114371668228976745"><em>Caution</em>: This story does not have a happy ending. It is neither a story for the faint of heart nor for the critical of mouth. If you're easily offended, or prone to being a disagreeable knave in blog comments, please stop reading now.Before we begin the story, let's get some conceptual gunk out of the way.</div>
<strong>The Garbage Overfloweth</strong>
<div><strong></strong>All Java people love "use cases", so let's begin with a use case: namely, taking out the garbage. As in, "Johnny, take out that garbage! It's overflowing!"</div>
<div id="post-body-114371668228976745">

If you're a normal, everyday, garden-variety, English-speaking person, and you're asked to describe the act of taking out the garbage, you probably think about it roughly along these lines:
<pre>  <em>get</em> the garbage bag from under the sink
  <em>carry</em> it out to the garage
  <em>dump</em> it in the garbage can
  <em>walk</em> back inside
  <em>wash</em> your hands
  <em>plop</em> back down on the couch
  <em>resume</em> playing your video game (or whatever you were doing)</pre>
Even if you don't think in English, you still probably still thought of a similar set of actions, except in your favorite language. Regardless of the language you chose, or the exact steps you took, taking out the garbage is a series of actions that terminates in the garbage being outside, and you being back inside, because of the <em>actions</em> you took.

Our thoughts are filled with brave, fierce, passionate actions: we live, we breathe, we walk, we talk, we laugh, we cry, we hope, we fear, we eat, we drink, we stop, we go, we take out the garbage. Above all else, we are free to <em>do</em> and to <em>act</em>. If we were all just rocks sitting in the sun, life might still be OK, but we wouldn't be free. Our freedom comes precisely from our ability to <em>do</em> things.

Of course our thoughts are also filled with nouns. We eat nouns, and buy nouns from the store, and we sit on nouns, and sleep on them. Nouns can fall on your head, creating a big noun on your noun. Nouns are <em>things</em>, and where would we be without things? But they're<em>just</em> things, that's all: the means to an end, or the ends themselves, or precious possessions, or names for the objects we observe around around us. There's a building. Here's a rock. Any child can point out the nouns. It's the <em>changes</em> happening to those nouns that make them interesting.

Change requires action. Action is what gives life its spice. Action even gives spices their spice! After all, they're not spicy until you <em>eat</em>them. Nouns may be everywhere, but life's constant change, and constant interest, is all in the verbs.

And of course in addition to verbs and nouns, we also have our adjectives, our prepositions, our pronouns, our articles, the inevitable conjunctions, the yummy expletives, and all the other lovely parts of speech that let us think and say interesting things. I think we can all agree that the parts of speech each play a role, and <em>all</em> of them are important. It would be a shame to lose any of them.

Wouldn't it be strange if we suddenly decided that we could no longer use verbs?

Let me tell you a story about a place that did exactly that...

<strong>The Kingdom of Nouns</strong>

In the Kingdom of Javaland, where King Java rules with a silicon fist, people aren't allowed to think the way you and I do. In Javaland, you see, nouns are <em>very</em> important, by order of the King himself. Nouns are the most important citizens in the Kingdom. They parade around looking distinguished in their showy finery, which is provided by the Adjectives, who are quite relieved at their lot in life. The Adjectives are nowhere near as high-class as the Nouns, but they consider themselves <em>quite</em> lucky that they weren't born Verbs.

Because the Verb citizens in this Kingdom have it very, very bad.

In Javaland, by King Java's royal decree, Verbs are <em>owned</em> by Nouns. But they're not mere pets; no, Verbs in Javaland perform all the chores and manual labor in the entire kingdom. They are, in effect, the kingdom's slaves, or at very least the serfs and indentured servants. The residents of Javaland are quite content with this situation, and are indeed scarcely aware that things could be any different.

Verbs in Javaland are responsible for all the work, but as they are held in contempt by all, no Verb is ever permitted to wander about freely. If a Verb is to be seen in public at all, it must be escorted at all times by a Noun.

Of course "escort", being a Verb itself, is hardly allowed to run around naked; one must procure a VerbEscorter to facilitate the escorting. But what about "procure" and "facilitate?" As it happens, Facilitators and Procurers are both rather important Nouns whose job is is the chaperonement of the lowly Verbs "facilitate" and "procure", via Facilitation and Procurement, respectively.

The King, consulting with the Sun God on the matter, has at times threatened to banish entirely <em>all</em> Verbs from the Kingdom of Java. If this should ever to come to pass, the inhabitants would surely need at least one Verb to do all the chores, and the King, who possesses a rather cruel sense of humor, has indicated that his choice would be most assuredly be "execute".

The Verb "execute", and its synonymous cousins "run", "start", "go", "justDoIt", "makeItSo", and the like, can perform the work of any other Verb by replacing it with an appropriate Executioner and a call to execute(). Need to wait? Waiter.execute(). Brush your teeth? ToothBrusher(myTeeth).go(). Take out the garbage? TrashDisposalPlanExecutor.doIt(). No Verb is safe; all can be replaced by a Noun on the run.

In the more patriotic corners of Javaland, the Nouns have entirely ousted the Verbs. It may appear to casual inspection that there are still Verbs here and there, tilling the fields and emptying the chamber pots. But if one looks more closely, the secret is soon revealed: Nouns can rename their execute() Verb after themselves without changing its character in the slightest. When you observe the FieldTiller till(), the ChamberPotEmptier empty(), or the RegistrationManager register(), what you're really seeing is one of the evil King's army of executioners, masked in the clothes of its owner Noun.

<strong>Verbs in Neighboring Kingdoms</strong>

In the neighboring programming-language kingdoms, taking out the trash is a straightforward affair, very similar to the way we described it in English up above. As is the case in Java, data objects are nouns, and functions are verbs.<sup><a href="http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html#note2">2</a></sup> But unlike in Javaland, citizens of other kingdoms may mix and match nouns and verbs however they please, in whatever way makes sense for conducting their business.

For instance, in the neighboring realms of C-land, JavaScript-land, Perl-land and Ruby-land, someone might model taking out the garbage as a series of actions — that is to say, verbs, or <em>functions</em>. Then if they apply the actions to the appropriate objects, in the appropriate order (<em>get</em> the trash, <em>carry</em> it outside, <em>dump</em> it in the can, etc.), the garbage-disposal task will complete successfully, with no superfluous escorts or chaperones required for any of the steps.

There's rarely any need in these kingdoms to create wrapper nouns to swaddle the verbs. They don't have GarbageDisposalStrategy nouns, nor GarbageDisposalDestinationLocator nouns for finding your way to the garage, nor PostGarbageActionCallback nouns for putting you back on your couch. They just write the verbs to operate on the nouns lying around, and then have a master verb, take_out_garbage(), that springs the subtasks to action in just the right order.

These neighboring kingdoms generally provide mechanisms for creating important nouns, when the need arises. If the diligent inventors in these kingdoms create an entirely new, useful concept that didn't exist before, such as a house, or a cart, or a machine for tilling fields faster than a person can, then they can give the concept a Class, which provides it with a name, a description, some state, and operating instructions.

The difference is that when Verbs are allowed to exist independently, you don't need to invent new Noun concepts to hold them.

Javalanders look upon their neighbors with disdain; this is the way of things in the Kingdoms of Programming.

<strong>If You Dig a Hole Deep Enough...</strong>

On the other side of the world is a sparsely inhabited region in whose kingdoms Verbs are the citizens of eminence. These are the Functional Kingdoms, including Haskellia, Ocamlica, Schemeria, and several others. Their citizens rarely cross paths with the kingdoms near Javaland. Because there are few other kingdoms nearby, the Functional Kingdoms must look with disdain upon each other, and make mutual war when they have nothing better to do.

In the Functional Kingdoms, Nouns and Verbs are generally considered equal-caste citizens. However, the Nouns, being, well, nouns, mostly sit around doing nothing at all. They don't see much point in running or executing anything, because the Verbs are quite active and see to all that for them. There are no strange laws mandating the creation of helper Nouns to escort each Verb, so there are only exactly as many Nouns as there are Things in each kindgom.

As a result of all this, the Verbs have the run of the place, if you'll pardon the expression. As an outsider, you could easily form the impression that Verbs (i.e., the functions) are the most important citizens by far. That, incidentally, is why they're called the Functional Kingdoms and not the Thingy Kingdoms.

In the remotest regions, beyond the Functional Kingdoms, lies a fabled realm called Lambda the Ultimate. In this place it is said that there are no nouns at all, only verbs! There are "things" there, but all things are created from verbs, even the very integers for counting lambs, which are the most popular form of trading currency there, if the rumors speak truth. The number zero is simply lambda(), and 1 is lambda(lambda()), 2 is lambda(lambda(lambda())), and so on. Every single Thing in this legendary region, be it noun, verb or otherwise, is constructed from the primal verb "lambda".<sup><a href="http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html#note3">3</a></sup>

To be quite honest, most Javalanders are blissfully unaware of the existence of the other side of the world. Can you imagine their culture shock? They would find it so disorienting that they might have to invent some new nouns (such as "Xenophobia") to express their new feelings.

<strong>Are Javalanders Happy?</strong>

You might think daily life in Javaland would be at best a little strange, and at worst grossly inefficient. But you can tell how happy a society is through their nursery rhymes, and Javaland's are whimsically poetic. For instance, Javaland children oft recite the famous cautionary tale:
<pre>For the lack of a nail,
    throw new HorseshoeNailNotFoundException("no nails!");

For the lack of a horseshoe,
    EquestrianDoctor.getLocalInstance().getHorseDispatcher().shoot();

For the lack of a horse,
    RidersGuild.getRiderNotificationSubscriberList().getBroadcaster().run(
      new BroadcastMessage(StableFactory.getNullHorseInstance()));

For the lack of a rider,
    MessageDeliverySubsystem.getLogger().logDeliveryFailure(
      MessageFactory.getAbstractMessageInstance(
        new MessageMedium(MessageType.VERBAL),
        new MessageTransport(MessageTransportType.MOUNTED_RIDER),
        new MessageSessionDestination(BattleManager.getRoutingInfo(
                                        BattleLocation.NEAREST))),
      MessageFailureReasonCode.UNKNOWN_RIDER_FAILURE);

For the lack of a message,
    ((BattleNotificationSender)
      BattleResourceMediator.getMediatorInstance().getResource(
        BattleParticipant.PROXY_PARTICIPANT,
        BattleResource.BATTLE_NOTIFICATION_SENDER)).sendNotification(
          ((BattleNotificationBuilder)
            (BattleResourceMediator.getMediatorInstance().getResource(
            BattleOrganizer.getBattleParticipant(Battle.Participant.GOOD_GUYS),
            BattleResource.BATTLE_NOTIFICATION_BUILDER))).buildNotification(
              BattleOrganizer.getBattleState(BattleResult.BATTLE_LOST),
              BattleManager.getChainOfCommand().getCommandChainNotifier()));

For the lack of a battle,
    try {
        synchronized(BattleInformationRouterLock.getLockInstance()) {
          BattleInformationRouterLock.getLockInstance().wait();
        }
    } catch (InterruptedException ix) {
      if (BattleSessionManager.getBattleStatus(
           BattleResource.getLocalizedBattleResource(Locale.getDefault()),
           BattleContext.createContext(
             Kingdom.getMasterBattleCoordinatorInstance(
               new TweedleBeetlePuddlePaddleBattle()).populate(
                 RegionManager.getArmpitProvince(Armpit.LEFTMOST)))) ==
          BattleStatus.LOST) {
        if (LOGGER.isLoggable(Level.TOTALLY_SCREWED)) {
          LOGGER.logScrewage(BattleLogger.createBattleLogMessage(
            BattleStatusFormatter.format(BattleStatus.LOST_WAR,
                                         Locale.getDefault())));
        }
      }
    }

For the lack of a war,
    new ServiceExecutionJoinPoint(
      DistributedQueryAnalyzer.forwardQueryResult(
        NotificationSchemaManager.getAbstractSchemaMapper(
          new PublishSubscribeNotificationSchema()).getSchemaProxy().
            executePublishSubscribeQueryPlan(
              NotificationSchema.ALERT,
              new NotificationSchemaPriority(SchemaPriority.MAX_PRIORITY),
              new PublisherMessage(MessageFactory.getAbstractMessage(
                MessageType.WRITTEN,
                new MessageTransport(MessageTransportType.WOUNDED_SURVIVOR),
                new MessageSessionDestination(
                  DestinationManager.getNullDestinationForQueryPlan()))),
              DistributedWarMachine.getPartyRoleManager().getRegisteredParties(
                PartyRoleManager.PARTY_KING &#124;&#124;
                PartyRoleManager.PARTY_GENERAL &#124;&#124;
                PartyRoleManager.PARTY_AMBASSADOR)).getQueryResult(),
        PriorityMessageDispatcher.getPriorityDispatchInstance())).
      waitForService();

All for the lack of a horseshoe nail.</pre>
It remains wonderful advice, even to this very day.

Although the telling of the tale in Javaland differs in some ways from Ben Franklin's original, Javalanders feel their rendition has a distinct charm all its own.

The main charm is that the <em>architecture</em> is there for all to see. Architecture is held in exceptionally high esteem by King Java, because architecture consists entirely of nouns. As we know, nouns are <em>things</em>, and things are prized beyond all actions in the Kingdom of Java. Architecture is made of things you can see and touch, things that tower over you imposingly, things that emit a satisfying clunk when you whack them with a stick. King Java dearly loves clunking noises; he draws immense satisfaction from kicking the wheels when he's trying out a new horse-drawn coach. Whatever its flaws may be, the tale above does not want for <em>things</em>.

One of our first instincts as human beings is to find shelter from the elements; the stronger the shelter, the safer we feel. In Javaland, there are many strong things to make the citizens feel safe. They marvel at the massive architectural creations and think "this must be a strong design". This feeling is reinforced when they try to make any changes to the structure; the architectural strength then becomes daunting enough that they feel <em>nobody</em> could bring this structure down.

In addition to the benefits of a strong architecture, everything in Javaland is nicely organized: you'll find every noun in its proper place. And the stories all take a definite shape: object construction is the dominant type of expression, with a manager for each abstraction and a run() method for each manager. With a little experience at this kind of conceptual modeling, Java citizens realize they can express <em>any</em> story in this style. There's a kind of "noun calculus" backing it that permits the expression of any abstraction, any computation you like. All one needs are sufficient nouns, constructors for those nouns, accessor methods for traversing the noun-graph, and the all-important execute() to carry out one's plans.

The residents of the Kingdom of Java aren't merely happy — they're bursting with pride!

<strong>StateManager.getConsiderationSetter("Noun Oriented Thinking", State.HARMFUL).run() </strong>

Or, as it is said outside the Kingdom of Java, "Noun Oriented Thinking Considered Harmful".

Object Oriented Programming puts the Nouns first and foremost. Why would you go to such lengths to put one part of speech on a pedestal? Why should one kind of concept take precedence over another? It's not as if OOP has suddenly made verbs less important in the way we actually think. It's a strangely skewed perspective. As my friend Jacob Gabrielson once put it, advocating Object-Oriented Programming is like advocating Pants-Oriented Clothing.

Java's static type system, like any other, has its share of problems. But the extreme emphasis on noun-oriented thought processes (and consequently, modeling processes) is more than a bit disturbing. Any type system will require you to re-shape your thoughts somewhat to fit the system, but eliminating standalone verbs seems a step beyond all rationale or reason.

C++ doesn't exhibit the problem, because C++, being a superset of C, allows you to define standalone functions. Moreover, C++ provides a distinct namespace abstraction; Java overloads the idea of a Class to represent namespaces, user-defined types, syntactic delegation mechanisms, some visibility and scoping mechanisms, and more besides.

Don't get me wrong; I'm not claiming C++ is "good". But I do find myself appreciating the flexibility of its type system, at least compared with Java's. C++ suffers from problems causing reasonable-looking sentences to cause listeners to snap and try to kill you (i.e., unexpected segfaults and other pitfalls for the unwary), and it can be extremely difficult to find the exact incantation for expressing a particular thought in C++. But the range of succinctly expressible thoughts far exceeds Java's, because C++ gives you <em>verbs</em>, and who'd want to speak in a language that doesn't?

Classes are really the only modeling tool Java provides you. So whenever a new idea occurs to you, you have to sculpt it or wrap it or smash at it until it becomes a <em>thing</em>, even if it began life as an action, a process, or any other non-"thing" concept.

I've really come around to what Perl folks were telling me 8 or 9 years ago: "Dude, not everything is an object."

It's odd, though, that Java<sup><a href="http://steve-yegge.blogspot.com/2006/03/note4">4</a></sup> appears to be the only mainstream object-oriented language that exhibits radically noun-centric behavior. You'll almost never find an AbstractProxyMediator, a NotificationStrategyFactory, or any of their ilk in Python or Ruby. Why do you find them everywhere in Java? It's a sure bet that the difference is in the verbs. Python, Ruby, JavaScript, Perl, and of course all Functional languages allow you to declare and pass around functions as distinct entities without wrapping them in a class.

It's certainly easier to do this in dynamically typed languages; you just pass a reference to the function, obtained from its name, and it's up to the caller to invoke the function with the proper arguments and use its return value correctly.

But many statically-typed languages have first-class functions as well. This includes verbosely-typed languages like C and C++, and also type-inferring languages like Haskell and ML. The languages just need to provide a syntax for creating, passing and invoking function literals with an appropriate type signature.

There's no reason Java couldn't simply add first-class functions and finally enter the grown-up, non-skewed world that allows people to use verbs as part of their thought processes. In fact there's a JVM language called <a href="http://nice.sourceforge.net/">The Nice programming language</a> that sports a very Java-like syntax, but also includes expressive facilities for using verbs: standalone functions, which Java forces you to wrap with Callbacks or Runnables or other anonymous interface implementation classes to be able to refer to them.

Sun wouldn't even have to break their convention of requiring all functions to be "owned" by classes. Every anonymous function could carry an implicit "this" pointer to the class in which it was defined; problem solved.

I don't know why Sun insists on keeping Java squarely planted in the Kingdom of Nouns. I doubt it's a matter of underestimating their constituency; they added generics, which are a far more complex concept, so they clearly no longer care deeply about keeping the language simple. And that's not a bad thing, necessarily, because Java's established now: it makes more sense to start giving Java programmers tools that let them program the way they think.

I sure hope they fix this, so I can take the trash out and get back to my video game. Or whatever I was doing.

<hr />

<strong>Notes</strong>

<a name="note1"></a>[1] Beginning with the verb "to stamp out", which is being replaced by a call to VerbEliminatorFactory.createVerbEliminator(currentContext).operate(). But that's getting waaaaay ahead of ourselves...

<a name="note2"></a>[2] And variable names are proper nouns, attributes are adjectives, operators often serve as conjunctions, varargs are the pronoun "y'all", and so on. But this is all beside the point of our story.

<a name="note3"></a>[3] The meaning of the verb "lambda" is allegedly "to lambda".

<a name="note4"></a>[4] And arguably C#, due to its similar roots.

</div>
<div>
<div>POSTED BY <a title="author profile" href="http://www.blogger.com/profile/14812997485690838920" rel="author">STEVE YEGGE </a>AT <a title="permanent link" href="http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html" rel="bookmark"><abbr title="2006-03-30T03:00:00-08:00">3:00 AM</abbr></a></div>
</div>
<div><span class="Apple-style-span" style="font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 12px; line-height: normal;">
</span></div>]]></description>
			<content:encoded><![CDATA[<h3><span class="Apple-style-span" style="font-size: 13px; font-weight: normal;">Forward from: </span><a style="font-size: 13px; font-weight: normal;" href="http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html">http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html</a></h3>
<h3><span class="Apple-style-span" style="font-size: 13px; font-weight: normal;">They&#8217;ve a temper, some of them—particularly verbs: they&#8217;re the proudest—adjectives you can do anything with, but not verbs—however, <em>I</em> can manage the whole lot of them! Impenetrability! That&#8217;s what <em>I</em> say!<br />
— Humpty Dumpty<br />
</span></h3>
<h3><span class="Apple-style-span" style="font-size: 13px; font-weight: normal;">Hello, world! Today we&#8217;re going to hear the story of Evil King Java and his quest for worldwide verb stamp-outage.</span><sup><a href="http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html#note1">1</a></sup></h3>
<div id="post-body-114371668228976745"><em>Caution</em>: This story does not have a happy ending. It is neither a story for the faint of heart nor for the critical of mouth. If you&#8217;re easily offended, or prone to being a disagreeable knave in blog comments, please stop reading now.Before we begin the story, let&#8217;s get some conceptual gunk out of the way.</div>
<p><strong>The Garbage Overfloweth</strong></p>
<div><strong></strong>All Java people love “use cases”, so let&#8217;s begin with a use case: namely, taking out the garbage. As in, “Johnny, take out that garbage! It&#8217;s overflowing!”</div>
<div id="post-body-114371668228976745">
<p>If you&#8217;re a normal, everyday, garden-variety, English-speaking person, and you&#8217;re asked to describe the act of taking out the garbage, you probably think about it roughly along these lines:</p>
<pre>  <em>get</em> the garbage bag from under the sink
  <em>carry</em> it out to the garage
  <em>dump</em> it in the garbage can
  <em>walk</em> back inside
  <em>wash</em> your hands
  <em>plop</em> back down on the couch
  <em>resume</em> playing your video game (or whatever you were doing)</pre>
<p>Even if you don&#8217;t think in English, you still probably still thought of a similar set of actions, except in your favorite language. Regardless of the language you chose, or the exact steps you took, taking out the garbage is a series of actions that terminates in the garbage being outside, and you being back inside, because of the <em>actions</em> you took.</p>
<p>Our thoughts are filled with brave, fierce, passionate actions: we live, we breathe, we walk, we talk, we laugh, we cry, we hope, we fear, we eat, we drink, we stop, we go, we take out the garbage. Above all else, we are free to <em>do</em> and to <em>act</em>. If we were all just rocks sitting in the sun, life might still be OK, but we wouldn&#8217;t be free. Our freedom comes precisely from our ability to <em>do</em> things.</p>
<p>Of course our thoughts are also filled with nouns. We eat nouns, and buy nouns from the store, and we sit on nouns, and sleep on them. Nouns can fall on your head, creating a big noun on your noun. Nouns are <em>things</em>, and where would we be without things? But they&#8217;re<em>just</em> things, that&#8217;s all: the means to an end, or the ends themselves, or precious possessions, or names for the objects we observe around around us. There&#8217;s a building. Here&#8217;s a rock. Any child can point out the nouns. It&#8217;s the <em>changes</em> happening to those nouns that make them interesting.</p>
<p>Change requires action. Action is what gives life its spice. Action even gives spices their spice! After all, they&#8217;re not spicy until you <em>eat</em>them. Nouns may be everywhere, but life&#8217;s constant change, and constant interest, is all in the verbs.</p>
<p>And of course in addition to verbs and nouns, we also have our adjectives, our prepositions, our pronouns, our articles, the inevitable conjunctions, the yummy expletives, and all the other lovely parts of speech that let us think and say interesting things. I think we can all agree that the parts of speech each play a role, and <em>all</em> of them are important. It would be a shame to lose any of them.</p>
<p>Wouldn&#8217;t it be strange if we suddenly decided that we could no longer use verbs?</p>
<p>Let me tell you a story about a place that did exactly that&#8230;</p>
<p><strong>The Kingdom of Nouns</strong></p>
<p>In the Kingdom of Javaland, where King Java rules with a silicon fist, people aren&#8217;t allowed to think the way you and I do. In Javaland, you see, nouns are <em>very</em> important, by order of the King himself. Nouns are the most important citizens in the Kingdom. They parade around looking distinguished in their showy finery, which is provided by the Adjectives, who are quite relieved at their lot in life. The Adjectives are nowhere near as high-class as the Nouns, but they consider themselves <em>quite</em> lucky that they weren&#8217;t born Verbs.</p>
<p>Because the Verb citizens in this Kingdom have it very, very bad.</p>
<p>In Javaland, by King Java&#8217;s royal decree, Verbs are <em>owned</em> by Nouns. But they&#8217;re not mere pets; no, Verbs in Javaland perform all the chores and manual labor in the entire kingdom. They are, in effect, the kingdom&#8217;s slaves, or at very least the serfs and indentured servants. The residents of Javaland are quite content with this situation, and are indeed scarcely aware that things could be any different.</p>
<p>Verbs in Javaland are responsible for all the work, but as they are held in contempt by all, no Verb is ever permitted to wander about freely. If a Verb is to be seen in public at all, it must be escorted at all times by a Noun.</p>
<p>Of course “escort”, being a Verb itself, is hardly allowed to run around naked; one must procure a VerbEscorter to facilitate the escorting. But what about “procure” and “facilitate?” As it happens, Facilitators and Procurers are both rather important Nouns whose job is is the chaperonement of the lowly Verbs “facilitate” and “procure”, via Facilitation and Procurement, respectively.</p>
<p>The King, consulting with the Sun God on the matter, has at times threatened to banish entirely <em>all</em> Verbs from the Kingdom of Java. If this should ever to come to pass, the inhabitants would surely need at least one Verb to do all the chores, and the King, who possesses a rather cruel sense of humor, has indicated that his choice would be most assuredly be “execute”.</p>
<p>The Verb “execute”, and its synonymous cousins “run”, “start”, “go”, “justDoIt”, “makeItSo”, and the like, can perform the work of any other Verb by replacing it with an appropriate Executioner and a call to execute(). Need to wait? Waiter.execute(). Brush your teeth? ToothBrusher(myTeeth).go(). Take out the garbage? TrashDisposalPlanExecutor.doIt(). No Verb is safe; all can be replaced by a Noun on the run.</p>
<p>In the more patriotic corners of Javaland, the Nouns have entirely ousted the Verbs. It may appear to casual inspection that there are still Verbs here and there, tilling the fields and emptying the chamber pots. But if one looks more closely, the secret is soon revealed: Nouns can rename their execute() Verb after themselves without changing its character in the slightest. When you observe the FieldTiller till(), the ChamberPotEmptier empty(), or the RegistrationManager register(), what you&#8217;re really seeing is one of the evil King&#8217;s army of executioners, masked in the clothes of its owner Noun.</p>
<p><strong>Verbs in Neighboring Kingdoms</strong></p>
<p>In the neighboring programming-language kingdoms, taking out the trash is a straightforward affair, very similar to the way we described it in English up above. As is the case in Java, data objects are nouns, and functions are verbs.<sup><a href="http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html#note2">2</a></sup> But unlike in Javaland, citizens of other kingdoms may mix and match nouns and verbs however they please, in whatever way makes sense for conducting their business.</p>
<p>For instance, in the neighboring realms of C-land, JavaScript-land, Perl-land and Ruby-land, someone might model taking out the garbage as a series of actions — that is to say, verbs, or <em>functions</em>. Then if they apply the actions to the appropriate objects, in the appropriate order (<em>get</em> the trash, <em>carry</em> it outside, <em>dump</em> it in the can, etc.), the garbage-disposal task will complete successfully, with no superfluous escorts or chaperones required for any of the steps.</p>
<p>There&#8217;s rarely any need in these kingdoms to create wrapper nouns to swaddle the verbs. They don&#8217;t have GarbageDisposalStrategy nouns, nor GarbageDisposalDestinationLocator nouns for finding your way to the garage, nor PostGarbageActionCallback nouns for putting you back on your couch. They just write the verbs to operate on the nouns lying around, and then have a master verb, take_out_garbage(), that springs the subtasks to action in just the right order.</p>
<p>These neighboring kingdoms generally provide mechanisms for creating important nouns, when the need arises. If the diligent inventors in these kingdoms create an entirely new, useful concept that didn&#8217;t exist before, such as a house, or a cart, or a machine for tilling fields faster than a person can, then they can give the concept a Class, which provides it with a name, a description, some state, and operating instructions.</p>
<p>The difference is that when Verbs are allowed to exist independently, you don&#8217;t need to invent new Noun concepts to hold them.</p>
<p>Javalanders look upon their neighbors with disdain; this is the way of things in the Kingdoms of Programming.</p>
<p><strong>If You Dig a Hole Deep Enough&#8230;</strong></p>
<p>On the other side of the world is a sparsely inhabited region in whose kingdoms Verbs are the citizens of eminence. These are the Functional Kingdoms, including Haskellia, Ocamlica, Schemeria, and several others. Their citizens rarely cross paths with the kingdoms near Javaland. Because there are few other kingdoms nearby, the Functional Kingdoms must look with disdain upon each other, and make mutual war when they have nothing better to do.</p>
<p>In the Functional Kingdoms, Nouns and Verbs are generally considered equal-caste citizens. However, the Nouns, being, well, nouns, mostly sit around doing nothing at all. They don&#8217;t see much point in running or executing anything, because the Verbs are quite active and see to all that for them. There are no strange laws mandating the creation of helper Nouns to escort each Verb, so there are only exactly as many Nouns as there are Things in each kindgom.</p>
<p>As a result of all this, the Verbs have the run of the place, if you&#8217;ll pardon the expression. As an outsider, you could easily form the impression that Verbs (i.e., the functions) are the most important citizens by far. That, incidentally, is why they&#8217;re called the Functional Kingdoms and not the Thingy Kingdoms.</p>
<p>In the remotest regions, beyond the Functional Kingdoms, lies a fabled realm called Lambda the Ultimate. In this place it is said that there are no nouns at all, only verbs! There are “things” there, but all things are created from verbs, even the very integers for counting lambs, which are the most popular form of trading currency there, if the rumors speak truth. The number zero is simply lambda(), and 1 is lambda(lambda()), 2 is lambda(lambda(lambda())), and so on. Every single Thing in this legendary region, be it noun, verb or otherwise, is constructed from the primal verb “lambda”.<sup><a href="http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html#note3">3</a></sup></p>
<p>To be quite honest, most Javalanders are blissfully unaware of the existence of the other side of the world. Can you imagine their culture shock? They would find it so disorienting that they might have to invent some new nouns (such as “Xenophobia”) to express their new feelings.</p>
<p><strong>Are Javalanders Happy?</strong></p>
<p>You might think daily life in Javaland would be at best a little strange, and at worst grossly inefficient. But you can tell how happy a society is through their nursery rhymes, and Javaland&#8217;s are whimsically poetic. For instance, Javaland children oft recite the famous cautionary tale:</p>
<pre>For the lack of a nail,
    throw new HorseshoeNailNotFoundException("no nails!");

For the lack of a horseshoe,
    EquestrianDoctor.getLocalInstance().getHorseDispatcher().shoot();

For the lack of a horse,
    RidersGuild.getRiderNotificationSubscriberList().getBroadcaster().run(
      new BroadcastMessage(StableFactory.getNullHorseInstance()));

For the lack of a rider,
    MessageDeliverySubsystem.getLogger().logDeliveryFailure(
      MessageFactory.getAbstractMessageInstance(
        new MessageMedium(MessageType.VERBAL),
        new MessageTransport(MessageTransportType.MOUNTED_RIDER),
        new MessageSessionDestination(BattleManager.getRoutingInfo(
                                        BattleLocation.NEAREST))),
      MessageFailureReasonCode.UNKNOWN_RIDER_FAILURE);

For the lack of a message,
    ((BattleNotificationSender)
      BattleResourceMediator.getMediatorInstance().getResource(
        BattleParticipant.PROXY_PARTICIPANT,
        BattleResource.BATTLE_NOTIFICATION_SENDER)).sendNotification(
          ((BattleNotificationBuilder)
            (BattleResourceMediator.getMediatorInstance().getResource(
            BattleOrganizer.getBattleParticipant(Battle.Participant.GOOD_GUYS),
            BattleResource.BATTLE_NOTIFICATION_BUILDER))).buildNotification(
              BattleOrganizer.getBattleState(BattleResult.BATTLE_LOST),
              BattleManager.getChainOfCommand().getCommandChainNotifier()));

For the lack of a battle,
    try {
        synchronized(BattleInformationRouterLock.getLockInstance()) {
          BattleInformationRouterLock.getLockInstance().wait();
        }
    } catch (InterruptedException ix) {
      if (BattleSessionManager.getBattleStatus(
           BattleResource.getLocalizedBattleResource(Locale.getDefault()),
           BattleContext.createContext(
             Kingdom.getMasterBattleCoordinatorInstance(
               new TweedleBeetlePuddlePaddleBattle()).populate(
                 RegionManager.getArmpitProvince(Armpit.LEFTMOST)))) ==
          BattleStatus.LOST) {
        if (LOGGER.isLoggable(Level.TOTALLY_SCREWED)) {
          LOGGER.logScrewage(BattleLogger.createBattleLogMessage(
            BattleStatusFormatter.format(BattleStatus.LOST_WAR,
                                         Locale.getDefault())));
        }
      }
    }

For the lack of a war,
    new ServiceExecutionJoinPoint(
      DistributedQueryAnalyzer.forwardQueryResult(
        NotificationSchemaManager.getAbstractSchemaMapper(
          new PublishSubscribeNotificationSchema()).getSchemaProxy().
            executePublishSubscribeQueryPlan(
              NotificationSchema.ALERT,
              new NotificationSchemaPriority(SchemaPriority.MAX_PRIORITY),
              new PublisherMessage(MessageFactory.getAbstractMessage(
                MessageType.WRITTEN,
                new MessageTransport(MessageTransportType.WOUNDED_SURVIVOR),
                new MessageSessionDestination(
                  DestinationManager.getNullDestinationForQueryPlan()))),
              DistributedWarMachine.getPartyRoleManager().getRegisteredParties(
                PartyRoleManager.PARTY_KING ||
                PartyRoleManager.PARTY_GENERAL ||
                PartyRoleManager.PARTY_AMBASSADOR)).getQueryResult(),
        PriorityMessageDispatcher.getPriorityDispatchInstance())).
      waitForService();

All for the lack of a horseshoe nail.</pre>
<p>It remains wonderful advice, even to this very day.</p>
<p>Although the telling of the tale in Javaland differs in some ways from Ben Franklin&#8217;s original, Javalanders feel their rendition has a distinct charm all its own.</p>
<p>The main charm is that the <em>architecture</em> is there for all to see. Architecture is held in exceptionally high esteem by King Java, because architecture consists entirely of nouns. As we know, nouns are <em>things</em>, and things are prized beyond all actions in the Kingdom of Java. Architecture is made of things you can see and touch, things that tower over you imposingly, things that emit a satisfying clunk when you whack them with a stick. King Java dearly loves clunking noises; he draws immense satisfaction from kicking the wheels when he&#8217;s trying out a new horse-drawn coach. Whatever its flaws may be, the tale above does not want for <em>things</em>.</p>
<p>One of our first instincts as human beings is to find shelter from the elements; the stronger the shelter, the safer we feel. In Javaland, there are many strong things to make the citizens feel safe. They marvel at the massive architectural creations and think “this must be a strong design”. This feeling is reinforced when they try to make any changes to the structure; the architectural strength then becomes daunting enough that they feel <em>nobody</em> could bring this structure down.</p>
<p>In addition to the benefits of a strong architecture, everything in Javaland is nicely organized: you&#8217;ll find every noun in its proper place. And the stories all take a definite shape: object construction is the dominant type of expression, with a manager for each abstraction and a run() method for each manager. With a little experience at this kind of conceptual modeling, Java citizens realize they can express <em>any</em> story in this style. There&#8217;s a kind of “noun calculus” backing it that permits the expression of any abstraction, any computation you like. All one needs are sufficient nouns, constructors for those nouns, accessor methods for traversing the noun-graph, and the all-important execute() to carry out one&#8217;s plans.</p>
<p>The residents of the Kingdom of Java aren&#8217;t merely happy — they&#8217;re bursting with pride!</p>
<p><strong>StateManager.getConsiderationSetter(“Noun Oriented Thinking”, State.HARMFUL).run() </strong></p>
<p>Or, as it is said outside the Kingdom of Java, “Noun Oriented Thinking Considered Harmful”.</p>
<p>Object Oriented Programming puts the Nouns first and foremost. Why would you go to such lengths to put one part of speech on a pedestal? Why should one kind of concept take precedence over another? It&#8217;s not as if OOP has suddenly made verbs less important in the way we actually think. It&#8217;s a strangely skewed perspective. As my friend Jacob Gabrielson once put it, advocating Object-Oriented Programming is like advocating Pants-Oriented Clothing.</p>
<p>Java&#8217;s static type system, like any other, has its share of problems. But the extreme emphasis on noun-oriented thought processes (and consequently, modeling processes) is more than a bit disturbing. Any type system will require you to re-shape your thoughts somewhat to fit the system, but eliminating standalone verbs seems a step beyond all rationale or reason.</p>
<p>C++ doesn&#8217;t exhibit the problem, because C++, being a superset of C, allows you to define standalone functions. Moreover, C++ provides a distinct namespace abstraction; Java overloads the idea of a Class to represent namespaces, user-defined types, syntactic delegation mechanisms, some visibility and scoping mechanisms, and more besides.</p>
<p>Don&#8217;t get me wrong; I&#8217;m not claiming C++ is “good”. But I do find myself appreciating the flexibility of its type system, at least compared with Java&#8217;s. C++ suffers from problems causing reasonable-looking sentences to cause listeners to snap and try to kill you (i.e., unexpected segfaults and other pitfalls for the unwary), and it can be extremely difficult to find the exact incantation for expressing a particular thought in C++. But the range of succinctly expressible thoughts far exceeds Java&#8217;s, because C++ gives you <em>verbs</em>, and who&#8217;d want to speak in a language that doesn&#8217;t?</p>
<p>Classes are really the only modeling tool Java provides you. So whenever a new idea occurs to you, you have to sculpt it or wrap it or smash at it until it becomes a <em>thing</em>, even if it began life as an action, a process, or any other non-”thing” concept.</p>
<p>I&#8217;ve really come around to what Perl folks were telling me 8 or 9 years ago: “Dude, not everything is an object.”</p>
<p>It&#8217;s odd, though, that Java<sup><a href="http://steve-yegge.blogspot.com/2006/03/note4">4</a></sup> appears to be the only mainstream object-oriented language that exhibits radically noun-centric behavior. You&#8217;ll almost never find an AbstractProxyMediator, a NotificationStrategyFactory, or any of their ilk in Python or Ruby. Why do you find them everywhere in Java? It&#8217;s a sure bet that the difference is in the verbs. Python, Ruby, JavaScript, Perl, and of course all Functional languages allow you to declare and pass around functions as distinct entities without wrapping them in a class.</p>
<p>It&#8217;s certainly easier to do this in dynamically typed languages; you just pass a reference to the function, obtained from its name, and it&#8217;s up to the caller to invoke the function with the proper arguments and use its return value correctly.</p>
<p>But many statically-typed languages have first-class functions as well. This includes verbosely-typed languages like C and C++, and also type-inferring languages like Haskell and ML. The languages just need to provide a syntax for creating, passing and invoking function literals with an appropriate type signature.</p>
<p>There&#8217;s no reason Java couldn&#8217;t simply add first-class functions and finally enter the grown-up, non-skewed world that allows people to use verbs as part of their thought processes. In fact there&#8217;s a JVM language called <a href="http://nice.sourceforge.net/">The Nice programming language</a> that sports a very Java-like syntax, but also includes expressive facilities for using verbs: standalone functions, which Java forces you to wrap with Callbacks or Runnables or other anonymous interface implementation classes to be able to refer to them.</p>
<p>Sun wouldn&#8217;t even have to break their convention of requiring all functions to be “owned” by classes. Every anonymous function could carry an implicit “this” pointer to the class in which it was defined; problem solved.</p>
<p>I don&#8217;t know why Sun insists on keeping Java squarely planted in the Kingdom of Nouns. I doubt it&#8217;s a matter of underestimating their constituency; they added generics, which are a far more complex concept, so they clearly no longer care deeply about keeping the language simple. And that&#8217;s not a bad thing, necessarily, because Java&#8217;s established now: it makes more sense to start giving Java programmers tools that let them program the way they think.</p>
<p>I sure hope they fix this, so I can take the trash out and get back to my video game. Or whatever I was doing.</p>
<hr />
<p><strong>Notes</strong></p>
<p><a name="note1"></a>[1] Beginning with the verb “to stamp out”, which is being replaced by a call to VerbEliminatorFactory.createVerbEliminator(currentContext).operate(). But that&#8217;s getting waaaaay ahead of ourselves&#8230;</p>
<p><a name="note2"></a>[2] And variable names are proper nouns, attributes are adjectives, operators often serve as conjunctions, varargs are the pronoun “y&#8217;all”, and so on. But this is all beside the point of our story.</p>
<p><a name="note3"></a>[3] The meaning of the verb “lambda” is allegedly “to lambda”.</p>
<p><a name="note4"></a>[4] And arguably C#, due to its similar roots.</p>
</div>
<div>
<div>POSTED BY <a title="author profile" href="http://www.blogger.com/profile/14812997485690838920" rel="author">STEVE YEGGE </a>AT <a title="permanent link" href="http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html" rel="bookmark"><abbr title="2006-03-30T03:00:00-08:00">3:00 AM</abbr></a></div>
</div>
<div><span class="Apple-style-span" style="font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 12px; line-height: normal;"><br />
</span></div>
]]></content:encoded>
			<wfw:commentRss>http://www.codingguy.net/?feed=rss2&#038;p=32</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
