android存储系统源码走读
1、storageManagerservice的启动:
在SystemServer的startOtherServices中,storageManagerservice启动。
private void startOtherServices() {
final Context context = mSystemContext;
VibratorService vibrator = null;
IStorageManager storageManager = null;
......(省略N多代码)
启动storageManagerservice启动服务
mSystemServiceManager.startService(STORAGE_MANAGER_SERVICE_CLASS);
......(省略N多代码)
2、StorageManagerService服务分析
由Lifecycle启动:
public void onStart() {
mStorageManagerService = new StorageManagerService(getContext());
publishBinderService("mount", mStorageManagerService);
mStorageManagerService.start();
}
public StorageManagerService(Context context) {
......忽略部分代码
//新建handle,多数操作经此流转
mHandler = new StorageManagerServiceHandler(hthread.getLooper());
// Add OBB Action Handler to StorageManagerService thread.
mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());
// Initialize the last-fstrim tracking if necessary
File dataDir = Environment.getDataDirectory();
File systemDir = new File(dataDir, "system");
mLastMaintenanceFile = new File(systemDir, LAST_FSTRIM_FILE);
if (!mLastMaintenanceFile.exists()) {
// Not setting mLastMaintenance here means that we will force an
// fstrim during reboot following the OTA that installs this code.
try {
(new FileOutputStream(mLastMaintenanceFile)).close();
} catch (IOException e) {
Slog.e(TAG, "Unable to create fstrim record " + mLastMaintenanceFile.getPath());
}
} else {
mLastMaintenance = mLastMaintenanceFile.lastModified();
}
mSettingsFile = new AtomicFile(
new File(Environment.getDataSystemDirectory(), "storage.xml"));
synchronized (mLock) {
readSettingsLocked();
}
LocalServices.addService(StorageManagerInternal.class, mStorageManagerInternal);
//新建vold与cryptd线程,大部分与存储有关操作都是通过这两个线程与远程socket通信完成,会在连接成功和有消息返回时候回调
mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25,
null);
mConnector.setDebug(true);
mConnector.setWarnIfHeld(mLock);
mConnectorThread = new Thread(mConnector, VOLD_TAG);
// Reuse parameters from first connector since they are tested and safe
mCryptConnector = new NativeDaemonConnector(this, "cryptd",
MAX_CONTAINERS * 2, CRYPTD_TAG, 25, null);
mCryptConnector.setDebug(true);
mCryptConnectorThread = new Thread(mCryptConnector, CRYPTD_TAG);
final IntentFilter userFilter = new IntentFilter();
userFilter.addAction(Intent.ACTION_USER_ADDED);
userFilter.addAction(Intent.ACTION_USER_REMOVED);
mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
synchronized (mLock) {
addInternalVolumeLocked();
}
//添到watchdog监视队列中
if (WATCHDOG_ENABLE) {
Watchdog.getInstance().addMonitor(this);
}
}
构造函数完成后立即启动vold跟cryptd线程:
private void start() {
mConnectorThread.start();
mCryptConnectorThread.start();
}
NativeDaemonConnector:启动后连接并且监听socket返回信息
@Override
public void run() {
mCallbackHandler = new Handler(mLooper, this);
while (true) {
try {
listenToSocket();
} catch (Exception e) {
loge("Error in NativeDaemonConnector: " + e);
SystemClock.sleep(5000);
}
}
}
private void listenToSocket() throws IOException {
LocalSocket socket = null;
try {
socket = new LocalSocket();
LocalSocketAddress address = determineSocketAddress();
socket.connect(address);
InputStream inputStream = socket.getInputStream();
synchronized (mDaemonLock) {
mOutputStream = socket.getOutputStream();
}
//连接上socket之后回调storagemanagerservice
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);
log("RCV <- {" + event + "}");
if (event.isClassUnsolicited()) {
// TODO: migrate to sending NativeDaemonEvent instances
if (mCallbacks.onCheckHoldWakeLock(event.getCode())
&& mWakeLock != null) {
mWakeLock.acquire();
releaseWl = true;
}
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;
}
}
if (start == 0) {
log("RCV incomplete");
}
// We should end at the amount we read. If not, compact then
// buffer and read again.
if (start != count) {
final int remaining = BUFFER_SIZE - start;
System.arraycopy(buffer, start, buffer, 0, remaining);
start = remaining;
} else {
start = 0;
}
}
} catch (IOException ex) {
loge("Communications error: " + ex);
throw ex;
} finally {
synchronized (mDaemonLock) {
if (mOutputStream != null) {
try {
loge("closing stream for " + mSocket);
mOutputStream.close();
} catch (IOException e) {
loge("Failed closing output stream: " + e);
}
mOutputStream = null;
}
}
try {
if (socket != null) {
socket.close();
}
} catch (IOException ex) {
loge("Failed closing socket: " + ex);
}
}
}
与vold跟crypted通信返回的数据格式都是使用的:NativeDaemonEvent,通过将从数据流中获取到的string资源解析成NativeDaemonEvent对象。
private NativeDaemonEvent(int cmdNumber, int code, String message,
String rawEvent, String logMessage, FileDescriptor[] fdList) {
mCmdNumber = cmdNumber;
mCode = code;
mMessage = message;
mRawEvent = rawEvent;
mLogMessage = logMessage;
mParsed = null;
mFdList = fdList;
}
public static NativeDaemonEvent parseRawEvent(String rawEvent, FileDescriptor[] fdList) {
final String[] parsed = rawEvent.split(" ");
if (parsed.length < 2) {
throw new IllegalArgumentException("Insufficient arguments");
}
int skiplength = 0;
final int code;
try {
code = Integer.parseInt(parsed[0]);
skiplength = parsed[0].length() + 1;
} catch (NumberFormatException e) {
throw new IllegalArgumentException("problem parsing code", e);
}
int cmdNumber = -1;
if (isClassUnsolicited(code) == false) {
if (parsed.length < 3) {
throw new IllegalArgumentException("Insufficient arguemnts");
}
try {
cmdNumber = Integer.parseInt(parsed[1]);
skiplength += parsed[1].length() + 1;
} catch (NumberFormatException e) {
throw new IllegalArgumentException("problem parsing cmdNumber", e);
}
}
String logMessage = rawEvent;
if (parsed.length > 2 && parsed[2].equals(SENSITIVE_MARKER)) {
skiplength += parsed[2].length() + 1;
logMessage = parsed[0] + " " + parsed[1] + " {}";
}
final String message = rawEvent.substring(skiplength);
return new NativeDaemonEvent(cmdNumber, code, message, rawEvent, logMessage, fdList);
}
3、unmount流程framework层流程分析:
@Override
public void unmount(String volId) {
enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
waitForReady();
//查找卷信息
final VolumeInfo vol = findVolumeByIdOrThrow(volId);
//通知pms卷设备变化信息
if (vol.isPrimaryPhysical()) {
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mUnmountLock) {
mUnmountSignal = new CountDownLatch(1);
mPms.updateExternalMediaStatus(false, true);
waitForLatch(mUnmountSignal, "mUnmountSignal");
mUnmountSignal = null;
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
try {
//连接socket执行unmount命令
mConnector.execute("volume", "unmount", vol.id);
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
}
public NativeDaemonEvent[] executeForList(long timeoutMs, String cmd, Object... args)
throws NativeDaemonConnectorException {
if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) {
Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x"
+ Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable());
}
final long startTime = SystemClock.elapsedRealtime();
final ArrayList<NativeDaemonEvent> events = Lists.newArrayList();
final StringBuilder rawBuilder = new StringBuilder();
final StringBuilder logBuilder = new StringBuilder();
final int sequenceNumber = mSequenceNumber.incrementAndGet();
makeCommand(rawBuilder, logBuilder, sequenceNumber, cmd, args);
final String rawCmd = rawBuilder.toString();
final String logCmd = logBuilder.toString();
log("SND -> {" + logCmd + "}");
synchronized (mDaemonLock) {
if (mOutputStream == null) {
throw new NativeDaemonConnectorException("missing output stream");
} else {
try {
//将命令写入到socket流中 mOutputStream.write(rawCmd.getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
throw new NativeDaemonConnectorException("problem sending command", e);
}
}
}
......
流程如图:
unmount流程图
4、底层实现:
底层实现主要涉及四大类:
VolumeManager
CommandListener
CryptCommandListener
NetlinkManager首先分析commandListener:
main.cpp
int main(int argc, char** argv) {
......省略部分代码
VolumeManager *vm;
CommandListener *cl;
CryptCommandListener *ccl;
NetlinkManager *nm;
//初始化
cl = new CommandListener();
//启动监听
if (cl->startListener()) {
PLOG(ERROR) << "Unable to start CommandListener";
exit(1);
}
......
}
CommandListener.cpp
在初始化过程中将部分命令添加到mCommands命令列表中,同时调用父类初始化方法,出入参数:vold,也就是即将要连接的socket名称:
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());
}
FrameworkCommandCollection *mCommands;
void FrameworkListener::registerCmd(FrameworkCommand *cmd) {
mCommands->push_back(cmd);
}
启动监听,在SocketListener中:
int SocketListener::startListener(int backlog) {
此处mSocketName已经设置为了vold
if (!mSocketName && mSock == -1) {
SLOGE("Failed to start unbound listener");
errno = EINVAL;
return -1;
} else if (mSocketName) {
if ((mSock = android_get_control_socket(mSocketName)) < 0) {
SLOGE("Obtaining file descriptor socket '%s' failed: %s",
mSocketName, strerror(errno));
return -1;
}
SLOGV("got mSock = %d for %s", mSock, mSocketName);
fcntl(mSock, F_SETFD, FD_CLOEXEC);
}
if (mListen && listen(mSock, backlog) < 0) {
SLOGE("Unable to listen on socket (%s)", strerror(errno));
return -1;
} else if (!mListen)
mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));
if (pipe(mCtrlPipe)) {
SLOGE("pipe failed (%s)", strerror(errno));
return -1;
}
//启动监听线程
if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {
SLOGE("pthread_create (%s)", strerror(errno));
return -1;
}
return 0;
}
void *SocketListener::threadStart(void *obj) {
SocketListener *me = reinterpret_cast<SocketListener *>(obj);
me->runListener();
pthread_exit(NULL);
return NULL;
}
void SocketListener::runListener() {
SocketClientCollection pendingList;
while(1) {
......
/* 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();
}
}
}
FrameworkListener具体执行从socket中接收到的数据
bool FrameworkListener::onDataAvailable(SocketClient *c) {
......
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;
}
void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) {
FrameworkCommandCollection::iterator i;
......
//mCommands是在commandListener初始化时候添加的一个命令列表,此处将列表中数据取出与命令对比,通过对比结果看使用哪个具体实现来实现socket发送过来的命令。
for (i = mCommands->begin(); i != mCommands->end(); ++i) {
FrameworkCommand *c = *i;
if (!strcmp(argv[0], c->getCommand())) {
//具体实现命令在runcommand
if (c->runCommand(cli, argc, argv)) {
SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno));
}
goto out;
}
}
cli->sendMsg(500, "Command not recognized", false);
out:
int j;
for (j = 0; j < argc; j++)
free(argv[j]);
return;
overflow:
cli->sendMsg(500, "Command too long", false);
goto out;
}
VolumeCmd为例:
CommandListener::VolumeCmd::VolumeCmd() :
VoldCommand("volume") {
}
VoldCommand::VoldCommand(const char *cmd) :
FrameworkCommand(cmd) {
}
FrameworkCommand::FrameworkCommand(const char *cmd) {
mCommand = cmd;
}
FrameworkCommand声明如下:
class FrameworkCommand {
private:
const char *mCommand;
public:
FrameworkCommand(const char *cmd);
virtual ~FrameworkCommand() { }
virtual int runCommand(SocketClient *c, int argc, char **argv) = 0;
const char *getCommand() { return mCommand; }
};
如果从socket中获取到的字符是是以volume开头,则会调用VolumeCmd中的runCommand方法,至此CommandListener主要通信流程分析结束。
NetlinkManager分析
int main(int argc, char** argv) {
......
NetlinkManager *nm;
......
if (!(nm = NetlinkManager::Instance())) {
LOG(ERROR) << "Unable to create NetlinkManager";
exit(1);
}
......
nm->setBroadcaster((SocketListener *) cl);
......
//
if (nm->start()) {
PLOG(ERROR) << "Unable to start NetlinkManager";
exit(1);
}
}
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) {
SLOGE("Unable to create uevent socket: %s", strerror(errno));
return -1;
}
//设置socket运行环境
// When running in a net/user namespace, SO_RCVBUFFORCE is not available.
// Try using SO_RCVBUF first.
if ((setsockopt(mSock, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz)) < 0) &&
(setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0)) {
SLOGE("Unable to set uevent socket SO_RCVBUF/SO_RCVBUFFORCE option: %s", strerror(errno));
goto out;
}
if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
SLOGE("Unable to set uevent socket SO_PASSCRED option: %s", strerror(errno));
goto out;
}
//绑定socket
if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
SLOGE("Unable to bind uevent socket: %s", strerror(errno));
goto out;
}
//启动监听handler流程
mHandler = new NetlinkHandler(mSock);
if (mHandler->start()) {
SLOGE("Unable to start NetlinkHandler: %s", strerror(errno));
goto out;
}
return 0;
out:
close(mSock);
return -1;
}
NetlinkHandler的初始化和start:
NetlinkHandler::NetlinkHandler(int listenerSocket) :
NetlinkListener(listenerSocket) {
}
NetlinkListener::NetlinkListener(int socket) :
SocketListener(socket, false) {
mFormat = NETLINK_FORMAT_ASCII;
}
至此将socket描述符传递给了SocketListener
int NetlinkHandler::start() {
return this->startListener();
}
int SocketListener::startListener(int backlog) {
if (!mSocketName && mSock == -1) {
SLOGE("Failed to start unbound listener");
errno = EINVAL;
return -1;
} else if (mSocketName) {
if ((mSock = android_get_control_socket(mSocketName)) < 0) {
SLOGE("Obtaining file descriptor socket '%s' failed: %s",
mSocketName, strerror(errno));
return -1;
}
SLOGV("got mSock = %d for %s", mSock, mSocketName);
fcntl(mSock, F_SETFD, FD_CLOEXEC);
}
if (mListen && listen(mSock, backlog) < 0) {
SLOGE("Unable to listen on socket (%s)", strerror(errno));
return -1;
} else if (!mListen)
mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));
if (pipe(mCtrlPipe)) {
SLOGE("pipe failed (%s)", strerror(errno));
return -1;
}
if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {
SLOGE("pthread_create (%s)", strerror(errno));
return -1;
}
return 0;
}
void *SocketListener::threadStart(void *obj) {
SocketListener *me = reinterpret_cast<SocketListener *>(obj);
me->runListener();
pthread_exit(NULL);
return NULL;
}
SocketListener之后的运行过程与CommandLister一致,最终进入到子类的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));
if (count < 0) {
SLOGE("recvmsg failed (%s)", strerror(errno));
return false;
}
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;
}
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);
}
}
由此NetlinkManager通过连接socket来接收来自kernel层的sd插拔消息,收到消息后通过VolumeManager来更新当前的disk信息
VolumeManager真正负责处理存储相关消息,执行mount、unmount之类的命令,更新disk信息等。