For the complete documentation index, see llms.txt. This page is also available as Markdown.

Interview AOSP 1

Boot

1. Walk through the complete Android boot sequence from power-on to system_server startup.

Answer:

  1. SoC Boot ROM: Loads and verifies the bootloader from boot media (eMMC/UFS/SSD).

  2. Bootloader (e.g., U-Boot/LK): Initializes DRAM, loads boot.img (kernel + ramdisk), verifies AVB signatures, and jumps to the kernel.

  3. Kernel: Decompresses, sets up memory management, mounts rootfs from the ramdisk, executes /init as PID 1.

  4. First-Stage Init (/system/bin/init): Lives in the initramfs. It mounts system, vendor, product partitions using fstab, then execs /system/bin/init entering second stage.

  5. Second-Stage Init: Parses init.rc scripts, triggers early-initinitlate-init. It starts core daemons (ueventd, logd, servicemanager).

  6. Zygote: Started by an init.rc service. Preloads common Java classes and resources.

  7. Zygote Forks System Server: Zygote receives a start-system-server argument and forks a dedicated process.

  8. System Server: Enters com.android.server.SystemServer.main(), initializes all Java system services.

// system/core/init/init.cpp - Second stage entry
int SecondStageMain(int argc, char** argv) {
    // ...
    InitKernelLogging(argv);
    // Parse init.rc
    ActionManager& am = ActionManager::GetInstance();
    Parser& parser = Parser::GetInstance();
    parser.ParseConfig("/system/etc/init/hw/init.rc");
    // ...
    while (true) {
        // Execute pending commands
        am.ExecuteOneCommand();
    }
}

2. What is the role of the Boot ROM, and how does it verify the next stage bootloader?

Answer: The Boot ROM is mask-programmed into the SoC. It locates the bootloader from a predefined physical offset. Verification uses a Root of Trust public key (often fused in OTP/eFuses) to verify a digital signature over the bootloader image.


3. Explain the differences between U-Boot, Little Kernel (LK), and proprietary bootloaders in AOSP.

Answer:

  • U-Boot: Open-source, highly configurable, common on ARM64 development boards. Supports complex scripting and network boot.

  • Little Kernel (LK): Minimalist bootloader from Qualcomm. Fast, small footprint. Used extensively on Qualcomm devices. Supports fastboot protocol natively.

  • Proprietary Bootloaders: OEM-specific (e.g., Samsung S-Boot). Often closed-source, tightly coupled to SoC security features, and may implement custom download/verification protocols.

AOSP expects the bootloader to implement the fastboot protocol and AVB (Android Verified Boot) interfaces.


4. How does avb_verify work in the context of Verified Boot 2.0 (AVB)?

Answer: AVB 2.0 uses a hashtree for integrity and a signed vbmeta structure. The bootloader calls avb_slot_verify() which:

  1. Reads vbmeta partition.

  2. Verifies the signature chain against the trusted public key.

  3. For each partition listed in descriptors, verifies the digest in the hashtree root against the signed expected value.

  4. Sets the androidboot.verifiedbootstate kernel cmdline parameter.


5. What is the purpose of the boot.img header, and how do the V3 and V4 formats differ from V1/V2?

Answer: The boot.img header tells the bootloader where the kernel, ramdisk, and DTB are located within the partition.

  • V1/V2: Contained kernel, ramdisk, second stage, recovery DTBO, and DTB. V2 added boot.img signature for AVB.

  • V3 (Android 11+): Simplified. Removed second stage, recovery DTBO. Added vendor_boot partition to hold vendor ramdisk and kernel modules. Header size reduced.

  • V4 (Android 12+): Extends V3 to support multiple vendor ramdisk fragments for GKI (Generic Kernel Image) modules.


6. Describe the process of loading and verifying the vendor_boot partition.

Answer: The bootloader loads vendor_boot alongside boot. The vendor_boot image contains:

  • Vendor ramdisk (modules, vendor-specific init scripts)

  • DTB (Device Tree Blob)

  • Kernel command line fragments

The bootloader concatenates the kernel cmdline from boot and vendor_boot. AVB verification ensures the vendor_boot hashtree matches the descriptor in vbmeta.


7. How does the bootloader pass the kernel command line and device tree (DTB) to the Linux kernel?

Answer: The bootloader passes the command line via a CPU register (e.g., x0/r0 pointing to a structure) or by placing it in the device tree /chosen/bootargs node. The DTB is passed via a dedicated register pointing to its physical address.

In start_kernel(), the architecture-specific setup code parses these:

  • setup_arch() extracts the DTB address.

  • early_init_dt_scan() parses /chosen/bootargs into boot_command_line.


8. What is the role of init in early userspace, and how does it parse init.rc scripts?

