Android -Recovery
时间:2023-01-06 12:30:00
Recovery简介Android利用Recovery恢复出厂设置的模式,OTA升级,patch升级及firmware升级。
升级一般通过运行升级包中的升级META-INF/com/google/android/update-script脚本是自定义升级,脚本是一组recovery可识别系统UI控制、文件系统操作命令等write_raw_image(写FLASH分区),copy_dir(复制目录)。这个包通常下载到SDCARD和CACHE分区下。如果您对包的内容感兴趣,可以从http://forum.xda-developers.com/showthread.php?t=442480下载JF看升级包。
升级还涉及数字签名、签名方式和普通包JAR文件签名不错。公钥将被硬编译成recovery,编译时生成:out/target/product/XX/obj/PACKAGING/ota_keys_inc_intermediates/keys.inc
G三种启动启动模式MAGIC KEY:
camera power:bootloader模式,ADP可用于内部fastboot模式
home power:recovery模式
正常启动
Bootloader正常启动有三种方三种方式BCB(Bootloader Control Block, 下节介绍)中的command分类:
command == 'boot-recovery' → 启动recovery.img。recovery模式
command == 'update-radio/hboot' → 更新firmware(bootloader)
其他 → 启动boot.img
Recovery其他涉及的系统和文件
CACHE分区文件
Recovery 工具通过NAND cache分区上的三个文件和主系统打交道。主系统(包括恢复出厂设置和OTA可以写入升级)recovery读出所需的命令recovery过程中的LOG和intent。
/cache/recovery/command: 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
/cache/recovery/log:recovery过程日志,由主系统读出
/cache/recovery/intent:recovery输出的intent
MISC分区内容Bootloader Control Block (BCB) 存放recovery bootloader message。结构如下:
struct bootloader_message {
char command[32];
char status[32]; // 未知用途
char recovery[1024];
};
command有以下两个值
“boot-recovery”:标示recovery正在进行,或指示bootloader应该进入recovery mode
“update-hboot/radio”:指示bootloader更新firmware
recovery内容
“recovery\n
<recovery command>\n
<recovery command>”
其中recovery command为CACHE:/recovery/command命令
两种Recovery Case
FACTORY RESET(恢复出厂设置)
用户选择恢复出厂设置
设置系统将"--wipe_data"命令写入/cache/recovery/command
系统重启并进入recover模式(/sbin/recovery)
get_args() 将 "boot-recovery"和"--wipe_data"写入BCB
erase_root() 格式化(擦除)DATA分区
erase_root() 格式化(擦除)CACHE分区
finish_recovery() 擦除BCB
重启系统
OTA INSTALL(OTA升级)
下载升级系统 OTA包到/cache/some-filename.zip
写入升级系统recovery命令"--update_package=CACHE:some-filename.zip"
重启并进入recovery模式
get_args() 将"boot-recovery" 和 "--update_package=..." 写入BCB
install_package() 作升级
finish_recovery() 擦除 BCB
** 若安装包失败 ** prompt_and_wait() 等待用户操作,选择ALT S或ALT W 出厂设置升级或恢复
main() 调用 maybe_install_firmware_update()
如果包里有hboot/radio的firmware继续,否则返回
将 "boot-recovery" 和 "--wipe_cache" 写入BCB
将 firmware image写入cache分区
将 "update-radio/hboot" 和 "--wipe_cache" 写入BCB
重启系统
bootloader自身更新firmware
bootloader 将 "boot-recovery" 写入BCB
erase_root() 擦除CACHE分区
清除 BCB
main() 调用 reboot() 重启系统
Recovery模式流程
/init → init.rc → /sbin/recovery →
main():recovery.c
ui_init():ui.c [UI initialize]
gr_init():minui/graphics.c [set tty0 to graphic mode, open fb0]
ev_init():minui/events.c [open /dev/input/event*]
res_create_surface:minui/resource.c [create surfaces for all bitmaps used later, include icons, bmps]
create 2 threads: progress/input_thread [create progress show and input event handler thread]
get_args():recovery.c
get_bootloader_message():bootloader.c [read mtdblock0(misc partition) 2nd page for commandline]
check if nand misc partition has boot message. If yes, fill argc/argv.
If no, get arguments from /cache/recovery/command, and fill argc/argv.
set_bootloader_message():bootloader.c [set bootloader message back to mtdblock0]
Parser argv[] filled above
register_update_commands():commands.c [ register all commands with name and hook function ]
registerCommand():commands.c
Register command with name, hook, type, cookie.
Commands, e.g: assert, delete, copy_dir, symlink, write_raw_image.
registerFunction():commands.c
Register function with name, hook, cookie.
Function, e.g: get_mark, matches, getprop, file_contains
install_package():
translate_root_path():roots.c [ "SYSTEM:lib" and turns it into a string like "/system/lib", translate the updater.zip path ]
mzOpenZipArchive():zip.c [ open updater.zip file (uncompass) ]
handle_update_package():install.c
verify_jar_signature():verifier.c [ verify signature with keys.inc key; verify manifest and zip package archive ]
verifySignature() [ verify the signature file: CERT.sf/rsa. ]
digestEntry():verifier.c [ get SHA-1 digest of CERT.sf file ]
RSA_verify(public key:keys.inc, signature:CERT.rsa, CERT.sf's digest):libc/rsa.c [ Verify a 2048 bit RSA PKCS1.5 signature against an expected SHA-1 hash. Use public key to decrypt the CERT.rsa to get original SHA digest, then compare to digest of CERT.sf ]
verifyManifest() [ Get manifest SHA1-Digest from CERT.sf. Then do digest to MANIFEST.MF. Compare them ]
verifyArchive() [ verify all the files in update.zip with digest listed in MANIFEST.MF ]
find_update_script():install.c [ find META-INF/com/google/android/update-script updater script ]
handle_update_script():install.c [ read cmds from script file, and do parser, exec ]
parseAmendScript():amend.c [ call yyparse() to parse to command ]
exeCommandList():install.c
exeCommand():execute.c [ call command hook function ]
erase DATA/CACHE partition
prompt_and_wait():recovery.c [ wait for user input: 1) reboot 2) update.zip 3) wipe data ]
ui_key_xxx get ALT+x keys
1) do nothing
2) install_package('SDCARD:update.zip')
3) erase_root() → format_root_device() DATA/CACHE
may_install_firmware_update():firmware.c [ remember_firmware_update() is called by write_hboot/radio_image command, it stores the bootloader image to CACHE partition, and write update-hboot/radio command to MISC partition for bootloader message to let bootloader update itself after reboot ]
set_bootloader_message()
write_update_for_bootloader():bootloader.c [ write firmware image into CACHE partition with update_header, busyimage and failimage ]
finish_recovery():recovery.c [ clear the recovery command and prepare to boot a (hopefully working) system, copy our log file to cache as well (for the system to read), and record any intent we were asked to communicate back to the system. ]
reboot()
本讲主要概述Linux设备驱动框架、驱动程序的配置文件及常用的加载驱动程序的方法;并且介绍Red Hat Linux安装程序是如何加载驱动的,通过了解这个过程, 我们可以自己将驱动程序放到引导盘中;安装完系统后,使用kudzu自动配置硬件程序。
Linux设备驱动概述
1. 内核和驱动模块
操作系统是通过各种驱动程序来驾驭硬件设备,它为用户屏蔽了各种各样的设备,驱动硬件是操作系统最基本的功能,并且提供统一的操作方式。正如我们查看屏幕上的文档时,不用去管到底使用nVIDIA芯片,还是ATI芯片的显示卡,只需知道输入命令后,需要的文字就显示在屏幕上。硬件驱动程序是操作系统最基本的组成部分,在Linux内核源程序中也占有较高的比例。
Linux内核中采用可加载的模块化设计(LKMs ,Loadable Kernel Modules),一般情况下编译的Linux内核是支持可插入式模块的,也就是将最基本的核心代码编译在内核中,其它的代码可以选择是在内核中,或者编译为内核的模块文件。
如果需要某种功能,比如需要访问一个NTFS分区,就加载相应的NTFS模块。这种设计可以使内核文件不至于太大,但是又可以支持很多的功能,必要时动态地加载。这是一种跟微内核设计不太一样,但却是切实可行的内核设计方案。
我们常见的驱动程序就是作为内核模块动态加载的,比如声卡驱动和网卡驱动等,而Linux最基础的驱动,如CPU、PCI总线、TCP/IP协议、APM(高级电源管理)、VFS等驱动程序则编译在内核文件中。有时也把内核模块就叫做驱动程序,只不过驱动的内容不一定是硬件罢了,比如ext3文件系统的驱动。
理解这一点很重要。因此,加载驱动时就是加载内核模块。下面来看一下有关模块的命令,在加载驱动程序要用到它们:lsmod、modprob、insmod、rmmod、modinfo。
lsmod 列出当前系统中加载的模块,例如:
#lsmod (与cat /proc/modules 得出的内容是一致的) Module Size Used by Not tainted radeon 115364 1 agpgart 56664 3 nls_iso8859-1 3516 1 (autoclean) loop 12120 3 (autoclean) smbfs 44528 2 (autoclean) parport_pc 19076 1 (autoclean) lp 9028 0 (autoclean) parport 37088 1 (autoclean) [parport_pc lp] autofs 13364 0 (autoclean) (unused) ds 8704 2 yenta_socket 13760 2 pcmcia_core 57184 0 [ds yenta_socket] tg3 55112 1 sg 36940 0 (autoclean) sr_mod 18104 0 (autoclean) microcode 4724 0 (autoclean) ide-scsi 12208 0 scsi_mod 108968 3 [sg sr_mod ide-scsi] ide-cd 35680 0 cdrom 33696 0 [sr_mod ide-cd] nls_cp936 124988 1 (autoclean) nls_cp437 5148 1 (autoclean) vfat 13004 1 (autoclean) fat 38872 0 (autoclean) [vfat] keybdev 2976 0 (unused) mousedev 5524 1 hid 22212 0 (unused) input 5888 0 [keybdev mousedev hid] ehci-hcd 20104 0 (unused) usb-uhci 26412 0 (unused) usbcore 79392 1 [hid ehci-hcd usb-uhci] ext3 91592 2 jbd 52336 2 [ext3] |
上面显示了当前系统中加载的模块,左边数第一列是模块名,第二列是该模块大小,第三列则是该模块使用的数量。
如果后面为unused,则表示该模块当前没在使用。如果后面有autoclean,则该模块可以被rmmod -a命令自动清洗。rmmod -a命令会将目前有autoclean的模块卸载,如果这时候某个模块未被使用,则将该模块标记为autoclean。如果在行尾的[ ]括号内有模块名称,则括号内的模块就依赖于该模块。例如:
cdrom 34144 0 [sr_mod ide-cd] |
其中ide-cd及sr_mod模块就依赖于cdrom模块。
系统的模块文件保存在/lib/modules/2.4.XXX/kerne目录中,根据分类分别在fs、net等子目录中,他们的互相依存关系则保存在/lib/modules/2.4.XXX/modules.dep 文件中。
需要注意,该文件不仅写入了模块的依存关系,同时内核查找模块也是在这个文件中,使用modprobe命令,可以智能插入模块,它可以根据模块间依存关系,以及/etc/modules.conf文件中的内容智能插入模块。比如希望加载ide的光驱驱动,则可运行下面命令:
# modprobe ide-cd |
此时会发现,cdrom模块也会自动插入。
insmod也是插入模块的命令,但是它不会自动解决依存关系,所以一般加载内核模块时使用的命令为modprobe。
rmmod可以删除模块,但是它只可以删除没有使用的模块。
Modinfo用来查看模块信息,如modinfo -d cdrom,在Red Hat Linux系统中,模块的相关命令在modutils的RPM包中。
2.设备文件
当我们加载了设备驱动模块后,应该怎样访问这些设备呢?Linux是一种类Unix系统,Unix的一个基本特点是“一切皆为文件”,它抽象了设备的处理,将所有的硬件设备都像普通文件一样看待,也就是说硬件可以跟普通文件一样来打开、关闭和读写。
系统中的设备都用一个设备特殊文件代表,叫做设备文件,设备文件又分为Block(块)型设备文件、Character(字符)型设备文件和Socket(网络插件)型设备文件。Block设备文件常常指定哪些需要以块(如512字节)的方式写入的设备,比如IDE硬盘、SCSI硬盘、光驱等。
而Character型设备文件常指定直接读写,没有缓冲区的设备,比如并口、虚拟控制台等。Socket(网络插件)型设备文件指定的是网络设备访问的BSD socket 接口。
#ls -l /dev/hda /dev/video0 /dev/log brw-rw---- 1 root disk 3, 0 Sep 15 2003 /dev/hda srw-rw-rw- 1 root root 0 Jun 3 16:55 /dev/log crw------- 1 root root 81, 0 Sep 15 2003 /dev/video0 |
上面显示的是三种设备文件,注意它们最前面的字符,Block型设备为b,Character型设备为c,Socket设备为s。
由此可以看出,设备文件都放在/dev目录下,比如硬盘就是用/dev/hd*来表示,/dev/hda表示第一个IDE接口的主设备,/dev/hda1表示第一个硬盘上的第一个分区;而/dev/hdc 表示第二个IDE接口的主设备。可以使用下面命令:
#dd if=/dev/hda of=/root/a.img bs=446 count=1 |
把第一个硬盘上前446个字节的MBR信息导入到a.img文件中。
对于Block和Character型设备,使用主(Major)和辅(minor)设备编号来描述设备。主设备编号来表示某种驱动程序,同一个设备驱动程序模块所控制的所有设备都有一个共同的主设备编号,而辅设备编号用于区分该控制器下不同的设备,比如,/dev/hda1(block 3/1)、/dev/hda2(block 3/2 )和/dev/hda3( block3/3 )都代表着同一块硬盘的三个分区,他们的主设备号都是3,辅设备号分别为1、2、3。 这些设备特殊文件用mknod命令来创建:
# mknod harddisk b 3 0 |
我们就在当前位置创建出一个与 /dev/hda一样的、可以访问第一个IDE设备主硬盘的文件,文件名叫做harddisk。
使用下面命令可以查看设备编号:
#file /dev/hda /dev/hda: block special (3/0) |
其中Block代表/dev/hda是系统的Block型(块型)设备文件,它的主设备编号为3,辅设备编号为0。
#ls -l /dev/hda /dev/hdb brw-rw---- 1 root disk 3, 0 Sep 15 2003 /dev/hda brw-rw---- 1 root disk 3, 64 Sep 15 2003 /dev/hdb |
使用ls -l也可以看到设备编号,/dev/hdb代表第一个IDE接口的从设备(Slave)也是Block设备,编号为(3/64),还有另外一种设备文件是/dev/tty*。使用如下命令:
#echo "hello tty1" > /dev/tty1 |
将字符串“hello tty1”输出到/dev/tty1代表的第一个虚拟控制台上,此时按“Alt + F1”可以看到该字符出现在屏幕上,这个特殊的文件就代表着我们的第一虚拟控制台。
#file /dev/tty1 /dev/tty1: character special (4/1) |
由上可以看到,它的类型为Character 型(字符型)设备文件,主设备号为4,辅设备号为1。同样,/dev/tty2代表着第二个虚拟控制台,是Character设备,编号为 (4/2)。
当将/dev/cdrom加载到/mnt/cdrom中时,只要访问/mnt/cdrom系统就会自动引入到/dev/cdrom对应的驱动程序中,访问实际的数据。
有关设备文件的编号可以看内核文档/usr/src/linux-2.*/Documentation/devices.txt 文件(在Kernel的源文件解包后的Documentation目录中),其中详细叙述了各种设备文件编号的意义。
3.使用/proc目录中的文件监视驱动程序的状态
通过设备文件怎样访问到相应的驱动程序呢?它们中间有一个桥梁,那就是proc文件系统,它一般会被加载到/proc目录。访问设备文件时,操作系统通常会通过查找/proc目录下的值,确定由哪些驱动模块来完成任务。如果proc文件系统没有加载,访问设备文件时就会出现错误。
Linux系统中proc文件系统是内核虚拟的文件系统,其中所有的文件都是内核中虚拟出来的,各种文件实际上是当前内核在内存中的参数。它就像是专门为访问内核而打开的一扇门,比如访问/proc/cpuinfo文件,实际上就是访问目前的CPU的参数,每一次系统启动时系统都会通过/etc/fstab中设置的信息自动将proc文件系统加载到/proc目录下:
# grep proc /etc/fstab none /proc proc defaults 0 0 |
此外,也可以通过mount命令手动加载:
# mount -t proc none /proc |
通过/proc目录下的文件可以访问或更改内核参数,可以通过/proc目录查询驱动程序的信息。下面先让我们看一下/proc目录中的信息:
# ls /proc 1 4725 5032 5100 5248 5292 crypto kcore partitions 14 4794 5044 5110 5250 5293 devices kmsg pci 2 4810 5075 5122 5252 5295 dma ksyms self 3 4820 5079 5132 5254 5345 driver loadavg slabinfo 4 4831 5080 5151 5256 6 execdomains locks stat 4316 4910 5081 5160 5258 7 fb lvm swaps 4317 4912 5082 5170 5262 70 filesystems mdstat sys 4318 4924 5083 5180 5271 8 fs meminfo sysrq-trigger 4319 4950 5084 5189 5287 9 ide misc sysvipc 4620 4963 5085 5232 5288 apm interrupts modules tty 4676 5 5086 5242 5289 bus iomem mounts uptime 4680 5005 5087 5244 5290 cmdline ioports mtrr version 4706 5018 5088 5246 5291 cpuinfo irq net |
需要知道的是,这些文件都是实时产生的虚拟文件,访问它们就是访问内存中真实的数据。这些数据是实时变化产生的,可以通过以下命令来查看文件的具体值:
# cat /proc/interrupts CPU0 0: 50662 XT-PIC timer 1: 3 XT-PIC keyboard 2: 0 XT-PIC cascade 5: 618 XT-PIC ehci-hcd, eth1 8: 1 XT-PIC rtc 9: 0 XT-PIC usb-uhci, usb-uhci 11: 50 XT-PIC usb-uhci, eth0 12: 16 XT-PIC PS/2 Mouse 14: 8009 XT-PIC ide0 15: 0 XT-PIC ide1 NMI: 0 ERR: 0 |
其它文件的含意见表1所示。
/proc/sys目录下的文件一般可以直接更改,相当于直接更改内核的运行参数,例如:
# echo 1 > /proc/sys/net/ipv4/ip_forward |
上面代码可以将内核中的数据包转发功能打开。
另外,Linux系统中提供一些命令来查询系统的状态,如free可以查看目前的内存使用情况,ide_info可以查看ide设备的信息,例如: #ide_info /dev/had。类似的命令还有scsi_info,可以查看SCSI设备的信息。这些命令一般也是查询/proc目录下的文件,并返回结果。
系统初始化过程驱动程序的安装
在Linux安装过程中,系统上的硬件会被检测,基于检测到的结果安装程序会决定哪些模块需要在引导时被载入。Red Hat的安装程序为anaconda,它提供了自动检测硬件,并且安装的机制。
但是,如果计算机内的某些硬件没有默认的驱动程序,比如一块SCSI卡,我们可以在启动后的boot提示符下,输入“linux dd”,在加载完内核后,系统会自动提示插入驱动盘,这时就有机会把该硬件的Linux驱动程序装入。
如果在安装系统时,某种硬件总是因为中断冲突(ISA总线的设备较常见,比如一块ISA网卡)没法正常驱动,或者是缺少驱动程序,那么可以在boot提示符下输入“linux noprobe”。在这种模式下,安装程序不会自动配置找到的硬件,可以自己来选择现有驱动,配置驱动程序的参数,或者选择用光盘或软盘加载驱动程序。
定制引导盘
系统启动时是如何加载驱动的?下面让我们来看一下Red Hat的安装光盘是怎样引导的。当Linux安装光盘启动时,加载位于光盘上isolinux中的内核文件vmlinuz,内核运行完毕后,又将initrd.img的虚拟文件系统加载到内存中。这个文件为ext2文件系统的镜像,经过gzip压缩,可以通过以下步骤查看该镜像中的内容:
# mount /mnt/cdrom # mkdir /mnt/imgdir # gunzip < /mnt/cdrom/isolinux/initrd.img > /ext2img # mount -t ext2 -o loop /ext2img /mnt/imgdir # cd /mnt/imgdir # ls -F bin@ dev/ etc/ linuxrc@ lost+found/ modules/ proc/ sbin/ tmp/ var/ # cd modules # ls module-info modules.cgz modules.dep modules.pcimap pcitable |
其中modules.dep为模块的注册文件,同时有各种模块的依存关系。modules.cgz为cpio的打包文件,实际的各种驱动模块就在该文件中。我们可以通过以下命令解包:
# cpio -idmv < modules.cgz |
由此可以看到,解包出来的目录2.4.21-4XXX。进入该目录下的i386目录,就可以看到当前启动盘中支持的所以驱动程序:
# ls 3c59x.o 3w-xxxx.o 8139cp.o 8139too.o 8390.o aacraid.o acenic.o aic79xx.o …… |
若希望在系统中加入需要的驱动程序,可以相应地修改这些文件,比如在modules.dep中加入该模块的名字和依存关系,将编译好的驱动模块文件加入modules.cgz中,这样就可以制定自己的安装光盘。
硬盘上的系统启动过程与上面类似,但是initrd的镜像文件要更简单些,一般在initrd-2.4.XXX.img的虚拟文件系统中,只会在/lib目录下包含ext3.o jbd.o lvm-mod.o等少数文件,用来驱动硬盘上的ext3的文件系统。加载文件系统后,就可以使用/lib/modules/2.4.XXX/下的modules.dep文件及Kernel目录中的各种驱动文件。
元器件数据手册、IC替代型号,打造电子元器件IC百科大全!
相关文章
动力学技术KTU1121 USB Type-C 端口保护器的介绍、特性、及应用
Sensata PTE7300密封数字压力传感器的介绍、特性、及应用
PANJIT PBHV8110DA/PBHV9110DA低Vce(sat)晶体管的介绍、特性、及应用
ams OSRAM OSLON 黑色平板X LED器件的介绍、特性、及应用
Cree LED CLQ6A三合一贴片LED的介绍、特性、及应用
Cree LED CLQ6B 4-in-1 RGBW贴片LED的介绍、特性、及应用
NDK NX1210AB表面贴装晶体的介绍、特性、及应用
伊顿ACE2V3225共模芯片电感器的介绍、特性、及应用
意法半导体X040灵敏型栅可控硅和Z040可控硅的介绍、特性、及应用
ABLIC S-82Y1B电池保护芯片的介绍、特性、及应用
#!/bin/bash |
adb-eclair2.2 shell am start -a com.android.contacts.action.LIST_DEFAULT |
echo "press menu"|telnet 127.0.0.1 1080 |
for i in `seq 0 10` |
do |
echo "sleep 1000"|telnet 127.0.0.1 1080 |
echo "press menu"|telnet 127.0.0.1 1080 |
done |
monkey --port 1080 -v -v |
netstat -an | grep 1080 |
sudo adb-eclair2.2 forward tcp:1080 tcp:1080 |
关于如何添加自己的库或者别的文件进入apk |
参见development/pdk/ndk下的内容 |
简单的说把编译好的apk解开 |
unzip testapp.apk -d temp/ |
建立目录 |
mkdir temp/lib/ |
mkdir temp/lib/armeabi |
然后把编译好的库放进armeabi目录下 (也许以后会有x86。。。) |
至于其他文件也可以类似的处理 |
然后 apkbuilder testapp.apk -v -rf temp/ 即可 |
最后,本帖对于山寨厂这样自己整系统可以随意乱放native库或者执行程序的例外。。。 |
安装动态库到 /system/lib/ 目录 |
在工程的 Android.mk 文件中加如下内容 |
include $(CLEAR_VARS) |
LOCAL_PREBUILT_LIBS := gears.so |
include $(BUILD_MULTI_PREBUILT) |
|
|
|
$(combo_target)CC := $($(combo_target)TOOLS_PREFIX)gcc$(HOST_EXECUTABLE_SUFFIX) |
$(combo_target)CXX := $($(combo_target)TOOLS_PREFIX)g++$(HOST_EXECUTABLE_SUFFIX) |
$(combo_target)AR := $($(combo_target)TOOLS_PREFIX)ar$(HOST_EXECUTABLE_SUFFIX) |
$(combo_target)OBJCOPY := $($(combo_target)TOOLS_PREFIX)objcopy$(HOST_EXECUTABLE_SUFFIX) |
$(combo_target)LD := $($(combo_target)TOOLS_PREFIX)ld$(HOST_EXECUTABLE_SUFFIX) |
允许连接的客户端 |
echo 'ALLOWEDNETS="127.0.0.1 172.20.120.0/24"' >> /etc/default/distcc |
连接以下机器进行编译 |
export DISTCC_HOSTS='172.20.120.88 172.20.120.67 172.20.120.65' |
最佳答案-网友投票选出 |
1.深圳市南山区蛇口星艺幼儿园 |
0755-26670733 |
南山区蛇口湾夏路42号 |
2.深圳蛇口北大附中南海玫瑰幼儿园 |
地址:深圳市南山区蛇口望海路南海玫瑰园 二期内 |
电话0755——26813720 |
——26812946 |
3,这里是一个blog上的南山幼儿园名单 |
http://xiaochongzhi.bb.iyaya.com/biji-1339736.html |
http://sz3322.com/html/96.html |