本文基于android 早期版本 可能是4.4
1. 相关代码目录:
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
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) {
application = true;
} else if (strncmp(arg, "--nice-name=", 12) == 0) {
niceName = arg + 12;
} else {
className = arg;
break;
}
}
if (niceName && *niceName) {
setArgv0(argv0, niceName);
set_process_name(niceName);
}
runtime.mParentDir = parentDir;
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit",
startSystemServer ?"start-system-server" : "");
} else if(className) {
// Remainder of args get passed to startup class main()
runtime.mClassName = className;
runtime.mArgC = argc - i;
runtime.mArgV = argv + i;
runtime.start("com.android.internal.os.RuntimeInit",
application ?"application" : "tool");
}else {
fprintf(stderr, "Error: no class name or --zygotesupplied.\n");
app_usage();
LOG_ALWAYS_FATAL("app_process: no class name or --zygotesupplied.");
return 10;
}
}
ZygoteInit.java 找到主函数:
public static void main(String argv[]) {
try {
// Start profiling the zygoteinitialization.
SamplingProfilerIntegration.start();
registerZygoteSocket();
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
preload();
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
// Finish profiling the zygoteinitialization.
SamplingProfilerIntegration.writeZygoteSnapshot();
// Do an initial gc to clean upafter startup
gc();
// Disable tracing so that forkedprocesses do not inherit stale tracing tags from
// Zygote.
Trace.setTracingEnabled(false);
// If requested, start systemserver directly from Zygote
if (argv.length != 2) {
throw newRuntimeException(argv[0] + USAGE_STRING);
}
if(argv[1].equals("start-system-server")) {
startSystemServer();
//ADDED BY MARS BEGIN
// startMrvlRootServer();
//ADDED BY MARS END
} else if (!argv[1].equals("")) {
throw newRuntimeException(argv[0] + USAGE_STRING);
}
Log.i(TAG, "Accepting commandsocket connections");
runSelectLoop();
closeServerSocket();
} catch (MethodAndArgsCaller caller) {
caller.run();
} catch (RuntimeException ex) {
Log.e(TAG, "Zygote died withexception", ex);
closeServerSocket();
throw ex;
}
}
private static boolean startSystemServer()
throws MethodAndArgsCaller,RuntimeException {
long capabilities =posixCapabilitiesAsBits(
OsConstants.CAP_KILL,
OsConstants.CAP_NET_ADMIN,
OsConstants.CAP_NET_BIND_SERVICE,
OsConstants.CAP_NET_BROADCAST,
OsConstants.CAP_NET_RAW,
OsConstants.CAP_SYS_MODULE,
OsConstants.CAP_SYS_NICE,
OsConstants.CAP_SYS_RESOURCE,
OsConstants.CAP_SYS_TIME,
OsConstants.CAP_SYS_TTY_CONFIG
);
/* Hardcoded command line to start thesystem server */
String args[] = {
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007",
"--capabilities=" +capabilities + "," + capabilities,
"--runtime-init",
"--nice-name=system_server",
"com.android.server.SystemServer",
};
ZygoteConnection.Arguments parsedArgs =null;
int pid;
try {
parsedArgs = newZygoteConnection.Arguments(args);
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
/* Requestto fork the system server process */
pid =Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.debugFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}
/* For child process */
if (pid == 0) {
handleSystemServerProcess(parsedArgs);
}
return true;
}
SystemServer.java
public static void main(String[] args) {
SystemProperties.set("persist.sys.dalvik.vm.lib",
VMRuntime.getRuntime().vmLibrary());
if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
// If a device's clock is before 1970 (before 0), a lot of
// APIs crash dealing with negative numbers, notably
// java.io.File#setLastModified, so instead we fake it and
// hope that time from cell towers or NTP fixes it
// shortly.
Slog.w(TAG, "System clock is before 1970; setting to 1970.");
SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
}
if (SamplingProfilerIntegration.isEnabled()) {
SamplingProfilerIntegration.start();
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
SamplingProfilerIntegration.writeSnapshot("system_server",null);
}
}, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);
}
// Mmmmmm... more memory!
dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();
// The system server has to run all of the time, so it needs to be
// as efficient as possible with its memory usage.
VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
Environment.setUserRequired(true);
System.loadLibrary("android_servers");
Slog.i(TAG, "Entered the Android systemserver!");
// Initialize native services.
nativeInit();
// This used to be its own separate thread, but now it is
// just the loop we run on the main thread.
ServerThread thr = new ServerThread();
thr.initAndLoop();
}
initAndLoop函数代码比较长,它会初始化系统的service, 当然也包括我们关心的MountService:
先构造函数:
mountService = new MountService(context);
然后调用ActivityManagerService.self().systemReady
// We now tell the activity manager itis okay to run third party
// code. It will call back into us once it has gottento the state
// where third party code can reallyrun (but before it has actually
// started launching the initialapplications), for us to complete our
// initialization.
ActivityManagerService.self().systemReady(newRunnable() {
public void run() {
Slog.i(TAG, "Makingservices ready");
try {
ActivityManagerService.self().startObservingNativeCrashes();
} catch (Throwable e) {
reportWtf("observingnative crashes", e);
}
if (!headless) {
startSystemUi(contextF);
}
try {
if(mountServiceF != null) mountServiceF.systemReady();
} catch(Throwable e) {
reportWtf("making Mount Service ready", e);
}
MountService 构造函数:
public MountService(Context context) {
mContext = context;
synchronized (mVolumesLock) {
readStorageListLocked();
}
// XXX: This will go away soon in favorof IMountServiceObserver
mPms = (PackageManagerService)ServiceManager.getService("package");
新建一个重要的HandlerThread,用来处理一些重要的消息,主要处理开机和卸载的时候的一些消息
HandlerThreadhthread = new HandlerThread(TAG);
hthread.start();
mHandler = newMountServiceHandler(hthread.getLooper());
// Watch for user changes
final IntentFilter userFilter = newIntentFilter();
userFilter.addAction(Intent.ACTION_USER_ADDED);
userFilter.addAction(Intent.ACTION_USER_REMOVED);
mContext.registerReceiver(mUserReceiver,userFilter, null, mHandler);
// Watch for USB changes on availablevolumes
StorageVolume[] volumes =getVolumeList();
boolean allowUMS = false;
for (StorageVolume volume : volumes) {
if (volume != null &&volume.allowMassStorage()) {
allowUMS = true;
break;
}
}
if (allowUMS) {
mContext.registerReceiver(mUsbReceiver, newIntentFilter(UsbManager.ACTION_USB_STATE),
null, mHandler);
}
// Watch for idle maintenance changes
IntentFilter idleMaintenanceFilter =new IntentFilter();
idleMaintenanceFilter.addAction(Intent.ACTION_IDLE_MAINTENANCE_START);
mContext.registerReceiverAsUser(mIdleMaintenanceReceiver,UserHandle.ALL,
idleMaintenanceFilter, null,mHandler);
// Add OBB Action Handler toMountService thread.
mObbActionHandler = newObbActionHandler(IoThread.get().getLooper());
/*
* Create the connection to vold with amaximum queue of twice the
* amount of containers we'd everexpect to have. This keeps an
* "asec list" from blockinga thread repeatedly.
*/
mConnector =new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG,25);
Thread thread = new Thread(mConnector,VOLD_TAG);
thread.start();
这里启用了一个新线程,最终会在listenToSocke()函数中回调到onDaemonConnected(),
// Add ourself to the Watchdog monitorsif enabled.
if (WATCHDOG_ENABLE) {
Watchdog.getInstance().addMonitor(this);
}
}
//构造函数
NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, Stringsocket,
int responseQueueSize, StringlogTag, int maxLogSize) {
mCallbacks = callbacks;
mSocket = socket;
mResponseQueue = newResponseQueue(responseQueueSize);
mSequenceNumber = new AtomicInteger(0);
TAG = logTag != null ? logTag :"NativeDaemonConnector";
mLocalLog = new LocalLog(maxLogSize);
}
@Override
public void run() {
mCallbackHandler = newHandler(FgThread.get().getLooper(), this);
while (true) {
try {
//开始监听来自于底层vold部分的消息
listenToSocket();
} catch (Exception e) {
loge("Error inNativeDaemonConnector: " + e);
SystemClock.sleep(5000);
}
}
}
public void onDaemonConnected() {
/*
* Since we'll be calling back into theNativeDaemonConnector,
* we need to do our work in a newthread.
*/
newThread("MountService#onDaemonConnected") {
@Override
public void run() {
/**
* Determine media state andUMS detection status
*/
try {
//给vold下发volume list命令,先列出系统目前有几个volume对象,获取到这些对象的标签
final String[] vols =NativeDaemonEvent.filterMessageList(
mConnector.executeForList("volume", "list"),
VoldResponseCode.VolumeListResult);
for (String volstr : vols){
String[] tok =volstr.split(" ");
// FMT:
String path = tok[1];
String state =Environment.MEDIA_REMOVED;
final StorageVolumevolume;
synchronized(mVolumesLock) {
volume =mVolumesByPath.get(path);
}
……
}
MountService.java
public void systemReady() {
mSystemReady = true;
mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget();
}
此处通过向MountServiceHandler发送H_SYSTEM_READY 消息来调用handleSystemReady()函数:
private void handleSystemReady() {
// Snapshot current volume states sinceit's not safe to call into vold
// while holding locks.
final HashMap
synchronized (mVolumesLock) {
snapshot = new HashMap
}
for (Map.Entry
final String path = entry.getKey();
final String state =entry.getValue();
if(state.equals(Environment.MEDIA_UNMOUNTED)) {
int rc = doMountVolume(path);
if (rc !=StorageResultCode.OperationSucceeded) {
Slog.e(TAG,String.format("Boot-time mount failed (%d)",
rc));
}
} else if(state.equals(Environment.MEDIA_SHARED)) {
/*
* Bootstrap UMS enabled statesince vold indicates
* the volume is shared(runtime restart while ums enabled)
*/
notifyVolumeStateChange(null,path, VolumeState.NoMedia,
VolumeState.Shared);
}
}
// Push mounted state for all emulatedstorage
synchronized (mVolumesLock) {
for (StorageVolume volume :mVolumes) {
if (volume.isEmulated()) {
updatePublicVolumeState(volume, Environment.MEDIA_MOUNTED);
}
}
}
/*
* If UMS was connected on boot, sendthe connected event
* now that we're up.
*/
if (mSendUmsConnectedOnBoot) {
sendUmsIntent(true);
mSendUmsConnectedOnBoot = false;
}
}
doMountVolume就是之前讲过的挂载函数,NativeDaemonConnector 和CommandListener 作为桥梁将volume mount 命令发送给vold 模块的另一大类VolumeManager来执行相应的挂载操作,挂载完成后会将相应的状态信息再通过这个桥梁发送给Mountservice中的onEvent,于是执行以下函数:
private void notifyVolumeStateChange(Stringlabel, String path, int oldState, int newState) {
final StorageVolume volume;
final String state;
synchronized (mVolumesLock) {
volume = mVolumesByPath.get(path);
state = getVolumeState(path);
}
if (DEBUG_EVENTS) Slog.i(TAG,"notifyVolumeStateChange::" + state);
String action = null;
if (oldState == VolumeState.Shared&& newState != oldState) {
if (LOCAL_LOGD) Slog.d(TAG,"Sending ACTION_MEDIA_UNSHARED intent");
sendStorageIntent(Intent.ACTION_MEDIA_UNSHARED, volume, UserHandle.ALL);
}
if (newState == VolumeState.Init) {
} else if (newState ==VolumeState.NoMedia) {
// NoMedia is handled via DiskRemove events
} else if (newState ==VolumeState.Idle) {
/*
* Don't notify if we're inBAD_REMOVAL, NOFS, UNMOUNTABLE, or
* if we're in the process of enablingUMS
*/
if (!state.equals(
Environment.MEDIA_BAD_REMOVAL) && !state.equals(
Environment.MEDIA_NOFS) && !state.equals(
Environment.MEDIA_UNMOUNTABLE)&& !getUmsEnabling()) {
if (DEBUG_EVENTS) Slog.i(TAG,"updating volume state for media bad removal nofs and unmountable");
updatePublicVolumeState(volume,Environment.MEDIA_UNMOUNTED);
action =Intent.ACTION_MEDIA_UNMOUNTED;
}
} else if (newState ==VolumeState.Pending) {
} else if (newState ==VolumeState.Checking) {
if (DEBUG_EVENTS) Slog.i(TAG,"updating volume state checking");
updatePublicVolumeState(volume,Environment.MEDIA_CHECKING);
action =Intent.ACTION_MEDIA_CHECKING;
} else if(newState == VolumeState.Mounted) {
if(DEBUG_EVENTS) Slog.i(TAG, "updating volume state mounted");
updatePublicVolumeState(volume, Environment.MEDIA_MOUNTED);
action =Intent.ACTION_MEDIA_MOUNTED;
} else if (newState == VolumeState.Unmounting) {
action = Intent.ACTION_MEDIA_EJECT;
} else if (newState ==VolumeState.Formatting) {
} else if (newState ==VolumeState.Shared) {
if (DEBUG_EVENTS) Slog.i(TAG,"Updating volume state media mounted");
/* Send the media unmounted eventfirst */
updatePublicVolumeState(volume,Environment.MEDIA_UNMOUNTED);
sendStorageIntent(Intent.ACTION_MEDIA_UNMOUNTED, volume,UserHandle.ALL);
if (DEBUG_EVENTS) Slog.i(TAG,"Updating media shared");
updatePublicVolumeState(volume,Environment.MEDIA_SHARED);
action =Intent.ACTION_MEDIA_SHARED;
if (LOCAL_LOGD) Slog.d(TAG,"Sending ACTION_MEDIA_SHARED intent");
} else if (newState ==VolumeState.SharedMnt) {
Slog.e(TAG, "Live shared mountsnot supported yet!");
return;
} else {
Slog.e(TAG, "UnhandledVolumeState {" + newState + "}");
}
if (action != null) {
sendStorageIntent(action,volume, UserHandle.ALL);
}
}
private void sendStorageIntent(Stringaction, StorageVolume volume, UserHandle user) {
final Intent intent = newIntent(action, Uri.parse("file://" + volume.getPath()));
intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, volume);
Slog.d(TAG, "sendStorageIntent "+ intent + " to " + user);
mContext.sendBroadcastAsUser(intent,user);
}
3. 关机卸载SD卡部分
MountServiceHandler 接收消息顺序:
1 H_UNMOUNT_PM_UPDATE
2 H_UNMOUNT_PM_DONE
3 H_UNMOUNT_MS
关机确认后,启动关机线程ShutdownThread的run 函数,
public void run() {
……
synchronized (mActionDoneSync) {
try {
final IMountService mount =IMountService.Stub.asInterface(
ServiceManager.checkService("mount"));
if(mount != null) {
mount.shutdown(observer);
} else{
Log.w(TAG, "MountService unavailable for shutdown");
}
} catch (Exception e) {
Log.e(TAG, "Exceptionduring MountService shutdown", e);
}
while (!mActionDone) {
long delay = endShutTime -SystemClock.elapsedRealtime();
if (delay <= 0) {
Log.w(TAG, "Shutdownwait timed out");
break;
}
try {
mActionDoneSync.wait(delay);
} catch (InterruptedExceptione) {
}
}
}
……
}
这里调用到MountService 中的shutdown 函数:
public void shutdown(final IMountShutdownObserver observer) {
validatePermission(android.Manifest.permission.SHUTDOWN);
Slog.i(TAG, "Shutting down");
synchronized (mVolumesLock) {
for (String path : mVolumeStates.keySet()) {
String state = mVolumeStates.get(path);
if(state.equals(Environment.MEDIA_SHARED)) {
/*
* If the media is currently shared, unshareit.
* XXX: This is stilldangerous!. We should not
* be rebooting at *all* ifUMS is enabled, since
* the UMS host could havedirty FAT cache entries
* yet to flush.
*/
setUsbMassStorageEnabled(false);
} else if(state.equals(Environment.MEDIA_CHECKING)) {
/*
* If the media is being checked,then we need to wait for
* it to complete beforebeing able to proceed.
*/
// XXX: @hackbod - Shouldwe disable the ANR timer here?
int retries = 30;
while(state.equals(Environment.MEDIA_CHECKING) && (retries-- >=0)) {
try {
Thread.sleep(1000);
} catch(InterruptedException iex) {
Slog.e(TAG, "Interruptedwhile waiting for media", iex);
break;
}
state =Environment.getExternalStorageState();
}
if (retries == 0) {
Slog.e(TAG, "Timedout waiting for media to check");
}
}
if (state.equals(Environment.MEDIA_MOUNTED)){
// Post a unmount message.
ShutdownCallBack ucb = newShutdownCallBack(path, observer);
mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb));
} elseif (observer != null) {
/*
* Observer is waiting foronShutDownComplete when we are done.
* Since nothing will bedone send notification directly so shutdown
* sequence can continue.
*/
try {
observer.onShutDownComplete(StorageResultCode.OperationSucceeded);
} catch (RemoteException e){
Slog.w(TAG,"RemoteException when shutting down");
}
}
}
}
}
通过给MountServiceHandler发送H_UNMOUNT_PM_UPDATE消息调用PM中的updateExternalMediaStatus函数来更新外部媒体状态,PM中unloadAllContainers();会先调用SecureContainer 卸载安全目录(如果有挂载该安全目录), 处理完成后调用MountService中的finishMediaUpdate()来给MountServiceHandler再发送 H_UNMOUNT_PM_DONE,H_UNMOUNT_MS消息来杀死运行中的进程,
最后调用到doUnmountVolume 函数,和挂载时一样通过给vold 发送卸载命令来卸载SD卡。
可以看到安卓为了模块间的独立大量使用了轻量级的IPC binder 和一些线程间消息的传递。
4. 热插拔SD卡简介
NetlinkManager 中监听Linux内核的热插拔事件,uevent事件
void NetlinkHandler::onEvent(NetlinkEvent*evt) {
VolumeManager *vm = VolumeManager::Instance();
const char *subsys = evt->getSubsystem();
if (!subsys) {
SLOGW("No subsystem found in netlink event");
return;
}
if (!strcmp(subsys, "block")) {
vm->handleBlockEvent(evt);
}
int DirectVolume::handleBlockEvent(NetlinkEvent*evt) 对以下六种磁盘的操作动作做出判断
void handleDiskAdded(const char *devpath,NetlinkEvent *evt);
void handleDiskRemoved(const char *devpath,NetlinkEvent *evt);
void handleDiskChanged(const char *devpath,NetlinkEvent *evt);
void handlePartitionAdded(const char*devpath, NetlinkEvent *evt);
void handlePartitionRemoved(const char*devpath, NetlinkEvent *evt);
void handlePartitionChanged(const char*devpath, NetlinkEvent *evt);
主要用来处理存储卡插入移除和SD卡改变,以及一些分区的处理,同时发送状态的改变信息给MountService. 再由MountService 来下发相应的命令给vold中的VolumeManager来做相应的处理。
1. Socket 通信
未完。。。