Answer: init is PID 1. It sets up the userspace environment: creates directories, mounts filesystems, starts daemons, and sets permissions. It parses init.rc using a lexer/parser built into system/core/init/.

The Parser class handles three types of statements: Actions (on trigger), Commands (within actions), and Services (background processes).


9. Explain the difference between early-init, init, and late-init stages in init.rc.

Answer:

  • early-init: Runs before any device nodes are created. Used for initial cgroup setup, proc/sys mounts, and setting up the init environment.

  • init: Runs after device coldplug (ueventd has processed /sys). Used for creating directories, symlinks, and setting permissions.

  • late-init: Runs after all init actions. Triggers module loading, property setup, and starting core services like servicemanager, surfaceflinger, zygote.


10. How does init handle the transition from the rootfs ramdisk to the system partition?

Answer: In first-stage init (running from initramfs), it mounts the real system partition over /system (or as root via switch_root), then executes /system/bin/init to enter second stage. The initramfs is freed from memory.


11. What is the purpose of the system/etc/init/ directory and how does it relate to first-stage vs second-stage init?

Answer: /system/etc/init/ holds .rc files packaged inside the system image. These are parsed by second-stage init after the system partition is mounted. First-stage init only has access to files inside the initramfs (e.g., /init.rc there). Second-stage init imports all .rc files from /system/etc/init/, /vendor/etc/init/, and /odm/etc/init/ to start module-specific services.


12. How do you debug early boot failures before logd and logcat are available?

Answer:

  1. Kernel printk: Use printk in kernel code; read via serial console or last_kmsg.

  2. Init logging: init writes to /dev/kmsg directly using InitKernelLogging().

  3. Serial Console: Enable console=ttyAMA0 in kernel cmdline for UART output.

  4. Ramdump/JTAG: For hard crashes.

  5. Bootloader logs: Most bootloaders have their own log buffer accessible via fastboot oem get_log.

  6. Init .rc debugging: Add exec /system/bin/sh in init.rc to drop to a shell at a specific trigger.


13. Explain how dm-verity is initialized during boot and its impact on I/O performance.

Answer: init (or the kernel via the verity kernel parameter) sets up a dm-verity device-mapper target over the block device. The root hash is passed via kernel cmdline (veritykeyid or dm="... verity ..."). Every read triggers a hash verification up the Merkle tree.

Performance Impact: Read amplification. A 4KB read may require reading multiple hash blocks. Using FEC (Forward Error Correction) adds overhead but allows correction of small corruptions without panic.


14. What is the purpose of the vbmeta partition, and how are rollback indexes used?

Answer: vbmeta contains signed metadata (descriptors) for all verified partitions. It includes:

  • Hash descriptors: For partitions without hashtrees (e.g., boot).

  • Hashtree descriptors: For system, vendor.

  • Rollback indexes: Monotonic counters stored in tamper-evident storage (RPMB or fuses). If an OS image has a rollback index lower than the stored value, boot is rejected to prevent downgrade attacks.


15. How does the boot sequence differ between a normal boot and a recovery boot?

Answer:

  • Normal Boot: Bootloader loads boot.img → kernel mounts system partition → init starts zygotesystem_server.

  • Recovery Boot: Bootloader loads recovery.img (or boot with androidboot.force_normal_boot=0). The kernel starts init from the recovery ramdisk. Recovery init.rc starts /system/bin/recovery (or adbd for sideload). The rootfs stays as ramdisk; system partition is mounted at /system only if needed for tools.


Build

1. Explain the AOSP build system architecture: how do Soong, Kati, and Ninja interact?

Answer:

  • Kati: Converts Android.mk (GNU Make syntax) into .ninja files. It is a Make clone written in C++.

  • Soong: The newer build system that reads Android.bp (Blueprint files, JSON-like) and generates .ninja files directly. It replaces the need for Make for most modules.

  • Ninja: The low-level build executor. It takes the generated .ninja files and runs the actual compilation/linking commands. Ninja is extremely fast at incremental builds.

Flow: Android.bp → Soong → .ninja → Ninja compiler commands. Legacy Android.mk → Kati → .ninja → Ninja.


2. What is the difference between Android.bp and Android.mk, and when would you still need the latter?

Answer:

  • Android.bp: Declarative, JSON-like, parsed by Soong. No conditionals (no ifeq). Supports modules like cc_binary, cc_library, java_library, android_app. Preferred for all new code.

  • Android.mk: GNU Make syntax, parsed by Kati. Supports complex conditionals and host-side logic. Still needed for:

    • Complex conditional logic not supported in Blueprint.

    • Some legacy host tools.

    • BUILD_PREBUILT patterns that haven't been migrated.


3. How does the Android.bp module system handle dependencies between shared libraries and static libraries?

Answer: Use shared_libs for runtime-linked .so files and static_libs for .a files linked at build time. Soong tracks transitive dependencies. If libA statically links libB, and libC links libA, libC does not automatically get libB's symbols unless whole_static_libs is used or libA exports the dependency.


