




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、Android本質(zhì)上就是一個(gè)基于Linux核的操作系統(tǒng)。與Ubuntu Linux、Fedora Linux類似。只是Android在應(yīng)用層專門為移動設(shè)備添加了一些特有的支持。既然Android是Linux核的系統(tǒng),那么基本的啟動過程也應(yīng)符合Linux的規(guī)則。如果研究過其他Linux系統(tǒng)應(yīng)該了解,一個(gè)完整的Linux系統(tǒng)首先會將一個(gè)Linux核裝載到存,也就是編譯Linux核源代碼生成的bzImage文件,對于為Android優(yōu)化的Linux核源代碼會生成zImage文件。該文件就是Linux核的二進(jìn)制版本。由于zImage在核空間運(yùn)行,而我們平常使用的軟件都是在應(yīng)用空間運(yùn)行(關(guān)于核空間和應(yīng)用
2、空間的詳細(xì)描述,可以參考Android深度探索(卷1):HAL與驅(qū)動開發(fā)一書的容,在后續(xù)的各卷中將會對Android的整體體系進(jìn)行全方位的剖析)。核空間和應(yīng)用空間是不能直接通過存地址級別訪問的,所以就需要建立某種通訊機(jī)制。 目前Linux有很多通訊機(jī)制可以在用戶空間和核空間之間交互,例如設(shè)備驅(qū)動文件(位于/dev目錄中)、存文件(/proc、/sys目錄等)。了解Linux的同學(xué)都應(yīng)該知道Linux的重要特征之一就是一切都是以文件的形式存在的,例如,一個(gè)設(shè)備通常與一個(gè)或多個(gè)設(shè)備文件對應(yīng)。這些與核空間交互的文件都在用戶空間,所以在Linux核裝載完
3、,需要首先建立這些文件所在的目錄。而完成這些工作的程序就是本文要介紹的init。Init是一個(gè)命令行程序。其主要工作之一就是建立這些與核空間交互的文件所在的目錄。當(dāng)Linux核加載完后,要做的第一件事就是調(diào)用init程序,也就是說,init是用戶空間執(zhí)行的第一個(gè)程序。在分析init的核心代碼之前,還需要初步了解init除了建立一些目錄外,還做了如下的工作1. 初始化屬性2. 處理配置文件的命令(主要是init.rc文件),包括處理各種Action。3. 性能分析(使用bootchart工具)。4. 無限循環(huán)執(zhí)行command(啟動其他的進(jìn)程)。
4、盡管init完成的工作不算很多,不過代碼還是非常復(fù)雜的。Init程序并不是由一個(gè)源代碼文件組成的,而是由一組源代碼文件的目標(biāo)文件而成的。這些文件位于如下的目錄。<Android源代碼本目錄>/system/core/init 其中init.c是init的主文件,現(xiàn)在打開該文件,看看其中的容。由于init是命令行程序,所以分析init.c首先應(yīng)從main函數(shù)開始,現(xiàn)在好到main函數(shù),代碼如下:int main(int argc, char *argv) int fd_count = 0; struct pollfd ufds4; ch
5、ar *tmpdev; char* debuggable; char tmp32; int property_set_fd_init = 0; int signal_fd_init = 0; int keychord_fd_init = 0; bool is_charger = false; if (!strcmp(basename(argv0), "ueventd") return ueventd_main(argc, argv); if (!strcmp(basename(argv0), "watchdogd") return watchdogd_m
6、ain(argc, argv); /* clear the umask */ umask(0); / 下面的代碼開始建立各種用戶空間的目錄,如/dev、/proc、/sys等 mkdir("/dev", 0755); mkdir("/proc", 0755); mkdir("/sys", 0755); mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"); mkdir("/dev/pts&
7、quot;, 0755); mkdir("/dev/socket", 0755); mount("devpts", "/dev/pts", "devpts", 0, NULL); mount("proc", "/proc", "proc", 0, NULL); mount("sysfs", "/sys", "sysfs", 0, NULL); /* 檢測/dev/.booting文件是否可讀寫和創(chuàng)
8、建*/ close(open("/dev/.booting", O_WRONLY | O_CREAT, 0000); open_devnull_stdio(); klog_init(); / 初始化屬性 property_init(); get_hardware_name(hardware, &revision); / 處理核命令行 process_kernel_cmdline(); is_charger = !strcmp(bootmode, "charger"); INFO("property initn"); if (!
9、is_charger) property_load_boot_defaults(); INFO("reading config filen"); / 分析/init.rc文件的容 init_parse_config_file("/init.rc"); / 執(zhí)行初始化文件中的動作 action_for_each_trigger("init", action_add_queue_tail); / 在charger模式下略過mount文件系統(tǒng)的工作 if (!is_charger) action_for_each_trigger("
10、;early-fs", action_add_queue_tail); action_for_each_trigger("fs", action_add_queue_tail); action_for_each_trigger("post-fs", action_add_queue_tail); action_for_each_trigger("post-fs-data", action_add_queue_tail); queue_builtin_action(property_service_init_action, &
11、quot;property_service_init"); queue_builtin_action(signal_init_action, "signal_init"); queue_builtin_action(check_startup_action, "check_startup"); if (is_charger) action_for_each_trigger("charger", action_add_queue_tail); else action_for_each_trigger("early-b
12、oot", action_add_queue_tail); action_for_each_trigger("boot", action_add_queue_tail); /* run all property triggers based on current state of the properties */ queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");#if BOOTCHART queue_builtin_action(b
13、ootchart_init_action, "bootchart_init");#endif / 進(jìn)入無限循環(huán),建立init的子進(jìn)程(init是所有進(jìn)程的父進(jìn)程) for(;) int nr, i, timeout = -1; / 執(zhí)行命令(子進(jìn)程對應(yīng)的命令) execute_one_command(); restart_processes(); if (!property_set_fd_init && get_property_set_fd() > 0) ufdsfd_count.fd = get_property_set_fd(); ufdsfd_
14、count.events = POLLIN; ufdsfd_count.revents = 0; fd_count+; property_set_fd_init = 1; if (!signal_fd_init && get_signal_fd() > 0) ufdsfd_count.fd = get_signal_fd(); ufdsfd_count.events = POLLIN; ufdsfd_count.revents = 0; fd_count+; signal_fd_init = 1; if (!keychord_fd_init && get_
15、keychord_fd() > 0) ufdsfd_count.fd = get_keychord_fd(); ufdsfd_count.events = POLLIN; ufdsfd_count.revents = 0; fd_count+; keychord_fd_init = 1; if (process_needs_restart) timeout = (process_needs_restart - gettime() * 1000; if (timeout < 0) timeout = 0; if (!action_queue_empty() | cur_action)
16、 timeout = 0;/ bootchart是一個(gè)性能統(tǒng)計(jì)工具,用于搜集硬件和系統(tǒng)的信息,并將其寫入磁盤,以便其/ 他程序使用#if BOOTCHART if (bootchart_count > 0) if (timeout < 0 | timeout > BOOTCHART_POLLING_MS) timeout = BOOTCHART_POLLING_MS; if (bootchart_step() < 0 | -bootchart_count = 0) bootchart_finish(); bootchart_count = 0; #endif / 等待下
17、一個(gè)命令的提交 nr = poll(ufds, fd_count, timeout); if (nr <= 0) continue; for (i = 0; i < fd_count; i+) if (ufdsi.revents = POLLIN) if (ufdsi.fd = get_property_set_fd() handle_property_set_fd(); else if (ufdsi.fd = get_keychord_fd() handle_keychord(); else if (ufdsi.fd = get_signal_fd() handle_signal
18、(); return 0; 我們可以看到main函數(shù)是非常復(fù)雜的,不過我們也不需要每條語句都弄得非常清楚(因?yàn)檫@樣弄是非常困難的),通常只需要了解init的主線即可。其實(shí)從init的main函數(shù)可以看出。Init實(shí)際上就分為如下兩部分。1. 初始化(包括建立/dev、/proc等目錄、初始化屬性、執(zhí)行init.rc等初始化文件中的action等)。2. 使用for循環(huán)無限循環(huán)建立子進(jìn)程。 第一項(xiàng)工作很好理解。而第二項(xiàng)工作是init中的核心。在Linux系統(tǒng)中init是一切應(yīng)用
19、空間進(jìn)程的父進(jìn)程。所以我們平常在Linux終端執(zhí)行的命令,并建立進(jìn)程。實(shí)際上都是在這個(gè)無限的for循環(huán)中完成的。也就是說,在Linux終端執(zhí)行ps e 命令后,看到的所有除了init外的其他進(jìn)程,都是由init負(fù)責(zé)創(chuàng)建的。而且init也會常駐容。當(dāng)然,如果init掛了,Linux系統(tǒng)基本上就崩潰了。 由于init比較復(fù)雜,所以本文只分析其中的一部分,在后續(xù)文章中將詳細(xì)分析init的各個(gè)核心組成部分。 對于main函數(shù)最開始完成的建立目錄的工作比較簡單,這部分也沒什么可以分析的。就是調(diào)用了一些普通的A
20、PI(mkdir)建立一些目錄?,F(xiàn)在說一些題外話,由于Android的底層源代碼(包括init)實(shí)際上是屬于Linux應(yīng)用編程領(lǐng)域,所以要想充分理解Android源代碼,除了Linux的基本結(jié)構(gòu)要了解外,Linux應(yīng)用層的API需要熟悉。為了滿足這些讀者的需要,后續(xù)我會寫一些關(guān)于Linux應(yīng)用編程的文章。Ok,現(xiàn)在言歸正傳,接下來分析一個(gè)比較重要的部分:配置文件的解析。 這里的配置文件主要指init.rc。讀者可以進(jìn)到Android的shell,會看到根目錄有一個(gè)init.rc文件。該文件是只讀的,即使有了root權(quán)限,可以修改該文件
21、也沒有。因?yàn)槲覀冊诟夸浛吹降奈募皇谴嫖募溺R像。也就是說,android啟動后,會將init.rc文件裝載到存。而修改init.rc文件的容實(shí)際上只是修改存中的init.rc文件的容。一旦重啟android,init.rc文件的容又會恢復(fù)到最初的裝載。想徹底修改init.rc文件容的唯一方式是修改Android的ROM中的核鏡像(boot.img)。其實(shí)boot.img名曰核鏡像,不過該文件除了包含完整的Linux核文件(zImage)外,還包括另外一個(gè)鏡像文件(ramdisk.img)。ramdisk.img就包含了init.rc文件和init命令。所以只有修改ramdisk.img文件
22、中的init.rc文件,并且重新打包boot.img文件,并刷機(jī),才能徹底修改init.rc文件。如果讀者有Android源代碼,編譯后,就會看到out目錄中的相關(guān)子目錄會生成一個(gè)root目錄,該目錄實(shí)際上就是ramdisk.img解壓后的容。會看到有init命令和init.rc文件。在后續(xù)的文章中將會討論具體如何修改init.rc文件,如何刷機(jī)。不過這些容與本文關(guān)系不大,所以不做詳細(xì)的討論。現(xiàn)在回到main函數(shù),在創(chuàng)建完目錄后,會看到執(zhí)行了如下3個(gè)函數(shù)。 property_init(); get_hardware_nam
23、e(hardware, &revision); process_kernel_cmdline(); 其中property_init主要是為屬性分配一些存儲空間,該函數(shù)并不是核心。不過當(dāng)我們查看init.rc文件時(shí)會發(fā)現(xiàn)該文件開始部分用一些import語句導(dǎo)入了其他的配置文件,例如,/init.usb.rc。大多數(shù)配置文件都直接使用了確定的文件名,只有如下的代碼使用了一個(gè)變量($ro.hardware)執(zhí)行了配置文件名的一部分。那么這個(gè)變量值是從哪獲得的呢?import /init.$ro.hardwar
24、e.rc 首先要了解init.$ro.hardware.rc配置文件的容通常與當(dāng)前的硬件有關(guān)。現(xiàn)在我們先來關(guān)注get_hardware_name函數(shù),代碼如下:void get_hardware_name(char *hardware, unsigned int *revision) char data1024; int fd, n; char *x, *hw, *rev; /* 如果hardware已經(jīng)有值了,說明hardware通過核命令行提供,直接返回 */ if (hardware0) return; / 打開/proc/cpuinfo文
25、件 fd = open("/proc/cpuinfo", O_RDONLY); if (fd < 0) return; / 讀取/proc/cpuinfo文件的容 n = read(fd, data, 1023); close(fd); if (n < 0) return; datan = 0; / 從/proc/cpuinfo文件中獲取Hardware字段的值 hw = strstr(data, "nHardware"); rev = strstr(data, "nRevision"); / 成功獲取Hardware字段
26、的值 if (hw) x = strstr(hw, ": "); if (x) x += 2; n = 0; while (*x && *x != 'n') if (!isspace(*x) / 將Hardware字段的值都轉(zhuǎn)換為小寫,并更新hardware參數(shù)的值 / hardware也就是在init.c文件中定義的hardware數(shù)組 hardwaren+ = tolower(*x); x+; if (n = 31) break; hardwaren = 0; if (rev) x = strstr(rev, ": "
27、); if (x) *revision = strtoul(x + 2, 0, 16); 從get_hardware_name方法的代碼可以得知,該方法主要用于確定hardware和revision的變量的值。Revision這里先不討論,只要研究hardware。獲取hardware的來源是從Linux核命令行或/proc/cpuinfo文件中的容。Linux核命令行暫且先不討論(因?yàn)楹苌賯鬟f該值),先看看/proc/cpuinfo,該文件是虛擬文件(存文件),執(zhí)行cat /proc/cpuinfo命令會看
28、到該文件中的容,如圖1所示。在白框中就是Hardware字段的值。由于該設(shè)備是Nexus 7,所以值為grouper。如果程序就到此位置,那么與硬件有關(guān)的配置文件名是init.grouper.rc。有Nexus 7的讀者會看到在根目錄下確實(shí)有一個(gè)init.grouper.rc文件。說明Nexus 7的原生ROM并沒有在其他的地方設(shè)置配置文件名,所以配置文件名就是從/proc/cpuinfo文件的Hardware字段中取的值。
29、160; 圖1現(xiàn)在來看在get_hardware_name函數(shù)后面調(diào)用的process_kernel_cmdline函數(shù),代碼如下:static void process_kernel_cmd
30、line(void) /* don't expose the raw commandline to nonpriv processes */ chmod("/proc/cmdline", 0440); / 導(dǎo)入核命令行參數(shù) import_kernel_cmdline(0, import_kernel_nv); if (qemu0) import_kernel_cmdline(1, import_kernel_nv); / 用屬性值設(shè)置核變量 export_kernel_boot_props();
31、 在process_kernel_cmdline函數(shù)中除了使用import_kernel_cmdline函數(shù)導(dǎo)入核變量外,主要的功能就是調(diào)用export_kernel_boot_props函數(shù)通過屬性設(shè)置核變量,例如,通過ro.boot.hardware屬性設(shè)置hardware變量,也就是說可以通過ro.boot.hardware屬性值可以修改get_hardware_name函數(shù)中從/proc/cpuinfo文件中得到的hardware字段值。下面看一下export_kernel_boot_props函數(shù)的代碼。static void export_kernel_boot_props(voi
32、d) char tmpPROP_VALUE_MAX; const char *pval; unsigned i; struct const char *src_prop; const char *dest_prop; const char *def_val; prop_map = "ro.boot.serialno", "ro.serialno", "", , "ro.boot.mode", "ro.bootmode", "unknown", , "ro.boot.
33、baseband", "ro.baseband", "unknown", , "ro.boot.bootloader", "ro.bootloader", "unknown", , ; / 通過核的屬性設(shè)置應(yīng)用層配置文件的屬性 for (i = 0; i < ARRAY_SIZE(prop_map); i+) pval = property_get(prop_mapi.src_prop); property_set(prop_mapi.dest_prop, pval ?: pro
34、p_mapi.def_val); / 根據(jù)ro.boot.console屬性的值設(shè)置console變量 pval = property_get("ro.boot.console"); if (pval) strlcpy(console, pval, sizeof(console); /* save a copy for init's usage during boot */ strlcpy(bootmode, property_get("ro.bootmode"), sizeof(bootmode); /* if this was given o
35、n kernel command line, override what we read * before (e.g. from /proc/cpuinfo), if anything */ / 獲取ro.boot.hardware屬性的值 pval = property_get("ro.boot.hardware"); if (pval) / 這里通過ro.boot.hardware屬性再次改變hardware變量的值 strlcpy(hardware, pval, sizeof(hardware); / 利用hardware變量的值設(shè)置設(shè)置ro.hardware屬性 /
36、 這個(gè)屬性就是前面提到的設(shè)置初始化文件名的屬性,實(shí)際上是通過hardware變量設(shè)置的 property_set("ro.hardware", hardware); snprintf(tmp, PROP_VALUE_MAX, "%d", revision); property_set("ro.revision", tmp); /* TODO: these are obsolete. We should delete them */ if (!strcmp(bootmode,"factory") property_s
37、et("ro.factorytest", "1"); else if (!strcmp(bootmode,"factory2") property_set("ro.factorytest", "2"); else property_set("ro.factorytest", "0"); 從export_kernel_boot_props函數(shù)的代碼可以看出,該函數(shù)實(shí)際上就是來回設(shè)置一些屬性值,并且利
38、用某些屬性值修改console、hardware等變量。其中hardware變量(就是一個(gè)長度為32的字符數(shù)組)在get_hardware_name函數(shù)中已經(jīng)從/proc/cpuinfo文件中獲得過一次值了,在export_kernel_boot_props函數(shù)中又通過ro.boot.hardware屬性設(shè)置了一次值,不過在Nexus 7中并沒有設(shè)置該屬性,所以hardware的值仍為grouper。最后用hardware變量設(shè)置ro.hardware屬性,所以最后的初始化文件名為init.grouper.rc。 這里還有一個(gè)問題,前
39、面多次提到屬性或?qū)傩晕募?,那么這些屬性文件指的是什么呢?是init.rc?當(dāng)然不是。實(shí)際上這些屬性文件是一些列位于不同目錄,系統(tǒng)依次讀取的配置文件。屬性服務(wù)(Property Service) 在研究這些配置文件之前應(yīng)先了解init是如何處理這些屬性的。編寫過Windows本地應(yīng)用的讀者都應(yīng)了解,在windows中有一個(gè)注冊表機(jī)制,在注冊表中提供了大量的屬性。在Linux中也有類似的機(jī)制,這就是屬性服務(wù)。init在啟動的過程中會啟動屬性服務(wù)(Socket服務(wù)),并且在存中建立一塊存儲區(qū)域,用來存儲這些屬性。當(dāng)讀取這些屬性時(shí),直接從這一
40、存區(qū)域讀取,如果修改屬性值,需要通過Socket連接屬性服務(wù)完成。在init.c文件中的一個(gè)action函數(shù)中調(diào)用了start_property_service函數(shù)來啟動屬性服務(wù),action是init.rc及其類似文件中的一種執(zhí)行機(jī)制,由于容比較多,所以關(guān)于init.rc文件中的執(zhí)行機(jī)制將在下一篇文章中詳細(xì)討論。 現(xiàn)在順藤摸瓜,找到start_property_service函數(shù),該函數(shù)在Property_service.c文件中,該文件與init.c文件中同一個(gè)目錄。void start_property_service(void) int
41、fd; / 裝載不同的屬性文件 load_properties_from_file(PROP_PATH_SYSTEM_BUILD); load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT); load_override_properties(); /* Read persistent properties after all default values have been loaded. */ load_persistent_properties(); / 創(chuàng)建socket服務(wù)(屬性服務(wù)) fd = create_socket(PROP_SER
42、VICE_NAME, SOCK_STREAM, 0666, 0, 0); if(fd < 0) return; fcntl(fd, F_SETFD, FD_CLOEXEC); fcntl(fd, F_SETFL, O_NONBLOCK); / 開始服務(wù)監(jiān)聽 listen(fd, 8); property_set_fd = fd; 現(xiàn)在我們已經(jīng)知道屬性服務(wù)的啟動方式了,那么在start_property_service函數(shù)中還涉及到如下兩個(gè)宏。PROP_PATH_SYSTEM_BUILDPROP_PATH_SYSTEM_DEFAU
43、LT 這兩個(gè)宏都是系統(tǒng)預(yù)定義的屬性文件名的路徑。為了獲取這些宏的定義,我們先進(jìn)行另外一個(gè)函數(shù)的分析。 在前面讀取屬性值時(shí)使用過一個(gè)property_get函數(shù),該函數(shù)在Property_service.c中實(shí)現(xiàn),代碼如下:const char* property_get(const char *name) prop_info *pi; if(strlen(name) >= PROP_NAME_MAX) return 0; pi = (prop_info*) _syste
44、m_property_find(name); if(pi != 0) return pi->value; else return 0; 可以看到,在property_get函數(shù)中調(diào)用了一個(gè)核心函數(shù)_system_property_find,該函數(shù)真正實(shí)現(xiàn)了獲取屬性值的功能。該函數(shù)屬于bionic的一個(gè)library,在system_properties.c文件中實(shí)現(xiàn),讀者可以在如下的目錄找到該文件。<Android源代碼根目錄>/bionic/libc/bionic_system_property_find函數(shù)的代
45、碼如下:const prop_info *_system_property_find(const char *name) / 獲取屬性存儲存區(qū)域的首地址 prop_area *pa = _system_property_area_; unsigned count = pa->count; unsigned *toc = pa->toc; unsigned len = strlen(name); prop_info *pi; while(count-) unsigned entry = *toc+; if(TOC_NAME_LEN(entry) != len) continue; p
46、i = TOC_TO_INFO(pa, entry); if(memcmp(name, pi->name, len) continue; return pi; return 0; 從_system_property_find函數(shù)的代碼很容易看出,第一行使用了一個(gè)_system_property_area_變量,該變量是全局的。在前面分析main函數(shù)時(shí)涉及到一個(gè)property_init函數(shù),該函數(shù)調(diào)用了init_property_area函數(shù),該函數(shù)用于初始化屬性存區(qū)域,也就是_system_property_area_變量。s
47、tatic int init_property_area(void) prop_area *pa; if(pa_info_array) return -1; if(init_workspace(&pa_workspace, PA_SIZE) return -1; fcntl(pa_workspace.fd, F_SETFD, FD_CLOEXEC); pa_info_array = (void*) (char*) pa_workspace.data) + PA_INFO_START); pa = pa_workspace.data; memset(pa, 0, PA_SIZE); pa
48、->magic = PROP_AREA_MAGIC; pa->version = PROP_AREA_VERSION; /* 初始化屬性存區(qū)域,屬性服務(wù)會使用該區(qū)域 */ _system_property_area_ = pa; property_area_inited = 1; return 0; 在前面涉及到的system_properties.c文件對應(yīng)的頭文件system_properties.h中定義了前面提到的兩個(gè)表示屬性文件路徑的宏,其實(shí)還有另外兩個(gè)表示路徑的宏,一共4個(gè)屬性文件。system_propert
49、ies.h文件可以在<Android源代碼根目錄>/bionic/libc/include/sys目錄中找到。這4個(gè)宏定義如下:#define PROP_PATH_RAMDISK_DEFAULT "/p"#define PROP_PATH_SYSTEM_BUILD "/system/p"#define PROP_PATH_SYSTEM_DEFAULT "/system/p"#define PROP_PATH_LOCAL_OVERRIDE "/data/
50、p" 現(xiàn)在讀者可以進(jìn)入Android設(shè)備的相應(yīng)目錄,通??梢哉业缴鲜?個(gè)文件,如一般會在根目錄,會發(fā)現(xiàn)一個(gè)p文件,cat p會看到該文件的容。而屬性服務(wù)就是裝載所有這4個(gè)屬性文件中的所有屬性以及使用property_set設(shè)置的屬性。在Android設(shè)備的終端可以直接使用getprop命令從屬性服務(wù)獲取所有的屬性值。如圖2所示。getprop命令還可以直接根屬性名還獲取具體的屬性值,例如,getprop duct。 &
51、#160; &
52、#160; 圖2 如果讀者感興趣,可以看一下getprop是如何通過屬性服務(wù)讀寫屬性的。getprop命令的源代碼文件是getprop.c。讀者可以在<Android源代碼根目錄>/system/core/toolbox目錄中找到該文件。實(shí)際上,getprop獲取屬性值也是通過property_get函數(shù)完成的。在前面分析過該函數(shù),實(shí)際上調(diào)用了_system_property_find函數(shù)從_system_property_area_變量指定的存區(qū)域獲取相應(yīng)的屬性值。 此外在system_properties.c文件中還有如下兩個(gè)函數(shù)用于通過屬性服務(wù)修改或添加某個(gè)屬性的值。static int send_prop_msg(prop_msg *msg) struct pollfd pollfds1; struct sockaddr_un addr; socklen_t alen; size_t namelen; int s; int r; int result = -1;
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 學(xué)區(qū)房學(xué)位使用權(quán)購買合同年限約定及使用細(xì)則
- 電影院線與影視制作公司聯(lián)合制作合同
- 工業(yè)遺存改造為文化創(chuàng)意空間的合作協(xié)議
- 智能物流解決方案AGV小車租賃與技術(shù)支持協(xié)議
- 智能健身倉健身APP開發(fā)與推廣合作協(xié)議
- 商業(yè)航天測控技術(shù)培訓(xùn)與聘用一體化服務(wù)協(xié)議
- 企業(yè)班車運(yùn)營安全責(zé)任承包合同
- 智能家居安防演示系統(tǒng)租賃與智能家居解決方案合作協(xié)議
- 旅游景區(qū)門票銷售與托管運(yùn)營合同
- 護(hù)理質(zhì)量管理制度
- 虎符銅砭刮痧課件
- 數(shù)字媒體對人際親密關(guān)系的影響機(jī)制研究
- 稅務(wù)審計(jì)理論試題及答案解析
- 智能海洋牧場裝備行業(yè)跨境出海戰(zhàn)略研究報(bào)告
- 麻醉鎮(zhèn)靜藥與阿片類
- 中考化學(xué)第一輪復(fù)習(xí) 物質(zhì)的性質(zhì)與應(yīng)用(常見的酸堿鹽)測試題(解析版)
- 病理學(xué)課件-炎癥的機(jī)制
- 2025世界高血壓日控住血壓穩(wěn)住幸福高血壓健康講座
- 安徽卓越縣中聯(lián)盟2024-2025學(xué)年高三下學(xué)期5月份檢測政治試卷+答案
- 廣東省珠海市2024-2025學(xué)年下學(xué)期期中八年級數(shù)學(xué)質(zhì)量監(jiān)測試卷(含答案)
- 焊接工程師職業(yè)技能考核試題及答案
評論
0/150
提交評論