项目原因先用蹩脚英文写的,过些天我会用中文描述一下。查看不方便可以用浏览器的翻译菜单翻译一下。

summary

Android bootstap involves three stages.

1, Linux kernel bootstrap:  The Linux kernel bootstrap from physical device is comprised of CPU boot rom, SBL, and bootloader. All these are based on CPU manufacturer’s design and particular LINUX kernel implementation on specific CPU architecture. These are not components of AOSP. Linux kernel can boot from a virtual machine as well. For example, QVM from QNX.

2, init process & native bootstrap: This step is AOSP open source. Including: loading system/vendor image, applying SElinux rules, loading android native process, encrypting data partition, etc

init - OpenGrok cross reference for /system/core/init/ (aospxref.com)

3, Android framework bootstrap: This is phase from starting process zygote to enabling screen. There is considerable number of mechanisms like: zygote & JVM, system services, boot progress.

Boot Rom & Boot Loader

1, PBL(Processor Boot Loader or Primary Boot Loader): Arm CPU will execute the first instruction from 0x0000000 (or 0xBFC00000 if MIPS). This instructions are PBL which record in Boot ROM. QC’s PBL also providers Emergency Download mode.

2,3 SBL(Secondary or Slave Boot Loader): PBL load SBL from EMMC/UFS/NAND/PCIe, etc.) to SRAM, then execute the SBL. SBL do something like initializing memory subsystem(buses, DDR, clocks), load Trust Environment, and then load LK.

4,5 LK(Little Kernel): LK is used to load Linux kernel, to enter recovery mode, to enter charge mode, to enable fastboot, etc. LK is open source. Different vendor may have different name for it. For example, fastboot.

DDR is one kind of Dynamic RAM, it is essential to initialize the Driver before CPU uses it due to different kind of DDR has difference attributes (for e.g. voltage, tCK, data rate, refresh rate). The configurations are customized in SBL. Hisilicon’s solution is as below: SBL set the voltage of different PINs for different kind of DDR. CPU loads the combination to map to driver & configurations then.

QNX GVM

 

Boot image is comprised of kernel, rootfs, dtb(Device Rree Blob). Recovery image is similar to boot image. It has a extra partition recovery_dtbo. Dtbo (DTB Overlays) begins from Android 9. It is loaded from dtbo.img . It is convenient for vendor to upgrade without upgrade system.img since boot.img & system.img can not be flashed respectively now for security.

If you want to learn more about boot image, use tools below for more detail:

 out/host/linux-x86/bin/mkbootimg, unpackbootimgunmkbootimg, split_bootimg, obooting.

Linux Kernel Bootstrap

0, Before bootloader(LK) runs kernel, bootloader(LK) set MMU = off, D-cache = off, I-cache = on or off, x0 = physical address to the FDT blob. Since MMU is not enabled, bootloader will map the virtual address to the boot.img’s physical address.

1, vmlinux.lds defines the entry of kernel. Section .head.text = PAGE_OFFSET(boot.imag address) + TEXT_OFFSET (kernel address offset) .This address is the beginning of head.S since head.S is the implementation of vmlinux.lds.S. Bootloader will start to run kernel from this address.

2, preserve_boot_args: saves x0, x1, x2, x3 which are from bootloader to boot_args array.  x0 saves the address of FDT.

3, __create_page_tablescreate permanent mapping in idmap_pg section for physical memory id_map.text. All kernel image’s physical address mapping information is stored in init_pg section

4, __primary_switchconfigure TTBR0 and TTBR1 with idmap_pg_dirinit_pag_dir ; enable MMU, redirect .rela.dyn section.

5, __primary_switchedinitiate the stack of kernel; initiate execption vector table; start kernel.

6, start_kernel: Start_kernel sets the initialization state of the kernel, initializes all required subsystems, and ultimately enters user space to execute the first user process init. Steps are as below.

6.1, Set the initialization state of the kernel: This includes initializing GCC built-in special segments, setting the kernel's page table, and so on.

6.2, Memory management initialization: Set up subsystems for memory management, such as page tables, initializing memory allocators, etc.

