In-depth analysis of the Android Init process implementation of the C language source code _c language

Source: Internet
Author: User
Tags eol goto locale strcmp strlen unix domain socket

Overview

Init is a process, to be sure, it is the first process of user space in a Linux system. Since Android is based on the Linux kernel, Init is also the first process of user space in the Android system. The process number for INIT is 1. As a bully process, Init has a lot of important work to do:

    • Init provides property service (attribute services) to manage the properties of the Android system.
    • Init is responsible for creating key processes in the system, including zygote.

The previous article on the introduction of the Init source code, but I am here first from these two major work started. To figure out how these two major jobs are achieved, let's look back at the source code of INIT.

This article is mainly about the property services of the Init process.

The source directory associated with the Init attribute service is as follows:

    system/core/init/
    bionic/libc/bionic/
    system/core/libcutils/

Property Services

On the Windows platform there is something called a registry that stores some key/value-like key-value pairs. In general, the system or some applications store some of their own properties in the registry, even if the system reboots or the application is restarted, it can initialize itself based on the property values previously set in the registry.

The Android system also provides a similar mechanism, called the property service. The application can query or set properties through this service. We can get the property key value pairs on the phone by using the following command.

ADB Shell Getprop

For example, the properties of the Red meter note phone are as follows:

[Ro.product.device]: [LCSH92_WET_JB9]
[ro.product.locale.language]: [en]
[ro.product.locale.region]: [CN]
[Ro.product.manufacturer]: [Xiaomi]


In the main function of the system/core/init/init.c file, the code associated with the property service is as follows:

Property_init ();
Queue_builtin_action (property_service_init_action, "property_service_init");

Next, let's take a look at the actual implementation of these two codes.
Property Service Initialization
Creating storage space

First, let's take a look at the source code for the Property_init function (/system/core/init/property_service.c):

void Property_init (void)
{
  init_property_area ();
}


The Property_init function simply calls the Init_property_area method, and then we look at the concrete implementation of this method:

static int property_area_inited = 0;
static workspace pa_workspace;
The static int init_property_area (void)
{
  //property space has initialized if
  (property_area_inited)
    return-1;

  if (__system_property_area_init ())
    return-1;

  if (Init_workspace (&pa_workspace, 0))
    return-1;

  Fcntl (PA_WORKSPACE.FD, F_SETFD, fd_cloexec);

  property_area_inited = 1;
  return 0;
}

From the Init_property_area function, we can see that the function first determines whether the property memory region has been initialized, and returns 1 if it has been initialized. If not initialized, we will then find that there are two key functions __system_property_area_init and init_workspace should be related to memory area initialization. So let's analyze each of these two functions concretely.

The __system_property_area_init __system_property_area_init function is located in the/bionic/libc/bionic/system_properties.c file, and the specific code implementation is as follows:
  struct Prop_area {unsigned bytes_used;
  unsigned volatile serial;
  Unsigned magic;
  unsigned version;
  unsigned reserved[28];
Char data[0];
};
typedef struct PROP_AREA Prop_area;

Prop_area *__system_property_area__ = NULL; 

#define PROP_FILENAME "/dev/__properties__" static char Property_filename[path_max] = prop_filename;
  #define PA_SIZE (128 * 1024) static int map_prop_area_rw () {Prop_area *pa;
  int FD;

  int ret; /** * O_rdwr ==> Read/write * O_creat ==> if not present, create * O_nofollow ==> if filename is a soft link, open failure * O_EXCL ==> if you use O_creat is a file exists, you can return the error message * * fd = open (Property_filename, O_RDWR | O_creat | O_nofollow | o_cloexec |
  O_EXCL, 0444);
    if (FD < 0) {if (errno = = eacces) {abort ();
  } return-1;
  ret = Fcntl (FD, F_SETFD, fd_cloexec);

  if (Ret < 0) goto out; if (Ftruncate (FD, Pa_size) < 0) goto Out
  Pa_size = pa_size;
  Pa_data_size = pa_size-sizeof (Prop_area);

  Compat_mode = false; Mmap mapping file Implementation shared Memory PA = mmap (NULL, pa_size, Prot_read |
  Prot_write, map_shared, FD, 0);

  if (PA = = map_failed) goto out;
  /* Initializes all values in the memory address as 0*/memset (PA, 0, pa_size);
  Pa->magic = Prop_area_magic;
  Pa->version = prop_area_version;

  pa->bytes_used = sizeof (PROP_BT);

  __system_property_area__ = PA;
  Close (FD);

