Android在init.rc中自定义开机启动进程(service)

原文链接:Android如何配置init.rc中的开机启动进程(service)(有删改)

前言

首先我先来解释一下本文到底讲什么的。

用一句话来说:本文讲解的主要内容是,如何通过修改Android操作系统源码,来配置一个自定义的开机启动进程。

有些人也许会问,这有什么用?问的好,一项实用的技术必然要有用处才会有价值。

首先说明的是,如果你的工作或项目只是做一个应用程序app,那本文确实没有什么用处。但如果你的公司做的是Android系统开发,或者本身就是一家做硬件的公司,那本文可能就会有不少用处了;

举个例子:假如你们公司做了一台搭载Android的嵌入式设备,这台设备有某个特殊的传感器是一般手机没有的,传感器属于硬件,那想让硬件工作就必然有驱动程序,现在我们想让这个传感器在设备一开机的时候就立刻启动,那我们就需要知道如何配置一个Android的开机启动进程了。而本文正是讲这部分内容的。如果用最简单的一句话描述本文是讲什么的,那其实只要文章题目的一句话,但是其实涉及到的知识又多又杂,加上本人也处在底层开发的探索阶段,所以,涉及到的知识我只讲到我们能用到的深度为止,如果想深入学习,我会附上其他博主对这些知识深入分析的文章的链接。

需要做哪些准备工作?

首先,在硬件上,我希望你能有一块能搭载Android系统的嵌入式开发板,比如我用的是Friendly-arm的NanoPi M3,也许你会问,一台普通的Android手机行不行,这个说实话我没有试过,但是市面上的手机有很多权限是被厂商限制的,所以如果用手机来测试,可能会发生很多迷之问题,所以我建议还是使用一块开发板,不一定非要和我的型号一样,只要能跑Android就行。其次,在软件上,我希望你准备好了一份Android系统的源码,关于如何获取Android的源码我这里就不讲了,网上有很多文章讲这个,你可以从Google官方的渠道获取,如果你使用开发板,一般开发板的提供商也会提供定制的Android源码,那我们就直接从开发板的提供商的网站获取就行了。最后,我希望你有一台装有mac OS或者Linux操作系统的电脑,本文所开展的工作只支持以上两种系统,不支持Windows,其实我比较推荐unbuntu 14.04,这也是我使用的开发板的官方文档所推荐的,你当然也可以用Mac,但是说实话,我最开始开展工作时用的是搭载mac OS 10.12.02的Macbook pro 2016,各种发生迷之错误,其实按道理来说是可以解决的,但是由于做底层开发的人本来就不多,以及用Mac做底层开发的人就更少了,所以网上关于解决这些问题的学习资料以及文章少之又少,导致问题长时间无法解决,浪费时间,所以还是推荐使用ubuntu 14.04。

最后,阅读本文需要哪些知识?本文尽量讲的通俗且浅显易懂,你不需要有任何底层开发的前置知识,你只需要对Android系统有一个比较全面的认识就行,你说你写App的水平不高?这些都没关系,都不会影响你阅读这篇文章。但是我希望你能了解最起码的Linux命令,不用太复杂,最基本的就行,实在不行,Windows的cmd命令总用过吧,只要会用命令行工具进入硬盘下某个目录就行。

大体上有哪些知识点

大体上有哪些知识点,我画了以下一张图来描述:

这么一看,一目了然,我们需要将我们自己写的程序(示例中我用的是C语言)将它配置给init.rc这个文件;然后通过编写Android.mk来对它进行编译描述,什么是编译描述呢?我们可以这么理解,只要我们写的这个程序的所在目录下有Android.mk文件,它就可以和Android源码一样用make命令编译;然后我们要通过SEAndroid给我们的程序授权,否则程序会因为权限问题而无法执行;以上这些都是在Android源码中进行修改的;最后,我们将源码编译,刷机,运行,你亲自编译的Android操作系统就可以运行在你的开发板上,同时,你的C程序也可以跟随Android系统的启动而实现开机启动。

