{"id":26,"date":"2023-06-28T11:15:00","date_gmt":"2023-06-28T11:15:00","guid":{"rendered":"https:\/\/embeddedbits.org\/?p=26"},"modified":"2024-03-02T09:45:32","modified_gmt":"2024-03-02T09:45:32","slug":"what-differs-android-from-other-linux-based-systems-embeddedbits","status":"publish","type":"post","link":"https:\/\/embeddedbits.org\/what-differs-android-from-other-linux-based-systems-embeddedbits\/","title":{"rendered":"What differs Android from other Linux based systems?"},"content":{"rendered":"<p>This article is an introduction to embedded Android from the perspective of an embedded Linux developer.<\/p>\n<p>If you are an embedded Linux developer but have never worked with embedded Android, this article is for you. If you develop or maintain Linux distros, and I want to start developing Android distros, this article is for you. If you are an Android application developer and want to understand a bit of how Android (internally) works, this article is also for you. And if you are just curious, this article is also for you! \ud83d\ude42<\/p>\n<p>We will compare a GNU\/Linux system with Android in different perspectives, from the build system to the partition layout, from the content of the rootfs to the architecture of the operating system components, from the IPC\/RPC mechanism to how hardware access works. I hope you have fun!<\/p>\n<p>Now, if you prefer a one hour talk instead of reading this article, you can also watch the talk \u201cWhat Differs the Android Open Source Project from Other Linux Distributions?\u201d presented at Embedded Linux Conference Europe 2020 (<a href=\"http:\/\/www.youtube.com\/watch?v=kR-Cnoef1s4\">YouTube link<\/a>).<\/p>\n<p>Let\u2019s start with a high-level overview\u2026<\/p>\n<h2>The difference in a nutshell<\/h2>\n<p>If you look at the architecture of any embedded Linux system, you will always find the same main components:<\/p>\n<ol>\n<li>One or more bootloader(s) to bootstrap, configure the hardware and boot the Linux kernel.<\/li>\n<li>The Linux kernel.<\/li>\n<li>The root filesystem (rootfs) with the libraries and applications.<\/li>\n<\/ol>\n<p><img decoding=\"async\" src=\"http:\/\/embeddedbits.org\/images\/20210404-embedded-linux-arch.png\" \/><\/p>\n<p>Now, if you look at the same diagram for an Android-based system, what would be the differences?<\/p>\n<ol>\n<li>The bootloader is there. Android doesn\u2019t require anything special in the bootloader, although it is common for people to add support to <a href=\"http:\/\/android.googlesource.com\/platform\/bootable\/bootloader\/legacy\/+\/b1fde5cd7d5158b8e6876139ca76a341d0e49708\/fastboot_protocol.txt\">fastboot<\/a>, a protocol Google created for users and developers to interact with bootloaders on Android-based systems.<\/li>\n<li>The Linux kernel is also there, but with a \u201cfew\u201d changes. More on that later.<\/li>\n<li>The root filesystem is also there. But it is REALLY different! Nothing like a typical root filesystem from Debian or a custom-built rootfs from Buildroot or OpenEmbedded.<\/li>\n<\/ol>\n<p><img decoding=\"async\" src=\"http:\/\/embeddedbits.org\/images\/20210404-android-architecture.png\" \/><\/p>\n<p>As we can see from the image above, Android userspace components are clearly divided in three main layers:<\/p>\n<ol>\n<li>Native: this is where all native (C\/C++) applications and libraries resides. It is called native because it runs outside the ART Virtual Machine. The native layer basically serves the purpose of abstracting Linux kernel interfaces to the framework layer.<\/li>\n<li>Framework: this is where all operating system services are implemented (mostly in Java). Access to operating system resources are (remotely) exposed via components called system services, using an IPC\/RPC mechanism called Binder. And an API will abstract the access to those system services for the applications.<\/li>\n<li>Application: Usually written in Java or Kotlin, they just see the exposed operating system API.<\/li>\n<\/ol>\n<p>Before studying Android userspace components in details, let\u2019s talk a little bit about the kernel.<\/p>\n<h2>Linux kernel<\/h2>\n<p>To run an Android-based system, we need a few extra \u201cfeatures\u201d enabled in the Linux kernel. This article would be too long if I would try to go over most features, but I can comment on some:<\/p>\n<ul>\n<li>Binder: this is the IPC (Inter-Process Communication) and RPC (Remote Procedure Call) mechanism used in Android. You could do a rough comparition with DBUS, but DBUS runs in userspace, and Binder is a faster and lighter kernel-based implementation.<\/li>\n<li>Ashmem: the default shared memory allocator in Android (Google doesn\u2019t like POSIX SHM).<\/li>\n<li>Low memory killer: a logic built on top of the kernel\u2019s OOM (Out-of-Memory) killer, that in conjunction with a daemon (lmkd), helps to manage the system in low memory situations.<\/li>\n<\/ul>\n<p>Most of those features are already available in the mainline kernel, but if you want the full list of \u201cAndroidisms\u201d, you can clone <a href=\"http:\/\/android.googlesource.com\/kernel\/common\/\">Google\u2019s kernel-common repository<\/a> and search for commits starting with \u201cANDROID:&#8221;:<\/p>\n<pre><code>$ git clone https:\/\/android.googlesource.com\/kernel\/common kernel-common\n$ git checkout remotes\/origin\/android11-5.4\n$ git log --oneline | grep \"ANDROID:\" | less\n5427f8b72fc0 ANDROID: GKI: update xiaomi symbol list\necb88922f521 ANDROID: GKI: update Vivo symbol list\n32b242337266 ANDROID: sysrq: add vendor hook for sysrq crash information\n42e516f6b23b ANDROID: ABI: update allowed list for galaxy\nde198b0f2d39 ANDROID: GKI: update Vivo symbol list\n\n$ git log --oneline | grep \"ANDROID:\" | wc -l\n1157<\/code><\/pre>\n<p>Despite these (and a few other) main changes in the Linux kernel, Android really differs from an GNU\/Linux system in the userspace components and their architecture (the so-called Android platform), and the source-code for the Android platform is provided in a project called <a href=\"http:\/\/source.android.com\/\">AOSP<\/a> (Android Open Source Project).<\/p>\n<h2>AOSP<\/h2>\n<p>The AOSP is made of hundreds of repositories (specifically 780 in Android 11), and you can see all of them in <a href=\"http:\/\/android.googlesource.com\/\">https:\/\/android.googlesource.com\/<\/a>.<\/p>\n<p>The source code is managed with known tools like <a href=\"http:\/\/source.android.com\/setup\/develop\/repo\">repo<\/a> and <a href=\"http:\/\/git-scm.com\/\">git<\/a>, and it is huge! Android 11 is 100GB of source code plus 115GB after one build. So you really need a lot of disk space to work with the Android source code.<\/p>\n<p>Cloning the latest AOSP source code is as simple as running the two commands below (<em>-b<\/em> can be used in <em>repo init<\/em> to clone an specific <a href=\"http:\/\/source.android.com\/setup\/start\/build-numbers\">Android release tag or branch<\/a>):<\/p>\n<pre><code>$ repo init -u https:\/\/android.googlesource.com\/platform\/manifest\n$ repo sync<\/code><\/pre>\n<p>After a few hours, you will have the Android source code there in your machine:<\/p>\n<pre><code>$ ls\nAndroid.bp      dalvik       libcore           read-snapshot.txt\nart             developers   libnativehelper   sdk\nbionic          development  Makefile          system\nbootable        device       out               test\nbootstrap.bash  external     packages          toolchain\nbuild           frameworks   pdk               tools\ncompatibility   hardware     platform_testing\ncts             kernel       prebuilts<\/code><\/pre>\n<p>As an open source project, there are <a href=\"http:\/\/groups.google.com\/d\/forum\/android-platform\">several discussion groups<\/a> to communicate with the community and the developers, and anyone can contribute to the project via the <a href=\"http:\/\/android-review.googlesource.com\/\">Gerrit code review<\/a> tool.<\/p>\n<p>The vast majority of software components are under the permissive Apache and BSD licenses, some software components are under GPL\/LGPL licenses, and some Google applications are closed source (e.g. Google Play, Gmail, Google Maps, YouTube, etc). Those applications are available in a package called <a href=\"http:\/\/en.wikipedia.org\/wiki\/Google_mobile_services\">Google Mobile Services<\/a> (GMS), and to obtain them, you need to certify the device via <a href=\"http:\/\/source.android.com\/compatibility\/overview\">Android Compatibility Program<\/a> (ACP).<\/p>\n<p>When we download AOSP source code, we can see some differences when compared to other approaches for embedded Linux development.<\/p>\n<p>Unlike ready-to-be-used distros (e.g. Debian), you can easily download the full source code and build the distro from scratch (if you want to create a custom Debian system for example, you usually do it from pre-compiled packages).<\/p>\n<p>Comparing to build system approaches (e.g. Buildroot, OpenEmbedded), in Android it seems we have a \u201cbig application\u201d downloaded with the <em>repo sync<\/em> command. Of course this is not true. We have thousands of projects and repositories there, that will compose in the end the operating system images. And the responsibility to put everything together rests with the Android build system\u2026<\/p>\n<h2>Android build system<\/h2>\n<p>In previous Android versions, the build system was purely based on makefiles, where instructions for compiling each software component were defined in <em>Android.mk<\/em> files. Here is just an example of an <em>Android.mk<\/em> file to build a \u201cHello World\u201d C application in Android:<\/p>\n<table>\n<tbody>\n<tr>\n<td>\n<pre><code>1\n2\n3\n4\n5\n6\n7\n8\n<\/code><\/pre>\n<\/td>\n<td>\n<pre><code>LOCAL_PATH := $(call my-dir)\ninclude $(CLEAR_VARS) LOCAL_SRC_FILES = helloworld.c\nLOCAL_MODULE = helloworld\nLOCAL_MODULE_TAGS = optional include $(BUILD_EXECUTABLE)\n<\/code><\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The Makefile-based build system had several shortcomings, including low performance in incremental builds, and was replaced in the latest versions of Android by the <a href=\"http:\/\/android.googlesource.com\/platform\/build\/soong\">Soong build system<\/a>.<\/p>\n<p>In the Soong build system, the rules for compiling software components are defined in Blueprint files (<em>Android.bp<\/em>), which have a syntax similar to JSON. Here is the same example of building a \u201cHello World\u201d C application in Android, but using a Blueprint file:<\/p>\n<pre><code>cc_binary {\n    name: \"helloworld\",\n    srcs: [\"helloworld.c\"],\n    tags: [\"optional\"],\n}<\/code><\/pre>\n<p>Blueprint files are processed by a tool called <a href=\"http:\/\/opensource.google.com\/projects\/blueprint\">Blueprint<\/a>, which produces <em>.ninja<\/em> files with all the rules for compiling Android software components. The <em>.ninja<\/em> files are then processed by a tool called <a href=\"http:\/\/ninja-build.org\/\">Ninja<\/a>, which will compile all the software components and generate the Android images (more on the images later).<\/p>\n<p>As of this writing, not all makefiles (<em>Android.mk<\/em>) were converted to Blueprint files (<em>Android.bp<\/em>). For this reason, there is a tool called <a href=\"http:\/\/github.com\/google\/kati\">kati<\/a>, responsible for converting <em>Android.mk<\/em> files to <em>.ninja<\/em> files. Over time, all <em>Android.mk<\/em> files should gradually be converted to <em>Android.bp<\/em>, eliminating the need to use the kati tool in the Android build system.<\/p>\n<p>The following diagram is a summary of the Android build process:<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/embeddedbits.org\/images\/20210404-android-build-system.png\" \/><\/p>\n<p>Building Android is very simple. You can do it with three simple commands: one to source a script that will initialize the environment, the second to select the target device (<em>product-variant<\/em>), and the last to start the build. The commands below will build Android for the emulator:<\/p>\n<pre><code>$ source build\/envsetup.sh\n$ lunch aosp_x86_64-eng\n$ make<\/code><\/pre>\n<p>After a few hours, we have the images in <em>out\/target\/product\/<\/em>:<\/p>\n<pre><code>$ cd out\/target\/product\/generic_x86_64\/ &amp;&amp; ls *.img\ncache.img          super_empty.img    vbmeta.img\ndtb.img            super.img          vendor_boot-debug.img\nencryptionkey.img  system.img         vendor_boot.img\nramdisk-debug.img  system-qemu.img    vendor.img\nramdisk.img        userdata.img       vendor-qemu.img\nramdisk-qemu.img   userdata-qemu.img<\/code><\/pre>\n<p>Now, what are all those images? How is the rootfs organized in Android?<\/p>\n<h2>Rootfs organization and partition layout<\/h2>\n<p>The rootfs organization on Linux systems is (mostly) standardized, basically defined by two standards: <a href=\"http:\/\/www.pathname.com\/fhs\/\">Filesystem Hierarchy Standard<\/a> and <a href=\"http:\/\/wiki.linuxfoundation.org\/lsb\/start\">Linux Standard Base<\/a>.<\/p>\n<p>Linux distributions try to conform to these standards, making the applications easily portable, and simplifying the life of users and developers when they need to work with different Linux systems.<\/p>\n<p>But as you would expect, Android is an exception!<\/p>\n<p>This is the listing of the root partition of an Android system (Android 11, built for QEMU). May I ask you where is <em>\/sbin<\/em>, <em>\/usr<\/em>, <em>\/lib<\/em> and other common Linux system directories?<\/p>\n<pre><code># ls \/\nacct        d              etc              mnt      sdcard\napex        data           init             odm      storage\nbin         data_mirror    init.environ.rc  oem      sys\nbugreports  debug_ramdisk  linkerconfig     proc     system\ncache       default.prop   lost+found       product  system_ext\nconfig      dev            metadata         res      vendor<\/code><\/pre>\n<p>They are not there! In Android, operating system components (applications, libraries) are located in the <em>\/system<\/em> directory (mount point for the system partition), and user data\/configuration (including applications installed at runtime) is located in the <em>\/data<\/em> directory (mount point for the data partition). And there are many other partitions like cache (downloaded files and temporary data), vendor (specific files from the SoC manufacturer) and odm (specific files from the device manufacturer).<\/p>\n<p>This is a basic overview of the partition layout on Android 11 (may vary depending on the manufacturer\/device):<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/embeddedbits.org\/images\/20210404-android-partition-layout.png\" \/><\/p>\n<p>Very different from a typical embedded Linux system, right?<\/p>\n<p>So now, why don\u2019t we talk a little bit about the contents of the filesystem? Because they also differs, a lot. Let\u2019s start with the C library.<\/p>\n<h2>Android C library<\/h2>\n<p>One of the main components of an operating system based on the Linux kernel is the C library.<\/p>\n<p>The C library implements the operating system\u2019s API, providing an interface for applications to access kernel services through system calls.<\/p>\n<p>Several C libraries are available for Linux systems, including glibc, uclibc-ng and musl. But Android has its own C library: <a href=\"http:\/\/android.googlesource.com\/platform\/bionic\/\">Bionic<\/a>!<\/p>\n<p>I can imagine at least three reasons that may have motivated Google to implement its own C library: license, speed and size. The implementation is really simple, lightweight and released under the BSD license.<\/p>\n<p>One important thing to mention is that it doesn\u2019t have full POSIX support, which can make it more difficult to build native Linux applications for Android.<\/p>\n<p>See for example the code snippet below from <a href=\"http:\/\/git.busybox.net\/busybox\/tree\/libbb\/missing_syscalls.c?h=1_31_stable\">libbb\/missing_syscalls.c in BusyBox<\/a>. The <em>#if defined(ANDROID)<\/em> was required since some Bionic functions do not follow the POSIX standard.<\/p>\n<table>\n<tbody>\n<tr>\n<td>\n<pre><code> 1\n 2\n 3\n 4\n 5\n 6\n 7\n 8\n 9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n<\/code><\/pre>\n<\/td>\n<td>\n<pre><code>#if defined(ANDROID) || defined(__ANDROID__)\n\/*# include  - for struct timex, but may collide with  *\/\n# include \npid_t getsid(pid_t pid)\n{ return syscall(__NR_getsid, pid);\n} int sethostname(const char *name, size_t len)\n{ return syscall(__NR_sethostname, name, len);\n} struct timex;\nint adjtimex(struct timex *buf)\n{ return syscall(__NR_adjtimex, buf);\n} int pivot_root(const char *new_root, const char *put_old)\n{ return syscall(__NR_pivot_root, new_root, put_old);\n}<\/code><\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>And talking about BusyBox\u2026<\/p>\n<h2>Why doesn\u2019t Android use BusyBox?<\/h2>\n<p>It is very common to use BusyBox on embedded Linux devices.<\/p>\n<p>Busybox provides the (re)implementation of common tools and applications such as an init program, a shell and several utilities to manipulate and configure the system.<\/p>\n<p>But Android does not ship with BusyBox by default!<\/p>\n<p>Android uses two other (conceptually similar) implementations called <a href=\"http:\/\/android.googlesource.com\/platform\/system\/core.git\/+\/refs\/heads\/android11-mainline-release\/toolbox\/\">Toolbox<\/a> and <a href=\"http:\/\/landley.net\/toybox\/about.html\">Toybox<\/a>, both released under a BSD license. Toolbox is a tool implemented by Google and Toybox is a tool implemented by the community (started by Rob Landley, BusyBox ex-maintainer).<\/p>\n<p>And because these tools have some limitations, it is common to install BusyBox on an Android device, especially during development. One motivation would be to have a good text editor (<em>vi<\/em>) available in the command line.<\/p>\n<p>Now, an essential part of a Linux-based operating system is the init system. And how does the initialization work in Android?<\/p>\n<h2>Android init system<\/h2>\n<p>In a nutshell, the init application is executed by the kernel right after mounting the rootfs, being responsible for system initialization and management.<\/p>\n<p>There are several implementations of the init process for Linux systems, including sysvinit, systemd and upstart. And as you may already expect, Android has its own init system!<\/p>\n<p>The Android init process has 3 primary responsibilities:<\/p>\n<ol>\n<li>Initialize and configure the operating system execution environment (export environment variables, create and set permissions on files and directories, create links, mount file systems, setup selinux, etc).<\/li>\n<li>Start and monitor daemons.<\/li>\n<li>Manage system properties.<\/li>\n<\/ol>\n<p>The behavior of the init process is defined in a configuration file (<em>\/etc\/init\/hw\/init.rc<\/em> by default), and it\u2019s very different from any init configuration file we are used to. Here is a snippet from the default Android <em>init.rc<\/em> file:<\/p>\n<pre><code>import \/init.environ.rc\nimport \/system\/etc\/init\/hw\/init.usb.rc\nimport \/init.${ro.hardware}.rc\nimport \/vendor\/etc\/init\/hw\/init.${ro.hardware}.rc\nimport \/system\/etc\/init\/hw\/init.usb.configfs.rc\nimport \/system\/etc\/init\/hw\/init.${ro.zygote}.rc\n\n# Cgroups are mounted right before early-init using list from \/etc\/cgroups.json\non early-init\n    # Disable sysrq from keyboard\n    write \/proc\/sys\/kernel\/sysrq 0\n\n    # Android doesn't need kernel module autoloading, and it causes SELinux\n    # denials.  So disable it by setting modprobe to the empty string.  Note: to\n    # explicitly set a sysctl to an empty string, a trailing newline is needed.\n    write \/proc\/sys\/kernel\/modprobe n\n\n    ...\n\non init\n    sysclktz 0\n\n    # Mix device-specific information into the entropy pool\n    copy \/proc\/cmdline \/dev\/urandom\n    copy \/system\/etc\/prop.default \/dev\/urandom\n\n    symlink \/proc\/self\/fd\/0 \/dev\/stdin\n    symlink \/proc\/self\/fd\/1 \/dev\/stdout\n    symlink \/proc\/self\/fd\/2 \/dev\/stderr\n\n    ...\n\n# Mount filesystems and start core system services.\non late-init\n    trigger early-fs\n\n    # Mount fstab in init.{$device}.rc by mount_all command. Optional parameter\n    # '--early' can be specified to skip entries with 'latemount'.\n    # \/system and \/vendor must be mounted by the end of the fs stage,\n    # while \/data is optional.\n    trigger fs\n\non property:ro.debuggable=1\n    # Give writes to anyone for the trace folder on debug builds.\n    # The folder is used to store method traces.\n    chmod 0773 \/data\/misc\/trace\n    # Give reads to anyone for the window trace folder on debug builds.\n    chmod 0775 \/data\/misc\/wmtrace\n\nservice ueventd \/system\/bin\/ueventd\n    class core\n    critical\n    seclabel u:r:ueventd:s0\n    shutdown critical\n\nservice console \/system\/bin\/sh\n    class core\n    console\n    disabled\n    user shell\n    group shell log readproc\n    seclabel u:r:shell:s0\n    setenv HOSTNAME console\n\n...<\/code><\/pre>\n<p>It is indeed very different. You have declarations of actions (e.g. <em>on init<\/em>) and declarations of services (e.g. <em>service console \/system\/bin\/sh<\/em>). When an action is triggered at boot time, let\u2019s say <em>early-init<\/em>, the commands declared in that trigger will be executed.<\/p>\n<p>There are a lot of details here, but we don\u2019t have much space in this article to talk about it (we could actually have a full article on this). For now, let\u2019s focus on an important piece of this puzzle, the daemons!<\/p>\n<h2>Android daemons<\/h2>\n<p>Daemons are processes that run in the background and are responsible for managing some system functionality. Most of them are executed at startup by the init process, and usually they run in the background for as long as the system is functional.<\/p>\n<p>Daemons are normally used to control and centralize access to a system resource, and on Android, many daemons are an interface between the Android framework (Java code) and system resources (network, storage, energy, radio, logging, etc). Some examples:<\/p>\n<ul>\n<li><em>ueventd<\/em>: responsible for managing the connection of hardware devices (device hotplugging). It is the equivalent of udev or mdev on GNU\/Linux systems.<\/li>\n<li><em>vold<\/em>: (volume daemon) is responsible for monitoring events from storage devices.<\/li>\n<li><em>rild<\/em>: (radio interface layer daemon) manages communication with the modem chip (voice and data).<\/li>\n<li><em>netd<\/em>: (network management service daemon) is responsible for managing network connections (Bluetooth, Wi-Fi, USB, etc). It is the equivalent of NetworkManager or connman on GNU\/Linux systems.<\/li>\n<li><em>installd<\/em>: (install daemon) is responsible for managing the installation of Android applications (* .apk) and their associated resources.<\/li>\n<li><em>lmkd<\/em>: (low memory killer daemon) is responsible for managing the kernel low memory killer interface.<\/li>\n<\/ul>\n<p>Here is a (mostly) complete list of daemons running on Android 11:<\/p>\n<pre><code># ps -A\nUSER            PID   PPID     VSZ    RSS WCHAN            ADDR S NAME                       \nroot              1      0 10782796  9696 do_epoll_+          0 S init\nroot            122      1 10761204  7376 do_sys_po+          0 S ueventd\nlogd            145      1 10764228  7932 __x64_sys+          0 S logd\nlmkd            146      1 10756496  2456 do_epoll_+          0 S lmkd\nsystem          147      1 10759476  5016 do_epoll_+          0 S servicemanager\nsystem          148      1 10761244  6488 do_epoll_+          0 S hwservicemanager\nsystem          149      1 10759572  4028 do_epoll_+          0 S vndservicemanager\nroot            153      1 10770096  8732 binder_th+          0 S vold\ntombstoned      250      1 10755388  2128 do_epoll_+          0 S tombstoned\nstatsd          266      1 10766140  4572 do_epoll_+          0 S statsd\nroot            267      1 10781776  9532 binder_th+          0 S netd\ncredstore       306      1 10764440  7296 binder_th+          0 S credstore\ngpu_service     307      1 10762672  6804 binder_th+          0 S gpuservice\nsystem          308      1 10873496 31972 do_epoll_+          0 S surfaceflinger\nroot            316      1 10756876  2656 do_sys_po+          0 S netmgr\nroot            318      1 10758880  3072 do_sys_po+          0 S wifi_forwarder\nwifi            320      1 10759960  5464 do_select           0 S hostapd_nohidl\nlogd            326      1 10756544  3160 __skb_wai+          0 S logcat\nroot            352      1 10773084  6376 0                   0 S adbd\nnobody          354      1 10757496  3164 do_sys_po+          0 S traced_probes\nnobody          355      1 10757632  3464 do_sys_po+          0 S traced\ncameraserver    356      1   58984  17240 binder_th+          0 S cameraserver\ndrm             357      1   25952   6512 binder_th+          0 S drmserver\nincidentd       359      1 10761968  4992 do_epoll_+          0 S incidentd\nroot            360      1 10765704  6452 binder_th+          0 S installd\niorapd          361      1 10775424  9536 futex_wai+          0 S iorapd\nkeystore        362      1 10764916  7404 binder_th+          0 S keystore\nroot            366      1 10765596  5648 binder_th+          0 S storaged\n...<\/code><\/pre>\n<p>Have you realized that almost all daemons are Android specific? Yes, they really are. Android is an operating system where almost all userspace components were built from scratch!<\/p>\n<p>In particular, it is worth mentioning how logging works on Android, since it doesn\u2019t use common logging Linux daemons like journald or rsyslog. So let\u2019s talk about this now.<\/p>\n<h2>Android logging system<\/h2>\n<p>In Android, the log daemon (<em>logd<\/em>) is responsible for managing all operating system logs, from applications down to the framework and native applications.<\/p>\n<p>Access to logs is done through sockets exported in <em>\/dev\/socket\/<\/em>:<\/p>\n<pre><code># ls \/dev\/socket\/logd*\n\/dev\/socket\/logd  \/dev\/socket\/logdr  \/dev\/socket\/logdw<\/code><\/pre>\n<p>To read or write to the logs, it\u2019s not necessary to directly access these sockets. For this, applications can use the <em>liblog<\/em> library. And in the terminal, the user can write to the logs with the <em>log<\/em> command, and read the logs using the <em>logcat<\/em> tool:<\/p>\n<pre><code># logcat\n...\n10-14 13:36:51.722   771   934 D SmsNumberUtils: enter filterDestAddr. destAddr=\"[BajqU4K5_YhSYbs-7QUn0dOwcmI]\"\n10-14 13:36:51.723   771   934 D SmsNumberUtils: destAddr is not formatted.\n10-14 13:36:51.723   771   934 D SmsNumberUtils: leave filterDestAddr, new destAddr=\"[BajqU4K5_YhSYbs-7QUn0dOwcmI]\"\n10-14 13:36:57.054   316   316 E netmgr  : qemu_pipe_open_ns:62: Could not connect to the 'pipe:qemud:network' service: \n10-14 13:36:57.054   316   316 E netmgr  : Failed to open QEMU pipe 'qemud:network': Invalid argument\n10-14 13:36:57.324   318   318 E wifi_forwarder: qemu_pipe_open_ns:62: Could not connect to the 'pipe:qemud:wififorward' service: \n10-14 13:36:57.325   318   318 E wifi_forwarder: RemoteConnection failed to initialize: RemoteConnection failed to open pipe\n...\n10-14 14:37:45.408   494  1324 D WifiNl80211Manager: Scan result ready event\n10-14 14:37:45.408   494  1324 D WifiNative: Scan result ready event\n10-14 14:37:59.109   316   316 E netmgr  : qemu_pipe_open_ns:62: Could not connect to the 'pipe:qemud:network' service: \n10-14 14:37:59.109   316   316 E netmgr  : Failed to open QEMU pipe 'qemud:network': Invalid argument\n10-14 14:37:59.574   318   318 E wifi_forwarder: qemu_pipe_open_ns:62: Could not connect to the 'pipe:qemud:wififorward' service: \n10-14 14:37:59.575   318   318 E wifi_forwarder: RemoteConnection failed to initialize: RemoteConnection failed to open pipe\n10-14 14:38:00.003   642   642 D KeyguardClockSwitch: Updating clock: 2\uee0138\n10-14 14:38:59.127   316   316 E netmgr  : qemu_pipe_open_ns:62: Could not connect to the 'pipe:qemud:network' service: \n10-14 14:38:59.127   316   316 E netmgr  : Failed to open QEMU pipe 'qemud:network': Invalid argument\n10-14 14:38:59.585   318   318 E wifi_forwarder: qemu_pipe_open_ns:62: Could not connect to the 'pipe:qemud:wififorward' service: \n10-14 14:38:59.585   318   318 E wifi_forwarder: RemoteConnection failed to initialize: RemoteConnection failed to open pipe\n10-14 14:39:00.003   642   642 D KeyguardClockSwitch: Updating clock: 2\uee0139\n10-14 14:39:59.142   316   316 E netmgr  : qemu_pipe_open_ns:62: Could not connect to the 'pipe:qemud:network' service: \n10-14 14:39:59.142   316   316 E netmgr  : Failed to open QEMU pipe 'qemud:network': Invalid argument\n10-14 14:39:59.634   318   318 E wifi_forwarder: qemu_pipe_open_ns:62: Could not connect to the 'pipe:qemud:wififorward' service: \n10-14 14:39:59.634   318   318 E wifi_forwarder: RemoteConnection failed to initialize: RemoteConnection failed to open pipe\n10-14 14:40:00.006   642   642 D KeyguardClockSwitch: Updating clock: 2\uee0140\n...<\/code><\/pre>\n<p>After several years working with Android, I can say that the Android logging system is pretty decent and very useful when developing in the platform.<\/p>\n<p>And talking about development, when porting Android to an embedded device, writing code that will talk to the hardware is an important part of the process. So why don\u2019t we talk now about how hardware access works in Android?<\/p>\n<h2>Hardware access and Android HAL<\/h2>\n<p>On an embedded Linux system, access to hardware devices is usually exposed to applications via entries in <em>\/dev<\/em> or <em>\/sys<\/em>. But on Android, we rely on an additional layer called <a href=\"http:\/\/source.android.com\/devices\/architecture\">HAL<\/a> (Hardware Abstraction Layer) to abstract access to hardware devices.<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/embeddedbits.org\/images\/20210404-android-hal.png\" \/><\/p>\n<p>The main idea is to decouple the system services (more on it later) from the interfaces exposed by the Linux kernel, so if a kernel interface change, you have just to replace the HAL, and the system services will keep working. Most HALs are basically services running as a separated process that exposes an interface (declared in a language called <a href=\"http:\/\/source.android.com\/devices\/architecture\/hidl\">HIDL<\/a>) consumed via Binder. There are HAL definitions and implementations for most <a href=\"http:\/\/source.android.com\/devices\">supported hardware devices in Android<\/a> like displays, cameras, audio, sensors, etc.<\/p>\n<p>But to completely understand the picture above, we have to talk about the Android framework and the system services.<\/p>\n<h2>Android framework and system services<\/h2>\n<p>So the Android framework is where all Java (and also now Kotlin) code are. We have there the system services and the APIs exposed to applications.<\/p>\n<p>The system services in particular are a very important part of the Android operating system. They are basically objects that expose an interface (via Binder) to be consumed by other system services and applications (via API).<\/p>\n<p>On an Android terminal, you can list the system services with the command below:<\/p>\n<pre><code># service list\nFound 184 services:\n0       DockObserver: []\n1       SurfaceFlinger: [android.ui.ISurfaceComposer]\n2       accessibility: [android.view.accessibility.IAccessibilityManager]\n3       account: [android.accounts.IAccountManager]\n4       activity: [android.app.IActivityManager]\n5       activity_task: [android.app.IActivityTaskManager]\n6       adb: [android.debug.IAdbManager]\n7       alarm: [android.app.IAlarmManager]\n8       android.hardware.identity.IIdentityCredentialStore\/default: [android.hardware.identity.IIdentityCredentialStore]\n9       android.hardware.light.ILights\/default: [android.hardware.light.ILights]\n10      android.hardware.power.IPower\/default: [android.hardware.power.IPower]\n11      android.hardware.rebootescrow.IRebootEscrow\/default: [android.hardware.rebootescrow.IRebootEscrow]\n12      android.hardware.vibrator.IVibrator\/default: [android.hardware.vibrator.IVibrator]\n13      android.security.identity: [android.security.identity.ICredentialStoreFactory]\n14      android.security.keystore: [android.security.keystore.IKeystoreService]\n15      android.service.gatekeeper.IGateKeeperService: [android.service.gatekeeper.IGateKeeperService]\n16      app_binding: []\n17      app_integrity: [android.content.integrity.IAppIntegrityManager]\n18      appops: [com.android.internal.app.IAppOpsService]\n19      appwidget: [com.android.internal.appwidget.IAppWidgetService]\n20      audio: [android.media.IAudioService]\n21      auth: [android.hardware.biometrics.IAuthService]\n...<\/code><\/pre>\n<p>Let\u2019s say you are writing an Android application to read a sensor. This is what is going to happen:<\/p>\n<ol>\n<li>The application will call methods from the Android API (SensorManager) to request data from the sensor.<\/li>\n<li>The API (SensorManager) will send a message (via Binder) to a system service (in this case SensorService).<\/li>\n<li>The system service is responsible for managing the access to the resource it controls. In this example, the SensorService manages the access to sensors. And the first thing it will do is check for permissions: does the application has permission to access the sensors? If not, it will return an exception to the application. If access is granted, it will send a message via Binder to the HAL (Sensors HAL) to request data from the sensor.<\/li>\n<li>The Sensors HAL will read the sensor, probably via files exposed by a kernel IIO driver, and return the data to the system service (SensorService).<\/li>\n<li>The system service (SensorService) will return sensor data to the application.<\/li>\n<\/ol>\n<p>Here is another diagram explaining how those components communicate with each other:<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/embeddedbits.org\/images\/20210404-android-service.png\" \/><\/p>\n<p>Now you see how Android really differs from a typical Linux system?<\/p>\n<p>And we still need to talk about applications\u2026<\/p>\n<h2>Android applications<\/h2>\n<p>One of the advantages of using Android on embedded devices is the <a href=\"http:\/\/developer.android.com\/reference\/packages.html\">well-defined set of APIs<\/a>, which simplifies the development a lot and improves productivity significantly.<\/p>\n<p>In Android, applications are written in Java or Kotlin using the Google SDK, and packaged in files with the <em>.apk<\/em> extension, which contains the compiled code, data and resources used by the application.<\/p>\n<p>Android applications are basically composed of 4 types of components: activities, services, broadcast receivers and content providers. An application can contain one or more components, and one nice thing is that components can be reused and communicate with each other via a mechanism called <a href=\"http:\/\/developer.android.com\/guide\/components\/intents-filters\">intent<\/a>.<\/p>\n<p>In the end, even if we want to work with Android but don\u2019t care about the operating system internal architecture, we still need to learn the Android paradigm, that again, differs a lot from usual Linux application development, let\u2019s say in Qt or GTK.<\/p>\n<p>Let\u2019s wrap up now?<\/p>\n<h2>Is Android a Linux distribution or not?<\/h2>\n<p>We could see in this article that Android really differs from a typical GNU\/Linux system, from the way we manage the source code and build the system, to the organization and components of the filesystem, and the modular architecture where all components communicate via IPC\/RPC.<\/p>\n<p>The only similarity we can clearly see is the usage of the Linux kernel. Almost everything else is different in Android.<\/p>\n<p>So is Android a Linux distribution?<\/p>\n<p>It depends on how you \u201cclassify\u201d a Linux distribution. If a Linux distribution is any system that uses the Linux kernel, then we can probably say that Android is a Linux distribution. If a Linux distribution is a system that follows the same standards and shares some common components, like those provided by the GNU project, then Android is definitely not a Linux distribution.<\/p>\n<p>It is important to mention that Android is evolving a lot over time. One of the main challenges that Google faces is software updates. They cannot update any device out there because it is not in their control.<\/p>\n<p>Apple manufactures the SoC, the device itself (of course!) and the software, controlling almost every aspect of the supply chain. So they can update all devices in the field (at any time) if they want.<\/p>\n<p>Now Google doesn\u2019t have this ability. With the exception of Pixel devices, they don\u2019t have much control over devices manufactured by other companies like Samsung or Xiaomi.<\/p>\n<p>But they want this kind of control. And that is why they created projects to improve this situation, like <a href=\"http:\/\/android-developers.googleblog.com\/2017\/05\/here-comes-treble-modular-base-for.html\">Project Trebble<\/a>, <a href=\"http:\/\/source.android.com\/setup\/build\/gsi\">Generic System Images<\/a> and <a href=\"http:\/\/source.android.com\/devices\/architecture\/kernel\/generic-kernel-image\">Generic Kernel Image<\/a>.<\/p>\n<p>Many of the architectural designs we saw in this article came from those projects, and probably there will be more to come. If it\u2019s for the better, only the users and the market will tell.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This article is an introduction to embedded Android from the perspective of an embedded Linux developer. If you are an embedded Linux developer but have never worked with embedded Android, this article is for you. If you develop or maintain Linux distros, and I want to start developing Android distros, this article is for you. [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":140,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-26","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog"],"_links":{"self":[{"href":"https:\/\/embeddedbits.org\/wp-json\/wp\/v2\/posts\/26","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/embeddedbits.org\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/embeddedbits.org\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/embeddedbits.org\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/embeddedbits.org\/wp-json\/wp\/v2\/comments?post=26"}],"version-history":[{"count":3,"href":"https:\/\/embeddedbits.org\/wp-json\/wp\/v2\/posts\/26\/revisions"}],"predecessor-version":[{"id":103,"href":"https:\/\/embeddedbits.org\/wp-json\/wp\/v2\/posts\/26\/revisions\/103"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/embeddedbits.org\/wp-json\/wp\/v2\/media\/140"}],"wp:attachment":[{"href":"https:\/\/embeddedbits.org\/wp-json\/wp\/v2\/media?parent=26"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/embeddedbits.org\/wp-json\/wp\/v2\/categories?post=26"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/embeddedbits.org\/wp-json\/wp\/v2\/tags?post=26"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}