基於android2.3.5系統:開天闢地Android啟動機制[三]

來源:互聯網
上載者:User

***************************************************************************************************************************
作者:EasyWave                                                                                 時間:2012.08.01

類別:Android系統源碼分析                                                              聲明:轉載,請保留連結

注意:如有錯誤,歡迎指正。這些是我學習的日誌文章......

***************************************************************************************************************************

         在我的博文基於goldfish和android2.3.5學習之:開天闢地Android啟動機制[二]中,部分的介紹了uevent事件機制,這篇博文將更深入的詳細分析uevent的機制以及如何android是如何透過核心傳遞過來的資料通過uevent機制檢測裝置的hotplug事件。同時也分析到了andorid_ids,還是先把get_android_id()函數拿出來分析一下吧,代碼如下:

static int get_android_id(const char *id){    unsigned int i;    for (i = 0; i < ARRAY_SIZE(android_ids); i++) //尋找android_ids表格        if (!strcmp(id, android_ids[i].name)) //比較android_ids中的name            return android_ids[i].aid; //返回andorid_ids表格中的aid    return 0;}

而andorid_ids是在android_filesystem_config.h檔案中,具體的位置在andorid2.3.5/system/core/include/private中。具體的代碼如下:

struct android_id_info {    const char *name;    unsigned aid;};static const struct android_id_info android_ids[] = {    { "root",      AID_ROOT, },    { "system",    AID_SYSTEM, },    { "radio",     AID_RADIO, },    { "bluetooth", AID_BLUETOOTH, },    { "graphics",  AID_GRAPHICS, },    { "input",     AID_INPUT, },    { "audio",     AID_AUDIO, },    { "camera",    AID_CAMERA, },    { "log",       AID_LOG, },    { "compass",   AID_COMPASS, },    { "mount",     AID_MOUNT, },    { "wifi",      AID_WIFI, },    { "dhcp",      AID_DHCP, },    { "adb",       AID_ADB, },    { "install",   AID_INSTALL, },    { "media",     AID_MEDIA, },    { "nfc",       AID_NFC, },    { "shell",     AID_SHELL, },    { "cache",     AID_CACHE, },    { "diag",      AID_DIAG, },    { "net_bt_admin", AID_NET_BT_ADMIN, },    { "net_bt",    AID_NET_BT, },    { "sdcard_rw", AID_SDCARD_RW, },    { "vpn",       AID_VPN, },    { "keystore",  AID_KEYSTORE, },    { "usb",       AID_USB, },    { "gps",       AID_GPS, },    { "inet",      AID_INET, },    { "net_raw",   AID_NET_RAW, },    { "net_admin", AID_NET_ADMIN, },    { "misc",      AID_MISC, },    { "nobody",    AID_NOBODY, },};#define android_id_count \    (sizeof(android_ids) / sizeof(android_ids[0]))  

宏定義如下代碼:

/* This is the master Users and Groups config for the platform.** DO NOT EVER RENUMBER.*/#define AID_ROOT             0  /* traditional unix root user */#define AID_SYSTEM        1000  /* system server */#define AID_RADIO         1001  /* telephony subsystem, RIL */#define AID_BLUETOOTH     1002  /* bluetooth subsystem */#define AID_GRAPHICS      1003  /* graphics devices */#define AID_INPUT         1004  /* input devices */#define AID_AUDIO         1005  /* audio devices */#define AID_CAMERA        1006  /* camera devices */#define AID_LOG           1007  /* log devices */#define AID_COMPASS       1008  /* compass device */#define AID_MOUNT         1009  /* mountd socket */#define AID_WIFI          1010  /* wifi subsystem */#define AID_ADB           1011  /* android debug bridge (adbd) */#define AID_INSTALL       1012  /* group for installing packages */#define AID_MEDIA         1013  /* mediaserver process */#define AID_DHCP          1014  /* dhcp client */#define AID_SDCARD_RW     1015  /* external storage write access */#define AID_VPN           1016  /* vpn system */#define AID_KEYSTORE      1017  /* keystore subsystem */#define AID_USB           1018  /* USB devices */#define AID_GPS           1021  /* GPS daemon */#define AID_UNUSED1       1022  /* deprecated, DO NOT USE */#define AID_RFU1          1023  /* RFU */#define AID_RFU2          1024  /* RFU */#define AID_NFC           1025  /* nfc subsystem */#define AID_SHELL         2000  /* adb and debug shell user */#define AID_CACHE         2001  /* cache access */#define AID_DIAG          2002  /* access to diagnostic resources *//* The 3000 series are intended for use as supplemental group id's only. * They indicate special Android capabilities that the kernel is aware of. */#define AID_NET_BT_ADMIN  3001  /* bluetooth: create any socket */#define AID_NET_BT        3002  /* bluetooth: create sco, rfcomm or l2cap sockets */#define AID_INET          3003  /* can create AF_INET and AF_INET6 sockets */#define AID_NET_RAW       3004  /* can create raw INET sockets */#define AID_NET_ADMIN     3005  /* can configure interfaces and routing tables. */#define AID_MISC          9998  /* access to misc storage */#define AID_NOBODY        9999#define AID_APP          10000 /* first app user */

上面的都是部分摘錄,如果要想看明白這些代碼,你手邊必須要有android2.3.5的源碼,否則,這些你還是無法看明白的。還記得這個函數嗎?void set_device_permission(int nargs, char **args),看我的上一篇博文。這裡只摘錄跟上面有關部分的代碼,如下:

    ret = get_android_id(args[2]); //得到android_id定義的name,具體見:android_ids表格。    if (ret < 0) {        ERROR("invalid uid '%s'\n", args[2]);        free(tmp);        return;    }    uid = ret; //設定使用者id    ret = get_android_id(args[3]); //得到android_id定義的id,具體見:android_ids表格,    if (ret < 0) {        ERROR("invalid gid '%s'\n", args[3]);        free(tmp);        return;    }    gid = ret; //設定group的id    add_dev_perms(name, attr, perm, uid, gid, prefix); //添加到鏈表中。

    以/dev/null            0666  root      root來分析吧,如何得到uid   

ret = get_android_id(args[2]);這個是抓取前面/dev/null 中的第三項,也就是紅色加粗部分,透過root匹配之後,讀取到了AID_ROOT。

     以/dev/null            0666   root       root來分析吧,如何得到gid   

ret = get_android_id(args[3]);這個是抓取前面/dev/null 中的第四項,也就是藍色加粗部分,透過root匹配之後,讀取到了AID_ROOT。

     

      現在再來詳細介紹ueventd_main()沒有分析完的代碼,源碼分析繼續中。當然先說明源碼的位置:在Andorid2.3.5源碼system/core/init.c中。詳細的代碼如下:

int ueventd_main(int argc, char **argv){    struct pollfd ufd;    int nr;    char tmp[32];    open_devnull_stdio();    log_init();    INFO("starting ueventd\n");    get_hardware_name(hardware, &revision);    ueventd_parse_config_file("/ueventd.rc");    snprintf(tmp, sizeof(tmp), "/ueventd.%s.rc", hardware);    ueventd_parse_config_file(tmp); ////解析ueventd.xxxxxx.rc檔案,比如:goldfish為ueventd.goldfish.rc檔案,具體的分析可以參考ueventd.rc    device_init(); //初始化uevent socket,用於從Linux核心動態抓取裝置的狀態變化,同時處理冷開機事件。     ufd.events = POLLIN; //POLLIN的意思,當核心有資料可讀時,無阻塞的返回    ufd.fd = get_device_fd(); //得到相應的從核心傳過來的有資料具體檔案描述符fd.    while(1) { //迴圈操作        ufd.revents = 0;        nr = poll(&ufd, 1, -1);        if (nr <= 0)            continue;        if (ufd.revents == POLLIN)               handle_device_fd(); //處理具體的從核心傳遞過來的裝置變化事件,像null、usb、ttyS0等等,很多吧。這是我的理解,如有不對之處還望見諒    } //至於核心的ueventd事件,就需要去理解linux裝置驅動模型了,這個會在以後專門在linux核心欄目中詳細的介紹這個,因為這個驅動模型很複雜。}

        應用程式如果需要檢測裝置的熱插拔事件,一般會用到這個特殊的socket,在linux中就是這個NETLINK,我們可以透過這個socket中的NETLINK_KOBJ_UEVEN來檢測裝置的熱插拔的動作。其實android的檔案系統採用和busybox以及udev類似的方式。在busybox中採用的mdev來自動的抓取linux所有的裝置驅動,一般是從sys目錄中去抓取。自動根據驅動的名稱來分配相應裝置的主裝置號和次裝置號,以及是字元裝置,還是塊裝置和網路裝置。。如果我們能夠用這個方式來理解andorid的檔案系統,這樣對於分析android的檔案系統有很大的協助。

        說了太多的廢話了,還是先來具體看看device_init()函數吧,函數的具體位置在system/core/init/devices.c中,代碼如下:

void device_init(void){    suseconds_t t0, t1;    struct stat info;    int fd;    device_fd = open_uevent_socket(); //建立socket,並且將進程ID和socket建立起串連    if(device_fd < 0)        return;    fcntl(device_fd, F_SETFD, FD_CLOEXEC);//這兩句詩設定裝置檔案的屬性,同時強制加鎖    fcntl(device_fd, F_SETFL, O_NONBLOCK);    //因為android系統冷啟動時,會在dev/下產生一個.coldboot_done檔案。所以需要檢查這個檔案。    if (stat(coldboot_done, &info) < 0) { //查詢coldboot_done的狀態,並且存入info中,如果不成功的話,則倒計時進入冷啟動。        t0 = get_usecs(); //得到當前的時間        coldboot("/sys/class");         coldboot("/sys/block");        coldboot("/sys/devices");        t1 = get_usecs();        fd = open(coldboot_done, O_WRONLY|O_CREAT, 0000);        close(fd);        log_event_print("coldboot %ld uS\n", ((long) (t1 - t0)));     } else {        log_event_print("skipping coldboot, already done\n"); //冷啟動完成    }}

具體的分析下open_uevent_socket()函數,這個需要重點關注下,這個可是即時的監視著核心中裝置驅動的變化。因此詳細的分析一下。

static int open_uevent_socket(void){    struct sockaddr_nl addr;    int sz = 64*1024; // XXX larger? udev uses 16MB!    int on = 1;    int s;    memset(&addr, 0, sizeof(addr));    addr.nl_family = AF_NETLINK; //透過AF_NETLINK與核心進行通訊    addr.nl_pid = getpid(); //得到進程PID    addr.nl_groups = 0xffffffff;     //定義socket描述符,這是一個非同步通訊機制,SOCK_DGRAM的意思是無串連不可靠的串連    s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); //具體的事件為NETLINK_KOBJECT_UEVENT,對於這個需要對linux的裝置驅動模型需要有一定的瞭解    if(s < 0) //如果失敗,直接返回-1,也就是0xFFFFFF。        return -1;    setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)); //SO_RCVBUFFORCE是一個特殊的接收緩衝區,意思是不受接收緩衝區大小的上限限制    setsockopt(s, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)); //SO_PASSCRED的意思是:允許接收進程輔助資訊發送的信用證明。    if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { //將進程和socket聯絡起來。        close(s);        return -1; //失敗的話,返回-1.    }    return s; //成功返回}

   分析到了這一步之後,基本上ueventd機制基本上也差不多了。還是接上device_init()函數下部分的代碼來回顧一下,部分代碼如下:

    ufd.events = POLLIN;     ufd.fd = get_device_fd(); ///得到相應的從核心傳過來的有資料具體檔案描述符fd.    while(1) {        ufd.revents = 0; //先將實際動作的事件清零        nr = poll(&ufd, 1, -1); //監視發生的事件        if (nr <= 0) //如果無事件繼續            continue;        if (ufd.revents == POLLIN) //如果監視到發生的事件,則進入具體的事件處理中,比如字元裝置,塊裝置,還是網路裝置。               handle_device_fd(); //具體的處理事件在這個函數中。    }

   對於ueventd的理解也許是比較困難一點,這個是因為需要對linux核心的裝置驅動模型要有一定的理解,並且需要知道核心的裝置驅動模式的運行機制有一定的理解。簡單的講一下,在linux核心中,只要是載入裝置驅動,就會產生uevent事件。如果可以將核心的調試資訊列印出來,會看到諸如此類的add@xxxxxxx 以及移除裝置驅動的時候會出現remove@xxxxxxx等等資訊。android核心是如何啟動ueventd的呢?在init.rc中有很詳細的指示。init.rc的部分代碼如下:

on early-init    start ueventdon initsysclktz 0loglevel 3# setup the global environment    export PATH /sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin    export LD_LIBRARY_PATH /vendor/lib:/system/lib    export ANDROID_BOOTLOGO 1    export ANDROID_ROOT /system    export ANDROID_ASSETS /system/app    export ANDROID_DATA /data    export EXTERNAL_STORAGE /mnt/sdcard    export ASEC_MOUNTPOINT /mnt/asec    export LOOP_MOUNTPOINT /mnt/obb

         看到了 on early-init 下的start uventd的嗎?對就是這個。因為init是個守護進程,也是核心啟動之後,第一個要調用啟動並執行程式。而init進程會首先去抓取init.rc檔案。至於核心啟動之後,為什麼說init是第一個啟動並執行程式呢。這個會在以後會專門開闢一篇博文來詳細講述這個問題。這裡就不詳細說了,好了關於ueventd部分。已經基本上分析完了,其實ueventd就是初始化核心中所有的裝置驅動,然後透過ueventd分配好所有的裝置。當然,這個是需要根據核心的具體已有的裝置驅動。


         未完,Andriod源碼的分析還請繼續關注《基於android2.3.5學習之:開天闢地Android啟動機制[四]》 。。。

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.