| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 1 | Bionic C Library Overview: | 
|  | 2 | ========================== | 
|  | 3 |  | 
|  | 4 | Introduction: | 
|  | 5 |  | 
|  | 6 | Core 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 |  | 
|  | 22 | Architectures: | 
|  | 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 |  | 
|  | 36 | Syscall 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 |  | 
|  | 57 | time_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 |  | 
| The Android Open Source Project | edbe7fc | 2009-03-18 22:20:24 -0700 | [diff] [blame] | 66 | strftime() uses time64_t internally, so the '%s' format (seconds since the | 
|  | 67 | epoch) is supported for dates >= 2038. | 
|  | 68 |  | 
|  | 69 |  | 
|  | 70 | strftime_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 |  | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 78 |  | 
|  | 79 | Timezone 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 |  | 
|  | 90 | off_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 |  | 
|  | 97 | Linux 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 |  | 
|  | 114 | PThread 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 |  | 
|  | 148 | pthread_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 |  | 
|  | 179 | pthread_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 |  | 
|  | 192 | Thread-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 |  | 
|  | 210 | Multi-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 |  | 
|  | 217 | Android-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 |  | 
|  | 276 | DNS 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 |  | 
|  | 309 | PThread 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 |  | 
|  | 327 | Binary 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 |  | 
|  | 351 | Dynamic 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 |  | 
|  | 358 | C++ 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 |  | 
|  | 382 | System 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 |  | 
|  | 389 | Include 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. |