2017-04-18

 

概述

    在TV开发板中,可以在串口中直接使用grep命令。这是因为在/system/bin/下有一个'grep'链接。这个链接指向'/system/bin/toolbox'程序。
【图1】
当在串口中键入:
grep um
命令时也就等效于键入
toolbox grep um
 
  toolbox程序是Android系统中携带的工具​之一。其源码位于:
./system/core/toolbox/

【图2】

  由上图2可以看到该目录下包含有大多数常用命令的源代码。toolbox程序的意义就是将这些零散的程序的入口进行打包。根据用户在串口中键入的toolbox命令后面的参数不同来选择执行对应的程序。例如,当键入上述的 ‘toolbox grep um’命令时,系统会先将命令的参数通过toolbox的进行解析,最终调用grep.c中的grep_main()函数进行二次解析。

 

toolbox处理流程

./system/core/toolbox/toolbox.c
  该源码文件结构简单。内部仅两个函数:1.int main(int argc, char **argv);2.static int toolbox_main(int argc, char **argv);以及一个封装了各工具集入口函数的结构体数组tools[]。在这个源码中,最重要的就是这个静态结构体数组,其定义如下:
 #define TOOL(name) int name##_main(int, char**);
#include "tools.h"
#undef TOOL static struct
{
const char *name;
int (*func)(int, char**);
} tools[] = {
{ "toolbox", toolbox_main },
#define TOOL(name) { #name, name##_main },
#include "tools.h"
#undef TOOL
{ , },
};
  上述代码中,第1~3行的定义方式在我看来很新奇。但此处就简单把它理解成从tools.h中读取定义的信息,事实上也确实是这样。然后将这些字符串替换成相应的函数声明。tools.h是在本目录下的Android.mk文件中生成的。位于out目录下。
 
其内容类型如下
上述代码中,第1~3行是声明各工具的入口函数。第11~13行是使用这些外部函数。经过这样的声明以后,toolbox程序在运行时这个tools数组的实际值为
 tools[] = {
{ "toolbox", toolbox_main },
{"ls", ls_main},
.
.
.
{"grep", grep_main},
{ , },
};
而tools结构体的第二个参数又是一个函数指针,因此,tools数组中包含的就是toolbox目录下的所有工具的入口函数。估计这也是它会被取名为toolbox的原因吧。
 
  在运行toolbox程序的时候,首先会调用其主函数main()。在这个主函数main()中主要就是取跟在toolbox后面的参数来决定到底是要执行哪一个工具程序。如当键入:toolbox ls。则toolbox.c的执行顺序为:1.main();2.toolbox_main();3.main();4.ls_main()
 

grep

    grep程序的入口函数为:grep_main()
 ./system/core/toolbox/grep/grep.c
在这个文件的首部,定义了多个标志位用于区分不同的参数响应。
常用的功能及其执行参数都已标示了出来。
    在grep_main()函数中,首先判断了键入参数的首字符。 __progname[0]等效于argv[0][0]。一般我们使用grep命令时,都是键入grep -n "xx",这时,__progname[0]得到的值就是字符g。看注释貌似是说区分于二进制模式下的什么什么的。对于我们由串口键入命令来执行程序的情况,是统一解析成字符g的,故而不需要理会它的真实用意。
 
    然后会从环境变量中读取搜索环境。
读取到环境变量后做了什么事,我们姑且不管。不过这个的结果一般都是(null),因此实际上会执行如下操作:
    接下来就是去解析命令后面跟的参数了。
图【3】
函数getopt_long()的含义可查询百度。
不得不承认,这个函数的功能很强大。它能解析各种花式输入的参数。同时它还具有排序的功能,将花式输入的命令行重新排序成'grep'在前,参数在其中,需要筛选的字符串在末尾的顺序。具体功能验证如下系列图所示,getopt_long()的排序功能验证如下图7所示。

    总之,经过图3所示的while循环后,能够识别所有的参数。例如,识别-n参数的代码如下图所示。
    接下来就是筛减aargv中的参数。
其中,optind是getopt_long()函数中的一个变量,它的值是键入的'grep'字符串以及所有的参数的数量。
 
    接下来是去读取需要过滤的字符串。