6.3, Set interrupt handling: Initialize the subsystem for interrupt handling, including SMP (Symmetric Multiprocessing) interrupt handling.

6.4, Initialize the clock system: Set the clock interrupt handling program to enable clock interrupts.

6.5, Start other core processes and threads: Create the kthreadd process (tid=2), which is the ancestor of all kernel threads (kworkerkblockdkhugepaged, kswapd, ksoftirqd, etc).

6.6,  Start CPU related tasks, such as scheduler initialization, starting task schedulers on each online CPU, etc. Start other core services, such as initializing process creation, file system, loading modules, etc.

6.7, Enter user space: Start the first process init(tid=1) in user space.

init

1, Init process: is the first user space process of linux. It is the ancestor of all Android processes, including zygote, system_server, all JAVA applications. Its pid is 1.

2, ueventd / watchdogd: ueventd / watchdogd are symlinks of init process. Check the Android.bp of init:

    symlinks: [
      "sbin/ueventd",
      "sbin/watchdogd",
    ],

    ueventd is to manager devices. It will create new node in /dev if kernel detects new device inserting.  Then ueventd forks a new process to process related procedure.

    Watchdogd write a message to watchdog device periodically to avoid CPU being reset.

why init, ueventd and watchdogd use identical executable?
These three static executables will use its static libc rather than dynamic libc.so. Since the code segments for ueventd & watchdogd are very little. It is better to re-use the same static libc within one executable.
Dynamic loading is not available when init process starting. Android uses bionic/libc as dynamic libc.so, uses bionic/linker as dynamic interpreter. These modules use BSD license. ueventd and watchdogd shall be initialized as early as possible. but these are not loaded together with init process running. Android linker will be loaded after /system partition mounted.  

3, First Stage: essential prepare for second stage.

4, Second Stage: Load & apply selinux policy, init property service, load & parse .rc files, then run commands generated from the .rc files.

5, DoFirstStageMount: mount system/vendor, etc partitions from fastab. Fastab is loaded from specific directory of device tree, for e.g. /etc/fstab. Cross Reference: /system/core/fs_mgr/fs_mgr_fstab.cpp (androidxref.com)

init.rc

1, trigger action: actions from early-init to late-init are triggered in init.cpp. The other actions are triggered at preceding action which defined in /system/core/rootdir/init.rc.

For e.g:

on late-init

    trigger early-fs

    trigger fs

    trigger post-fs

Trigger Action is not an event. It is more similar to a status. after an action like trigger1 is triggered, condition check like:

on <trgger1> [&& <trigger2>]*

 will just check trigger2 then.

For e.g.

on zygote-start && property:ro.crypto.state=unsupported

    exec_start update_verifier_nonencrypted

    start netd

    start zygote

2, choose appropriate action: If your module depends on some other modules, it is proper to configure the trigger action of your module later then any of them. One other important action choosing factor is that whether & when your module uses /data partition.

3, FBE(File-Based Encrypt): /data partition will be encrypted when post-fs by calling mount_all(). After /data partition mounted, modules which require on /data partition should be triggered after post-fs-data.

File-based Encrypt

1Android 7.0 and higher supports file-based encryption (FBE). File-based encryption allows different files to be encrypted with different keys that can be unlocked independently.

2On an FBE-enabled device, each user of the device has two storage locations available to applications:

  • Credential Encrypted (CE) storage, which is the default storage location and only available after the user has unlocked the device.
  • Device Encrypted (DE) storage, which is a storage location available both during Direct Boot mode and after the user has unlocked the device.

3This separation makes work profiles more secure because it allows more than one user to be protected at a time as the encryption is no longer based solely on a boot time password.

The Direct Boot API allows encryption-aware applications to access each of these areas. There are changes to the application lifecycle to accommodate the need to notify applications when a user’s CE storage is unlocked in response to first entering credentials at the lock screen, or in the case of work profile providing a work challenge. Devices running Android 7.0 must support these new APIs and lifecycles regardless of whether or not they implement FBE. Although, without FBE, DE and CE storage will always be in the unlocked state.