Android源码目录结构介绍

我相信读者手里已经拿到一份Android源码了,无论它是从哪里获得的(哪怕是同学同事拷贝给你的)。我的源码版本是5.1.1,源码版本对本文的影响不大,只要版本不是太老就行。我们先来对Android源码做个简要的介绍。打开源码的文件夹,我们会发现有很多目录,让我们眼花缭乱,确实,Android系统是一个非常复杂的软件,它必须面面俱到,所以这里面的源码覆盖了方方面面,想要全部把它看完是不可能的,我相信有不少人看过Linux内核源码,光是Linux内核的源码可能就能让一个人一生都无法穷尽,而Linux内核只是Android的最底层,可想而知Android的源码数量有多么庞大,所以我在这里只说几个我们最常用的目录以及本文会涉及到的目录。

不少人做Android都是做应用开发,做应用开发入门以后很多人都想要进阶,这时候就会买一些进阶的书,这些进阶的书很多都涉及Android源码分析,比如比较火的《Android开发艺术探索》,《Andoird源码设计模式解析与实战》等等,我们刚学Android的时候就知道,Android系统分为四层,我们开发的应用处于Application层,而Application层的下面一层是framework层,想做好应用开发,了解一下下层机制是必不可少的,所以我刚才说的源码分析的书籍所讲解的源码都在framework层,大家其实也能发现,这些书里所讲的源码都是java代码。那打开Android源码目录,我们能看到一个framework文件夹,所以framework层的源码就在这个文件夹下,你进去找找,可以找到不少应用开发时常用的API。

上面说的是闲话,现在我来介绍一个等一下会多次使用的一个目录——device,点开这个目录,我们会看到很多手机品牌的名字,比如htc啊,moto啊,samsung啊等等。这是什么意思呢?Android系统会运行在各种品牌的手机上,但是各种品牌的手机在硬件上都会有差异,因此,很多厂商都会对源码进行定制,以修改它的某些部分来配合自家硬件的特性,比如我有某个传感器,别的厂商没有,我的摄像头比较特殊,运行起来比较复杂,这些都属于硬件差异。由于我使用的Friendly-arm提供的源码,所以我可以在这个目录下看到一个friendly-arm的文件夹,里面是针对friendly-arm的开发板定制的一些代码,等会儿我们会多次访问这里。

还有一些等下我们会常用的目录,比如system,external,out等等,这些我们等会儿用到的时候再说。

如何在源码中添加自己的可执行文件

我们如果想要一个属于自己的开机启动进程,那首先就要一个我们自己编写的程序了,一般来说,在实际项目中这个程序就是我们想要开机启动的驱动,正如文章开头所说的那样,但是在我们这个例子中,我就不搞那么复杂了,写一个最简单的C语言程序,让它作为我们的开机启动进程。我给这个程序命名为loop,也就是循环的意思,代码如下:

#include <stdio.h>

int main() {
int i = 0;
for(i;i<100;i++)
{
sleep(180);
printf("I am a process\n");
} return 0;
}

怎么样,是不是非常简单,任何有任何语言编程基础的人都能看懂:我们设置了一个循环,每次在执行循环体的内容前,将主线程休眠180秒,一共循环100次,而循环的内容就是输出一条语句。

我为什么要这么做,主要是因为,如果这个程序一下子就执行完成,这个进程就死掉了,那我们就不能在命令行终端中看到这个进程,所以每次循环的时候我都会让它休眠180秒,这样算下来,这个进程理论上可以保活5小时,嗯,够长了,手速再慢的人也能在5小时内用命令行终端登入开发板,然后输入命令查看当前活动的进程了。

现在我们要把这个写好的.c文件放到Android源码目录下,进入Android源码目录,找到vendor文件夹,然后新建一个自己的文件夹,我给它起名叫“while-process”,我们就把它放在这个里面。那么如何才能让它和源码一起编译呢,这时就涉及到了一个知识点——Android.mk。

