以下分析基于android-6.0.1_r3源码。
关于android关机流程,推荐以下博文(感谢博主的辛勤付出):
Android关机流程源码分析本文主要分析关机时Framework层对存储设备的操作。在上面推荐的博文的后半部,有一段这样的代码:
public void run() {
BroadcastReceiver br = new BroadcastReceiver() {
@Override public void onReceive(Context context, Intent intent) {
// 用于接收关机广播
actionDone();
}
};
//写属性"sys.shutdown.requested"保存关机原因
{
String reason = (mReboot ? "1" : "0") + (mRebootReason != null ? mRebootReason : "");
SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);
}
//如果是安全模式关机,写属性"persist.sys.safemode"
if (mRebootSafeMode) {
SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");
}
Log.i(TAG, "Sending shutdown broadcast...");
// First send the high-level shut down broadcast.
mActionDone = false;
//发送关机广播
mContext.sendOrderedBroadcast(new Intent(Intent.ACTION_SHUTDOWN), null,
br, mHandler, 0, null, null);
//等待10S,前面定义的广播接收器收到关机广播时mActionDone设置为true,同时取消等待
final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;
synchronized (mActionDoneSync) {
while (!mActionDone) {
long delay = endTime - SystemClock.elapsedRealtime();
if (delay <= 0) {
Log.w(TAG, "Shutdown broadcast timed out");
break;
}
try {
mActionDoneSync.wait(delay);
} catch (InterruptedException e) {
}
}
}
//10S时间内关闭ActivityManager服务
final IActivityManager am =ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));
if (am != null) {
try {
am.shutdown(MAX_BROADCAST_TIME);
} catch (RemoteException e) {
}
}
//12s内关闭radios.
shutdownRadios(MAX_RADIO_WAIT_TIME);
//10s内关闭ICCS
shutdownIccs(MAX_ICC_WAIT_TIME);
// Shutdown MountService to ensure media is in a safe state
IMountShutdownObserver observer = new IMountShutdownObserver.Stub() {
public void onShutDownComplete(int statusCode) throws RemoteException {
Log.w(TAG, "Result code " + statusCode + " from MountService.shutdown");
actionDone();
}
};
Log.i(TAG, "Shutting down MountService");
//20s内关闭MountService服务
mActionDone = false;
final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME;
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, "Exception during MountService shutdown", e);
}
while (!mActionDone) {
long delay = endShutTime - SystemClock.elapsedRealtime();
if (delay <= 0) {
Log.w(TAG, "Shutdown wait timed out");
break;
}
try {
mActionDoneSync.wait(delay);
} catch (InterruptedException e) {
}
}
}
//关机时间定义为5s,这里计算关机超过的时间
long shutdownDelay = shutdownTime - SystemClock.elapsedRealtime();
if (shutdownDelay > 0) {
Log.i(TAG, "Shutdown delay:"+shutdownDelay);
SystemClock.sleep(shutdownDelay);
}
//继续关机
rebootOrShutdown(mReboot, mRebootReason);
}
第65行:mount.shutdown(observer);而mount是MountService的变量,来看一下shutdown的实现。
一、MountService::shutdown
@Override
public void shutdown(final IMountShutdownObserver observer) {
enforcePermission(android.Manifest.permission.SHUTDOWN);
Slog.i(TAG, "Shutting down");
mHandler.obtainMessage(H_SHUTDOWN, observer).sendToTarget();
}
而mHandler则是这样定义的:
mHandler = new MountServiceHandler(hthread.getLooper());
所以我们来看一下MountServiceHandler是如何处理H_SHUTDOWN消息的:
case H_SHUTDOWN: {
final IMountShutdownObserver obs = (IMountShutdownObserver) msg.obj;
boolean success = false;
try {
success = mConnector.execute("volume", "shutdown").isClassOk();
} catch (NativeDaemonConnectorException ignored) {
}
if (obs != null) {
try {
obs.onShutDownComplete(success ? 0 : -1);
} catch (RemoteException ignored) {
}
}
break;
}
本端代码中mConnector则是这样定义的:
private final NativeDaemonConnector mConnector;
所以我们来看一下NativeDaemonConnector 类的execute函数的实现:
/**
* Issue the given command to the native daemon and return a single expected
* response. Any arguments must be separated from base command so they can
* be properly escaped.
*
* @throws NativeDaemonConnectorException when problem communicating with
* native daemon, or if the response matches
* {@link NativeDaemonEvent#isClassClientError()} or
* {@link NativeDaemonEvent#isClassServerError()}.
*/
public NativeDaemonEvent execute(String cmd, Object... args)
throws NativeDaemonConnectorException {
return execute(DEFAULT_TIMEOUT, cmd, args);
}
实际调用的是另外一个重载的execute函数,该execute函数最终调用了:
public NativeDaemonEvent[] executeForList(long timeoutMs, String cmd, Object... args)
函数将消息通过名字为“vold”的套接字将参数传递到了vold层的FrameworkListener.java中,
FrameworkListener的dispatchCommand函数会解析从socket发来的信息,如果是volume类型的信息则传递给VolumeCmd类型的变量进行处理,处理函数为runCommand,如下.
二、CommandListener::VolumeCmd::runCommand
</pre></p><p><span style="font-size:10px;"><span style="font-size:10px;"></span></span><pre name="code" class="cpp">int CommandListener::VolumeCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
dumpArgs(argc, argv, -1);
if (argc < 2) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
return 0;
}
VolumeManager *vm = VolumeManager::Instance();
std::lock_guard<std::mutex> lock(vm->getLock());
// TODO: tease out methods not directly related to volumes
std::string cmd(argv[1]);
if (cmd == "reset") {
return sendGenericOkFail(cli, vm->reset());
} else if (cmd == "shutdown") {
return sendGenericOkFail(cli, vm->shutdown());
} else if (cmd == "debug") {
return sendGenericOkFail(cli, vm->setDebug(true));
} else if (cmd == "partition" && argc > 3) {
// partition [diskId] [public|private|mixed] [ratio]
std::string id(argv[2]);
auto disk = vm->findDisk(id);
if (disk == nullptr) {
return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown disk", false);
}
std::string type(argv[3]);
if (type == "public") {
return sendGenericOkFail(cli, disk->partitionPublic());
} else if (type == "private") {
return sendGenericOkFail(cli, disk->partitionPrivate());
} else if (type == "mixed") {
if (argc < 4) {
return cli->sendMsg(ResponseCode::CommandSyntaxError, nullptr, false);
}
int frac = atoi(argv[4]);
return sendGenericOkFail(cli, disk->partitionMixed(frac));
} else {
return cli->sendMsg(ResponseCode::CommandSyntaxError, nullptr, false);
}
} else if (cmd == "mkdirs" && argc > 2) {
// mkdirs [path]
return sendGenericOkFail(cli, vm->mkdirs(argv[2]));
} else if (cmd == "user_added" && argc > 3) {
// user_added [user] [serial]
return sendGenericOkFail(cli, vm->onUserAdded(atoi(argv[2]), atoi(argv[3])));
} else if (cmd == "user_removed" && argc > 2) {
// user_removed [user]
return sendGenericOkFail(cli, vm->onUserRemoved(atoi(argv[2])));
} else if (cmd == "user_started" && argc > 2) {
// user_started [user]
return sendGenericOkFail(cli, vm->onUserStarted(atoi(argv[2])));
} else if (cmd == "user_stopped" && argc > 2) {
// user_stopped [user]
return sendGenericOkFail(cli, vm->onUserStopped(atoi(argv[2])));
} else if (cmd == "mount" && argc > 2) {
// mount [volId] [flags] [user]
std::string id(argv[2]);
auto vol = vm->findVolume(id);
if (vol == nullptr) {
return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
}
int mountFlags = (argc > 3) ? atoi(argv[3]) : 0;
userid_t mountUserId = (argc > 4) ? atoi(argv[4]) : -1;
vol->setMountFlags(mountFlags);
vol->setMountUserId(mountUserId);
int res = vol->mount();
if (mountFlags & android::vold::VolumeBase::MountFlags::kPrimary) {
vm->setPrimary(vol);
}
return sendGenericOkFail(cli, res);
} else if (cmd == "unmount" && argc > 2) {
// unmount [volId]
std::string id(argv[2]);
auto vol = vm->findVolume(id);
if (vol == nullptr) {
return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
}
return sendGenericOkFail(cli, vol->unmount());
} else if (cmd == "format" && argc > 3) {
// format [volId] [fsType|auto]
std::string id(argv[2]);
std::string fsType(argv[3]);
auto vol = vm->findVolume(id);
if (vol == nullptr) {
return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
}
return sendGenericOkFail(cli, vol->format(fsType));
} else if (cmd == "move_storage" && argc > 3) {
// move_storage [fromVolId] [toVolId]
auto fromVol = vm->findVolume(std::string(argv[2]));
auto toVol = vm->findVolume(std::string(argv[3]));
if (fromVol == nullptr || toVol == nullptr) {
return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
}
(new android::vold::MoveTask(fromVol, toVol))->start();
return sendGenericOkFail(cli, 0);
} else if (cmd == "benchmark" && argc > 2) {
// benchmark [volId]
std::string id(argv[2]);
nsecs_t res = vm->benchmarkPrivate(id);
return cli->sendMsg(ResponseCode::CommandOkay,
android::base::StringPrintf("%" PRId64, res).c_str(), false);
} else if (cmd == "forget_partition" && argc > 2) {
// forget_partition [partGuid]
std::string partGuid(argv[2]);
return sendGenericOkFail(cli, vm->forgetPartition(partGuid));
} else if (cmd == "remount_uid" && argc > 3) {
// remount_uid [uid] [none|default|read|write]
uid_t uid = atoi(argv[2]);
std::string mode(argv[3]);
return sendGenericOkFail(cli, vm->remountUid(uid, mode));
}
return cli->sendMsg(ResponseCode::CommandSyntaxError, nullptr, false);
}
通过该函数带代码可以知道,系统关机时处理的分支为第19行,如下:
else if (cmd == "shutdown") {
return sendGenericOkFail(cli, vm->shutdown());
}
这里的重点vm->shutdown的实现,而vm为VolumeManager类型的对象,其shutdown函数实现如下:
三、VolumeManager::shutdown()
</pre></p><p><pre name="code" class="cpp">int VolumeManager::shutdown() {
mInternalEmulated->destroy();
for (auto disk : mDisks) {
disk->destroy();
}
mDisks.clear();
return 0;
}
这里面mDisks的定义如下:
std::list<std::shared_ptr<android::vold::Disk>> mDisks;
说明mDisks是一个Disk类型的链表指针,那么Disk的destory又做了什么呢?
status_t Disk::destroy() {
CHECK(mCreated);
destroyAllVolumes();
mCreated = false;
notifyEvent(ResponseCode::DiskDestroyed);
return OK;
}
看destroyAllVolumes的实现:
void Disk::destroyAllVolumes() {
for (auto vol : mVolumes) {
vol->destroy();
}
mVolumes.clear();
}
很想知道,vol->destroy的实现,而mVolumes的定义如下:
/* Current partitions on disk */
std::vector<std::shared_ptr<VolumeBase>> mVolumes;
所以我们找到VolumeBase的destory函数:
status_t VolumeBase::destroy() {
CHECK(mCreated);
if (mState == State::kMounted) {
unmount();
setState(State::kBadRemoval);
} else {
setState(State::kRemoved);
}
notifyEvent(ResponseCode::VolumeDestroyed);
status_t res = doDestroy();
mCreated = false;
return res;
}
原来是调用了取消volume挂载的函数。
上面的notifyEvent函数被多次用到,看一下实现:
void Disk::notifyEvent(int event) {
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(event,
getId().c_str(), false);
}
向用户层发送磁盘取消挂载成功的消息;
void VolumeBase::notifyEvent(int event) {
if (mSilent) return;
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(event,
getId().c_str(), false);
}
向用户层发送分区取消挂载成功消息。
由此看来VolumeManager::shutdown()函数是将所有磁盘的所有分区从系统中取消挂载,并发送消息。
回到第二节的末尾,sendGenericOkFail函数的实现如下:
int CommandListener::sendGenericOkFail(SocketClient *cli, int cond) {
if (!cond) {
return cli->sendMsg(ResponseCode::CommandOkay, "Command succeeded", false);
} else {
return cli->sendMsg(ResponseCode::OperationFailed, "Command failed", false);
}
}
当
shutdown函数执行成功(返回0),则向应用层发送成功,否则发送失败。
关机总结:
vold会下载所有的磁盘及其分区。