4A complete implementation of file-based encryption on the Ext4 and F2FS file systems is provided in the Android Open Source Project (AOSP) and needs only be enabled on devices that meet the requirements. Manufacturers electing to use FBE may wish to explore ways of optimizing the feature based on the system on chip (SoC) used.

5All the necessary packages in AOSP have been updated to be direct-boot aware. However, where device manufacturers use customized versions of these apps, they will want to ensure at a minimum there are direct-boot aware packages providing the following services:

  • Telephony Services and Dialer
  • Input method for entering passwords into the lock screen

6To use the AOSP implementation of FBE securely, a device needs to meet the following dependencies:

  • Kernel Support for Ext4 encryption or F2FS encryption.
  • Keymaster Support with HAL version 1.0 or higher. There is no support for Keymaster 0.3 as that does not provide the necessary capabilities or assure sufficient protection for encryption keys.
  • Keymaster/Keystore and Gatekeeper must be implemented in a Trusted Execution Environment (TEE) to provide protection for the DE keys so that an unauthorized OS (custom OS flashed onto the device) cannot simply request the DE keys.
  • Hardware Root of Trust and Verified Boot bound to the Keymaster initialization is required to ensure that DE keys are not accessible by an unauthorized operating system.


File-Based Encryption  |  Android Open Source Project (google.cn)

zygote

service zygote /system/bin/app_process64   -Xzygote /system/bin --zygote --start-system-server
    class main
    priority -20
    user root
    group root readproc
    socket zygote stream 660 root system
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    onrestart restart wificond
    writepid /dev/cpuset/foreground/tasks

1, init.rczygote’s .rc file is system/core/rootdir/init.zygote64_32.rc , compiled to image from by macro: PRODUCT_COPY_FILES +=. Impoted to init.rc by command:

import /init.${ro.zygote}.rc

2, priority: The priority attribute in .rc file is within a range between -20 and 20. -20 is the highest priority. Zygote will reset the priority as 0 (NORMAL) when forking new applications.   zygote.java::forkAndSpecialize()->resetNicePriority()

1, Zygote register a local socket service /dev/socket/zygote.

2,  system_server: is the first JAVA process forked from zygote.

3, zygote starts a loop to receive request from AMS to generate applications.

4, AMS(Activity Manager Service): AMS is a module running I system_server process. It receives requests from difference modules through binder. Then AMS send request to zygote through local socket.

5, Every java application runs in individual JVM process.

 

boot progress 

Boot progress

Discription

boot_progress_start

Start zygote.

boot_progress_preload_start

Zygote loads JVM essential libs & resources.

boot_progress_preload_end

boot_progress_system_run

system_server launcherd, start  system services.

boot_progress_pms_start

Start Package Manager Service.

boot_progress_pms_system_scan_start

Start to scan builtin applications.

boot_progress_pms_data_scan_start

Start to scan applications in /data partition.

boot_progress_pms_scan_end

boot_progress_pms_ready

Application resources load ready.

boot_progress_ams_ready

Persistent applications launched ready.

boot_progress_enable_screen

Start to enter launcher.

1, AMS  invoke startHomeActivityLocked to start launcher after ready.

2, Launcher unlock storage, then invoke UserController.finishUserUnlockedComplete() to send BOOT_COMPLETED broadcast.

Customize - native

1, init_rc: label:init_rc in Android.bp & macro:LOCAL_INIT_RC in Android.mk declare the init.rc file to compile.
    The first line of the init.rc is:

    Service [service name] [process directory] [argument 0 … n]


    service can be a .sh script as well.

2, priority: The priority attribute in .rc file is within a range between -20 and 20. -20 is the highest priority. 
3, user: user identify. root, radio, system, media, shell, etc.
4, group: group id. root, system, vendor, radio, graphics, inet, etc.
5, disabled:  will not be started even if set its class. But this service can be launched when triggered. (on action or on property)6, oneshot: if set, the service will not be restarted after exit.
7, seclabel: selinux context label.

Customize - JAVA

  1.  AMS starts all the persistent applications before boot_completed. This label may not work if application is install in /data partition other than prebuilt in /system or /vendor partion.
  2. Application may not able to receive the BOOT_COMPLETED broadcast is it is installed in /data partition and not launched yet by user.
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