自定义Android.mk

这里简单介绍下如何编译Android源码,等下还会详细介绍。编译Android源码简单来说,就是做一大堆准备工作,然后在命令行工具中使用make命令进行编译,make命令会在源码目录中遍历所有目录,找到里面的Android.mk文件,然后根据Android.mk文件的内容编译当前目录下的代码。所以说我们可以理解Android.mk配置文件是一个编译指南。关于Android.mk文件所能扩展出来的知识点也是非常的多,这里我也只介绍一些我们最需要和最基本的东西。首先你需要随便找一个Android.mk文件然后用记事本之类的软件打开它。

首先,这行代码必须有:“LOCAL_PATH:= $(call my-dir)”,这行表示所要编译的内容在本Android.mk文件所在的目录下。

然后,Android.mk文件中可以指定多个编译模块,每个编译模块都是以include $(CLEAR_VARS)开始,以include $(BUILD_XXX)结束。

然后在这两代码中间我们找到LOCAL_SRC_FILES:= \xxx,后面的xxx就表示你要编译的源文件,比如我刚才写的程序叫loop,这里就写loop.c;我们还会看到LOCAL_MODULE:= xxx,这里表示编译的模块的名字,在这里我们把xxx换成loop。

由于我们这个程序非常简单,所以更多的属性在这里就不介绍了,感兴趣的可以去下面这篇文章去查阅:http://blog.chinaunix.net/uid-25838286-id-3204120.html

你如果不知道怎么创建Android.mk文件,最简单的方法就是随便找一个Android.mk文件拷贝过来,然后删掉些对你没用的语句,增加些对你有用的语句,然后改改某些语句的值或者变量名,就可以用了,如果编译失败,就按照提示进行修改,多试几次就可以了。

编译Android源码

由于讲解了Android.mk,所以我这里就先讲一下Android源码的编译,不过其实这是最后几步才要做的事情,但是先编译也是有好处的,因为第一次编译的时候时间会非常的长,你可以一边让它编译着,一边了解下面的知识点。当你后面的工作全部完成以后再次编译的时候,只要你不清空之前的编译结果,它就会进行增量编译,也就是只编译修改过的地方,这样只需要几分钟就能完成了。

Android源码怎么在ubuntu下编译,这个网上的文章有很多,我这里简要的说明一下。如果你使用的是开发板,请找到开发板对应的官方文档,然后严格按照文档中的教程一步一步来一般不会遇到什么问题。比如说我用的开发板的文档中给出的步骤大致如下:

1.搭建编译环境。这里需要一堆支持包,你可以先不用管这些支持包是什么,按照如下命令安装即可:

sudo apt-get install bison g++-multilib git gperf libxml2-utils make python-networkx zip
sudo apt-get install flex libncurses5-dev zlib1g-dev gawk minicom

2.使用命令行工具的cd命令进入Android源码目录,然后依次执行以下三个命令:

source build/envsetup.sh
lunch aosp_nanopi3-userdebug
make -j8

这三行命令第一行是设置编译环境,第二行是选择编译方案,也就是我刚才所说的选择厂商定制的方案,可以看到nanopi3是我的开发板的型号,所以就选择这个方案,第三行是开始编译,后面的-j8代表的是使用8线程同时编译,使用几个线程同时编译要看你的电脑配置,一般来说和你电脑的处理器有关。例如你的电脑装有四核处理器,每个核有两个线程,那你就可以使用j8,也就是4*2。选对同时编译的线程数量合适,编译的速度就能成倍增长。如果你是第一次编译源码,最慢的话时间可能长达一晚上之久,如果你之前成功编译过,那这次编译就是增量编译,系统只会编译你修改过的地方,很人性化,只需要几分钟。

编译过程中也许会遇到一些问题从而停止编译,比如你无权操作某些文件等等,这些都会在命令行工具中有英文提示,看着提示改就行了,这里的提示的英文也不复杂。建议在执行命令前先进入root用户,也就是先使用su命令。

