Android2.3.5-Based System: Launch of Android [2]

Source: Internet
Author: User
Tags file info

**************************************** **************************************** **************************************** ***
Author: EasyWave time: 2012.07.29

Category: Android source code analysis statement: reprinted. Please keep the link

NOTE: If any error occurs, please correct it. These are my Learning Log articles ......

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

My blog post is based on goldfish and android2.3.5: the launch mechanism of the entire Android system is introduced in [1, this time, we will give a more in-depth analysis of the uevent mechanism of android and how android uses the data transmitted through the kernel to establish device nodes and some hotplug events through uevent. In the Andorid2.3.5 source code system/core/init. c function, the ueventd_main () function. The detailed code is as follows:

If (! Strcmp (basename (argv [0]), "ueventd") // obtain the running program ueventd. ueventd return ueventd_main (argc, argv) under the full path name of rc; // if you can find ueventd. run the ueventd_main function.

There is a function that has to be said here. This function is the basename function. The main function is to get the file name in the path where the ueventd. rc file is located, that is, ueventd. The code for this function is as follows:

#include <sys/cdefs.h>#include <errno.h>#include <libgen.h>#include <stdlib.h>#include <string.h>#include <sys/param.h>char* basename(const char*  path){    static char*  bname = NULL;    int           ret;    if (bname == NULL) {        bname = (char *)malloc(MAXPATHLEN);        if (bname == NULL)            return(NULL);    }    ret = basename_r(path, bname, MAXPATHLEN);    return (ret < 0) ? NULL : bname;}

In the end, we call the basename_r function to parse the ueventd file name in the path where ueventd. rc is located. This function is in bionic/libc/bionic/basename. c. The specific implementation function is implemented in the basename_r function, which is also implemented in bionic/libc/bionic/basename_r.c. The specific code is as follows:

# Include <libgen. h> # include <errno. h> # include <string. h> # include <sys/param. h> int basename_r (const char * path, char * buffer, size_t bufflen) // security function of the file name in the returned path {const char * endp, * startp; int len, result; char temp [2];/* Empty or NULL string gets treated ". "*/if (path = NULL | * path = '\ 0') {startp = ". "; len = 1; goto Exit;}/* Strip trailing slashes */endp = path + strlen (path)-1; while (Endp> path & * endp = '/') endp --; /* All slashes becomes "/" */if (endp = path & * endp = '/') {startp = "/"; len = 1; goto Exit;}/* Find the start of the base */startp = endp; while (startp> path & * (startp-1 )! = '/') Startp --; len = endp-startp + 1; Exit: result = len; if (buffer = NULL) {return result ;} if (len> (int) bufflen-1) {len = (int) bufflen-1; result =-1; errno = ERANGE;} if (len> = 0) {memcpy (buffer, startp, len); buffer [len] = 0;} return result ;}

Through the above basename_r function, we can see that we can find the directory path "/" one by one and discard it, and finally find the ueventd and strcmp (basename (argv [0]), "ueventd") for comparison. If the file is found, the ueventd_main (argc, argv); process the main loop of the uevent event. In android2.3.5 source code, the ueventd. rc file in system/core/rootdir/is as follows:

/dev/null                 0666   root       root/dev/zero                 0666   root       root/dev/full                 0666   root       root/dev/ptmx                 0666   root       root/dev/tty                  0666   root       root/dev/random               0666   root       root/dev/urandom              0666   root       root/dev/ashmem               0666   root       root/dev/binder               0666   root       root# logger should be world writable (for logging) but not readable/dev/log/*                0662   root       log# the msm hw3d client device node is world writable/readable./dev/msm_hw3dc            0666   root       root# gpu driver for adreno200 is globally accessible/dev/kgsl                 0666   root       root# these should not be world writable/dev/diag                 0660   radio      radio/dev/diag_arm9            0660   radio      radio/dev/android_adb          0660   adb        adb/dev/android_adb_enable   0660   adb        adb/dev/ttyMSM0              0600   bluetooth  bluetooth/dev/ttyHS0               0600   bluetooth  bluetooth/dev/uinput               0660   system     bluetooth/dev/alarm                0664   system     radio/dev/tty0                 0660   root       system/dev/graphics/*           0660   root       graphics/dev/msm_hw3dm            0660   system     graphics/dev/input/*              0660   root       input/dev/eac                  0660   root       audio/dev/cam                  0660   root       camera/dev/pmem                 0660   system     graphics/dev/pmem_adsp*           0660   system     audio/dev/pmem_camera*         0660   system     camera/dev/oncrpc/*             0660   root       system/dev/adsp/*               0660   system     audio/dev/snd/*                0660   system     audio/dev/mt9t013              0660   system     system/dev/msm_camera/*         0660   system     system/dev/akm8976_daemon       0640   compass    system/dev/akm8976_aot          0640   compass    system/dev/akm8973_daemon       0640   compass    system/dev/akm8973_aot          0640   compass    system/dev/bma150               0640   compass    system/dev/cm3602               0640   compass    system/dev/akm8976_pffd         0640   compass    system/dev/lightsensor          0640   system     system/dev/msm_pcm_out*         0660   system     audio/dev/msm_pcm_in*          0660   system     audio/dev/msm_pcm_ctl*         0660   system     audio/dev/msm_snd*             0660   system     audio/dev/msm_mp3*             0660   system     audio/dev/audience_a1026*      0660   system     audio/dev/tpa2018d1*           0660   system     audio/dev/msm_audpre           0660   system     audio/dev/msm_audio_ctl        0660   system     audio/dev/htc-acoustic         0660   system     audio/dev/vdec                 0660   system     audio/dev/q6venc               0660   system     audio/dev/snd/dsp              0660   system     audio/dev/snd/dsp1             0660   system     audio/dev/snd/mixer            0660   system     audio/dev/smd0                 0640   radio      radio/dev/qemu_trace           0666   system     system/dev/qmi                  0640   radio      radio/dev/qmi0                 0640   radio      radio/dev/qmi1                 0640   radio      radio/dev/qmi2                 0640   radio      radio/dev/bus/usb/*            0660   root       usb/dev/usb_accessory        0660   root       usb# CDMA radio interface MUX/dev/ts0710mux*           0640   radio      radio/dev/ppp                  0660   radio      vpn/dev/tun                  0640   vpn        vpn# sysfs properties/sys/devices/virtual/input/input*   enable      0660  root   input/sys/devices/virtual/input/input*   poll_delay  0660  root   input/sys/devices/virtual/usb_composite/*   enable      0664  root   system

The ueventd_main code can be found below. Now we can analyze this function more deeply. This function is used in system/core/init/ueventd. c.

Int ueventd_main (int argc, char ** argv) {struct pollfd ufd; int nr; char tmp [32]; open_devnull_stdio (); // open/dev/_ null, and redirects stdin, stdout, and stderr log_init (); // open the log file INFO ("starting ueventd \ n"); get_hardware_name (hardware, & revision ); // obtain the hardware and revision ueventd_parse_config_file ("/ueventd. rc "); // parse ueventd. rc file snprintf (tmp, sizeof (tmp), "/ueventd. % s. rc ", hardware); ueventd_parse_config_file (tmp); // parse ueventd. xxxxxx. rc file, for example, goldfish is ueventd. goldfish. rc file device_init (); ufd. events = POLLIN; ufd. fd = get_device_fd (); while (1) {ufd. revents = 0; nr = poll (& ufd, 1,-1); if (nr <= 0) continue; if (ufd. revents = POLLIN) handle_device_fd ();}}

First, we will analyze open_devnull_stdio (); this function mainly enables/dev/_ null __and redirects stdin, stdout, and stderr. The specific code is as follows:

Void open_devnull_stdio (void) {int fd; static const char * name = "/dev/_ null _"; if (mknod (name, S_IFCHR | 0600, (1 <8) | 3) = 0) {// set the node attribute, S_IFCHR: that is, this is a character device. 0600 is the property of the file. Fd = open (name, O_RDWR); // open/dev/_ null _ DEVICE unlink (name ); // Delete the directory entry of a file and reduce the number of links to it. if (fd> = 0) {// open dup2 (fd, 0 ); // redirect stdin dup2 (fd, 1); // redirect stdout dup2 (fd, 2); // redirect stderr if (fd> 2) {// close the file and return close (fd);} return ;}// otherwise, return 'failed' exit (1 );}

Log_init (); creates a msg log file to record the above operation record files. The function code is as follows [this function is easy to understand. I believe everyone should remember this command: cat/proc/kmsg. You can run this command on the Development Board to see what information will appear .. The Code is as follows:

Void log_init (void) {static const char * name = "/dev/_ kmsg _"; if (mknod (name, S_IFCHR | 0600, (1 <8) | 11) = 0) {log_fd = open (name, O_WRONLY); fcntl (log_fd, F_SETFD, FD_CLOEXEC); // force lock the file and set the file to FD_CLOEXEC, this indicates that you can search for specific meanings on the network, mainly related to the exec () function. Unlink (name );}}

At the same time, this function is get_hardware_name (hardware, & revision). The name and version of the current hardware are obtained through/proc/cpuinfo, I believe that for linux and android kernel transplantation and driver development, we should all know this command: cat/proc/cpuinfo. You can test it on your own Development Board to see what will happen. Now we will focus on the ueventd_parse_config_file ("/ueventd. rc"); function. The function code is as follows:

int ueventd_parse_config_file(const char *fn){    char *data;    data = read_file(fn, 0);    if (!data) return -1;    parse_config(fn, data);    DUMP();    return 0;}

Here, read_file (fn, 0) is mainly used to read the file size of ueventd. rc and is stored in the memory. Parse_config (fn, data); this is the focus, which is to parse ueventd. rc file. This function is in system/core/init/ueventd_parser.c. Now we will analyze this function in depth.

Static void parse_config (const char * fn, char * s) {struct parse_state state; char * args [UEVENTD_PARSER_MAXARGS]; int nargs; nargs = 0; state. filename = fn; state. line = 1; state. ptr = s; state. nexttoken = 0; state. parse_line = parse_line_device; // The specific parsing device. This is a callback function for (;) {int token = next_token (& state); // query ueventd cyclically. switch (token) {case T_EOF: state. parse_line (& state, 0, 0); // to ueventd. at the end of rc, perform the final parsing and directly return; case T_NEWLINE: // If a line is changed, perform ueventd. rc parsing work if (nargs) {state. parse_line (& state, nargs, args); nargs = 0;} break; case T_TEXT: // If the row's data is being parsed, see ueventd for details. rc file if (nargs <UEVENTD_PARSER_MAXARGS) {args [nargs ++] = state. text ;}break ;}}}

This function has only four optional parameters in/dev/, and only one attr option is added in/sys/, that is, five options. The specific Parsing is detailed in set_device_permission () in the parse_line_device function. The specific code is as follows:

Void set_device_permission (int nargs, char ** args) {char * name; char * attr = 0; mode_t perm; uid_t uid; gid_t gid; int prefix = 0; char * endptr; int ret; char * tmp = 0; if (nargs = 0) return; if (args [0] [0] = '#') return; name = args [0]; // you can use ueventd. in the rc file,/dev/null 0666 root and/sys/devices/virtual/input * enable 0660 root input. if (! Strncmp (name, "/sys/", 5) & (nargs = 5) {// find/sys/. Generally, there are five parameters. INFO ("/sys/rule % s \ n", args [0], args [1]); attr = args [1]; // Therefore, assign args [1] to attr args ++; nargs --;} if (nargs! = 4) {// If the parameter is incorrect, the system exits directly and does not parse it because of an error. ERROR ("invalid line ueventd. rc line for '% s' \ n ", args [0]); return;}/* If path starts with mtd @ lookup the mount number. */if (! Strncmp (name, "mtd @", 4) {// check whether mtd partition exists. If the mount mtd partition exists, int n = mtd_name_to_number (name + 4 ); if (n> = 0) asprintf (& tmp, "/dev/mtd % d", n); name = tmp ;} else {// otherwise, the general device parsing int len = strlen (name); if (name [len-1] = '*') {prefix = 1; // if the device contains the '*' character, this indicates that add_dev_perms has a prefix. For example,/dev/input/* indicates that there may be multiple characters, such as 0, 1, and 2. Name [len-1] = '\ 0';} perm = strtol (args [1], & endptr, 8 ); // convert args [1] to an octal format. For example, convert character 0666 to an integer. If (! Endptr | * endptr! = '\ 0') {ERROR ("invalid mode' % s' \ n", args [1]); free (tmp); return ;} ret = get_android_id (args [2]); // obtain the name defined by android_id. For details, see the android_ids table. If (ret <0) {ERROR ("invalid uid '% s' \ n", args [2]); free (tmp); return;} uid = ret; // Set User id ret = get_android_id (args [3]); // obtain the id defined by android_id. For details, see the android_ids table. The next section will analyze if (ret <0) {ERROR ("invalid gid '% s' \ n", args [3]); free (tmp); return;} gid = ret; // set the group id add_dev_perms (name, attr, perm, uid, gid, prefix); // Add it to the linked list. Free (tmp );}

In the add_dev_perms () function, add/dev and/sys/to different linked lists respectively. The specific function implementation is as follows:

int add_dev_perms(const char *name, const char *attr,                  mode_t perm, unsigned int uid, unsigned int gid,                  unsigned short prefix) {    struct perm_node *node = calloc(1, sizeof(*node));    if (!node)        return -ENOMEM;    node->dp.name = strdup(name);    if (!node->dp.name)        return -ENOMEM;    if (attr) {        node->dp.attr = strdup(attr);        if (!node->dp.attr)            return -ENOMEM;    }    node->dp.perm = perm;    node->dp.uid = uid;    node->dp.gid = gid;    node->dp.prefix = prefix;    if (attr)        list_add_tail(&sys_perms, &node->plist);    else        list_add_tail(&dev_perms, &node->plist);    return 0;}

The analysis is completed inLearning from android2.3.5: Android startup mechanism [3]To analyze ....

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

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.