Skip to content

n4q7x/Baconator

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 

Repository files navigation

Baconator

An operating system is a privileged program that abstracts hardware resources and enforces protection, providing higher-level programs with controlled access to the CPU, memory, storage, I/O devices, and communication mechanisms. Formally, it implements: (1) a resource allocator, (2) a program execution environment, and (3) a protection/security boundary. Its functional surface is exposed via system calls, device drivers, interrupt handling, and process scheduling.

Operating System = Kernel + Device Drivers + Memory Management Subsystem + Process and Thread Scheduler + System Call Interface + Interrupt Handlers + File System Implementation + Networking Stack + IPC (Inter-Process Communication) Mechanisms + Security / Permissions Model + Bootstrapping / Initialization Code

Android as an Operating System

Android is an operating system because it contains every major component of a modern OS: a kernel, device drivers, memory management, scheduling, system calls, IPC, security, filesystems, networking, and a boot process. Each of these components exists in Android in a specific, Android-optimized form. Below is a structured breakdown of these components and how Android implements them.


1. Kernel

Android uses a modified Linux kernel.
It includes:

  • Standard Linux kernel subsystems (scheduler, virtual memory, VFS, networking)
  • Android-specific patches:
    • Binder (Android’s IPC mechanism)
    • Wakelocks for power management
    • Low Memory Killer / LMKD
    • SELinux enforcing mode
    • Android-specific sensor, touchscreen, and radio drivers

2. Device Drivers

Android’s drivers come from:

  • Standard Linux device drivers
  • Vendor drivers for GPU, modem, camera, and sensors
  • The Android HAL (Hardware Abstraction Layer):
    • Defines stable interfaces for hardware features
    • Allows Android to run on many different devices without rewriting the framework
    • Maps framework calls → vendor-specific driver behavior

3. Memory Management Subsystem

Android inherits the Linux virtual memory subsystem with enhancements:

  • cgroups for resource limits and app isolation
  • ashmem or ION/dmabuf for shared memory
  • Low Memory Killer daemon (Android’s OOM behavior)
  • ZRAM / compressed swap used on many devices
  • Per-app memory limits enforced by ActivityManager and cgroups

4. Process and Thread Scheduler

Android uses the Linux CFS scheduler, with Android-specific policies:

  • Each app runs in its own Linux process
  • Every app has:
    • Its own UID
    • Its own SELinux domain
    • A cgroup for CPU/memory scheduling
  • Foreground apps get priority
  • Background apps are throttled or cached
  • Cached apps may be killed when RAM is low

5. System Call Interface

Android inherits the Linux system call interface:

  • open(), read(), write(), mmap(), futex()
  • fork(), execve()
  • socket(), send(), recv()

But app developers never call syscalls directly.
Instead, Android apps call:

App → Framework API → System Service → Binder → Native code → Kernel syscall


6. Interrupt Handling

Handled by the Linux kernel:

  • Hardware interrupts (touchscreen, sensors, modem)
  • Timer interrupts
  • Syscall traps (via SVC on ARM)
  • Passed to drivers → HAL → system services → framework

7. File System Implementation

Android uses:

  • ext4 or f2fs for internal storage
  • binderfs for IPC nodes
  • Partition layout:
    • /system
    • /vendor
    • /data
    • /product
  • Per-app sandbox directories:
    • /data/data/<package>
    • /sdcard/Android/data/<package>
  • Heavily SELinux-labeled paths

8. Networking Stack

Android inherits Linux networking:

  • Full TCP/IP stack
  • iptables / nftables
  • DHCP, Wi-Fi, cellular data
    Android adds:
  • ConnectivityService
  • NetworkManager
  • APIs for handoff between Wi-Fi and cell networks

9. Inter-Process Communication (IPC)

Android’s primary IPC system is:

Binder

  • Kernel-level driver
  • Synchronous RPC semantics
  • Used by apps, system services, and HALs
  • Absolutely central to Android

Other IPC mechanisms:

  • Unix domain sockets
  • Shared memory (ashmem / dmabuf)
  • System properties service

10. Security Model

Android’s security architecture includes:

  • Per-app Linux UID sandboxing
  • SELinux in enforcing mode
  • Verified Boot
  • Mandatory app code-signing
  • Runtime permission model (camera, mic, location)
  • Sandboxed per-app data directories
  • Isolated processes (for WebView, media codecs)

11. Boot Process

Android’s boot sequence:

  1. OEM bootloader
  2. Verified Boot chain
  3. Load modified Linux kernel
  4. Android init (custom, not systemd)
  5. Start core services
  6. Launch Zygote (template process)
  7. Zygote forks:
    • system_server
    • Application processes on demand

Summary

Android fully qualifies as an operating system because it implements all core OS responsibilities: managing processes, memory, filesystems, hardware drivers, IPC, networking, and security through a structured and deeply integrated software stack built on the Linux kernel and extended with Android-specific services and abstractions.

