Learn Some Framework-2 Story begins at Init to Zygote
Intro
本章节主要介绍当我们按下Power键后到Zygote来到这段时间内发生的故事,主要是Android Framework都做了什么。
S1. Init
Linux启动后,Bootloader会现根据Kernel的入口地址载入Kernel(这部分如果感兴趣请参看其他资料,此处不再累述),Kernel加载成功后,会启动第一个用户进程--Init, Init会读取Init.RC的内容,并根据RC脚本的内容开始初始化系统,对于Android而言,系统即是指System Server部分。
请注意,因为Init进程是第一个用户进程,所以当我们看见/poc/1时,这个pid为1的进程就是Init,且恒真。
对于Android,Google将Init.RC文件放在 /system/core/rootdir/init.rc, 下面我们就来看一下init.rc到底做了什么(文件大家可以在之前章节提到的Androidxref上查看).
rc实质上是一个脚本文件,只是他的interpretter是Init这个进程而已,所以阅读上应该不会有障碍。
我们首先看见的是一系列的"on",譬如on early-init, on init...等等,它表示了Init的不同阶段所需要做的事情,我们可以形象地理解成类似于回调函数的标记即可,执行的顺序也是由上而下,首先:
on early-init
# Set init and its forked children's oom_adj.
write /proc/1/oom_score_adj -1000
# Set the security context of /adb_keys if present.
restorecon /adb_keys
start ueventd
我们之前讲过,一看见/proc/1就知道这是Init进程,所以现将这个进程的adj值设置为-1000,如此低的值保证了这个进程不会被Low Memory Killer杀掉,有关Low Memory Killer我们会在之后的章节介绍。
"restorecon"是标准的Linux命令,用于恢复SELinux的文件属性,所以与安全有关,这部分我们会在接下来的章节介绍到SELinux。
接下来通过start命令运行脚本ueventd,ueventd的源码位于/system/core/init/ueventd.cpp, 由于作者内核知识有限,只能带大家走马观花,大致了解一下作用:
int ueventd_main(int argc, char **argv)
{
/*
* init sets the umask to 077 for forked processes. We need to
* create files with exact permissions, without modification by
* the umask.
*/
umask(000);
/* Prevent fire-and-forget children from becoming zombies.
* If we should need to wait() for some children in the future
* (as opposed to none right now), double-forking here instead
* of ignoring SIGCHLD may be the better solution.
*/
signal(SIGCHLD, SIG_IGN);
open_devnull_stdio();
klog_init();
klog_set_level(KLOG_NOTICE_LEVEL);
NOTICE("ueventd started!\n");
selinux_callback cb;
cb.func_log = selinux_klog_callback;
selinux_set_callback(SELINUX_CB_LOG, cb);
char hardware[PROP_VALUE_MAX];
property_get("ro.hardware", hardware);
ueventd_parse_config_file("/ueventd.rc");
ueventd_parse_config_file(android::base::StringPrintf("/ueventd.%s.rc", hardware).c_str());
device_init();
pollfd ufd;
ufd.events = POLLIN;
ufd.fd = get_device_fd();
while (true) {
ufd.revents = 0;
int nr = poll(&ufd, 1, -1);
if (nr <= 0) {
continue;
}
if (ufd.revents & POLLIN) {
handle_device_fd();
}
}
return 0;
}
我们可以看到,这main函数内,首先打开了kernel log,这样开发者可以在第一时间通过串口打印kernel运行时的Log。
接下来处理了ueventd.rc这个脚本,这个脚本很简单,主要是对应了挂载点的权限声明,就不累述了。
最重要的一步便是device_init()这个方法的调用:
void device_init() {
sehandle = NULL;
if (is_selinux_enabled() > 0) {
sehandle = selinux_android_file_context_handle();
selinux_status_open(true);
}
/* is 256K enough? udev uses 16MB! */
device_fd = uevent_open_socket(256*1024, true);
if (device_fd == -1) {
return;
}
fcntl(device_fd, F_SETFL, O_NONBLOCK);
if (access(COLDBOOT_DONE, F_OK) == 0) {
NOTICE("Skipping coldboot, already done!\n");
return;
}
Timer t;
coldboot("/sys/class");
coldboot("/sys/block");
coldboot("/sys/devices");
close(open(COLDBOOT_DONE, O_WRONLY|O_CREAT|O_CLOEXEC, 0000));
NOTICE("Coldboot took %.2fs.\n", t.duration());
}
在Linux中,设备的挂载和卸载是kernel通过socket发送uevent给用户态的进程的,所以在这里首先打开这个socket以便于接受kernel的uevent。
之后做了coldboot,具体便是指针对在uevent收到之前已经挂载的设备再次发送uevent以便于全面的初始化,在Android上,主要针对sys下面的class, block和devices三个设备挂载点。
然后我们再回去/system/core/init/ueventd.cpp, 此时就开始通过poll方法等待socket上的uevent,一旦poll到uevent了,就进入handle_device_fd()处理。
至此,设备初始化已经完成了,这样我们就可以开始进入真正的操作系统的Init阶段了,我们再回到Init.rc文件:
on init
sysclktz 0
# Backward compatibility.
symlink /system/etc /etc
symlink /sys/kernel/debug /d
# Link /vendor to /system/vendor for devices without a vendor partition.
symlink /system/vendor /vendor
# Create cgroup mount point for cpu accounting
mkdir /acct
mount cgroup none /acct cpuacct
mkdir /acct/uid
# Create cgroup mount point for memory
mount tmpfs none /sys/fs/cgroup mode=0750,uid=0,gid=1000
mkdir /sys/fs/cgroup/memory 0750 root system
mount cgroup none /sys/fs/cgroup/memory memory
write /sys/fs/cgroup/memory/memory.move_charge_at_immigrate 1
chown root system /sys/fs/cgroup/memory/tasks
chmod 0660 /sys/fs/cgroup/memory/tasks
mkdir /sys/fs/cgroup/memory/sw 0750 root system
write /sys/fs/cgroup/memory/sw/memory.swappiness 100
write /sys/fs/cgroup/memory/sw/memory.move_charge_at_immigrate 1
chown root system /sys/fs/cgroup/memory/sw/tasks
chmod 0660 /sys/fs/cgroup/memory/sw/tasks
mkdir /system
mkdir /data 0771 system system
mkdir /cache 0770 system cache
mkdir /config 0500 root root
# Mount staging areas for devices managed by vold
# See storage config details at http://source.android.com/tech/storage/
mkdir /mnt 0755 root system
mount tmpfs tmpfs /mnt mode=0755,uid=0,gid=1000
restorecon_recursive /mnt
mkdir /mnt/secure 0700 root root
mkdir /mnt/secure/asec 0700 root root
mkdir /mnt/asec 0755 root system
mkdir /mnt/obb 0755 root system
mkdir /mnt/media_rw 0750 root media_rw
mkdir /mnt/user 0755 root root
mkdir /mnt/user/0 0755 root root
mkdir /mnt/expand 0771 system system
# Storage views to support runtime permissions
mkdir /storage 0755 root root
mkdir /mnt/runtime 0700 root root
mkdir /mnt/runtime/default 0755 root root
mkdir /mnt/runtime/default/self 0755 root root
mkdir /mnt/runtime/read 0755 root root
mkdir /mnt/runtime/read/self 0755 root root
mkdir /mnt/runtime/write 0755 root root
mkdir /mnt/runtime/write/self 0755 root root
# Symlink to keep legacy apps working in multi-user world
symlink /storage/self/primary /sdcard
symlink /mnt/user/0/primary /mnt/runtime/default/self/primary
# memory control cgroup
mkdir /dev/memcg 0700 root system
mount cgroup none /dev/memcg memory
write /proc/sys/kernel/panic_on_oops 1
write /proc/sys/kernel/hung_task_timeout_secs 0
write /proc/cpu/alignment 4
# scheduler tunables
# Disable auto-scaling of scheduler tunables with hotplug. The tunables
# will vary across devices in unpredictable ways if allowed to scale with
# cpu cores.
write /proc/sys/kernel/sched_tunable_scaling 0
write /proc/sys/kernel/sched_latency_ns 10000000
write /proc/sys/kernel/sched_wakeup_granularity_ns 2000000
write /proc/sys/kernel/sched_compat_yield 1
write /proc/sys/kernel/sched_child_runs_first 0
write /proc/sys/kernel/randomize_va_space 2
write /proc/sys/kernel/kptr_restrict 2
write /proc/sys/vm/mmap_min_addr 32768
write /proc/sys/net/ipv4/ping_group_range "0 2147483647"
write /proc/sys/net/unix/max_dgram_qlen 300
write /proc/sys/kernel/sched_rt_runtime_us 950000
write /proc/sys/kernel/sched_rt_period_us 1000000
# reflect fwmark from incoming packets onto generated replies
write /proc/sys/net/ipv4/fwmark_reflect 1
write /proc/sys/net/ipv6/fwmark_reflect 1
# set fwmark on accepted sockets
write /proc/sys/net/ipv4/tcp_fwmark_accept 1
# disable icmp redirects
write /proc/sys/net/ipv4/conf/all/accept_redirects 0
write /proc/sys/net/ipv6/conf/all/accept_redirects 0
# Create cgroup mount points for process groups
mkdir /dev/cpuctl
mount cgroup none /dev/cpuctl cpu
chown system system /dev/cpuctl
chown system system /dev/cpuctl/tasks
chmod 0666 /dev/cpuctl/tasks
write /dev/cpuctl/cpu.shares 1024
write /dev/cpuctl/cpu.rt_runtime_us 800000
write /dev/cpuctl/cpu.rt_period_us 1000000
mkdir /dev/cpuctl/bg_non_interactive
chown system system /dev/cpuctl/bg_non_interactive/tasks
chmod 0666 /dev/cpuctl/bg_non_interactive/tasks
# 5.0 %
write /dev/cpuctl/bg_non_interactive/cpu.shares 52
write /dev/cpuctl/bg_non_interactive/cpu.rt_runtime_us 700000
write /dev/cpuctl/bg_non_interactive/cpu.rt_period_us 1000000
# sets up initial cpusets for ActivityManager
mkdir /dev/cpuset
mount cpuset none /dev/cpuset
# this ensures that the cpusets are present and usable, but the device's
# init.rc must actually set the correct cpus
mkdir /dev/cpuset/foreground
write /dev/cpuset/foreground/cpus 0
write /dev/cpuset/foreground/mems 0
mkdir /dev/cpuset/foreground/boost
write /dev/cpuset/foreground/boost/cpus 0
write /dev/cpuset/foreground/boost/mems 0
mkdir /dev/cpuset/background
write /dev/cpuset/background/cpus 0
write /dev/cpuset/background/mems 0
# system-background is for system tasks that should only run on
# little cores, not on bigs
# to be used only by init, so don't change system-bg permissions
mkdir /dev/cpuset/system-background
write /dev/cpuset/system-background/cpus 0
write /dev/cpuset/system-background/mems 0
# change permissions for all cpusets we'll touch at runtime
chown system system /dev/cpuset
chown system system /dev/cpuset/foreground
chown system system /dev/cpuset/foreground/boost
chown system system /dev/cpuset/background
chown system system /dev/cpuset/tasks
chown system system /dev/cpuset/foreground/tasks
chown system system /dev/cpuset/foreground/boost/tasks
chown system system /dev/cpuset/background/tasks
chmod 0664 /dev/cpuset/foreground/tasks
chmod 0664 /dev/cpuset/foreground/boost/tasks
chmod 0664 /dev/cpuset/background/tasks
chmod 0664 /dev/cpuset/tasks
# qtaguid will limit access to specific data based on group memberships.
# net_bw_acct grants impersonation of socket owners.
# net_bw_stats grants access to other apps' detailed tagged-socket stats.
chown root net_bw_acct /proc/net/xt_qtaguid/ctrl
chown root net_bw_stats /proc/net/xt_qtaguid/stats
# Allow everybody to read the xt_qtaguid resource tracking misc dev.
# This is needed by any process that uses socket tagging.
chmod 0644 /dev/xt_qtaguid
# Create location for fs_mgr to store abbreviated output from filesystem
# checker programs.
mkdir /dev/fscklogs 0770 root system
# pstore/ramoops previous console log
mount pstore pstore /sys/fs/pstore
chown system log /sys/fs/pstore/console-ramoops
chmod 0440 /sys/fs/pstore/console-ramoops
chown system log /sys/fs/pstore/pmsg-ramoops-0
chmod 0440 /sys/fs/pstore/pmsg-ramoops-0
# enable armv8_deprecated instruction hooks
write /proc/sys/abi/swp 1
配合注释不难理解到,这一部就开始新建各种文件夹以及文件权限的设置了.
接下来:
# Healthd can trigger a full boot from charger mode by signaling this
# property when the power button is held.
on property:sys.boot_from_charger_mode=1
class_stop charger
trigger late-init
当boot_from_charger_mode这个系统属性为1的时候,表示可以在充电时启动系统,那么我们需要做的是停止charger这个脚本,并触发late-init Action。
那么charger又是干什么的呢?其实它的主要作用就是在关机充电时显示充电画面的脚本,如果需要boot,那么紧接着我们需要显示的是Android的Logo,所以自然需要停止它,有关charger的具体介绍,我们在后续章节接着讲。
紧接着我们就步入了late-init:
# Mount filesystems and start core system services.
on late-init
trigger early-fs
trigger fs
trigger post-fs
# Load properties from /system/ + /factory after fs mount. Place
# this in another action so that the load will be scheduled after the prior
# issued fs triggers have completed.
trigger load_system_props_action
# Now we can mount /data. File encryption requires keymaster to decrypt
# /data, which in turn can only be loaded when system properties are present
trigger post-fs-data
trigger load_persist_props_action
# Remove a file to wake up anything waiting for firmware.
trigger firmware_mounts_complete
trigger early-boot
trigger boot
可以看出,这个时候Init连续触发了文件系统相关的3个Action,分别是early-fs, fs, post-fs,原生代码中并没有early-fs和fs的Action, 我们简单看一下post-fs做了一些什么:
on post-fs
start logd
# once everything is setup, no need to modify /
mount rootfs rootfs / ro remount
# Mount shared so changes propagate into child namespaces
mount rootfs rootfs / shared rec
# Mount default storage into root namespace
mount none /mnt/runtime/default /storage slave bind rec
# We chown/chmod /cache again so because mount is run as root + defaults
chown system cache /cache
chmod 0770 /cache
# We restorecon /cache in case the cache partition has been reset.
restorecon_recursive /cache
# Create /cache/recovery in case it's not there. It'll also fix the odd
# permissions if created by the recovery system.
mkdir /cache/recovery 0770 system cache
#change permissions on vmallocinfo so we can grab it from bugreports
chown root log /proc/vmallocinfo
chmod 0440 /proc/vmallocinfo
chown root log /proc/slabinfo
chmod 0440 /proc/slabinfo
#change permissions on kmsg & sysrq-trigger so bugreports can grab kthread stacks
chown root system /proc/kmsg
chmod 0440 /proc/kmsg
chown root system /proc/sysrq-trigger
chmod 0220 /proc/sysrq-trigger
chown system log /proc/last_kmsg
chmod 0440 /proc/last_kmsg
# make the selinux kernel policy world-readable
chmod 0444 /sys/fs/selinux/policy
# create the lost+found directories, so as to enforce our permissions
mkdir /cache/lost+found 0770 root root
首先就是启动了logd,这边是用于Log输出的模块,有关logd的知识我们会在接下来的章节介绍。
从而看出,post-fs启动了logd,并且做了一些cache和log相关设备的权限修正,我们就顺带看一下post-fs-data这个Action都做了什么:
on post-fs-data
# We chown/chmod /data again so because mount is run as root + defaults
chown system system /data
chmod 0771 /data
# We restorecon /data in case the userdata partition has been reset.
restorecon /data
# Emulated internal storage area
mkdir /data/media 0770 media_rw media_rw
# Make sure we have the device encryption key
start logd
start vold
installkey /data
# Start bootcharting as soon as possible after the data partition is
# mounted to collect more data.
mkdir /data/bootchart 0755 shell shell
bootchart_init
# Avoid predictable entropy pool. Carry over entropy from previous boot.
copy /data/system/entropy.dat /dev/urandom
# create basic filesystem structure
mkdir /data/misc 01771 system misc
mkdir /data/misc/adb 02750 system shell
mkdir /data/misc/bluedroid 02770 bluetooth net_bt_stack
# Fix the access permissions and group ownership for 'bt_config.conf'
chmod 0660 /data/misc/bluedroid/bt_config.conf
chown bluetooth net_bt_stack /data/misc/bluedroid/bt_config.conf
mkdir /data/misc/bluetooth 0770 system system
mkdir /data/misc/keystore 0700 keystore keystore
mkdir /data/misc/gatekeeper 0700 system system
mkdir /data/misc/keychain 0771 system system
mkdir /data/misc/net 0750 root shell
mkdir /data/misc/radio 0770 system radio
mkdir /data/misc/sms 0770 system radio
mkdir /data/misc/zoneinfo 0775 system system
mkdir /data/misc/vpn 0770 system vpn
mkdir /data/misc/shared_relro 0771 shared_relro shared_relro
mkdir /data/misc/systemkeys 0700 system system
mkdir /data/misc/wifi 0770 wifi wifi
mkdir /data/misc/wifi/sockets 0770 wifi wifi
mkdir /data/misc/wifi/wpa_supplicant 0770 wifi wifi
mkdir /data/misc/ethernet 0770 system system
mkdir /data/misc/dhcp 0770 dhcp dhcp
mkdir /data/misc/user 0771 root root
mkdir /data/misc/perfprofd 0775 root root
# give system access to wpa_supplicant.conf for backup and restore
chmod 0660 /data/misc/wifi/wpa_supplicant.conf
mkdir /data/local 0751 root root
mkdir /data/misc/media 0700 media media
mkdir /data/misc/vold 0700 root root
# For security reasons, /data/local/tmp should always be empty.
# Do not place files or directories in /data/local/tmp
mkdir /data/local/tmp 0771 shell shell
mkdir /data/data 0771 system system
mkdir /data/app-private 0771 system system
mkdir /data/app-asec 0700 root root
mkdir /data/app-lib 0771 system system
mkdir /data/app 0771 system system
mkdir /data/property 0700 root root
mkdir /data/tombstones 0771 system system
# create dalvik-cache, so as to enforce our permissions
mkdir /data/dalvik-cache 0771 root root
mkdir /data/dalvik-cache/profiles 0711 system system
# create resource-cache and double-check the perms
mkdir /data/resource-cache 0771 system system
chown system system /data/resource-cache
chmod 0771 /data/resource-cache
# create the lost+found directories, so as to enforce our permissions
mkdir /data/lost+found 0770 root root
# create directory for DRM plug-ins - give drm the read/write access to
# the following directory.
mkdir /data/drm 0770 drm drm
# create directory for MediaDrm plug-ins - give drm the read/write access to
# the following directory.
mkdir /data/mediadrm 0770 mediadrm mediadrm
mkdir /data/adb 0700 root root
# symlink to bugreport storage location
symlink /data/data/com.android.shell/files/bugreports /data/bugreports
# Separate location for storing security policy files on data
mkdir /data/security 0711 system system
# Create all remaining /data root dirs so that they are made through init
# and get proper encryption policy installed
mkdir /data/backup 0700 system system
mkdir /data/media 0770 media_rw media_rw
mkdir /data/ss 0700 system system
mkdir /data/system 0775 system system
mkdir /data/system/heapdump 0700 system system
mkdir /data/user 0711 system system
setusercryptopolicies /data/user
# Reload policy from /data/security if present.
setprop selinux.reload_policy 1
# Set SELinux security contexts on upgrade or policy update.
restorecon_recursive /data
# Check any timezone data in /data is newer than the copy in /system, delete if not.
exec - system system -- /system/bin/tzdatacheck /system/usr/share/zoneinfo /data/misc/zoneinfo
# If there is no fs-post-data action in the init.<device>.rc file, you
# must uncomment this line, otherwise encrypted filesystems
# won't work.
# Set indication (checked by vold) that we have finished this action
#setprop vold.post_fs_data_done 1
很明显,这一个Action名副其实,对/data下的文件进行操作
接来下在late-init中,开始了load property的操作,首先是load_system_props_action
# Load properties from /system/ + /factory after fs mount.
on load_system_props_action
load_system_props
在这里调用了函数 load_system_props()
void load_system_props() {
load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL);
load_properties_from_file(PROP_PATH_VENDOR_BUILD, NULL);
load_properties_from_file(PROP_PATH_FACTORY, "ro.*");
load_recovery_id_prop();
}
我们主要关注一下三个path,其他的实现都是C代码,请读者自行参考即可:
#define PROP_PATH_SYSTEM_BUILD "/system/build.prop"
#define PROP_PATH_VENDOR_BUILD "/vendor/build.prop"
#define PROP_PATH_FACTORY "/factory/factory.prop"
至此,这边是我们常说的system props的来源。
接下来的一个Action:
on load_persist_props_action
load_persist_props
start logd
start logd-reinit
调用方法:
void load_persist_props(void) {
load_override_properties();
/* Read persistent properties after all default values have been loaded. */
load_persistent_properties();
}
其实不难看出,这里加载了原生的persistent的props和制造商override的部分props,我们看实现:
static void load_override_properties() {
if (ALLOW_LOCAL_PROP_OVERRIDE) {
char debuggable[PROP_VALUE_MAX];
int ret = property_get("ro.debuggable", debuggable);
if (ret && (strcmp(debuggable, "1") == 0)) {
load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE, NULL);
}
}
}
#define PROP_PATH_LOCAL_OVERRIDE "/data/local.prop"
static void load_persistent_properties() {
persistent_properties_loaded = 1;
std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(PERSISTENT_PROPERTY_DIR), closedir);
if (!dir) {
ERROR("Unable to open persistent property directory \"%s\": %s\n",
PERSISTENT_PROPERTY_DIR, strerror(errno));
return;
}
struct dirent* entry;
while ((entry = readdir(dir.get())) != NULL) {
if (strncmp("persist.", entry->d_name, strlen("persist."))) {
continue;
}
if (entry->d_type != DT_REG) {
continue;
}
// Open the file and read the property value.
int fd = openat(dirfd(dir.get()), entry->d_name, O_RDONLY | O_NOFOLLOW);
if (fd == -1) {
ERROR("Unable to open persistent property file \"%s\": %s\n",
entry->d_name, strerror(errno));
continue;
}
struct stat sb;
if (fstat(fd, &sb) == -1) {
ERROR("fstat on property file \"%s\" failed: %s\n", entry->d_name, strerror(errno));
close(fd);
continue;
}
// File must not be accessible to others, be owned by root/root, and
// not be a hard link to any other file.
if (((sb.st_mode & (S_IRWXG | S_IRWXO)) != 0) || (sb.st_uid != 0) || (sb.st_gid != 0) ||
(sb.st_nlink != 1)) {
ERROR("skipping insecure property file %s (uid=%u gid=%u nlink=%u mode=%o)\n",
entry->d_name, (unsigned int)sb.st_uid, (unsigned int)sb.st_gid,
(unsigned int)sb.st_nlink, sb.st_mode);
close(fd);
continue;
}
char value[PROP_VALUE_MAX];
int length = read(fd, value, sizeof(value) - 1);
if (length >= 0) {
value[length] = 0;
property_set(entry->d_name, value);
} else {
ERROR("Unable to read persistent property file %s: %s\n",
entry->d_name, strerror(errno));
}
close(fd);
}
}
#define PERSISTENT_PROPERTY_DIR "/data/property"
这样就完成了system和persistent这两种property的读取,对于property,会在之后的章节详细介绍.
接下来,late-init就将我们带入了early-boot和boot两个Action,由于early-boot在原生代码中没有实现,是留给制造商做客制化使用,所以我们只介绍boot:
on boot
# basic network init
ifup lo
hostname localhost
domainname localdomain
# set RLIMIT_NICE to allow priorities from 19 to -20
setrlimit 13 40 40
# Memory management. Basic kernel parameters, and allow the high
# level system server to be able to adjust the kernel OOM driver
# parameters to match how it is managing things.
write /proc/sys/vm/overcommit_memory 1
write /proc/sys/vm/min_free_order_shift 4
chown root system /sys/module/lowmemorykiller/parameters/adj
chmod 0664 /sys/module/lowmemorykiller/parameters/adj
chown root system /sys/module/lowmemorykiller/parameters/minfree
chmod 0664 /sys/module/lowmemorykiller/parameters/minfree
# Tweak background writeout
write /proc/sys/vm/dirty_expire_centisecs 200
write /proc/sys/vm/dirty_background_ratio 5
# Permissions for System Server and daemons.
chown radio system /sys/android_power/state
chown radio system /sys/android_power/request_state
chown radio system /sys/android_power/acquire_full_wake_lock
chown radio system /sys/android_power/acquire_partial_wake_lock
chown radio system /sys/android_power/release_wake_lock
chown system system /sys/power/autosleep
chown system system /sys/power/state
chown system system /sys/power/wakeup_count
chown radio system /sys/power/wake_lock
chown radio system /sys/power/wake_unlock
chmod 0660 /sys/power/state
chmod 0660 /sys/power/wake_lock
chmod 0660 /sys/power/wake_unlock
chown system system /sys/devices/system/cpu/cpufreq/interactive/timer_rate
chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/timer_rate
chown system system /sys/devices/system/cpu/cpufreq/interactive/timer_slack
chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/timer_slack
chown system system /sys/devices/system/cpu/cpufreq/interactive/min_sample_time
chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/min_sample_time
chown system system /sys/devices/system/cpu/cpufreq/interactive/hispeed_freq
chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/hispeed_freq
chown system system /sys/devices/system/cpu/cpufreq/interactive/target_loads
chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/target_loads
chown system system /sys/devices/system/cpu/cpufreq/interactive/go_hispeed_load
chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/go_hispeed_load
chown system system /sys/devices/system/cpu/cpufreq/interactive/above_hispeed_delay
chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/above_hispeed_delay
chown system system /sys/devices/system/cpu/cpufreq/interactive/boost
chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/boost
chown system system /sys/devices/system/cpu/cpufreq/interactive/boostpulse
chown system system /sys/devices/system/cpu/cpufreq/interactive/input_boost
chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/input_boost
chown system system /sys/devices/system/cpu/cpufreq/interactive/boostpulse_duration
chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/boostpulse_duration
chown system system /sys/devices/system/cpu/cpufreq/interactive/io_is_busy
chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/io_is_busy
# Assume SMP uses shared cpufreq policy for all CPUs
chown system system /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
chmod 0660 /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
chown system system /sys/class/timed_output/vibrator/enable
chown system system /sys/class/leds/keyboard-backlight/brightness
chown system system /sys/class/leds/lcd-backlight/brightness
chown system system /sys/class/leds/button-backlight/brightness
chown system system /sys/class/leds/jogball-backlight/brightness
chown system system /sys/class/leds/red/brightness
chown system system /sys/class/leds/green/brightness
chown system system /sys/class/leds/blue/brightness
chown system system /sys/class/leds/red/device/grpfreq
chown system system /sys/class/leds/red/device/grppwm
chown system system /sys/class/leds/red/device/blink
chown system system /sys/class/timed_output/vibrator/enable
chown system system /sys/module/sco/parameters/disable_esco
chown system system /sys/kernel/ipv4/tcp_wmem_min
chown system system /sys/kernel/ipv4/tcp_wmem_def
chown system system /sys/kernel/ipv4/tcp_wmem_max
chown system system /sys/kernel/ipv4/tcp_rmem_min
chown system system /sys/kernel/ipv4/tcp_rmem_def
chown system system /sys/kernel/ipv4/tcp_rmem_max
chown root radio /proc/cmdline
# Define default initial receive window size in segments.
setprop net.tcp.default_init_rwnd 60
class_start core
可以看到,最开始Init对网络做了简单设置,接下来对lowmemorykiller以及各个外设,包括power,cpu,led等做了权限设置,最后启动一个叫做core的class, 对于class_start这个command,我们可以在command的映射表内查询到它对应的函数为do_class_start:
KEYWORD(class_start, COMMAND, 1, do_class_start)
此时,core这个service便被加载起来,于是/system/core/init/ init.cpp便进入了main函数,其中出现了一段循环:
while (true) {
if (!waiting_for_exec) {
execute_one_command();
restart_processes();
}
int timeout = -1;
if (process_needs_restart) {
timeout = (process_needs_restart - gettime()) * 1000;
if (timeout < 0)
timeout = 0;
}
if (!action_queue_empty() || cur_action) {
timeout = 0;
}
bootchart_sample(&timeout);
epoll_event ev;
int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout));
if (nr == -1) {
ERROR("epoll_wait failed: %s\n", strerror(errno));
} else if (nr == 1) {
((void (*)()) ev.data.ptr)();
}
}
这一段做的事情就是讲init.rc内的各个service启动起来,这其中就有大名鼎鼎的logd, ueventd, healthd等等,当运行到此时,native的daemon进程全部被启动,而承接Android最关键的一步便是:
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
class main
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd
writepid /dev/cpuset/foreground/tasks
看到这里,我们便熟悉了,这样我们就正式进入了Zygote世代,接下来就会由Zygote大显神通了。