编译成功以后,我们先进入Android源码目录,然后进入以下这个目录:out/target/product/nanopi3;还是那句话,根据你选择的编译方案,即你使用的开发板型号不同目录会有区别。进入这个目录下面以后我们能看到很多个img镜像文件。

3.现在我们把我们编译好的系统刷到我们的开发板上,在这之前先准备一张足够大的SD卡,然后用读卡器把SD卡连接到电脑上。

我使用的方式是使用刷机脚本来刷。首先执行以下两条命令:

git clone https://github.com/friendlyarm/sd-fuse_s5p6818.git
cd sd-fuse_s5p6818

意思就是时候用git下载这个刷机工具,然后进入这个刷机工具的目录。执行以下两条命令:

su
./fusing.sh /dev/sdx

这两条命令的意思是,首先进入root用户,如果你刚才已经进入root用户了,可以不用执行su这条命令,下面一行就是开始刷写,其中sdx是你的sd卡的设备名,请把sdx换成你的设备名,比如我的sd卡叫做sdb,就把sdx换成sdb。

刷写成功后,我们把卡插入开发板,然后用USB线把开发板和电脑连接,然后执行命令:

adb remount

adb shell

这时我们就已经使用命令行工具登入到开发板了,现在我们要找到我们写的loop程序。比如我把它放在了system/bin目录下,使用cd命令进入这个目录,然后使用ls命令就可以看到它存在,如果想要执行它,就使用./命令,loop这个程序就执行了,执行以后我们能看到每三分钟就可以在命令行终端中看到它输出一行语句,但是我们需要确保这个loop这个进程确实存在,那我们就需要用ps -Z命令查看它,但是当前这个命令行工具窗口正在运行程序,无法使用命令,所以我们就新建一个命令行终端窗口,像刚才一样使用adb shell命令登入开发板,然后使用命令ps -Z。就能看到它正在运行了。

编译Android源码这一块不是我们本讲的重点,这一块没有什么概念需要理解,就是一些操作步骤的流水账,我写的比较简单,中间难免有疏漏会造成一些小问题,如果读者出现了问题,可以根据具体问题去网上搜索或者给我留言,网上关于如何编译Android源码如何编译的文章是非常多的,不过我还是建议你参照你使用的开发板的官方文档,严格按照上面的步骤一步一步来,这样发生不必要的问题的概率会小一些。

init.rc介绍

我先来做个名词解释,什么是init.rc,那就要从什么是init说起。init是由Android的Linux内核启动的第一个第一个进程,这个进程非常特殊,它的PID永远是1,并且这个进程是不会死亡的,如果它死亡,内核就会崩溃。init进程启动后会fork出很多及其重要的系统进程,比如我们做应用开发的时候都耳熟能详的zygote进程,我们所有的应用程序的进程都由zygote拉起。解释完了init进程,我们再说init.rc,init.rc是一个规定init进程行为和动作的配置文件。init进程可以做哪些事情,都由它规定。关于init.rc的详细介绍,大家可以参考这篇文章:

http://qiangbo.space/2017-01-28/AndroidAnatomy_Init/?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io。

我们这里只对init.rc做一个简单的介绍,init.rc文件中只包含两种声明,on和service,我们可以把on称为行为,把service称为服务(这里的服务和应用开发中四大组件中的服务以及通过context.getSystemService()所得到的系统服务都不是一个东西,我一直不知道该怎么给它起名,姑且叫它init服务)。service声明了服务以及服务的各种行为。我们标题中说的开机启动进程就是这里的init服务。service只定义服务,但不能让服务做任何事情,如果你需要服务能够产生启动或者停止等相关动作,你就需要on,每个on下面的有各种命令,其中就包括很多对init服务的操作。这里要提到的是,我们要修改的init.rc文件在device/friendly-arm/nanopi3目录下,也就是厂商定制的版本,如果你使用的是别的开发板,可以去相应的目录找找。我们来看看init.rc中on和service两个典型的定义:

