分区结构
在img写入后, 会产生两个分区
EMUELEC: 用于启动的文件, 例如dtb文件等, 以及system.img & system.img.md5, EmuELEC的系统文件都在这个img里面
STORAGE: 空
运行中目录结构
/dev/mmcblk1p1 511.7M 373.6M 138.2M 73% /flash /dev/loop0 357.5M 357.5M 0 100% / /dev/mmcblk1p2 28.6G 3.5G 25.1G 12% /storage
启动后, EMUELEC分区被挂载为 /flash, STORAGE分区被挂载为 /storage, system.img 通过 /dev/loop0 被挂载为系统根目录 /
所以, 用户能修改的仅仅是 /flash 和 /storage 目录下的内容
root用户的home目录被定位到 /storage, 如果需要添加登录后自动执行的命令(例如添加alias), 可以直接在 /storage 目录下新建 .profile 文件来实现
开机启动顺序
这个是在uboot中进行管理的, 可以通过fw_printenv命令进行查看
EmuELEC:/usr/sbin # fw_printenv ... baudrate=115200 boot_count=0 bootcmd=if test ${bootfromnand} = 1; then setenv bootfromnand 0; saveenv; else run bootfromsd; run bootfromusb; fi; run storeboot bootcount_check=echo bootcounts=${boot_count}; if itest ${boot_count} == 0; then setenv boot_count 1;saveenv;else if itest ${boot_count} == 1; then setenv boot_count 2;saveenv;else if itest ${boot_count} == 2; then setenv boot_count 3;saveenv;else if itest ${boot_count} == 3; then setenv boot_count 4;saveenv;else if itest ${boot_count} == 4; then run recovery_from_flash;fi;fi;fi;fi;fi bootdelay=0 bootfromnand=0 bootfromsd=mmcinfo; if fatload mmc 0 ${loadaddr} kernel.img; then run sddtb; setenv bootargs ${bootargs} bootfromsd; bootm; fi bootfromusb=usb start 0; if fatload usb 0 ${loadaddr} kernel.img; then run usbdtb; setenv bootargs ${bootargs} bootfromusb; bootm; fi bootmode_check=get_rebootmode; echo reboot_mode=${reboot_mode};if test ${reboot_mode} = factory_reset; then defenv_reserv;setenv upgrade_step 2; save;fi; cmdline_keys=if keyman init 0x1234; then if sec_keyunify read mac ${loadaddr} str; then setenv bootargs ${bootargs} mac=${mac} androidboot.mac=${mac};fi;fi; ...
可以看到其中的 bootfromnand 变量是用于控制设备的启动顺序, 如果值为1, 那么从nand(设备内部存储, eMMC等), 如果值为0, 那么依次从sd, 从usb启动, 在这个过程中如果某个介质可以启动了, 就把这个方式加到bootargs变量的值当中去, 例如
setenv bootargs ${bootargs} bootfromsd;
.然后调用系统函数bootm启动内核. bootm会调用 ./lib_arm/armlinux.c的do_bootm() 方法, 里面会调用./common/cmd_bootm.c的do_bootm_linux()
如果这些都不成功, 那就调用storeboot
storeboot=if imgread kernel boot ${loadaddr}; then bootm ${loadaddr}; fi;run update;
而update会依次尝试从各个媒介升级
update=run usb_burning; run sdc_burning; if mmcinfo; then run recovery_from_sdcard;fi;if usb start 0; then run recovery_from_udisk;fi;run recovery_from_flash;
中间还会记录启动次数, 如果启动次数达到4, 就会执行 recovery_from_flash
recovery_from_flash=setenv bootargs ${bootargs} aml_dt=${aml_dt} recovery_part={recovery_part} recovery_offset={recovery_offset};if imgread kernel ${recovery_part} ${loadaddr} ${recovery_offset}; then wipeisb; bootm ${loadaddr}; fi
ES的Quit菜单中的Reboot From NAND, 实际执行的就是 /usr/sbin/rebootfromnand 这个命令, 里面将 bootfromnand 值设为了1
EmuELEC:/usr/sbin # more rebootfromnand #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2016-2018 kszaq ([email protected]) # Copyright (C) 2018-present Team CoreELEC (https://coreelec.org) if /usr/sbin/fw_printenv whereToBootFrom > /dev/null 2>&1; then /usr/sbin/fw_setenv whereToBootFrom internal; fi /usr/sbin/fw_setenv bootfromnand 1
服务启动顺序
系统启动的服务是通过systemd管理的, 启动脚本位于 /usr/lib/systemd/system/ 下, 因为是过loop设备挂载的, 所以这里面的文件都不可修改. 默认的启动target为
EmuELEC:/usr/lib/systemd/system # systemctl get-default emuelec.target EmuELEC:/usr/lib/systemd/system # ll def*.* lrwxrwxrwx 1 root root 14 Nov 19 00:42 default.target -> emuelec.target
服务依赖关系为
EmuELEC:/usr/lib/systemd/system # systemctl list-dependencies emuelec.target emuelec.target ● ├─emuelec-autostart.service ● ├─emustation.service ● ├─retroarch.service ● ├─tmp-assets.mount ● ├─tmp-cores.mount ● ├─tmp-database.mount ● ├─tmp-joypads.mount ● ├─tmp-overlays.mount ● ├─tmp-shaders.mount ● ├─graphical.target ● │ ├─unbind-console.service ● │ └─multi-user.target ● │ ├─avahi-daemon.service ● │ ├─connman.service ● │ ├─dbus.service ● │ ├─entware.service ● │ ├─iptables.service ● │ ├─nmbd.service ● │ ├─pulseaudio.service ● │ ├─rpcbind.service ● │ ├─[email protected] ● │ ├─smbd.service ● │ ├─sshd.service ● │ ├─systemd-ask-password-wall.path ● │ ├─systemd-logind.service ● │ └─basic.target ● │ ├─add-entropy.service ● │ ├─amlogic-dvb.service ● │ ├─fstrim.service ● │ ├─hwdb.service ● │ ├─kvimfan.service ● │ ├─openvfd.service ● │ ├─show-version.service ● │ ├─swap.service ● │ ├─tmp.mount ● │ ├─var.mount ● │ ├─wetekdvb.service ● │ ├─paths.target ● │ ├─slices.target ● │ │ ├─-.slice ● │ │ └─system.slice ● │ ├─sockets.target ● │ │ ├─dbus.socket ● │ │ ├─systemd-initctl.socket ● │ │ ├─systemd-journald-audit.socket ● │ │ ├─systemd-journald-dev-log.socket ● │ │ ├─systemd-journald.socket ● │ │ ├─systemd-udevd-control.socket ● │ │ └─systemd-udevd-kernel.socket ● │ ├─sysinit.target ● │ │ ├─debug-shell.service ● │ │ ├─debugconfig.service ● │ │ ├─dev-hugepages.mount ● │ │ ├─dev-mqueue.mount ● │ │ ├─kmod-static-nodes.service ● │ │ ├─machine-id.service ● │ │ ├─openssl-config.service ● │ │ ├─sys-fs-fuse-connections.mount ● │ │ ├─sys-kernel-config.mount ● │ │ ├─sys-kernel-debug.mount ● │ │ ├─systemd-ask-password-console.path ● │ │ ├─systemd-hwdb-update.service ● │ │ ├─systemd-journal-catalog-update.service ● │ │ ├─systemd-journal-flush.service ● │ │ ├─systemd-journald.service ● │ │ ├─systemd-modules-load.service ● │ │ ├─systemd-sysctl.service ● │ │ ├─systemd-tmpfiles-setup-dev.service ● │ │ ├─systemd-tmpfiles-setup.service ● │ │ ├─systemd-udev-trigger.service ● │ │ ├─systemd-udevd.service ● │ │ ├─tz-data.service ● │ │ ├─usercache.service ● │ │ ├─userconfig.service ● │ │ ├─local-fs.target ● │ │ │ ├─kernel-overlays.service ● │ │ │ ├─libmali.service ● │ │ │ ├─tmp.mount ● │ │ │ └─var.mount ● │ │ └─swap.target ● │ └─timers.target ● │ └─systemd-tmpfiles-clean.timer ● └─multi-user.target ● ├─avahi-daemon.service ● ├─connman.service ● ├─dbus.service ● ├─entware.service ● ├─iptables.service ● ├─nmbd.service ● ├─pulseaudio.service ● ├─rpcbind.service ● ├─[email protected] ● ├─smbd.service ● ├─sshd.service ● ├─systemd-ask-password-wall.path ● ├─systemd-logind.service ● └─basic.target
在 emuelec-autostart.service 里, 执行了/storage/.config/autostart.sh
在autostart.sh的结尾, 又执行了 /storage/.config/custom_start.sh
最后一步, 通过 emustation.service, 把/usr/bin/emulationstation启动起来