本文基于android 早期版本 可能是4.4
1. 相关代码目录:
android \system\core\init
android\system\core\libsysutils\src\FrameworkListener.cpp
android \system\vold
android \frameworks\base\services\java\com\android\server
2. SD卡开机加载方法和简易流程图
总结起来SD卡加载大概有3种方式:
1. 开机自动加载;
2. 热插拔;
如果手机支持热插拔,底层驱动会将SD卡驱动信息发送给VOLD,VolumeManager 或者Volume类会将处理状态发送给MountService,MountService最后发送状态给APP;
3. 通过setting菜单安装
/*卸载该分区挂载的所有挂载点,这里为什么用所有来形容了,因为Android 系统挂载一个分区的期间,重复挂载在好几个目录,将分区挂载在/mnt/asec目录,也挂载
在/mnt/secure/asec目录,也挂载在/mnt/sdcard目录下,总共三次挂载,谷歌不知为什么搞这么复杂?
待深究。。*/
这里介绍下开机自动加载的过程,以下是一个简单流程图:
源代码分析:
1. 开机
Vold为一守护进程,初始化时,会创建classNetlinkManager和VolumeManager,
Class NetlinkManager接收来自底层的信息,然后转交给VolumeManager处理;
class VolumeManager 单例模式,它主要负责vold的管理操作
class DirectVolume封装了很多的方法和属性;
class CommandListener内部封装了一个socket 用来跨进程通信,它在vold 进程中属于监听类,即服务器端,主要收到上层 MountService发来的命令,分析后,转交给VolumeManager处理;VolumeManager处理信息后,或报告给上层MountService
关于vold 的其他介绍请参考之前的《SD卡基本功能的原理实现和流程分析》。
system\core\init\init.c
Init .c通过加载Init.rc文件初始化Vold 模块和app_process模块,找到主函数main开始执行
service vold /system/bin/vold
class core
socket vold stream 0660 root mount
ioprio be 2
service zygote /system/bin/app_process-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
找到主函数main开始执行,vold模块main 函数:
int main() {
VolumeManager *vm;
CommandListener *cl;
NetlinkManager *nm;
SLOGI("Vold 2.1 (the revenge) firing up");
mkdir("/dev/block/vold", 0755);
/* For when cryptfs checks and mounts an encrypted filesystem */
klog_set_level(6);
/* Create our singleton managers */
if (!(vm = VolumeManager::Instance())) {
SLOGE("Unable to create VolumeManager");
exit(1);
};
if (!(nm = NetlinkManager::Instance())) {
SLOGE("Unable to create NetlinkManager");
exit(1);
};
cl = new CommandListener();
vm->setBroadcaster((SocketListener *) cl);
nm->setBroadcaster((SocketListener *) cl);
if (vm->start()) {
SLOGE("Unable to start VolumeManager (%s)", strerror(errno));
exit(1);
}
if (process_config(vm)) {
SLOGE("Error reading configuration (%s)... continuing anyways",strerror(errno));
}
if (nm->start()) {
SLOGE("Unable to start NetlinkManager (%s)", strerror(errno));
exit(1);
}
coldboot("/sys/block");
// coldboot("/sys/class/switch");
/*
* Now that we're up, we can respond to commands
*/
if (cl->startListener()) {
SLOGE("Unable to start CommandListener (%s)",strerror(errno));
exit(1);
}
// Eventually we'll become the monitoring thread
while(1) {
sleep(1000);
}
SLOGI("Vold exiting");
exit(0);
}
app_main.cpp 主函数:
int main(int argc, char* const argv[])
{
#ifdef __arm__
/*
* b/7188322 - Temporarily revert to the compat memory layout
* to avoid breaking third party apps.
*
* THIS WILL GO AWAY IN A FUTURE ANDROID RELEASE.
*
*http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=7dbaa466
* changes the kernel mapping from bottom up to top-down.
* This breaks some programs which improperly embed
* an out of date copy of Android's linker.
*/
char value[PROPERTY_VALUE_MAX];
property_get("ro.kernel.qemu", value, "");
bool is_qemu = (strcmp(value, "1") == 0);
if ((getenv("NO_ADDR_COMPAT_LAYOUT_FIXUP") == NULL) &&!is_qemu) {
int current = personality(0xFFFFFFFF);
if ((current & ADDR_COMPAT_LAYOUT) == 0) {
personality(current | ADDR_COMPAT_LAYOUT);
setenv("NO_ADDR_COMPAT_LAYOUT_FIXUP", "1", 1);
execv("/system/bin/app_process", argv);
return -1;
}
}
unsetenv("NO_ADDR_COMPAT_LAYOUT_FIXUP");
#endif
// ADDED BY MARS BEGIN
setconnecthook(android::hook_connect);
// ADDED BY MARS END
//These are global variables in ProcessState.cpp
mArgC = argc;
mArgV = argv;
mArgLen = 0;
for (int i=0; i<argc; i++) {
mArgLen += strlen(argv[i]) + 1;
}
mArgLen--;
AppRuntime runtime;
const char* argv0 = argv[0];
// Process command line arguments
// ignore argv[0]
argc--;
argv++;
// Everything up to '--' or first non '-' arg goes to the vm
int i = runtime.addVmArguments(argc, argv);
// Parse runtime arguments. Stopat first unrecognized option.
bool zygote = false;
bool startSystemServer = false;
bool application = false;
const char* parentDir = NULL;
const char* niceName = NULL;
const char* className = NULL;
while (i < argc) {
const char* arg = argv[i++];
if (!parentDir) {
parentDir = arg;
} else if (strcmp(arg, "--zygote") == 0) {
zygote = true;
niceName = "zygote";
} else if (strcmp(arg, "--start-system-server") == 0) {
startSystemServer = true;
} else if (strcmp(arg, "--application") == 0) {