4. Describe the purpose of AndroidProducts.mk, BoardConfig.mk, and device.mk in a device build.

Answer:

  • AndroidProducts.mk: Defines the list of product makefiles for a lunch target. It sets PRODUCT_MAKEFILES which point to the main product definition file.

  • BoardConfig.mk: Hardware-specific settings. Defines partition sizes, kernel config, bootloader type, Wi-Fi/BT drivers, graphics HAL, and SELinux policy directories. It does NOT define user-facing features.

  • device.mk (or product.mk): Defines the product composition. Lists packages to install (PRODUCT_PACKAGES), properties (PRODUCT_PROPERTY_OVERRIDES), permissions, and overlays.


5. How do you add a new HAL implementation to the build without modifying AOSP core repositories?

Answer: Place the HAL implementation in the device or vendor directory. Use Android.bp with cc_library_shared and set relative_install_path: "hw". The module name must match the HAL interface name (e.g., mydevice.camera@1.0-impl). Reference it in device.mk via PRODUCT_PACKAGES.


6. Explain the difference between eng, user, userdebug, and user build variants at the build system level.

Answer:

  • eng: Development build. Includes all modules, adb enabled by default with root access, debug binaries, no optimization.

  • userdebug: Like user but with root access via adb, debuggable user space, and some profiling tools. Used for field testing.

  • user: Production build. Optimized, no root access, adb disabled or limited, no debug tools, strict SELinux enforcing.

  • user (variant target): The lunch target name (e.g., aosp_arm64-eng) combines product and variant.


7. What is the purpose of sepolicies in the build, and how are they compiled into the final image?

Answer: SELinux policies define security contexts and access rules for processes and files. During build:

  1. .te (type enforcement) files are parsed by checkpolicy (or secilc for CIL).

  2. Compiled into sepolicy binary.

  3. Placed in rootdir/sepolicy and loaded by init early in second stage via selinux_setup().


8. How does the build system generate OTA packages, and what is the role of releasetools.py?

Answer: OTA packages are generated by build/tools/releasetools/. The process:

  1. ota_from_target_files takes target_files.zip (produced by the build) as input.

  2. Computes binary diffs for partition images using bsdiff/imgdiff.

  3. Generates update.zip containing updater scripts and payload.

releasetools.py contains the core logic for:

  • Creating full vs incremental OTAs.

  • Signing the payload.

  • Generating A/B OTA metadata.


9. Describe how to create a custom build target that packages additional prebuilt binaries.

Answer: Use cc_prebuilt_binary or android_prebuilt_apk in Android.bp, or include $(BUILD_PREBUILT) in Android.mk. Place the binary in the device tree and reference it.


10. What are apex modules, and how do they change the traditional system image partitioning?

Answer: APEX (Android Pony EXpress) is a package format for lower-level system modules. An APEX is a file system image (ext4/erofs) packaged in a zip file, mounted at runtime via loop device.

Changes to partitioning:

  • Traditional: Libraries and services are scattered in /system, /vendor.

  • APEX: Self-contained modules (e.g., com.android.runtime, com.android.tzdata) can be updated independently via Google Play/System Update.


11. How does the build system handle kernel compilation out-of-tree vs in-tree?

Answer:

  • In-tree: Kernel source is inside AOSP (device/<vendor>/<board>/kernel). Build system runs make directly via build/build.sh or Android.bp kernel_build module.

  • Out-of-tree: Kernel is in a separate repository. AOSP build uses a prebuilt kernel image (TARGET_PREBUILT_KERNEL) or fetches the kernel repo as a Git project and builds it using a custom build rule.


12. Explain the purpose of PRODUCT_COPY_FILES vs PRODUCT_PACKAGES and their build-time implications.

Answer:

  • PRODUCT_COPY_FILES: Copies files verbatim from source to target image. No build processing. Used for configs, firmware, scripts. Syntax: src:dst.

  • PRODUCT_PACKAGES: Lists modules to build and install. The build system compiles the module, resolves dependencies, and installs the output. Used for binaries, libraries, APKs.


13. How do you implement a build-time flag that conditionally compiles source code across multiple modules?

Answer: Use soong_config_module_type and soong_config_string_variable. Define a config in Android.bp at the top level, then use it in modules.


14. What is the role of bionic in the build, and how does it differ from glibc-based builds?

