• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1Bionic C Library Overview:
2==========================
3
4Introduction:
5
6Core Philosophy:
7
8  The core idea behind Bionic's design is: KEEP IT REALLY SIMPLE.
9
10  This implies that the C library should only provide lightweight wrappers
11  around kernel facilities and not try to be too smart to deal with edge cases.
12
13  The name "Bionic" comes from the fact that it is part-BSD and part-Linux:
14  its source code consists in a mix of BSD C library pieces with custom
15  Linux-specific bits used to deal with threads, processes, signals and a few
16  others things.
17
18  All original BSD pieces carry the BSD copyright disclaimer. Bionic-specific
19  bits carry the Android Open Source Project copyright disclaimer. And
20  everything is released under the BSD license.
21
22Architectures:
23
24  Bionic currently supports the ARM and x86 instruction sets. In theory, it
25  should be possible to support more, but this may require a little work (e.g.
26  adding system call IDs to SYSCALLS.TXT, described below, or modifying the
27  dynamic linker).
28
29  The ARM-specific code is under arch-arm/ and the x86-specific one is under
30  arch-x86/
31
32  Note that the x86 version is only meant to run on an x86 Android device. We
33  make absolutely no claim that you could build and use Bionic on a stock x86
34  Linux distribution (though that would be cool, so patches are welcomed :-))
35
36Syscall stubs:
37
38  Each system call function is implemented by a tiny assembler source fragment
39  (called a "syscall stub"), which is generated automatically by
40  tools/gensyscalls.py which reads the SYSCALLS.TXT file for input.
41
42  SYSCALLS.TXT contains the list of all syscall stubs to generate, along with
43  the corresponding syscall numeric identifier (which may differ between ARM
44  and x86), and its signature
45
46  If you modify this file, you may want to use tools/checksyscalls.py which
47  checks its content against official Linux kernel header files, and will
48  report errors when invalid syscall ids are used.
49
50  Sometimes, the C library function is really a wrapper that calls the
51  corresponding syscall with another name. For example, the exit() function
52  is provided by the C library and calls the _exit() syscall stub.
53
54  See SYSCALLS.TXT for documentation and details.
55
56
57time_t:
58
59  time_t is 32-bit as defined by the kernel on 32-bit CPUs. A 64-bit version
60  would be preferrable to avoid the Y2038 bug, but the kernel maintainers
61  consider that this is not needed at the moment.
62
63  Instead, Bionic provides a <time64.h> header that defines a time64_t type,
64  and related functions like mktime64(), localtime64(), etc...
65
66  strftime() uses time64_t internally, so the '%s' format (seconds since the
67  epoch) is supported for dates >= 2038.
68
69
70strftime_tz():
71
72  Bionic also provides the non-standard strftime_tz() function, a variant
73  of strftime() which also accepts a time locale descriptor as defined
74  by "struct strftime_locale" in <time.h>.
75
76  This function is used by the low-level framework code in Android.
77
78
79Timezone management:
80
81  The name of the current timezone is taken from the TZ environment variable,
82  if defined. Otherwise, the system property named 'persist.sys.timezone' is
83  checked instead.
84
85  The zoneinfo timezone database and index files are located under directory
86  /system/usr/share/zoneinfo, instead of the more Posix-compliant path of
87  /usr/share/zoneinfo
88
89
90off_t:
91
92  For similar reasons, off_t is 32-bit. We define loff_t as the 64-bit variant
93  due to BSD inheritance, but off64_t should be available as a typedef to ease
94  porting of current Linux-specific code.
95
96
97Linux kernel headers:
98
99  Bionic comes with its own set of "clean" Linux kernel headers to allow
100  user-space code to use kernel-specific declarations (e.g. IOCTLs, structure
101  declarations, constants, etc...). They are located in:
102
103     ./kernel/common,
104     ./kernel/arch-arm
105     ./kernel/arch-x86
106
107  These headers have been generated by a tool (kernel/tools/update-all.py) to
108  only include the public definitions from the original Linux kernel headers.
109
110  If you want to know why and how this is done, read kernel/README.TXT to get
111  all the (gory) details.
112
113
114PThread implementation:
115
116   Bionic's C library comes with its own pthread implementation bundled in.
117   This is different from other historical C libraries which:
118
119    - place it in an external library (-lpthread)
120    - play linker tricks with weak symbols at dynamic link time
121
122   The support for real-time features (a.k.a. -lrt) is also bundled in the
123   C library.
124
125   The implementation is based on futexes and strives to provide *very* short
126   code paths for common operations. Notable features are the following:
127
128      - pthread_mutex_t, pthread_cond_t are only 4 bytes each.
129
130      - Normal, recursive and error-check mutexes are supported, and the code
131        path is heavily optimized for the normal case, which is used most of
132        the time.
133
134      - Process-shared mutexes and condition variables are not supported.
135        Their implementation requires far more complexity and was absolutely
136        not needed for Android (which uses other inter-process synchronization
137        capabilities).
138
139        Note that they could be added in the future without breaking the ABI
140        by specifying more sophisticated code paths (which may make the common
141        paths slightly slower though).
142
143      - There is currently no support for read/write locks, priority-ceiling in
144        mutexes and other more advanced features. Again, the main idea being
145        that this was not needed for Android at all but could be added in the
146        future.
147
148pthread_cancel():
149
150   pthread_cancel() will *not* be supported in Bionic, because doing this would
151   involve making the C library significantly bigger for very little benefit.
152
153   Consider that:
154
155     - A proper implementation must insert pthread cancellation checks in a lot
156       of different places of the C library. And conformance is very difficult
157       to test properly.
158
159     - A proper implementation must also clean up resources, like releasing
160       memory, or unlocking mutexes, properly if the cancellation happens in a
161       complex function (e.g. inside gethostbyname() or fprintf() + complex
162       formatting rules). This tends to slow down the path of many functions.
163
164     - pthread cancellation cannot stop all threads: e.g. it can't do anything
165       against an infinite loop
166
167     - pthread cancellation itself has short-comings and isn't very portable
168       (see http://advogato.org/person/slamb/diary.html?start=49 for example).
169
170   All of this is contrary to the Bionic design goals. If your code depends on
171   thread cancellation, please consider alternatives.
172
173   Note however that Bionic does implement pthread_cleanup_push() and
174   pthread_cleanup_pop(), which can be used to handle cleanups that happen when
175   a thread voluntarily exits through pthread_exit() or returning from its
176   main function.
177
178
179pthread_once():
180
181  Do not call fork() within a callback provided to pthread_once(). Doing this
182  may result in a deadlock in the child process the next time it calls
183  pthread_once().
184
185  Also, you can't throw a C++ Exception from the callback (see C++ Exception
186  Support below).
187
188  The current implementation of pthread_once() lacks the necessary support of
189  multi-core-safe double-checked-locking (read and write barriers).
190
191
192Thread-specific data
193
194  The thread-specific storage only provides for a bit less than 64
195  pthread_key_t objects to each process. The implementation provides 64 real
196  slots but also uses about 5 of them (exact number may depend on
197  implementation) for its own use (e.g. two slots are pre-allocated by the C
198  library to speed-up the Android OpenGL sub-system).
199
200  Note that Posix mandates a minimum of 128 slots, but we do not claim to be
201  Posix-compliant.
202
203  Except for the main thread, the TLS area is stored at the top of the stack.
204  See comments in bionic/libc/bionic/pthread.c for details.
205
206  At the moment, thread-local storage defined through the __thread compiler
207  keyword is not supported by the Bionic C library and dynamic linker.
208
209
210Multi-core support
211
212  At the moment, Bionic does not provide or use read/write memory barriers.
213  This means that using it on certain multi-core systems might not be
214  supported, depending on its exact CPU architecture.
215
216
217Android-specific features:
218
219  Bionic provides a small number of Android-specific features to its clients:
220
221  - access to system properties:
222
223       Android provides a simple shared value/key space to all processes on the
224       system. It stores a liberal number of 'properties', each of them being a
225       simple size-limited string that can be associated to a size-limited
226       string value.
227
228       The header <sys/system_properties.h> can be used to read system
229       properties and also defines the maximum size of keys and values.
230
231   - Android-specific user/group management:
232
233       There is no /etc/passwd or /etc/groups in Android. By design, it is
234       meant to be used by a single handset user. On the other hand, Android
235       uses the Linux user/group management features extensively to secure
236       process permissions, like access to various filesystem directories.
237
238       In the Android scheme, each installed application gets its own
239       uid_t/gid_t starting from 10000; lower numerical ids are reserved for
240       system daemons.
241
242       getpwnam() recognizes some hard-coded subsystems names (e.g. "radio")
243       and will translate them to their low-user-id values. It also recognizes
244       "app_1234" as the synthetic name of the application that was installed
245       with uid 10000 + 1234, which is 11234. getgrnam() works similarly
246
247       getgrouplist() will always return a single group for any user name,
248       which is the one passed as an input parameter.
249
250       getgrgid() will similarly only return a structure that contains a
251       single-element members list, corresponding to the user with the same
252       numerical value than the group.
253
254       See bionic/libc/bionic/stubs.c for more details.
255
256    - getservent()
257
258       There is no /etc/services on Android. Instead the C library embeds a
259       constant list of services in its executable, which is parsed on demand
260       by the various functions that depend on it. See
261       bionic/libc/netbsd/net/getservent.c and
262       bionic/libc/netbsd/net/services.h
263
264       The list of services defined internally might change liberally in the
265       future. This feature is mostly historically and is very rarely used.
266
267       The getservent() returns thread-local data. getservbyport() and
268       getservbyname() are also implemented in a similar fashion.
269
270     - getprotoent()
271
272       There is no /etc/protocol on Android. Bionic does not currently
273       implement getprotoent() and related functions. If added, it will
274       likely be done in a way similar to getservent()
275
276DNS resolver:
277
278  Bionic uses a NetBSD-derived resolver library which has been modified in
279  the following ways:
280
281     - don't implement the name-server-switch feature (a.k.a. <nsswitch.h>)
282
283     - read /system/etc/resolv.conf instead of /etc/resolv.conf
284
285     - read the list of servers from system properties. the code looks for
286       'net.dns1', 'net.dns2', etc.. Each property should contain the IP
287       address of a DNS server.
288
289       these properties are set/modified by other parts of the Android system
290       (e.g. the dhcpd daemon).
291
292       the implementation also supports per-process DNS server list, using the
293       properties 'net.dns1.<pid>', 'net.dns2.<pid>', etc... Where <pid> stands
294       for the numerical ID of the current process.
295
296     - when performing a query, use a properly randomized Query ID (instead of
297       a incremented one), for increased security.
298
299     - when performing a query, bind the local client socket to a random port
300       for increased security.
301
302     - get rid of *many* unfortunate thread-safety issues in the original code
303
304  Bionic does *not* expose implementation details of its DNS resolver; the
305  content of <arpa/nameser.h> is intentionally blank. The resolver
306  implementation might change completely in the future.
307
308
309PThread Real-Time Timers:
310
311  timer_create(), timer_gettime(), timer_settime() and timer_getoverrun() are
312  supported.
313
314  Bionic also now supports SIGEV_THREAD real-time timers (see timer_create()).
315  The implementation simply uses a single thread per timer, unlike GLibc which
316  uses complex heuristics to try to use the less threads possible when several
317  timers with compatible properties are used.
318
319  This means that if your code uses a lot of SIGEV_THREAD timers, your program
320  may consume a lot of memory. However, if your program needs many of these
321  timers, it'd better handle timeout events directly instead.
322
323  Other timers (e.g. SIGEV_SIGNAL) are handled by the kernel and use much less
324  system resources.
325
326
327Binary Compatibility:
328
329  Bionic is *not* in any way binary-compatible with the GNU C Library, ucLibc
330  or any known Linux C library. This means several things:
331
332  - You cannot expect to build something against the GNU C Library headers and
333    have it dynamically link properly to Bionic later.
334
335  - You should *really* use the Android toolchain to build your program against
336    Bionic. The toolchain deals with many important details that are crucial
337    to get something working properly.
338
339  Failure to do so will usually result in the inability to run or link your
340  program, or even runtime crashes. Several random web pages on the Internet
341  describe how you can succesfully write a "hello-world" program with the
342  ARM GNU toolchain. These examples usually work by chance, if anything else,
343  and you should not follow these instructions unless you want to waste a lot
344  of your time in the process.
345
346  Note however that you *can* generate a binary that is built against the
347  GNU C Library headers and then statically linked to it. The corresponding
348  executable should be able to run (if it doesn't use dlopen()/dlsym())
349
350
351Dynamic Linker:
352
353  Bionic comes with its own dynamic linker (just like ld.so on Linux really
354  comes from GLibc). This linker does not support all the relocations
355  generated by other GCC ARM toolchains.
356
357
358C++ Exceptions Support:
359
360  At the moment, Bionic doesn't support C++ exceptions, what this really means
361  is the following:
362
363    - If pthread_once() is called with a C++ callback that throws an exception,
364      then the C library will keep the corresponding pthread_once_t mutex
365      locked. Any further call to pthread_once() will result in a deadlock.
366
367      A proper implementation should be able to register a C++ exception
368      cleanup handler before the callback to properly unlock the
369      pthread_once_t. Unfortunately this requires tricky assembly code that
370      is highly dependent on the compiler.
371
372      This feature is not planned to be supported anytime soon.
373
374    - The same problem may arise if you throw an exception within a callback
375      called from the C library. Fortunately, these cases are very rare in the
376      real-world, but any callback you provide to the C library should *not*
377      throw an exception.
378
379    - Bionic lacks a few support functions to have exception support work
380      properly.
381
382System V IPCs:
383
384  Bionic intentionally does not provide support for System-V IPCs mechanisms,
385  like the ones provided by semget(), shmget(), msgget(). The reason for this
386  is to avoid denial-of-service. For a detailed rationale about this, please
387  read the file docs/SYSV-IPCS.TXT.
388
389Include Paths:
390
391  The Android build system should automatically provide the necessary include
392  paths required to build against the C library headers. However, if you want
393  to do that yourself, you will need to add:
394
395      libc/arch-$ARCH/include
396      libc/include
397      libc/kernel/common
398      libc/kernel/arch-$ARCH
399
400  to your C include path.
401