以下分析基于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会下载所有的磁盘及其分区。