Virtualizing Android

Given all of the above, it becomes clear that if you want to run an Android app on a non-Android system, it is not enough to simply emulate the ARM CPU instructions. Android apps depend on the entire Android OS stack — the Android framework, the system services, Binder IPC, the HAL, and the modified Linux kernel beneath them.

So virtualizing Android means recreating or translating all of the Android OS behaviors, not just the opcodes.

Strictly speaking, Android apps do not call Linux syscalls directly. Instead, an Android app calls:

App → Android Framework API → System Services → Binder IPC → Native Code → Linux Kernel

Therefore, to run an Android app on top of some other operating system (e.g. macOS, Linux desktop, Windows), you would need to provide:

  • an implementation of the Android Runtime (ART)
  • the Android Framework (Java/Kotlin APIs)
  • all the Android system services (ActivityManager, LocationService, Telephony, PackageManager, etc.)
  • a working Binder IPC system
  • a functional HAL layer or equivalent hardware simulation
  • translations of Android’s expectations into the host OS’s syscalls and drivers

In effect, you must either:

  1. Run a full Android OS inside a VM, so that all Android syscalls and framework calls behave exactly as expected,
    or
  2. Reimplement the entire Android OS stack on top of the host OS, translating Android’s APIs and Binder calls into the host system’s own syscall and driver model.

This is why Android virtualization is hard: an Android app isn’t just “an ARM program.” It is a program written for the Android operating system, and to run it, you must supply that operating system — or a perfect simulation of it.

I have been researching how to set this up for a while, and the hardest part has been understanding how to virtualize Android.

I am only just getting into systems-level programming, assembly, and operating systems, so I am working on understanding some fundamentals.

There are lots of different operating systems out there, but many of them run on the same underlying CPU instruction set. A CPU instruction set is generally a collection of binary strings. Like if it's a 32 bit instruction set, every command is literally some 32-bit binary string. (Roughly, maybe this is wrong).

However, an operating system is more like a collection of APIs, it is not just the ability to talk to a CPU in opcodes.

So when you have an Android app, it needs:

  • the Android kernel

If you are just learning this like I am: one hears the word kernel a lot without necessarily knowing what it specifically is. The kernel is the "privileged core" of the operating system that manages hardware.

A kernel often has 4 fundamental responsibilities:

Memory management.

Process and thread management.

Hardware and device management.

System calls.

An Android app expects more than “some random ARM chip.” It expects:

  • An Android kernel and userspace (the Android-specific Linux kernel, the bionic C library, the Android runtime/ART, system services, etc.).
  • The right application binary interface (ABI) for any native libraries in the APK (for example, arm64-v8a vs armeabi-v7a).
  • A set of Android framework APIs that behave in certain ways.

So just having an ARM CPU (like Apple Silicon) isn’t enough. You also need an Android environment running on that CPU. That’s where emulators, virtual machines, and containers come in: they give the app the illusion that it’s living inside a normal Android device.

There is another subtle point about “hardware” versus “syscalls.”

A typical Android app does not talk directly to the SIM card, antenna, or GPS chip. It doesn’t open /dev/radio0 and wiggle bits. Instead, it calls higher-level Android framework APIs like:

  • TelephonyManager for SIM and cellular information,
  • LocationManager for GPS,
  • Camera APIs,
  • Sensor APIs, and so on.

Those framework calls get routed to privileged system services, which in turn talk to kernel drivers and hardware.

So when I run Android inside a VM or some weird environment, the main questions are:

  • Does the Android system image itself boot and run normally on this CPU?
  • Which Android “features” does the system claim to have? (Telephony, GPS, accelerometer, etc.)
  • What happens when an app calls a feature that the environment doesn’t really support?

If the VM/device simply doesn’t expose telephony, for example, an app might see “no SIM,” or the telephony APIs might return null, throw exceptions, or just be missing entirely. Many apps are written to handle this (e.g., they work fine on Wi-Fi–only tablets that have no SIM), so they’ll keep running and just disable those bits of functionality. Other apps are sloppy and might crash if they assume the hardware is always there.

In other words:

  • Yes, you can often get Android apps to run as long as the CPU architecture and Android environment line up.
  • No, the CPU alone is not enough: you need the whole Android stack, not just “any ARM chip.”
  • Missing hardware features don’t usually map to literal “missing syscalls” from the app’s point of view. They show up as missing or failing Android framework features that the app may or may not handle gracefully.

This is the conceptual background for what I’m calling Baconator: taking advantage of the fact that the CPU instructions are compatible, but carefully recreating just enough of the Android world (kernel, runtime, and features) that the apps I care about will actually run.

About

An example of how to automate interaction with an Android app and why it's useful (i.e., bidirectional data syncing, ETL)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors