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. ML.NET 示例:推荐之矩阵分解

    写在前面 准备近期将微软的machinelearning-samples翻译成中文,水平有限,如有错漏,请大家多多指正. 如果有朋友对此感兴趣,可以加入我:https://github.com/fei ...

  2. Xamarin.Forms 3.0的新特性

    近期因为工作关系开始使用Xamarin,翻译了两篇国外的介绍3.0新特性的文章,供大家参考. 第一篇文章来自Xamarin官网,原文地址:https://blog.xamarin.com/xamari ...

  3. unixbench 物理机性能与虚拟机性能测试对比

    1.  测试方法 wget https://download.laobuluo.com/tools/UnixBench5.1.3.tgz tar -zxvf UnixBench5.1.3.tgz cd ...

  4. .NetCore 2.1中的HttpClientFactory最佳实践

    .NET Core 2.1中的HttpClientFactory最佳实践 ASP.NET Core 2.1中出现一个新的HttpClientFactory功能, 它有助于解决开发人员在使用HttpCl ...

  5. PHP中多个文件包含的问题 (二)

    首先php中有常用的两种方法将文件包含:include和require,而include_once和require_once无非就是升级版而已,这里就不阐述他们的区别,我只提一下我遇到的问题: 先看一 ...

  6. Linux 典型应用之缓存服务

    memcached 安装和简单使用 yum install memcached 启动 -d 表示以守护进程的方式启动 memcached -d 安装telnet 它可以检测某个端口是否是通的,可以发送 ...

  7. PHP之CLI模式

    转载: http://www.cnblogs.com/zcy_soft/archive/2011/12/10/2283437.html 所有的PHP发行版,不论是编译自源代码的版本还是预创建的版本,都 ...

  8. 【Python3练习题 005】输入三个整数x,y,z,请把这三个数由小到大输出

    import re x, y, z = re.split(',| |,| ', input('请输入3个数字,用逗号或空格隔开:'))x, y, z = int(x), int(y), int(z) ...

  9. Day 6-2简单的socket通信

    什么是socket? Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面 ...

  10. JDK 环境变量的设置、eclipse、Tomcat的配置

    一.JDK的环境变量的设置 环境变量设置: JDK下载好后,(1)选择电脑属性-高级系统设置-高级-环境变量,接着在系统变量中(2)新建JAVA_HOME,变量值设置为下载好后JDK在电脑中的路径;( ...