当键入的参数中包含-e  -f 时,needpattern的值就是0,否则为1。
由此处代码可知,grep命令仅能搜索一个参数。add_pattern()函数的实现如下图所示。
【图4】
    此函数的代码也算简单。grep命令是在pattern[]数组中保存要过滤的字符串的(pattern是一个二维数组)。而这个数组又被设计成“自动扩容”的形式。上图4所示代码中第230行的条件块就是一个自动扩容的处理流程了。grep_realloc()函数的定义位于
 ./system/core/toolbox/grep/util.c
然后将这个要过滤的字符串添加到pattern[]数组的末尾。至此,整个命令的解析就已经完成了。接下来就要开始执行过滤操作了。
    接下来就是
这个grepbehave在grep_main()的首部就已被赋值。对于我们由串口键入命令的情况来说,其值恒为GREP_BASIC。这里,不必理会。
 
    接下来是
这一块的作用我也不知道。程序一般会走694行。看695行的函数名fastcomp(),猜它应该是一个快速对比的功能。这个函数的定义位于
 ./system/core/toolbox/grep/fastgrep.c
有兴趣的话可以去详细阅读一下源码。这个函数返回0表示成功,返回-1表示失败。经测试,都是返回-1。此处略过这块代码。
 
    接下来是搜索前的最后的设置。
707行的lbflag是行缓冲。目前并不知道它的具体作用。经测试,由串口键入命令的方式,该值一般为0。此处暂时不予理会。
710行的Hflag,。该值默认为0。
由713行,当键入的过滤字符串只有一个时,就进行过滤操作,然后退出grep程序。
否则,就执行下面的代码。多个过滤字符串中后面的将会被认为是文件或目录的路径。这样就会被系统理解为在这个目录或文件中执行搜索命令。
dirbehave在键入的参数中有'-r'时其值会为DIR_RECURSE。其它情况,则执行else分支。
这里,暂时不讨论指定文件或目录的情况。
 
procfile()函数位于
 ./system/core/toolbox/grep/util.c
    这个函数内部定义了几个结构体变量。其中file与str结构体的定义位于
 ./system/core/toolbox/grep/grep.h

    file结构体结构简单,内部仅保存文件的句柄及这个文件是否是二进制文件的标志。str结构体也简单。其中*dat保存的是当前剩余要过滤的数据。对于在串口中使用grep而言,就是当前获得的文件流中的所有内容。
对于只有一个过滤字符串的情况,会执行上图所示代码中的197行代码块。且对于在串口中键入命令的情况,198行的fn得到的值是(standard input)。即标准输入流,而非某个文件流。接着去grep_open(NULL)函数,这个函数位于
 ./system/core/toolbox/grep/file.c
这个函数的结构也简单,
这个函数的重点在于第241行处。它会将文件结构体的文件句柄指向标准输入流处。
    接着再回到util.c处继续往下执行,现在就到了从流中过滤数据的时候了。核心代码如下图所示,
上面这个for循环语句就是用来过滤关键字并将结果打印在控制台用的。在第226行for循环的条件判断处可以看到两个状态位lflag与qflag。前面的状态位是标志是否只打印文件名,后面的状态位则是标志是否静默搜索(将结果输出到文件或其它什么的)。
 
    上图所示代码中,第228行的if语句的作用就是逐行读取源数据ln.dat。然后跳到第242行。这里调用了procline函数。上面的procfile是处理整个文件流,读取出一行数据后就传到procline中作进一步处理。随后procline在匹配到符合条件的行后,传到printline函数中打印出来。这三个函数均在util.c文件中。具体的实现流程就不再赘述了。
 
grep的详细流程在我看来是很复杂的,没有必要去弄懂这个流程中每一行代码的意义,只需要了解个大概流程就好了,毕竟是抱着扩充知识面而非研究代码的目的去学习的。

浅析Android设备中grep命令处理流程的更多相关文章

  1. 通过ADB命令行卸载或删除你的Android设备中的应用(转载)

    转自:http://mytiankong.com/?p=11755 如果你对你的Android设备在与命令行的交互间有一定的兴趣,那你可能想学习一些使用ADB卸载设备中已安装应用的技巧.为了使这种方法 ...

  2. bat如何创建多级文件夹(在android设备中)

    在android设备中要创建多个或者多级文件夹时,手动去创建费时费力(有点傻),一个bat文件就能很好的实现这个功能. 1.首先创建同级多个文件夹且在该文件夹下生成一个文件 @echo off ech ...

  3. Android开发中adb命令的常用方法

    Android的SDK中提供了很多有用的工具,在开发过程中如果能熟练使用这些工具,会让我们的开发事半功倍.adb是SDK提供的一个常用的命令行工具,全称为Android Debug Bridge,用于 ...

  4. 从Android设备中提取内核和逆向分析

    本文博客链接:http://blog.csdn.net/qq1084283172/article/details/57074695 一.手机设备环境 Model number: Nexus 5 OS ...

  5. 12个 Linux 中 grep 命令的超级用法实例

    12个 Linux 中 grep 命令的超级用法实例 你是否遇到过需要在文件中查找一个特定的字符串或者样式,但是不知道从哪儿开始?那么,就请grep来帮你吧. grep是每个Linux发行版都预装的一 ...

  6. linux中grep命令的使用

    转载:http://blog.csdn.net/universsky/article/details/8866402 linux中grep命令的使用 grep (global search regul ...

  7. 在桌面chrome中调试android设备中的web页面

    准备工作 1, 桌面版chrome 2, Android设备(安装有chrome浏览器) 3, Android-sdk Android-sdk安装及设置 SKD安装 从http://developer ...

  8. 如何获得Android设备名称(ADB命令详细介绍)

    豌豆荚.360手机管家等软件可以获取android设备名称,显示在界面上,如下图: 我们自己如何来获取设备名称 呢?答案如下: 在命令行中输入“adb shell”进入shell之后,再输入“cat ...

  9. shell 中grep命令详解

    用‘grep’搜索文本文件如果您要在几个文本文件中查找一字符串,可以使用‘grep’命令.‘grep’在文本中搜索指定的字符串.举个例子:假设您正在‘/usr/src/linux/Documentat ...

随机推荐

  1. 使用后台线程BackgroundWorker处理任务的总结

    在一些耗时的操作过程中,在长时间运行时可能会导致用户界面 (UI) 处于停止响应状态,用户在这操作期间无法进行其他的操作,为了不使UI层处于停止响应状态,我们倾向推荐用户使用BackgroundWor ...

  2. 朱晔和你聊Spring系列S1E8:凑活着用的Spring Cloud(含一个实际业务贯穿所有组件的完整例子)

    本文会以一个简单而完整的业务来阐述Spring Cloud Finchley.RELEASE版本常用组件的使用.如下图所示,本文会覆盖的组件有: Spring Cloud Netflix Zuul网关 ...

  3. Python-爬虫的基本原理

    什么是爬虫 爬虫就是请求网站并提取数据的自动化程序.其中请求,提取,自动化是爬虫的关键!下面我们分析爬虫的基本流程 爬虫的基本流程 发起请求通过HTTP库向目标站点发起请求,也就是发送一个Reques ...

  4. H5 字体属性补充

    04-字体属性补充 abc我是段落 <!DOCTYPE html> <html lang="en"> <head> <meta chars ...

  5. koa generator

    Koa (koajs) -- 基于 Node.js 平台的下一代 web 开发框架 | Koajs... Koa 框架教程 koa入门 如何评价 Node.js 的koa框架?

  6. echarts使用笔记三:柱子对比

    app.title = '坐标轴刻度与标签对齐'; option = { title : { //标题 x : 'center', y : 5, text : '对比图' //换行用 \n }, le ...

  7. Ubuntu 12.04 安装socks5代理服务器dante-server

    dante-server是一个很好的socks4/5代理服务器软件. 使用apt-get安装   1 apt-getinstall dante-server 添加一个用户   1 2 useradd ...

  8. rem移动端适配方案

    一. rem vs em 单位 定义 特点 rem font size of the root element 以根元素字体大小为基准 em font size of the element 以父元素 ...

  9. react render

    实际上react render方法返回一个虚拟dom 并没有去执行渲染dom 渲染的过程是交给react 去完成的 这就说明了为什么要在所有数据请求完成后才去实现render 这样做也提高了性能.只调 ...

  10. 解读event.returnValue和return false

    前言 首先我们要清楚returnValue是IE的一个属性,如果设置了该属性,它的值比事件句柄的返回值优先级要高,把它的值设置为false,可以取消发生事件源元素的默认动作:return false就 ...