return 0;
  Out:close (FD);
return-1;

 int __system_property_area_init () {return MAP_PROP_AREA_RW ();}


The code is better understood by using the mmap mapping Property_filename to create a shared memory area and assigning the first address of shared memory to the global variable __system_property_area__.

About MMAP mapping file implementation of shared memory IPC communication mechanism, you can refer to this article: MMAP implementation of IPC communication mechanism
Init_workspace

Next, let's take a look at the source code for the Init_workspace function (/system/core/init/property_service.c):

typedef struct {
  void *data;
  size_t size;
  int fd;
} Workspace;

static int init_workspace (workspace *w, size_t size)
{
  void *data;
  int fd = open (Prop_filename, o_rdonly | O_nofollow);
  if (FD < 0)
    return-1;

  w->size = size;
  W->FD = FD;
  return 0;
}

Client process Access Property memory area

Although the property memory area was created by the Init process, the Android system expects other processes to read the contents of the memory area as well. To do this, the INIT process does the following two things during the initialization of the property area:

The property memory area is created on shared memory, and shared memory can span processes. This is achieved through the MMAP mapping/dev/__properties__ file in the above code. The FD member in the Pa_workspace variable also holds the handle to the mapping file.
How do you let other processes know about this shared memory handle? Android first assigns the file mapping handle to the __SYSTEM_PROPERTY_AREA__ variable, which belongs to a variable in the output of the Bionic_lic library, and then leverages the constructor property of GCC, which indicates a __lib_ Prenit function, when the Bionic_lic library is loaded, the __libc_prenit is automatically invoked, which completes the mapping of shared memory to the local process.

Just talking about the principle is not possible, let's take a look at the related implementation of the __lib_prenit function code:

void __attribute__ ((constructor)) __libc_prenit (void);


void __libc_prenit (void) {//... __libc_init_common (elfdata);//Call this function//...} The __libc_init_common function is: void __libc_init_common (uintptr_t *elfdata) {//... __system_properties_init ();//Initialize client's property save The storage area} __system_properties_init function has returned to our familiar/BIONIC/LIBC/BIONIC/SYSTEM_PROPERTIES.C file: static int get_fd_from_env (void

  {Char *env = getenv ("Android_property_workspace");
  if (! env) {return-1;
return atoi (env);
  The static int Map_prop_area () {bool Formfile = true;
  int result =-1;
  int FD;

  int ret; FD = open (Property_filename, o_rdonly | O_nofollow |
  O_CLOEXEC);
    if (FD >= 0) {/* for the old kernels that don ' t support o_cloexec * * ret = FCNTL (FD, F_SETFD, fd_cloexec);
  if (Ret < 0) goto cleanup;
    if (FD < 0) && (Error = = enoent)) {fd = Get_fd_from_env ();
  FromFile = false;
  } if (FD < 0) {return-1;
  } struct stat Fd_stat; if (fsTat (FD, &fd_stat) < 0) {goto cleanup; } if ((Fd_stat.st_uid!= 0) | | (fd_stat.st_gid!= 0) | | (Fd_stat.st_mode & (S_iwgrp | S_iwoth)!= 0) | | (Fd_stat.st_size < sizeof (Prop_area))
  {goto cleanup;
  } pa_size = Fd_stat.st_size;

  Pa_data_size = pa_size-sizeof (Prop_area);
   /* Map the property memory created by Init to the local process space so that the local process can use this shared memory.
   * Note: The Prot_read property is developed when mapping, so the client process can read only properties and cannot set properties.

  * * Prop_area *PA = mmap (NULL, Pa_size, Prot_read, map_shared, FD, 0);
  if (PA = = map_failed) {goto cleanup; } if ((Pa->magic!= prop_area_magic) | | (pa->version!= prop_area_version && pa->version!=))
    {Munmap (PA, pa_size);
  Goto cleanup;
  } if (pa->version = = Prop_area_version_compat) {Compat_mode = true;

  result = 0;
__system_property_area__ = PA;
  Cleanup:if (FromFile) {close (FD);
return result;

 int __system_properties_init () {return Map_prop_area ();}


Through the source of the reading, you can find that the client through the mmap mapping, can read the contents of the property memory, but no permissions to set properties. How does the client set the property? This involves the following property server to be put.
analysis of the property server

The init process starts a property server, and the client can only set the property by interacting with the property server.
start the property server

First look at the content of the property server, it started by the Property_service_init_action function, the source code is as follows (/SYSTEM/CORE/INIT/INIT.C&&PROPERTY_SERVICE.C):

static int property_service_init_action (int nargs, char **args) {start_property_service ();
return 0;
  static void Load_override_properties () {#ifdef allow_local_prop_override char Debuggable[prop_value_max];

  int ret;
  ret = Property_get ("ro.debuggable", debuggable);
  if (Ret && (strcmp (debuggable, "1") = = 0)) {load_properties_from_file (prop_path_local_override);

  #endif} static void Load_properties (char *data) {char *key, *value, *eol, *sol, *tmp;
  Sol = data;
    while ((EOL = STRCHR (sol, ' \ n ')) {key = Sol;
    Assign the pointer to the next line to Sol *eol + + = 0;

    Sol = EOL;
    Value = STRCHR (key, ' = ');
    if (value = = 0) continue;

    *value++ = 0;
    while (Isspace (*key)) key + +;
    if (*key = = ' # ') continue;
    TMP = value-2;

    while (tmp > key) && isspace (*tmp)) *tmp--= 0;
    while (Isspace (*value)) value + +;
    TMP = EOL-2;

    while ((tmp > Value) && isspace (*tmp)) *tmp--= 0;
  Property_set (key, value);
}
}
int create_socket (const char *name, int type, mode_t perm, uid_t uid, gid_t gid) {struct sockaddr_un;
  int FD, RET;

  Char *secon;
  FD = socket (Pf_unix, type, 0);
    if (FD < 0) {ERROR ("Failed to open socket '%s ':%s\n", Name, Strerror (errno));
  return-1;
  } memset (&addr, 0, sizeof (addr));
  addr.sun_family = Af_unix;

  snprintf (Addr.sun_path, sizeof (Addr.sun_path), Android_socket_dir "/%s", name);
  ret = unlink (Addr.sun_path);
  if (Ret!= 0 && errno!= enoent) {goto out_close;
  ret = bind (FD, (struct sockaddr *) &addr, sizeof (addr));
  if (ret) {goto out_unlink;
  } chown (Addr.sun_path, UID, GID);

  chmod (Addr.sun_path, Perm);

return FD;
Out_unlink:unlink (Addr.sun_path);
  Out_close:close (FD);
return-1; #define PROP_PATH_SYSTEM_BUILD "/system/build.prop" #define Prop_path_system_default "/system/default.prop" #define
Prop_path_local_override "/data/local.prop" #define Prop_path_factory "/factory/factory.prop"
void Start_property_service (void) {int 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 ();
  FD = Create_socket (Prop_service_name, Sock_stream, 0666, 0, 0);
  if (FD < 0) return;
  Fcntl (FD, F_SETFD, fd_cloexec);

  Fcntl (FD, F_SETFL, O_nonblock);
  Listen (FD, 8);
PROPERTY_SET_FD = FD;

 }


As you can see from the preceding code, the INIT process will create a UNIX Domain Socket to accept client requests and build properties in addition to the specified file (for example, System/build.prop) attributes. So where is this socket request being processed?
The answer is: the For loop in Init has been dealt with.

Service-side processing Set Property request

The place where the request for property settings is received is in the Init process, and the relevant code looks like this:

int main (int argc, char **argv)
{
  //... Omit irrelevant code for

  (;;) {
    // ...
    for (i = 0; i < Fd_count i + +) {
      if (ufds[i].fd = = GET_PROPERTY_SET_FD ())
        handle_property_set_fd ();
    }
  }
}

As you can see from the code above, when a property server receives a client request, the INIT process calls the HANDLE_PROPERTY_SET_FD function for processing, where the function is: system/core/init/property_ SERVICE.C, let's take a look at the implementation source of this function:

void Handle_property_set_fd () {prop_msg msg;
  int s;
  int R;
  int res;
  struct ucred cr;
  struct Sockaddr_un addr;
  socklen_t addr_size = sizeof (addr);
  socklen_t cr_size = sizeof (CR);

  char *source_ctx = NULL;
  Receive the TCP connection if ((s = Accept (property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) {return;
  ///Receive client request data R = Temp_failure_retry (recv (S, &msg, sizeof (msg), 0)); if (r!= sizeof (PROP_MSG)) {ERROR ("Sys_prop:mis-match msg size received:%d expected:%d errno:%d\n", R, sizeof (pr
    op_msg), errno);
    Close (s);
  Return
    Switch (msg.cmd) {case Prop_msg_setprop:msg.name[prop_name_max-1] = 0;

    Msg.value[prop_value_max-1] = 0;
      if (memcmp (Msg.name, ctl., 4) = 0) {close (s); if (Check_control_perms (Msg.value, Cr.uid, Cr.gid, Source_ctx)) {handle_control_message (char*) Msg.name + 4, (ch
      ar*) msg.value); else {ERROR (' sys_prop:unable to%s service ctl [%s] uid:%d gid:%d pid:%d\n ", Msg.name + 4, Msg.value, Cr.uid, Cr.gid, cr.pid); } else {if (Check_perms (Msg.name, Cr.uid, Cr.gid, Source_ctx)) {property_set (char *) msg.name, (cha
      r*) msg.value);
    Close (s);
  } break;
    Default:close (s);
  Break

 }
}


When the client's permissions meet the requirements, Init invokes the Property_set for related processing. Property_set source code implementation is as follows:

 int property_set (const char *name, const char *value) {Prop_info *pi;

  int ret;
  size_t Namelen = strlen (name);

  size_t Valuelen = strlen (value);
  if (! Is_legal_property_name (name, Namelen)) return-1;

  if (Valuelen >= prop_value_max) return-1;
  Find out whether the property value Pi = (prop_info*) __system_property_find (name) is already present in the attribute space;

    if (pi!= 0) {//Ro the beginning of the property is set, it is not allowed to be modified if (! strncmp (name, "Ro.", 3)) return-1;
  __system_property_update (pi, value, Valuelen);
  else {ret = __system_property_add (name, Namelen, value, Valuelen); //There are special properties that require special handling, such as net. and persist. The Properties if (strncmp ("net.", Name, strlen ("net.") = = 0) {if (strcmp ("Net.change
    ", name) = = 0) {return 0;
  } property_set ("Net.change", name); else if (persistent_properties_loaded && strncmp ("persist.", Name, strlen ("persist.")) = = 0) {write_persist
  Ent_property (name, value);
  } property_changed (name, value);
return 0; }


The work on the property server side is basically done here. Finally, let's take a look at how the client sends a socket request to set properties.
Client Send Request

The Property_set ("Sys.istest", "true") method is invoked when the client sets the property. From the above analysis, this method is different from the server-side Property_set method, this method must be to send the socket request, the method source location is:/system/core/libcutils/properties.c:

int Property_set (const char *key, const char *value)
{return
  __system_property_set (key, value);
}

As you can see, Property_set calls the __system_property_set method, which is in:/BIONIC/LIBC/BIONIC/SYSTEM_PROPERTIES.C file:

struct prop_msg {unsigned cmd;
  Char Name[prop_name_max];
Char Value[prop_value_max];
};

typedef struct PROP_MSG prop_msg;
  static int send_prop_msg (prop_msg *msg) {struct POLLFD pollfds[1];
  struct Sockaddr_un addr;
  Socklen_t Alen;
  size_t Namelen;
  int s;
  int R;

  int result =-1;
  s = socket (af_local, sock_stream, 0);
  if (s < 0) {return result;
  } memset (&addr, 0, sizeof (addr));
  Namelen = strlen (Property_service_socket);
  strlcpy (Addr.sun_path, Property_service_socket, sizeof (Addr.sun_path));
  addr.sun_family = af_local;

  Alen = Namelen + offsetof (struct Sockaddr_un, sun_path) + 1;
    if (Temp_failure_retry connect (s, (struct sockaddr *) &addr, Alen)) < 0) {close (s);
  return result;

  R = Temp_failure_retry (send (S, msg, sizeof (PROP_MSG), 0));
  Close (s);
return result;
  int __system_property_set (const char *key, const char *value) {int err;

  Prop_msg msg;
  if (key = = 0) return-1;
if (value = = 0) value = "";  if (strlen (key) >= Prop_name_max) return-1;

  if (strlen (value) >= Prop_value_max) return-1;
  memset (&msg, 0, sizeof (msg));
  Msg.cmd = Prop_msg_setprop;
  strlcpy (Msg.name, Key, sizeof (Msg.name));

  strlcpy (msg.value, value, sizeof (Msg.value));
  Err = send_prop_msg (&msg);
  if (Err < 0) {return err;
return 0;

 }

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.