Answer: Bionic is Android's C library. It is smaller, faster, and BSD-licensed compared to glibc. Key differences:

  • No stdio file locking (not needed for Android's threading model).

  • Custom dynamic linker (/system/bin/linker64).

  • Built-in TLS (Thread Local Storage) optimized for ARM.

  • No full POSIX compliance (e.g., no pthread_cancel).

In the build, bionic/ is built early as the foundation for all native code. libc.so, libm.so, and libdl.so are generated from bionic/libc/.


15. How would you optimize a clean AOSP build time for a large team using distributed build caches?

Answer:

  1. ccache: Enable USE_CCACHE=1 with a shared NFS/cache server.

  2. RBE (Remote Build Execution): Use Google's Bazel/Soong remote execution to distribute compilation across a cluster.

  3. Ninja Pools: Limit link jobs (-j for compile, smaller -j for links) to prevent memory exhaustion.

  4. Prebuilt Modules: Use prebuilt kernel, prebuilt GSI images where possible.

  5. Build Server: Use a powerful build server with RAM disk for OUT_DIR.

  6. Incremental Builds: Ensure proper dependency tracking in Android.bp to avoid over-building.


Framework

1. Explain the Zygote startup process and why it uses a prefork model.

Answer: Zygote is started by init with an app_process command. It preloads the Android framework classes and resources into memory, then listens on a Unix domain socket (/dev/socket/zygote). When a new app needs to start, AMS sends a request to Zygote, which forks a new process.

Why prefork?

  • Copy-on-Write (COW): The child process shares memory pages with Zygote until they are modified. This saves ~100MB+ of RAM per app and drastically reduces startup time.

  • Preloaded state: Classes like android.app.Activity, Resources, and graphics buffers are already initialized.


2. What happens during ZygoteInit before the first application process is forked?

Answer:

  1. Register Server Socket: Opens /dev/socket/zygote to listen for fork requests.

  2. Preload: Loads preloaded-classes file (typically ~4000 classes), drawables, colors, and shared libraries.

  3. GC: Runs an explicit GC to clean up any garbage created during preload, ensuring a clean heap for children.

  4. Fork System Server: Calls forkSystemServer() which fork()s and then calls handleSystemServerProcess().

  5. Select Loop: Enters runSelectLoop() to block on poll() waiting for connections from ActivityManagerService.


3. Describe the Binder IPC mechanism: how does a client obtain a reference to a system service?

Answer:

  1. Service Registration: The system service (e.g., AlarmManagerService) publishes itself via ServiceManager.addService("alarm", this).

  2. Service Lookup: The client calls ServiceManager.getService("alarm") which returns a BinderProxy (Java) or BpBinder (native) handle.

  3. Transaction: The client calls methods on the proxy. The proxy marshals data into a Parcel, sends it via ioctl(BINDER_WRITE_READ) to /dev/binder.

  4. Kernel: The binder driver copies the transaction to the target process's thread pool.

  5. Server Thread: A thread in the server process reads the transaction from the binder driver, unmarshals it, and calls the real implementation.


4. What is the difference between BpBinder and BBinder, and how does the proxy/stub pattern work in native code?

Answer:

  • BBinder: The server-side implementation. It inherits from BBinder and implements onTransact(). It lives in the service process.

  • BpBinder: The client-side proxy handle. It holds an integer handle (e.g., handle 1 for servicemanager) and sends transactions to the binder driver.

Pattern:

  • interface_cast<<IXXX>(binder) on the client side creates a BpXXX object wrapping the BpBinder.

  • The server side inherits from BnXXX which inherits from BBinder and routes onTransact() to the implementation.


5. How does AIDL differ from HIDL and AIDL (stable) in terms of interface stability and versioning?

Answer:

  • AIDL (Legacy): Used for app-to-framework IPC. Not versioned. Changes to the interface require recompiling both sides. Used in frameworks/base/.

  • HIDL (Hardware Interface Definition Language): Used for HAL-to-framework IPC. Designed for stable, versioned interfaces. Uses explicit minor versioning (e.g., @1.0, @1.1). Replaced by stable AIDL.

  • Stable AIDL (AIDL-HAL): Introduced to replace HIDL. Uses the same syntax as app AIDL but with stability guarantees (@VintfStability). Backward compatible. Preferred for HALs in Android 11+.


6. Explain the role of ServiceManager vs hwservicemanager vs vndservicemanager.

Answer:

  • ServiceManager: The original binder context manager (/dev/binder). Registers Java/native framework services (e.g., activity, package). Accessible to apps and system services with servicemanager SELinux context.

  • hwservicemanager: Manages HIDL services (/dev/hwbinder). Used for HAL interfaces. Has its own SELinux domain. Services register with IServiceManager::addService().

  • vndservicemanager: A separate instance for vendor-specific native services (/dev/vndbinder). Isolates vendor services from framework services for Treble compliance. Started in vendor partition.


7. What is the purpose of the system_server process, and how is it started from Zygote?

Answer: system_server hosts all Java system services (ActivityManagerService, WindowManagerService, PackageManagerService, etc.). It is started by Zygote forking a dedicated process and then calling SystemServer.main().


8. Describe the ActivityThread initialization sequence when an application process starts.

Answer:

  1. Zygote forks the app process.

  2. ActivityThread.main() is called.

  3. Creates the main thread Looper.

  4. Attaches to the ActivityManagerService via IActivityManager.attachApplication().

  5. AMS replies with a bindApplication() call containing the ApplicationInfo, providers, etc.

  6. ActivityThread creates the Instrumentation, Application object, and calls Application.onCreate().

  7. AMS then sends scheduleLaunchActivity() to start the first Activity.


9. How does the PackageManagerService scan and resolve packages during boot?

Answer: PMS scans directories in PackageParser to find APKs:

  • /system/framework (framework-res.apk)

  • /system/app, /system/priv-app

  • /vendor/app

  • /data/app (user apps)

For each APK, it:

  1. Parses AndroidManifest.xml using PackageParser.

  2. Extracts permissions, components (activities, services, receivers, providers).

  3. Performs signature verification and dexopt.

  4. Stores resolved info in internal data structures (mPackages, mActivities, mServices).

  5. Updates the package database /data/system/packages.xml.


10. Explain the difference between system permissions, signature permissions, and normal permissions in AndroidManifest.xml.

Answer:

  • normal: Granted automatically at install time. Low risk (e.g., INTERNET, ACCESS_NETWORK_STATE).

  • signature: Granted only if the requesting app is signed with the same certificate as the app that declared the permission. Used for app pairs or OEM apps.

  • system (or privileged): Granted only to apps in the system/priv-app directory or signed with the platform key. Dangerous capabilities (e.g., WRITE_SECURE_SETTINGS, DIAGNOSTIC).


11. How does the WindowManagerService manage window layers and surface composition?

Answer: WMS maintains a hierarchy of WindowState objects. Each window has a mLayer value determined by its type and Z-order policy. WMS computes the final layer assignment and communicates with SurfaceFlinger via SurfaceControl.

  • WindowContainer: Base class for organizing windows (DisplayContent, Task, ActivityRecord).

  • WindowState: Represents a single window.

  • SurfaceControl: Creates and manipulates surfaces in SurfaceFlinger.

WMS does not directly composite pixels; it tells SurfaceFlinger where each surface is via setGeometry() and setLayer().


12. Describe the input event pipeline from kernel to application: EventHub, InputManagerService, InputDispatcher.

Answer:

  1. Kernel: Input drivers (evdev) generate events and write to /dev/input/eventX.

  2. EventHub (native): Scans input devices via inotify and epoll. Reads raw input_event structs from the kernel.

  3. InputReader (native): Consumes raw events from EventHub. Converts them into NotifyArgs (key, motion). Applies calibration, key remapping.

  4. InputDispatcher (native): Receives NotifyArgs on a dedicated thread. Determines the target window using WMS hit-testing. Places events into outbound queues per connection.

  5. App: InputDispatcher sends the event via InputChannel (Unix socket pair) to the app's ViewRootImpl. The app's main thread Looper wakes up and processes the event in deliverInputEvent().


13. What is the role of SurfaceFlinger in the display pipeline, and how does it interact with HWC?

Answer: SurfaceFlinger is the system compositor. It collects graphic buffers (Surfaces) from all windows, composites them into a final framebuffer, and presents it to the display.

HWC (Hardware Composer):

  • SurfaceFlinger attempts to offload composition to HWC by setting up layers.

  • HWC decides which layers can be handled by the display controller (overlay planes) vs which need GPU composition.

  • SurfaceFlinger composites only the remaining layers via OpenGL ES, then passes the final output to HWC for display.


14. How does the PowerManagerService coordinate with the kernel for suspend/resume and wakelocks?

Answer: PowerManagerService tracks user activity, display state, and wake locks. It decides when the system should sleep.

  • Wake Locks: Apps/native code acquire wake locks via PowerManager. PMS tracks them in mWakeLocks.

  • Native Daemon: PMS writes to /sys/power/wake_lock and /sys/power/wake_unlock via nativeAcquireWakeLock() in com_android_server_power_PowerManagerService.cpp.

  • Autosuspend: When no wake locks are held and the screen is off, PMS calls goToSleep(). The native autosuspend loop in the kernel eventually allows the system to enter suspend-to-RAM.


15. Explain the JobScheduler framework and how it interacts with Doze mode and App Standby.

Answer: JobScheduler allows apps to defer background work based on conditions (network, charging, idle). JobSchedulerService (in system_server) manages a queue of JobStatus objects.

  • Doze Mode: When the device is idle (screen off, stationary), DeviceIdleController signals JobSchedulerService to defer standard jobs. Only "whitelisted" jobs or those with setRequiresDeviceIdle(true) run during maintenance windows.

  • App Standby: UsageStatsService tracks app usage. Unused apps enter buckets (ACTIVE, WORKING_SET, FREQUENT, RARE, RESTRICTED). JobScheduler limits job execution frequency based on the bucket.


16. What is the difference between a ContentProvider running in its own process vs the caller's process?

Answer:

  • Same Process: If the provider and caller share a UID and process, ActivityThread returns a direct ContentProvider object reference. No IPC overhead.

  • Different Process: ActivityThread returns a ContentProviderProxy. Calls go through IContentProvider Binder IPC to the provider process. The provider process is started by AMS if not already running.


17. How does the ActivityManagerService handle process lifecycle and out-of-memory killing decisions?

Answer: AMS maintains a list of running processes in mLruProcesses (Least Recently Used). Each process has an oom_adj score managed by ProcessList.

  • Lifecycle: AMS starts processes via Zygote when components need them. It keeps them alive for caching.

  • OOM Killing: AMS updates oom_score_adj in /proc/<pid>/oom_score_adj. The Linux OOM killer uses this to select victims. Lower priority processes (background, empty) get higher scores and are killed first.

  • LRU Ordering: mLruProcesses is reordered on activity usage. The last process in the list is the first candidate for killing.


18. Describe how BroadcastReceiver delivery works, including ordered vs unordered broadcasts and background restrictions.

Answer:

  • Unordered: Sent to all receivers simultaneously. Parallel delivery.

  • Ordered: Delivered one-by-one based on priority in the manifest. Each receiver can abortBroadcast() to stop propagation.

  • Background Restrictions (Android 8+): Implicit broadcasts cannot be received by manifest-declared receivers unless the app is in the foreground or the broadcast is exempted (e.g., BOOT_COMPLETED). Explicit broadcasts (targeting a specific package/component) are still allowed.


19. What is the purpose of Looper, Handler, and MessageQueue in the Android threading model?

Answer:

  • Looper: Prepares a message loop for a thread. Looper.prepare() creates a MessageQueue and binds it to the thread. Looper.loop() blocks waiting for messages.

  • MessageQueue: A linked list of Message objects backed by a native epoll/pipe mechanism for waking the thread.

  • Handler: Sends and processes Messages and Runnables on a specific thread's MessageQueue. Used to communicate between threads (e.g., worker thread to UI thread).


20. How does the Resources framework handle runtime resource overlay (RRO) and static overlay?

Answer:

  • Static Overlay: Compiled into the framework or device build at build time. aapt2 merges overlay resources with base resources. Defined in Android.mk/Android.bp with LOCAL_PACKAGE_OVERLAYS or overlay property.

  • Runtime Resource Overlay (RRO): Installed as separate APKs (in /vendor/overlay or /product/overlay). AssetManager loads them at runtime. OverlayManagerService (OMS) manages which overlays are enabled per target package. Uses idmap to map resource IDs between base and overlay.


System Service

1. How do you implement a new system service that is accessible to third-party applications?

Answer:

  1. Define the AIDL interface in frameworks/base/.

  2. Implement the service in frameworks/base/services/core/java/....

  3. Register it in SystemServer.java via ServiceManager.addService().

  4. Add a Context.getSystemService() wrapper in ContextImpl.java and SystemServiceRegistry.java.

  5. Add the service name to Context.java constants.

  6. For third-party access: The AIDL interface must be in the SDK stub (frameworks/base/api/). The service methods must be annotated with @RequiresPermission and guarded by PermissionChecker.


2. What is the difference between a Java system service and a native system service in terms of registration?

Answer:

  • Java Service: Lives in system_server. Registered via ServiceManager.addService(name, IBinder). Clients get a BinderProxy and call through JNI Binder.

  • Native Service: Lives in its own daemon process (e.g., surfaceflinger, cameraserver). It calls defaultServiceManager()->addService() from C++. Clients use interface_cast<<IXXX>(sm->getService()).


3. Explain the SystemService base class and the onStart(), onBootPhase(), and onUserStarting() lifecycle methods.

Answer: All Java system services in system_server should extend SystemService.

  • onStart(): Called when SystemServer starts this service. Publish the binder service here via publishBinderService().

  • onBootPhase(int phase): Called at global boot milestones (PHASE_WAIT_FOR_DEFAULT_DISPLAY, PHASE_LOCK_SETTINGS_READY, PHASE_SYSTEM_SERVICES_READY, PHASE_BOOT_COMPLETED). Services can perform delayed initialization.

  • onUserStarting() / onUserStopped(): Called when a user is starting or stopping. Services should load per-user state here.


4. How do you ensure thread safety in a system service that receives concurrent Binder calls?

Answer: Binder calls are dispatched from a thread pool (typically 16 threads). The service implementation must synchronize access to shared state.

  1. Synchronized blocks/methods: Use synchronized on a private lock object.

  2. Handler with dedicated looper: Post all mutations to a single handler thread.

  3. ConcurrentHashMap / AtomicReference: For lock-free data structures.

  4. ReadWriteLock: For read-heavy workloads.

Never perform long-running I/O on the Binder thread directly; use an async handler.


5. Describe the watchdog mechanism (Watchdog.java) and how to register a system service with it.

Answer: Watchdog is a singleton thread in system_server that monitors critical threads for deadlocks or hangs. It sends a MONITOR message to registered handlers and waits for a response. If no response within 60 seconds, it kills system_server to generate a tombstone and trigger a restart.

Registration: The service implements Watchdog.Monitor and registers in onStart().


6. How does ActivityManagerService enforce background execution limits introduced in recent Android versions?

Answer: Starting Android 8.0 (O), background execution limits restrict implicit broadcasts, background services, and wakeup alarms.

  • Background Services: AMS tracks ActivityManager.RunningServiceInfo. If an app is not in the foreground (no visible Activity or foreground service), AMS throws IllegalStateException on startService() after a short grace period.

  • Broadcasts: Implicit broadcasts are dropped for manifest receivers unless the app is in the foreground.

  • JobScheduler: Replaces background services for deferrable work.


7. Explain the architecture of ConnectivityService and how it manages multiple network agents.

Answer: ConnectivityService is the central network coordinator. It maintains a list of NetworkAgentInfo objects, each representing a network (Wi-Fi, Mobile, Ethernet, VPN).

  • NetworkFactory: Subsystems (Wi-Fi, Telephony) register factories that score and offer networks.

  • NetworkAgent: Created by the subsystem when a network connects. Communicates with ConnectivityService via Binder.

  • NetworkRequests: Apps request networks (e.g., requestNetwork()). CS matches the request to the best-scoring NetworkAgent.

  • Default Network: CS selects the highest-scoring network as default and updates the routing table and DNS.


8. How does LocationManagerService interact with GNSS HAL and fuse location providers?

Answer: LocationManagerService manages location providers:

  • GnssLocationProvider: Talks to the android.hardware.gnss HAL via HIDL/AIDL. Receives raw NMEA, SV status, and location fixes.

  • FusedLocationProvider: A composite provider that uses FusedLocationProvider.java to blend GPS, network, and sensor data.

  • NetworkLocationProvider: Uses Wi-Fi/cell tower databases.

LMS registers providers and forwards location updates to client apps based on criteria (accuracy, power).


9. Describe the power management flow from PowerManagerService to the kernel power HAL.

Answer:

  1. User Activity: Touch or button wakes EventHubInputManagerServicePowerManagerService.userActivity().

  2. Wake Lock Updates: PMS updates internal state and decides if the display should change state (ON → DIM → OFF).

  3. Display Power Controller: PMS sends a message to DisplayPowerController to change the display state.

  4. Native Sleep Decision: When no wake locks are held and idle timeout expires, PMS calls nativeSetAutoSuspend() which writes to /sys/power/autosleep.

  5. Power HAL: IPower HAL (e.g., power.default.so) receives hints (POWER_HINT_INTERACTION, POWER_HINT_LOW_POWER) to adjust CPU governor and scheduler settings.


10. How does BatteryService monitor battery state and propagate events to the framework?

Answer: BatteryService polls the health HAL (android.hardware.health@2.0) via HealthServiceWrapper. It reads sysfs nodes (/sys/class/power_supply/battery/uevent).

When a change is detected:

  1. Reads voltage, temperature, status, level.

  2. Computes battery stats (e.g., BatteryStatsImpl).

  3. Sends a sticky Intent.ACTION_BATTERY_CHANGED broadcast.

  4. Notifies PowerManagerService to adjust low-power behavior.


11. Explain the role of StorageManagerService and how it handles adopted storage vs portable storage.

Answer: StorageManagerService (formerly MountService) talks to vold (Volume Daemon) via Binder.

  • Adopted Storage (Internal): An SD card encrypted and formatted as internal storage. Apps and data can be moved to it. Managed as a VolumeRecord with type=PUBLIC and adopted=true.

  • Portable Storage: Standard FAT32/exFAT SD card. Mounted read-only or read-write for media only. Apps cannot be installed on it.

vold handles the actual mounting via fsck and mount() syscalls.


12. How does AudioService manage audio focus, routing, and policy decisions across HAL implementations?

Answer: AudioService uses AudioPolicy and MediaFocusControl.

  • Audio Focus: Apps request focus (requestAudioFocus()). MediaFocusControl tracks the stack of focus holders. New requests can cause previous holders to receive AUDIOFOCUS_LOSS.

  • Routing: AudioService queries AudioPolicyManager (native) which decides the output device (speaker, headset, BT A2DP) based on strategy (MEDIA, VOICE_CALL, etc.).

  • HAL: AudioFlinger (native) mixes streams and writes to audio_hw_device_t HAL.


13. Describe the CameraService architecture and how it handles concurrent camera access from multiple apps.

Answer: CameraService (native) runs in cameraserver process. It manages the ICameraService Binder interface.

  • HAL: Talks to camera.device HAL (HIDL/AIDL).

  • Concurrent Access: Only one app can hold the camera at a time. CameraService maintains CameraClient objects. When a higher-priority client (foreground app) requests the camera, it evicts the lower-priority client via disconnect() with error CameraEvicted.

  • Multi-Camera: For devices with logical multi-camera, CameraService manages physical camera IDs and streams.


14. What is the purpose of SensorService, and how does it batch sensor events for power efficiency?

Answer: SensorService (native) runs in system_server. It connects to the sensors HAL (android.hardware.sensors).

  • Batching: Apps can request maxReportLatencyUs. SensorService accumulates events in a hardware FIFO (if the HAL supports batching) or software buffer, then delivers them in a batch via sensors_event_t[] to reduce CPU wakeups.

  • Wake-up Sensors: If a wake-up sensor (e.g., significant motion) fires, it wakes the AP to deliver the event.

  • Connection: Each app registers a SensorEventConnection. SensorService loops in threadLoop() reading from HAL and dispatching to connections.


15. How does TelephonyRegistry dispatch phone state changes to multiple listeners securely?

Answer: TelephonyRegistry maintains a list of IPhoneStateListener Binder proxies. When Phone state changes (service state, signal strength, call state), it iterates listeners and applies per-app permissions.

  • Permissions: Some events require READ_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE. TelephonyRegistry checks checkListenerPermission() before dispatching.

  • User Filtering: Listeners are filtered by user ID to prevent cross-user leaks.


16. Explain the VibratorService and LightsService abstractions over their respective HALs.

Answer:

  • VibratorService: Java service that calls IVibrator HAL (e.g., vibrator.default). Supports one-shot, waveform (pattern), and perform effects. It acquires a wakelock during vibration to prevent sleep.

  • LightsService: Manages backlight, notification LED, button backlight. Talks to ILight HAL (light.default). Maps LogicalLight IDs (BACKLIGHT, BATTERY, NOTIFICATIONS) to HAL type and ordinal.


17. How would you add a custom hardware feature (e.g., a proprietary sensor) and expose it through the framework?

Answer:

  1. HAL: Implement the sensor in the vendor HAL (sensors.<device>.so). Add a new sensor type (or use SENSOR_TYPE_DEVICE_PRIVATE_BASE + offset).

  2. SELinux: Add type mysensor_device and allow sensorservice access.

  3. Framework: In SensorService/SensorManager, the new sensor appears automatically via HAL enumeration if properly reported in getSensorsList().

  4. App Access: Apps can discover it via sensorManager.getSensorList(Sensor.TYPE_ALL). For a custom type, use the private base range.


18. Describe how DevicePolicyManagerService enforces enterprise policies at the system service level.

Answer: DevicePolicyManagerService (DPMS) stores policies per-user in /data/system/device_policies.xml. It acts as a gatekeeper for many system functions.

  • Policy Storage: ActiveAdmin objects hold policy state. DeviceAdminInfo parses the metadata from the admin app manifest.

  • Enforcement: DPMS intercepts calls in other services. For example, PackageManagerService checks isUserRestricted() before installing unknown sources. WindowManagerService checks if screen capture is disabled.

  • Provisioning: ACTION_PROVISION_MANAGED_DEVICE sets the Device Owner (DO) or Profile Owner (PO).


19. How does NetworkManagementService use netd to configure iptables and routing rules?

Answer: NetworkManagementService (NMS) is the Java frontend. netd (native daemon, /system/bin/netd) is the backend that executes iptables, ip, and ndc commands.

  • Interface: NMS calls INetd AIDL methods (e.g., firewallSetUidRule(), bandwidthSetInterfaceQuota()).

  • Netd Execution: netd translates these into iptables -A or tc (traffic control) commands. It also manages the DNS resolver via /system/etc/resolv.conf updates.

  • StrictMode: netd enforces strict firewall rules for UID-based network blocking.


20. What is the role of AppOpsService and how does it provide fine-grained permission auditing beyond runtime permissions?

Answer: AppOpsService tracks "operations" (e.g., OP_CAMERA, OP_RECORD_AUDIO, OP_FINE_LOCATION) per UID/package. It provides:

  • Mode Tracking: Each op has a mode (ALLOW, DENY, IGNORE, FOREGROUND).

  • Runtime Auditing: Even if an app has the manifest permission, AppOpsService can deny the operation at runtime.

  • Privacy Dashboard: Feeds data to UI showing which apps used which sensors when.

  • Note Operations: Services call noteOperation() which checks and logs usage.

Last updated