on early-init
# Set init and its forked children's oom_adj.
write /proc/1/oom_score_adj -1000 # Apply strict SELinux checking of PROT_EXEC on mmap/mprotect calls.
write /sys/fs/selinux/checkreqprot 0 # Set the security context for the init process.
# This should occur before anything else (e.g. ueventd) is started.
setcon u:r:init:s0 # Set the security context of /adb_keys if present.
restorecon /adb_keys start ueventd
# create mountpoints
mkdir /mnt 0775 root system ......
......
...... service ueventd /sbin/ueventd
class core
critical
seclabel u:r:ueventd:s0

#后面的一行是注释。

现在我们只重点关注几行,我们看到on下面有一行是“start ueventd”,而下面service的名字也是ueventd,这表明什么,我想大家都猜到了,那就是在early-init这个on启动了ueventd这个service。对,on就是这样启动sercice的,当然,on还有例如restart以及stop等等其它对service的操作,分别是让service停止并重新启动以及停止,不过on并不只是为service而生的,它还有许多其它的命令,在这里我就不详细介绍了,大家可以去网上搜索相关文章或者看这本书《构建嵌入式Android系统》。

我们看完了on再看看service,service我也只是简单介绍一下,service关键字声明了你要定义一个service,而ueventd就是这个service的名字,至于后面的目录则是这个service对应的可执行文件在系统中的位置。

注意:这里是说在系统中的位置,也就是在开发板运行你的Android源码编译的系统后的目录,而不是源码的目录,至于Android源码的编译,等下再讲。

接下来,我们可以看到service下面也有很多东西,这里我们不叫它们命令了,叫属性或者参数也许会比较好,其中比较重要的是class core,表示这个service属于core这个class,class我们不需要深入去管它,只要把它理解成一组service的集合就行,至于后面的属性,等下我们开始配置service的时候再说。

在init.rc中配置service

我们先来理一理,我们现在通过上文的讲解已经得到了什么。我们已经编写了一个自己的C语言程序loop,并且把它放在了Android的源码中,Android的源码也编译好了,如何把编译好的Android系统刷到开发板上并启动我们也已经学会了。

但是最重要的目的还没实现,那就是让loop这个可执行文件开机就可以被启动。而现在我们正要做的就是这件事。

首先打开Android源码目录,进入device/friendly-arm/nanopi3文件夹下,然后打开inti.rc文件,我们正式开始配置。

首先定义一个service,还记得service是怎么定义的吗,我这里定义的语句如下:service qya system/bin/loop。相信不难理解吧,我们定义了一个服务叫qya,它对应的程序是system/bin目录下的loop。这些上面都讲了。然后我在这个service下面增加几个配置属性:

service qya /system/bin/loop
class main
console
oneshot

其中console表示服务需要并运行在控制台,oneshot表示服务只运行一次,在退出时将服务设置为禁用。

你可以根据你的需要来增加这些属性,我写的两个属性并不一定都是必须的。《构建嵌入式Android系统》这本书的第六章对这些属性参数介绍的非常详细,如果网上找不到相应的文章可以拿这本书看看。

也许有人会发现,class main这是个什么东西,好像没讲,然而我并不是忘了,我在这里再详细讲讲。我之前讲过start命令是在on中启动serice,但是通览整个init.rc文件,我们会发现,直接使用start命令启动service的情况非常少,我之前也用这种方式试过几次,但都未能成功。所以我在仔细阅读和查询资料后发现,大多数inti进程fork出来的开机启动进程都是用另外一种方式来启动。我们来看看下面一个on行为的定义:

on property:vold.decrypt=trigger_restart_min_framework
class_start main

