Android8.0 存储系统
Android 一直在不断发展,可支持各种存储设备类型和功能。所有 Android 版本均支持配有传统存储(包括便携式存储和内置存储)的设备。便携式存储是指物理介质(如 SD 卡或 USB 设备),用于进行临时数据传输/文件存储。物理介质可以随设备一起保留更长时间,但并非固定在设备上,可以移除。自 Android 1.0 开始,SD 卡已可用作便携式存储;Android 6.0 增加对 USB 的支持。“内置”存储可通过将部分内部存储暴露于模拟层来实现存储,并且从 Android 3.0 开始便已支持此功能。
1. 后台进程Vold启动
system\vold\main.cpp
int main(int argc, char** argv) { VolumeManager *vm; //卷管理 CommandListener *cl; //命令监听 CryptCommandListener *ccl;//加密监听 NetlinkManager *nm;//连接管理 parse_args(argc, argv); sehandle = selinux_android_file_context_handle(); //selinux if (sehandle) { selinux_android_set_sehandle(sehandle);} // Quickly throw a CLOEXEC on the socket we just inherited from init fcntl(android_get_control_socket("vold"), F_SETFD, FD_CLOEXEC); //创建Vold通道 fcntl(android_get_control_socket("cryptd"), F_SETFD, FD_CLOEXEC); //创建加密通道 mkdir("/dev/block/vold", 0755); //创建文件 if (!(vm = VolumeManager::Instance())) { exit(1);} if (!(nm = NetlinkManager::Instance())) { exit(1);} cl = new CommandListener(); //创建注册一系列监听命令 ccl = new CryptCommandListener(); // vm->setBroadcaster((SocketListener *) cl); nm->setBroadcaster((SocketListener *) cl); if (vm->start()) { exit(1); } if (process_config(vm, &has_adoptable)) {} if (nm->start()) { exit(1);} if (cl->startListener()) { exit(1);} if (ccl->startListener()) {exit(1);} property_set("vold.has_adoptable", has_adoptable ? "1" : "0"); coldboot("/sys/block"); while(1) { pause(); } exit(0);}
2. CommandListener 与 VolumeManager
system\vold\CommandListener.cpp
注册一系列命令,这些Cmd均继承自VoldCommand,VoldCommand继承自FrameworkCommand
CommandListener::CommandListener() : FrameworkListener("vold", true) { registerCmd(new DumpCmd()); registerCmd(new VolumeCmd()); registerCmd(new AsecCmd()); registerCmd(new ObbCmd()); registerCmd(new StorageCmd()); //存储命令 registerCmd(new FstrimCmd()); registerCmd(new AppFuseCmd());}
system\core\libsysutils\src\FrameworkListener.cpp
FrameworkListener::FrameworkListener(const char *socketName, bool withSeq) : SocketListener(socketName, true, withSeq) { init(socketName, withSeq);}
system\core\libsysutils\src\SocketListener.cpp
SocketListener::SocketListener(const char *socketName, bool listen) { init(socketName, -1, listen, false);}
system\core\libsysutils\src\SocketListener.cpp
mClient 是一个List定义在SocketClient.h
void SocketListener::init(const char *socketName, int socketFd, bool listen, bool useCmdNum) { mListen = listen; mSocketName = socketName; mSock = socketFd; mUseCmdNum = useCmdNum; pthread_mutex_init(&mClientsLock, NULL); mClients = new SocketClientCollection();}
system\vold\CryptCommandListener.cpp
加密监听也是一样的
FrameworkListener("cryptd", true) { registerCmd(new CryptfsCmd());}
system\vold\VolumeManager.h
system\vold\NetlinkManager.h
void setBroadcaster(SocketListener *sl) { mBroadcaster = sl; }
system\vold\VolumeManager.cpp
int VolumeManager::start() { //清除状态防止崩溃 unmountAll(); //确保挂在内部存储 CHECK(mInternalEmulated == nullptr); mInternalEmulated = std::shared_ptr<android::vold::VolumeBase>( new android::vold::EmulatedVolume("/data/media")); mInternalEmulated->create(); //创建一个虚拟盘 updateVirtualDisk(); return 0;}
system\core\libsysutils\src\SocketListener.cpp
启动加密,和命令监听
int SocketListener::startListener() { return startListener(4);}
system\core\libsysutils\src\SocketListener.cpp
int SocketListener::startListener(int backlog) { if (!mSocketName && mSock == -1) { errno = EINVAL; return -1; } else if (mSocketName) { if ((mSock = android_get_control_socket(mSocketName)) < 0) { //mSock由系统控制提供 return -1; } fcntl(mSock, F_SETFD, FD_CLOEXEC); //创建Socket, mSock文件描述符 } if (mListen && listen(mSock, backlog) < 0) { return -1; } else if (!mListen){ mClients->push_back(new SocketClient(mSock, false, mUseCmdNum)); //入队列 } if (pipe(mCtrlPipe)) { return -1; } //创建线程,指定处理函数 threadStart if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {return -1;} return 0;}
system\core\libsysutils\src\SocketListener.cpp
void *SocketListener::threadStart(void *obj) { SocketListener *me = reinterpret_cast<SocketListener *>(obj); me->runListener(); pthread_exit(NULL); return NULL;}
system\core\libsysutils\src\SocketListener.cpp
开始循环监听
void SocketListener::runListener() { SocketClientCollection pendingList; while(1) { SocketClientCollection::iterator it; fd_set read_fds; int rc = 0; int max = -1; FD_ZERO(&read_fds); if (mListen) { max = mSock; FD_SET(mSock, &read_fds); } FD_SET(mCtrlPipe[0], &read_fds); if (mCtrlPipe[0] > max) max = mCtrlPipe[0]; pthread_mutex_lock(&mClientsLock); //加锁 for (it = mClients->begin(); it != mClients->end(); ++it) { // NB: calling out to an other object with mClientsLock held (safe) int fd = (*it)->getSocket(); //获取文件描述符 FD_SET(fd, &read_fds); if (fd > max) { max = fd; } } pthread_mutex_unlock(&mClientsLock); //使用Socket的select if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) { if (errno == EINTR) continue; SLOGE("select failed (%s) mListen=%d, max=%d", strerror(errno), mListen, max); sleep(1); continue; } else if (!rc) continue; ...... /* Process the pending list, since it is owned by the thread, * there is no need to lock it */ while (!pendingList.empty()) { /* Pop the first item from the list */ it = pendingList.begin(); SocketClient* c = *it; pendingList.erase(it); /* Process it, if false is returned, remove from list */ if (!onDataAvailable(c)) { //开始处理 release(c, false); } c->decRef(); } }}
system\core\libsysutils\src\FrameworkListener.cpp
由子类实现的onDataAvailable函数处理
bool FrameworkListener::onDataAvailable(SocketClient *c) { char buffer[CMD_BUF_SIZE]; //命令缓冲数组 int len; len = TEMP_FAILURE_RETRY(read(c->getSocket(), buffer, sizeof(buffer))); //读取 if (len < 0) { return false; } else if (!len) { return false; } else if (buffer[len-1] != '\0') { //读取到末尾 android_errorWriteLog(0x534e4554, "29831647"); c->sendMsg(500, "Command too large for buffer", false); mSkipToNextNullByte = true; return false; } int offset = 0; int i; for (i = 0; i < len; i++) { if (buffer[i] == '\0') { /* IMPORTANT: dispatchCommand() expects a zero-terminated string */ if (mSkipToNextNullByte) { mSkipToNextNullByte = false; } else { dispatchCommand(c, buffer + offset); } offset = i + 1; } } mSkipToNextNullByte = false; return true;}
system\core\libsysutils\src\FrameworkListener.cpp
由FrameworkCommand的子孙类去执行命令
void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) { ..... FrameworkCommandCollection::iterator i; for (i = mCommands->begin(); i != mCommands->end(); ++i) { FrameworkCommand *c = *i; if (!strcmp(argv[0], c->getCommand())) { if (c->runCommand(cli, argc, argv)) { //执行命令 SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno)); } goto out; } } ......}
system\vold\CommandListener.cpp
处理来自上层系统的命令,挂载,监听
CommandListener::VolumeCmd::VolumeCmd() : VoldCommand("volume") {}int CommandListener::VolumeCmd::runCommand(SocketClient *cli, int argc, char **argv) { 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);}
system\core\libsysutils\src\SocketClient.cpp
int SocketClient::sendMsg(int code, const char *msg, bool addErrno) { return sendMsg(code, msg, addErrno, mUseCmdNum);}int SocketClient::sendMsg(int code, const char *msg, bool addErrno, bool useCmdNum) { char *buf; int ret = 0; if (addErrno) { if (useCmdNum) { ret = asprintf(&buf, "%d %d %s (%s)", code, getCmdNum(), msg, strerror(errno)); } else { ret = asprintf(&buf, "%d %s (%s)", code, msg, strerror(errno)); } } else { if (useCmdNum) { ret = asprintf(&buf, "%d %d %s", code, getCmdNum(), msg); } else { ret = asprintf(&buf, "%d %s", code, msg); } } // Send the zero-terminated message if (ret != -1) { ret = sendMsg(buf); free(buf); } return ret;}
system\core\libsysutils\src\SocketClient.cpp
int SocketClient::sendMsg(const char *msg) { // Send the message including null character if (sendData(msg, strlen(msg) + 1) != 0) { SLOGW("Unable to send msg '%s'", msg); return -1; } return 0;}int SocketClient::sendData(const void *data, int len) { struct iovec vec[1]; vec[0].iov_base = (void *) data; vec[0].iov_len = len; pthread_mutex_lock(&mWriteMutex); int rc = sendDataLockedv(vec, 1); pthread_mutex_unlock(&mWriteMutex); return rc;}
system\core\libsysutils\src\SocketClient.cpp
向上层系统返回执行结果
int SocketClient::sendDataLockedv(struct iovec *iov, int iovcnt) { if (mSocket < 0) { errno = EHOSTUNREACH; return -1; } if (iovcnt <= 0) { return 0; } int ret = 0; int e = 0; // SLOGW and sigaction are not inert regarding errno int current = 0; struct sigaction new_action, old_action; memset(&new_action, 0, sizeof(new_action)); new_action.sa_handler = SIG_IGN; sigaction(SIGPIPE, &new_action, &old_action); for (;;) { ssize_t rc = TEMP_FAILURE_RETRY( writev(mSocket, iov + current, iovcnt - current)); //往Socket写入数据 if (rc > 0) { size_t written = rc; while ((current < iovcnt) && (written >= iov[current].iov_len)) { written -= iov[current].iov_len; current++; } if (current == iovcnt) { break; } iov[current].iov_base = (char *)iov[current].iov_base + written; iov[current].iov_len -= written; continue; } if (rc == 0) { e = EIO; SLOGW("0 length write :("); } else { e = errno; SLOGW("write error (%s)", strerror(e)); } ret = -1; break; } sigaction(SIGPIPE, &old_action, &new_action); if (e != 0) { errno = e; } return ret;}
3. NetLinkManager与VolumeManager
system\vold\NetlinkManager.cpp
启动监听来自内核的事件
int NetlinkManager::start() { struct sockaddr_nl nladdr; int sz = 64 * 1024; int on = 1; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; //协议家族 nladdr.nl_pid = getpid(); nladdr.nl_groups = 0xffffffff; //创建套接 if ((mSock = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT)) < 0) {return -1;} if (setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) { goto out;} if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) { goto out;} //绑定 if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {goto out; } mHandler = new NetlinkHandler(mSock); //套接事件处理句柄 if (mHandler->start()) { goto out;} return 0;}
system\vold\NetlinkHandler.cpp
int NetlinkHandler::start() { return this->startListener(); //SocketListener的Listener}
system\core\libsysutils\src\NetlinkListener.cpp
按照上面的分析最终会走到 onDataAvailable
bool NetlinkListener::onDataAvailable(SocketClient *cli){ int socket = cli->getSocket(); ssize_t count; uid_t uid = -1; bool require_group = true; if (mFormat == NETLINK_FORMAT_BINARY_UNICAST) { require_group = false; } //接收来自内核的啊、事件 count = TEMP_FAILURE_RETRY(uevent_kernel_recv(socket, mBuffer, sizeof(mBuffer), require_group, &uid)); NetlinkEvent *evt = new NetlinkEvent(); //新建一个内核事件 if (evt->decode(mBuffer, count, mFormat)) { //事件预处理 onEvent(evt); //交给子类执行 } else if (mFormat != NETLINK_FORMAT_BINARY) { // Don't complain if parseBinaryNetlinkMessage returns false. That can // just mean that the buffer contained no messages we're interested in. SLOGE("Error decoding NetlinkEvent"); } delete evt; return true;}
system\vold\NetlinkHandler.cpp
void NetlinkHandler::onEvent(NetlinkEvent *evt) { VolumeManager *vm = VolumeManager::Instance(); const char *subsys = evt->getSubsystem(); if (!strcmp(subsys, "block")) { vm->handleBlockEvent(evt); }}
system\vold\VolumeManager.cpp
处理来自NetLinkManager的阻塞事件
void VolumeManager::handleBlockEvent(NetlinkEvent *evt) { std::lock_guard<std::mutex> lock(mLock); std::string eventPath(evt->findParam("DEVPATH")?evt->findParam("DEVPATH"):""); std::string devType(evt->findParam("DEVTYPE")?evt->findParam("DEVTYPE"):""); //主次设备号 int major = atoi(evt->findParam("MAJOR")); int minor = atoi(evt->findParam("MINOR")); //创建设备 dev_t device = makedev(major, minor); //执行 switch (evt->getAction()) { case NetlinkEvent::Action::kAdd: { for (const auto& source : mDiskSources) { if (source->matches(eventPath)) { // For now, assume that MMC and virtio-blk (the latter is // emulator-specific; see Disk.cpp for details) devices are SD, // and that everything else is USB int flags = source->getFlags(); if (major == kMajorBlockMmc || (android::vold::IsRunningInEmulator() && major >= (int) kMajorBlockExperimentalMin && major <= (int) kMajorBlockExperimentalMax)) { flags |= android::vold::Disk::Flags::kSd; } else { flags |= android::vold::Disk::Flags::kUsb; } auto disk = new android::vold::Disk(eventPath, device, source->getNickname(), flags); disk->create(); mDisks.push_back(std::shared_ptr<android::vold::Disk>(disk)); break; } } break; } case NetlinkEvent::Action::kChange: { LOG(DEBUG) << "Disk at " << major << ":" << minor << " changed"; for (const auto& disk : mDisks) { if (disk->getDevice() == device) { disk->readMetadata(); disk->readPartitions(); } } break; } case NetlinkEvent::Action::kRemove: { auto i = mDisks.begin(); while (i != mDisks.end()) { if ((*i)->getDevice() == device) { (*i)->destroy(); i = mDisks.erase(i); } else { ++i; } } break; } default: { LOG(WARNING) << "Unexpected block event action " << (int) evt->getAction(); break; } }}
4. StorageMangerService
在Android8.0中MountService改名为StorageMangerService
frameworks\base\services\core\java\com\android\server\StorageManagerService.java
public StorageManagerService(Context context) { sSelf = this; mContext = context; mCallbacks = new Callbacks(FgThread.get().getLooper()); mLockPatternUtils = new LockPatternUtils(mContext); // XXX: This will go away soon in favor of IMountServiceObserver mPms = (PackageManagerService) ServiceManager.getService("package"); HandlerThread hthread = new HandlerThread(TAG); hthread.start(); //存储管理服务出处理句柄 mHandler = new StorageManagerServiceHandler(hthread.getLooper()); //Native后台进程链接器 mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25, null); mConnector.setDebug(true); mConnector.setWarnIfHeld(mLock); mConnectorThread = new Thread(mConnector, VOLD_TAG); ...... synchronized (mLock) { addInternalVolumeLocked(); } }
frameworks\base\services\core\java\com\android\server\NativeDaemonConnector.java
NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket, int responseQueueSize, String logTag, int maxLogSize, PowerManager.WakeLock wl) { this(callbacks, socket, responseQueueSize, logTag, maxLogSize, wl, FgThread.get().getLooper()); } NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket, int responseQueueSize, String logTag, int maxLogSize, PowerManager.WakeLock wl, Looper looper) { mCallbacks = callbacks; mSocket = socket; mResponseQueue = new ResponseQueue(responseQueueSize); mWakeLock = wl; if (mWakeLock != null) { mWakeLock.setReferenceCounted(true); } mLooper = looper; mSequenceNumber = new AtomicInteger(0); TAG = logTag != null ? logTag : "NativeDaemonConnector"; mLocalLog = new LocalLog(maxLogSize); }
frameworks\base\services\core\java\com\android\server\NativeDaemonConnector.java
@Override public void run() { mCallbackHandler = new Handler(mLooper, this); while (true) { try { listenToSocket(); //监听Socket } catch (Exception e) { loge("Error in NativeDaemonConnector: " + e); SystemClock.sleep(5000); } } }
frameworks\base\services\core\java\com\android\server\NativeDaemonConnector.java
监听来自Vold的事件
private void listenToSocket() throws IOException { LocalSocket socket = null; try { socket = new LocalSocket(); LocalSocketAddress address = determineSocketAddress(); socket.connect(address); //连接到Vold InputStream inputStream = socket.getInputStream(); synchronized (mDaemonLock) { mOutputStream = socket.getOutputStream(); } mCallbacks.onDaemonConnected(); FileDescriptor[] fdList = null; byte[] buffer = new byte[BUFFER_SIZE]; int start = 0; while (true) { int count = inputStream.read(buffer, start, BUFFER_SIZE - start); if (count < 0) { loge("got " + count + " reading with start = " + start); break; } fdList = socket.getAncillaryFileDescriptors(); // Add our starting point to the count and reset the start. count += start; start = 0; for (int i = 0; i < count; i++) { if (buffer[i] == 0) { // Note - do not log this raw message since it may contain // sensitive data final String rawEvent = new String( buffer, start, i - start, StandardCharsets.UTF_8); boolean releaseWl = false; try { //解析事件 final NativeDaemonEvent event = NativeDaemonEvent.parseRawEvent(rawEvent, fdList); if (event.isClassUnsolicited()) { // TODO: migrate to sending NativeDaemonEvent instances if (mCallbacks.onCheckHoldWakeLock(event.getCode()) && mWakeLock != null) { mWakeLock.acquire(); releaseWl = true; } //交给Handler处理 Message msg = mCallbackHandler.obtainMessage( event.getCode(), uptimeMillisInt(), 0, event.getRawEvent()); if (mCallbackHandler.sendMessage(msg)) { releaseWl = false; } } else { mResponseQueue.add(event.getCmdNumber(), event); //加入队列 } } catch (IllegalArgumentException e) { log("Problem parsing message " + e); } finally { if (releaseWl) { mWakeLock.release(); } } start = i + 1; } } ..... } } catch (IOException ex) { loge("Communications error: " + ex); throw ex; } finally { ...... } try { if (socket != null) { socket.close(); } } catch (IOException ex) { loge("Failed closing socket: " + ex); } } }
frameworks\base\services\core\java\com\android\server\NativeDaemonConnector.java
处理内核事件,实际上转发给了StorageManagerService.java
@Override public boolean handleMessage(Message msg) { final String event = (String) msg.obj; final int start = uptimeMillisInt(); final int sent = msg.arg1; try { //回调事件 if (!mCallbacks.onEvent(msg.what, event, NativeDaemonEvent.unescapeArgs(event))) { log(String.format("Unhandled event '%s'", event)); } } catch (Exception e) { loge("Error handling '" + event + "': " + e); } finally { ...... } return true; }
frameworks\base\services\core\java\com\android\server\StorageManagerService.java
处理和转发来自Vold的事件
@Override public boolean onEvent(int code, String raw, String[] cooked) { synchronized (mLock) { return onEventLocked(code, raw, cooked); } } private boolean onEventLocked(int code, String raw, String[] cooked) { switch (code) { case VoldResponseCode.DISK_CREATED: { ...... mDisks.put(id, new DiskInfo(id, flags)); break; } ...... default: { Slog.d(TAG, "Unhandled vold event " + code); } } return true; }
从 Android 6.0 开始,Android 支持可合并的存储设备,这种存储设备是指可以像内部存储设备那样进行加密和格式化的物理介质(例如 SD 卡或 USB 设备)。移动存储设备可存储各类应用数据。
更多相关文章
- GitHub 标星 2.5K+!教你通过玩游戏的方式学习 VIM!
- 如何在后台运行Linux命令?
- No.11 使用firewall配置的防火墙策略的生效模式
- 修改Android“长按”的反应时间
- Android热修复方案的兼容策略CLASS_ISPREVERIFIED问题
- Android(安卓)RxJava实际应用教学:你该什么时候使用RxJava?
- android之复选框点击事件(掌握CheckBox复选控件)
- Android(安卓)RxJava操作符详解系列: 变换操作符
- Android小白usb通信入门篇(一)