android关机时Framework层对存储设备的操作分析

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






  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值