我在这里再简单说一下on,on分为两种,第一种一共有7个,它们是一定会随inti进程的启动而执行的,比如我们上面介绍init.rc的时候展示的early-init正是这7个on中的第一个。而第二种on则是在满足某些特定条件时才会启动的,比如我们这里的这个on就是第二种。我们看到它下面有一条class_start main命令,而我们的service下面第一个属性正是class main。所以可以理解了,这个class_start main命令是启动main下面所有service。通览init.rc文件,我们会发现属于main的service非常多,所以我们的service也就搭一趟便车,挤上main的队伍。

SELinux/SEAndroid

看起来我们最后一步已经做了,把我们的loop程序成功添加到init.rc的文件中。还没完,我们将会面临本文从开头到现在为止最大的挑战。我们的进程会被SEAndroid这个东西禁止掉,从而你无论怎么ps -Z你也不会看到它的存在。那么,SEAndroid到底是个什么东西?如果你想深入研究它,那可得好好花上一段时日了,我在这里给出两位大神的系列文章,专门分析什么是SEAndroid。这两位大神分别是罗升阳前辈和阿拉神农前辈,两人讲解SEAndroid的文章地址如下:

http://blog.csdn.net/luoshengyang/article/details/35392905

http://blog.csdn.net/innost/article/details/19299937/

其中,罗升阳老师的文章比较长,分析的比较理论,有助于你全面而细致的了解SEAndroid。而阿拉神农的文章则更加实用,让你快速能看懂这个东西,但是理论上并没有罗老师的深,大家可以各取所需。

我在这里越俎代庖的稍微讲一下什么是SEAndroid。老习惯,一句话:Android的系统安全机制。它来源于Linux系统中的SELinux。关于它们的历史我这里也都不讲了,总之SEAndroid是这样管理权限的:凡是任何想要运行的进程,想要做任何事情,都必须在安全策略配置文件中赋予权限,如果没有声明某个权限,那它就没有这个权限。

要理解其实很容易,做应用开发的时候,我们常常需要在AndroidManifest.xml文件中赋予应用权限。

比如,如果你的应用想要读写磁盘数据,那你就要写permission语句,赋予它读写磁盘的语句,如果你的应用想要访问网络,那你就需要写一条关于网络的permission语句,以准许它访问网络。SEAndroid也是类似的东西,你的进程想要干什么,你就得给它写一个.te文件,然后在文件中使用allow语句赋予它权限,不同的是SEAndroid的安全策略文件.te比AndroidManifest.xml可是难写多了。

我这里对编写.te文件和上面Android.mk一样,不做深入介绍。想详细了解如何编写.te文件,就去参考阿拉神农前辈的文章。我这里只做一个简单的介绍。

我们随便来找一条.te文件中的allow语句:allow netd proc:file write。这条语句是阿拉神农的文章中给出的示例,他在文章详细分析了这条语句每个词是干什么的,但我在这里也不多说,还是老惯例,一句话:允许netd进程对proc type的file进行写(write)操作。

我们这里把这条语句换一下:写成:allow a b:c d。那意思就是允许a进程,对c这个b类型的objec class进行d操作。不过这里的类型(type)是SEAndroid中的概念,很难三言两语说清楚,所以请看上面的文章,而file也不是我们通常理解的文件,而是一种object class,表示一种可以被操作的对象,比如,除了file以外还有Dir,Socket等等,由系统规定,这里也不展开了。

到这里我再废话两句,SEAndroid把操作系统中的东西分为两种,能发起动作的进程,以及只能被进程操作的文件,而allow语句则就是规定允许谁对谁做什么的。其实SEAndroid的知识远不止这些,还有例如MLS分级系统等等,不过这里就不讨论了,再提示一下,想深入了解的,看上面两篇文章吧!

好的,现在我们要开始真正动手了。首先进入Android源码目录,然后进入:external/sepolicy。还是和上面一样,我也不知道怎么创建一个.te文件,我们直接随便找个.te文件,不过说是随便,我们不能真的随便,我们也要想一想,怎么做成功率高,记得我说过我们自定义的service是属于main这个class的吧,那我们就找一个同样在main这个class下面的其他服务的.te文件来修改,因为在同一个class中的进程,所需的权限应该是相近的。

好,我们找到一个,然后把它的名字改成loop.te。注意啊,我们的service的名字叫qya,但是我们要执行的程序叫loop,SEAndroid是赋予进程权限而不是赋予service权限,所以我们的.te名字叫loop.te而不是qya.te。.te文件中除了allow语句以外还有一些其它语句,比如type等等,它们是什么意思,大家就自己去查一查吧,

我这里给出大家一个投机取巧的办法,如果你不想现在了解SEAndroid,那我就教你一个办法,比如我的.te文件是复制uncrypt的,那进到这个文件里面以后,就把文件中所有写uncrypt的地方全部改成loop,一般来说就可以了。如果编译的时候不通过,你就仔细看错误提示,我当时不通过的原因是有两行allow语句和domain.te文件中的neverallow语句相冲突,看字面意思也能明白,neverallow的意思是从不允许,如果这里允许了一件事情,那里又不允许这件事情,势必发生冲突,那我们只需要把我们的.te文件中的相关allow语句注释掉或者删掉就行了。

测试

现在我们该修改的东西终于全部改完了,那我们要做的就是重新编译,怎么编译上面已经介绍过了,由于这次只是增量编译,所以只需几分钟就OK,我们把它刷到开发板上,然后给开发板插上USB线和电脑连接,然后在命令行工具中执行两条命令:

adb remount
adb shell

现在我们的命令行工具已经登入到开发板上了,直接使用命令ps -Z,我们就能在窗口中看到我们的进程正在后台运行了,我们没有用./命令去执行loop,所以它就是被init进程fork出来的。命令行窗口的截图如下所示:

我们可以看到最下面的我们最熟悉的进程zygote,它的上面就是我们自定义的loop进程,自此,自定义int.rc开机启动service成功,我们大功告成。

总结

理一理本文所涉及到的知识点,有:编译Android源码,Android.mk文件的编写,修改Android源码,init.rc介绍,SEAndroid。

每个知识点都是为了我们能成功运行自定义service而讲解,所以讲解的深度其实都是不够的,我在文中不少地方都已经贴出了详细介绍每个知识点的博文的地址供大家后续学习。加上本文篇幅也算比较长的了,加上介绍的知识又多又杂,难免有疏漏之处,如果你按照本文的方法在配置过程中出现了失败的地方,可以根据具体问题上网搜索,只要坚持,一定可以解决。

Android底层的知识的特点就是多而杂,所以做底层开发最需要的就是耐心,祝所有走在底层开发的小伙伴都能学习顺利。

Android在init.rc中自定义开机启动进程(service)的更多相关文章

  1. Android如何配置init.rc中的开机启动进程(service)【转】

    本文转载自:http://blog.csdn.net/qq_28899635/article/details/56289063 开篇:为什么写这篇文章 先说下我自己的情况,我是个普通的大四学生,之前在 ...

  2. MTK(android init.rc) 写一个开机启动的服务

    在开机往往我们想要做一些初始化的操作,这时候可以使用init.rc文件来实现,当然书写一个开机启动的服务也需要规范的. 假设是C程序,则需要准备C程序的源码,在我的例程中是一个在开机完成(androi ...

  3. Android 重定向 init.rc中服务的输出

    在init.rc中运行的服务,由于系统启动的时候将标准输出重定向到了/dev/null, 所以服务中的打印信息都不可见. 但调试时可能需要看到其中的打印信息,因此就有了logwrapper这个工具:l ...

  4. /etc/rc.d/rc.local 自定义开机启动程序

    /etc/rc.d/rc.local 用于用户自定义开机启动程序,可以往里写开机要执行的命令或脚本,线上的配置如下: [root@localhost ~]$ cat /etc/rc.d/rc.loca ...

  5. init进程 && 解析Android启动脚本init.rc && 修改它使不启动android && init.rc中启动一个sh文件

    Android启动后,系统执行的第一个进程是一个名称为init 的可执行程序.提供了以下的功能:设备管理.解析启动脚本.执行基本的功能.启动各种服务.代码的路径:system/core/init,编译 ...

  6. Android: 启动init.rc 中service的权限问题【转】

    转自:http://www.linuxidc.com/Linux/2011-04/35014.htm 通过property_set("ctl.start", service_xx) ...

  7. linux开机自启动设置,自定义开机启动模版,nginx开机自启动服务

    /etc/init.d 目录,我们把shell脚本放在这个目录下来作为启动脚本 都是用来放服务脚本的,当Linux启动时,会寻找这些目录中的服务脚本,并根据脚本的run level确定不同的启动级别. ...

  8. linux自定义开机启动服务和chkconfig使用方法

    linux自定义开机启动服务和chkconfig使用方法 1. 服务概述在linux操作系统下,经常需要创建一些服务,这些服务被做成shell脚本,这些服务需要在系统启动的时候自动启动,关闭的时候自动 ...

  9. (转)linux自定义开机启动服务和chkconfig使用方法

    原文:https://www.cnblogs.com/jimeper/archive/2013/03/12/2955687.html linux自定义开机启动服务和chkconfig使用方法 1. 服 ...

  10. Android5.1 在init.rc 中添加自己的服务【转】

    本文转载自:http://blog.csdn.net/VOlsenBerg/article/details/71085610 我有一个需求就是在Android系统开机的时候把一个配置文件放到Andro ...

随机推荐

  1. 如何将data中字符传的换行正常显示

    后端传来的字符串有换行符: 直接输出的效果: 解决方法demo: <p class="" v-html="text"></p> js: ...

  2. 应急响应--linux入侵排查

  3. Sermant在异地多活场景下的实践

    本文分享自华为云社区<Sermant在异地多活场景下的实践>,作者:华为云开源. Sermant社区在1.3.0和1.4.0版本相继推出了消息队列禁止消费插件和数据库禁写插件,分别用于解决 ...

  4. 在IDEA中配置GitHub

    目录 在IDEA中配置GitHub 安装GitHub插件 账号授权 方法一:点击Add Account... 添加账号 方法二:使用token登录 共享到GitHub 查看文件变更列表 add文件 移 ...

  5. Java 工程文件的 .gitignore

    以下是一个排查 Java 工程文件的 .gitignore 文件示例: # Java 编译器生成的文件 *.class # Maven 生成的文件夹 target/ # Eclipse 生成的文件夹 ...

  6. AIRIOT物联网低代码平台如何配置欧姆龙omron驱动?

    数据采集与控制是物联网的核心能力之一,AIRIOT物联网低代码平台提供了丰富的驱动,兼容了市面上95%以上的传感器.控制器及数据采集设备等,并且在持续增加中,能够快速.便捷地实现数据采集与控制功能. ...

  7. 生物医学顶刊论文(JBHI-2024):TransFOL:药物相互作用中复杂关系推理的逻辑查询模型

    (2024.5.17)JBHI-TransFOL:药物相互作用中复杂关系推理的逻辑查询模型 论文题目:TransFOL: A Logical Query Model for Complex Relat ...

  8. 使用tc命令模拟linux网络延迟环境

    tc(Traffic Control)是 Linux 中用于流量控制和网络模拟的强大工具.你可以使用它来模拟网络延迟.带宽限制.数据包丢失等. 以下是一个使用 tc 模拟网络延迟的基本步骤: 1.查看 ...

  9. springcloud整合geteway网关服务

    geteway网关 1. 什么是 API 网关(API Gateway)分布式服务架构.微服务架构与 API 网关在微服务架构里,服务的粒度被进一步细分,各个业务服务可以被独立的设计.开发.测试.部署 ...

  10. 【winform】 WeifenLuo.WinFormsUI.Docking.dll 组件学习

    这个组件是用来 对窗体的布局用的,可搭建一个管理系统的ui框架. 使用例子:https://blog.csdn.net/zzzzzzzert/article/details/80791554