Android -- Vold机制简要分析
- 格式:doc
- 大小:407.00 KB
- 文档页数:27
Android USB 驱动分析一、USB驱动代码架构和使用1、代码简介USB驱动代码在/drivers/usb/gadget下,有三个文件:android.c,f_adb.c,f_mass_storage.c;g_android.ko 是由这三个文件编译而来,其中android.c 依赖于f_adb.c 和 f_mass_storage.c(这两个文件之间无依赖关系)。
可在android.c中看到:static int __init android_bind_config(struct usb_configuration *c){struct android_dev *dev = _android_dev;int ret;printk(KERN_DEBUG "android_bind_config\n");ret = mass_storage_function_add(dev->cdev, c, dev->nluns); if (ret)return ret;return adb_function_add(dev->cdev, c);}2、驱动使用要使USB mass storage连接到主机:打开/sys/devices/platform/usb_mass_storage/lun0/file文件,向file文件写入一个存储设备的路径,例如/dev/block/vold/179:0 (major:minor)路径;这里的usb_mass_storage根据实际应用可以改的,由platform_device_register函数的参数决定。
例如:static struct platform_device fsg_platform_device ={.name = "usb_mass_storage",.id = -1,};static void __init tegra_machine_init(void){....(void) platform_device_register(&fsg_platform_device);....}能够连接的设备数,由驱动中的nluns变量来控制,最多支持8个。
Vold (Volume Daemon)用于管理和控制android 平台外部存储设备的后台进程。
service vold /system/bin/voldclass coresocket vold stream 0660 root mountioprio be 2 Vold 程序入口system\vold\Main.cppint main() {VolumeManager *vm;CommandListener *cl;NetlinkManager *nm;SLOGI("Vold 2.1 (the revenge) firing up");mkdir("/dev/block/vold", 0755);/* 创建 VolumeManager 对象实例*/if (!(vm = VolumeManager::Instance())) {SLOGE("Unable to create VolumeManager");exit(1);};/* 创建 NetlinkManager 对象实例*/if (!(nm = NetlinkManager::Instance())) {SLOGE("Unable to create NetlinkManager");exit(1);SystemServer Vold MountServiceCommandListener VolumeManager NetlinkManager Kernel};/* 创建CommandListener对象实例*/cl = new CommandListener();vm->setBroadcaster((SocketListener *) cl);nm->setBroadcaster((SocketListener *) cl);/* 启动VolumeManager*/if (vm->start()) {SLOGE("Unable to start VolumeManager (%s)", strerror(errno));exit(1);}/* 配置VolumeManager*/if (process_config(vm)) {SLOGE("Error reading configuration (%s)... continuing anyways", strerror(errno));}/* 启动NetlinkManager*/if (nm->start()) {SLOGE("Unable to start NetlinkManager (%s)", strerror(errno));exit(1);}/* 向/sys/block下的uevent文件写入消息来触发内核发送Uevent事件*/coldboot("/sys/block");/* 启动CommandListener开始循环监听事件*/if (cl->startListener()) {SLOGE("Unable to start CommandListener (%s)", strerror(errno));exit(1);}//进程循环while(1) {sleep(1000);}SLOGI("Vold exiting");exit(0);}根据不同类型的命令调用相应类型命令的runCommand函数,NetlinkManager模块成员变量:SocketListener *mBroadcaster;NetlinkHandler *mHandler;int mSock;启动流程1)nm = NetlinkManager::Instance()2)nm->setBroadcaster((SocketListener *) cl)3)nm->start()构造NetlinkManager实例使用单例模式创建NetlinkManager对象实例NetlinkManager *NetlinkManager::Instance() {if (!sInstance)sInstance = new NetlinkManager();return sInstance;}构造NetlinkManager对象NetlinkManager::NetlinkManager() {mBroadcaster = NULL;}设置事件广播监听void setBroadcaster(SocketListener *sl) { mBroadcaster = sl; }启动NetlinkManagerint 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;//创建socket,并设置该socketif ((mSock = socket(PF_NETLINK,SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0) { SLOGE("Unable to create uevent socket: %s", strerror(errno));return -1;}if (setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) { SLOGE("Unable to set uevent socket SO_RECBUFFORCE option: %s", strerror(errno));return -1;}if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) { SLOGE("Unable to set uevent socket SO_PASSCRED option: %s", strerror(errno));return -1;}if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {SLOGE("Unable to bind uevent socket: %s", strerror(errno));return -1;}//根据已创建的socket句柄构造NetlinkHandler对象,并启动NetlinkHandlermHandler = new NetlinkHandler(mSock);if (mHandler->start()) {SLOGE("Unable to start NetlinkHandler: %s", strerror(errno));return -1;}return 0;}NetlinkHandler的继承关系:NetlinkHandler -->NetlinkListener-->SocketListener构造NetlinkHandler对象NetlinkHandler::NetlinkHandler(int listenerSocket) :NetlinkListener(listenerSocket){}构造NetlinkHandler对象的父类对象NetlinkListenerNetlinkListener::NetlinkListener(int socket) :SocketListener(socket, false){}构造NetlinkListener对象的父类对象SocketListenerSocketListener::SocketListener(const char *socketName, bool listen) {mListen = listen; //mListen = falsemSocketName = socketName;mSock = -1;pthread_mutex_init(&mClientsLock, NULL);mClients = new SocketClientCollection();}typedef android::List<SocketClient *> SocketClientCollection;启动NetlinkHandlerint NetlinkHandler::start() {return this->startListener();}调用NetlinkHandler的祖父类SocketListener的startListener函数来启动事件监听int SocketListener::startListener() {if (!mSocketName && mSock == -1) {SLOGE("Failed to start unbound listener");errno = EINVA L;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;}}if (mListen && listen(mSock, 4) < 0) { //mListen = falseSLOGE("Unable to listen on socket (%s)", strerror(errno));return -1;} else if (!mListen)mClients->push_back(new SocketClient(mSock));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开始监听:void SocketListener::runListener() {while(1) {SocketClientCollection::iterator it;fd_set read_fds;int rc = 0;int max = 0;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];//迭代mClients,查询Socket句柄值最大的pthread_mutex_lock(&mClientsLock);for (it = mClients->begin(); it != mClients->end(); ++it) {FD_SET((*it)->getSocket(), &read_fds);if ((*it)->getSocket() > max)max = (*it)->getSocket();}pthread_mutex_unlock(&mClientsLock);//查询if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) { SLOGE("select failed (%s)", strerror(errno));sleep(1);continue;} else if (!rc)continue;//如果管道可读的话,表示需要退出工作线程if (FD_ISSET(mCtrlPipe[0], &read_fds))break;if (mListen && FD_ISSET(mSock, &read_fds)) {struct sockaddr addr;socklen_t alen = sizeof(addr);int c;//接收客户端的连接if ((c = accept(mSock, &addr, &alen)) < 0) {SLOGE("accept failed (%s)", strerror(errno));sleep(1);continue;}pthread_mutex_lock(&mClientsLock);mClients->push_back(new SocketClient(c));pthread_mutex_unlock(&mClientsLock);}do {pthread_mutex_lock(&mClientsLock);for (it = mClients->begin(); it != mClients->end(); ++it) {int fd = (*it)->getSocket();if (FD_ISSET(fd, &read_fds)) {pthread_mutex_unlock(&mClientsLock);if (!onDataAvailable(*it)) {close(fd);pthread_mutex_lock(&mClientsLock);delete *it;it = mClients->erase(it);pthread_mutex_unlock(&mClientsLock);}FD_CLR(fd, &read_fds);pthread_mutex_lock(&mClientsLock);continue;}}pthread_mutex_unlock(&mClientsLock);} while (0);}}通过Socket接收到数据后自动调用onDataAvailable()bool NetlinkListener::onDataAvailable(SocketClient *cli){int socket = cli->getSocket();ssize_t count;char cred_msg[CMSG_SPACE(sizeof(struct ucred))];struct sockaddr_nl snl;struct iovec iov = {mBuffer, sizeof(mBuffer)};struct msghdr hdr = {&snl, sizeof(snl), &iov, 1, cred_msg, sizeof(cred_msg), 0};if ((count = recvmsg(socket, &hdr, 0)) < 0) {SLOGE("recvmsg failed (%s)", strerror(errno));return false;}if ((snl.nl_groups != 1) || (snl.nl_pid != 0)) {SLOGE("ignoring non-kernel netlink multicast message");return false;}struct cmsghdr * cmsg = CMSG_FIRSTHDR(&hdr);if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIA LS) { SLOGE("ignoring message with no sender credentials");return false;}struct ucred * cred = (struct ucred *)CMSG_DATA(cmsg);if (cred->uid != 0) {SLOGE("ignoring message from non-root UID %d", cred->uid);return false;}NetlinkEvent *evt = new NetlinkEvent();//解析接收到的uevent消息if (!evt->decode(mBuffer, count)) {SLOGE("Error decoding NetlinkEvent");goto out;}onEvent(evt);out: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);} else if (!strcmp(subsys, "switch")) {vm->handleSwitchEvent(evt);} else if (!strcmp(subsys, "usb_composite")) {vm->handleUsbCompositeEvent(evt);} else if (!strcmp(subsys, "battery")) {} else if (!strcmp(subsys, "power_supply")) {}}NetlinkManager模块负责从kernel接收uevent消息,然后转换成为一个NetlinkEvent对象,最后交给VolumeManager模块来处理VolumeManager模块启动流程1)构造VolumeManager对象实例2)设置事件广播监听3)启动VolumeManager4)配置VolumeManager构造VolumeManager对象实例VolumeManager *VolumeManager::Instance() {if (!sInstance)sInstance = new VolumeManager();return sInstance;}VolumeManager::VolumeManager() {mDebug = false;mVolumes = new VolumeCollection();mActiveContainers = new AsecIdCollection();mBroadcaster = NULL;mCdromShared = false;mResetUsb = false;mUsbMassStorageEnabled = false;mUsbConnected = false;mUmsSharingCount = 0;mSavedDirtyRatio = -1;// set dirty ratio to 0 when UMS is activemUmsDirtyRatio = 0;readInitialState();}typedef android::List<Volume *> VolumeCollection;typedef android::List<ContainerData*> AsecIdCollection;void VolumeManager::readInitialState() {FILE *fp;char state[255];/** Read the initial mass storage enabled state*/if ((fp = fopen("/sys/devices/virtual/usb_composite/usb_mass_storage/enable", "r"))) { if (fgets(state, sizeof(state), fp)) {mUsbMassStorageEnabled = !strncmp(state, "1", 1);} else {SLOGE("Failed to read usb_mass_storage enabled state (%s)", strerror(errno));}fclose(fp);} else {SLOGD("USB mass storage support is not enabled in the kernel");}/** Read the initial USB connected state*/if ((fp = fopen("/sys/devices/virtual/switch/usb_configuration/state", "r"))) {if (fgets(state, sizeof(state), fp)) {mUsbConnected = !strncmp(state, "1", 1);} else {SLOGE("Failed to read usb_configuration switch (%s)", strerror(errno));}fclose(fp);} else {SLOGD("usb_configuration switch is not enabled in the kernel");}}设置事件广播监听void setBroadcaster(SocketListener *sl) { mBroadcaster = sl; }启动VolumeManagerint VolumeManager::start() {return 0;}配置VolumeManager读取配置文件/etc/vold.fstab中的内容来配置VolumeManager,/etc/vold.fstab文件内容如下:######################### Regular device mount#### Format: dev_mount <label> <mount_point> <part> <sysfs_path1...>## label - Label for the volume## mount_point - Where the volume will be mounted## part - Partition # (1 based), or 'auto' for first usable partition.## <sysfs_path> - List of sysfs paths to source devices####################### Mounts the first usable partition of the s pecified devicedev_mount s dcard /storage/sdcard0 auto /devices/platform/s prd-sdhci.0/mmc_host/mmc0|设备挂载||volume名字|| mount的位置| |没有分区|| MMC设备在sysfs中的位置| dev_mount sdcard /storage/sdcard0 auto /devices/platform/sprd-sdhci.0/mmc_host/mmc0static int process_config(VolumeManager *vm) {FILE *fp;int n = 0;char line[255];if (!(fp = fopen("/etc/vold.fstab", "r"))) {return -1;}//解析/etc/vold.fstab配置文件while(fgets(line, sizeof(line), fp)) {char *next = line;char *type, *label, *mount_point;n++;line[strlen(line)-1] = '\0';if (line[0] == '#' || line[0] == '\0')continue;if (!(type = strsep(&next, " \t"))) {SLOGE("Error parsing type");goto out_syntax;}if (!(label = strsep(&next, " \t"))) {SLOGE("Error parsing label");goto out_syntax;}if (!(mount_point = strsep(&next, " \t"))) {SLOGE("Error parsing mount point");goto out_syntax;}if (!strcmp(type, "dev_mount")) {DirectVolume *dv = NULL;char *part, *sysfs_path;if (!(part = strsep(&next, " \t"))) {SLOGE("Error parsing partition");goto out_syntax;}if (strcmp(part, "auto") && atoi(part) == 0) {SLOGE("Partition must either be 'auto' or 1 based index instead of '%s'", part);goto out_syntax;}if (!strcmp(part, "auto")) {dv = new DirectVolume(vm, label, mount_point, -1);} else {//构造一个DirectVolume对象,DirectVolume封装了外部存储卡的操作dv = new DirectVolume(vm, label, mount_point, atoi(part));}while((sysfs_path = strsep(&next, " \t"))) {//添加路径/devices/platform/sprd-sdhci.0/mmc_host/mmc0if (dv->addPath(sysfs_path)) {SLOGE("Failed to add devpath %s to volume %s", sysfs_path,label);goto out_fail;}}vm->addVolume(dv);} else if (!strcmp(type, "map_mount")) {} else {SLOGE("Unknown type '%s'", type);goto out_syntax;}}fclose(fp);return 0;out_syntax:SLOGE("Syntax error on config line %d", n);errno = -EINVA L;out_fail:fclose(fp);return -1;}DirectVolume::DirectVolume(VolumeManager *vm, const char *label,const char *mount_point, int partIdx) :Volume(vm, label, mount_point) {mPartIdx = partIdx;mPaths = new PathCollection(); //typedef android::List<char *> PathCollection;for (int i = 0; i < MAX_PA RTITIONS; i++)mPartMinors[i] = -1;mPendingPartMap = 0;mDiskMajor = -1;mDiskMinor = -1;mDiskNumParts = 0;setState(Volume::State_NoMedia);}void Volume::setState(int state) {char msg[255];int oldState = mState;if (oldState == state) {SLOGW("Duplicate state (%d)\n", state);return;}mState = state;SLOGD("Volume %s state changing %d (%s) -> %d (%s)", mLabel,oldState, stateToStr(oldState), mState, stateToStr(mState));snprintf(msg, sizeof(msg),"Volume %s %s state changed from %d (%s) to %d (%s)", getLabel(),getMountpoint(), oldState, stateToStr(oldState), mState,stateToStr(mState));mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeStateChange,msg, false); }int DirectVolume::addPath(const char *path) {mPaths->push_back(strdup(path));return 0;}VolumeManager处理uevent消息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);} else if (!strcmp(subsys, "switch")) {vm->handleSwitchEvent(evt);} else if (!strcmp(subsys, "usb_composite")) {vm->handleUsbCompositeEvent(evt);} else if (!strcmp(subsys, "battery")) {} else if (!strcmp(subsys, "power_supply")) {}}块设备事件void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {const char *devpath = evt->findParam("DEVPATH");/* Lookup a volume to handle this device */VolumeCollection::iterator it;bool hit = false;//遍历VolumeManager中的所有DirectVolume对象for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {if (!(*it)->handleBlockEvent(evt)) {#ifdef NETLINK_DEBUGSLOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel()); #endifhit = true;break;}}if (!hit) {#ifdef NETLINK_DEBUGSLOGW("No volumes handled block event for '%s'", devpath);#endif}}块设备事件:int DirectVolume::handleBlockEvent(NetlinkEvent *evt) {const char *dp = evt->findParam("DEVPATH");PathCollection::iterator it;for (it = mPaths->begin(); it != mPaths->end(); ++it) {if (!strncmp(dp, *it, strlen(*it))) {/* We can handle this disk */int action = evt->getAction();const char *devtype = evt->findParam("DEVTYPE");if (action == NetlinkEvent::NlActionAdd) {int major = atoi(evt->findParam("MAJOR"));int minor = atoi(evt->findParam("MINOR"));char nodepath[255];snprintf(nodepath,sizeof(nodepath), "/dev/block/vold/%d:%d",major, minor);//创建设备节点if (createDeviceNode(nodepath, major, minor)) {SLOGE("Error making device node '%s' (%s)", nodepath,strerror(errno));}if (!strcmp(devtype, "disk")) {//存储设备类型SLOGW("=== get disk event ====\n");//wonghandleDiskAdded(dp, evt);} else {//分区类型SLOGW("=== get partition event ====\n");//wonghandlePartitionAdded(dp, evt);}} else if (action == NetlinkEvent::NlActionRemove) {if (!strcmp(devtype, "disk")) {handleDiskRemoved(dp, evt);} else {handlePartitionRemoved(dp, evt);}} else if (action == NetlinkEvent::NlActionChange) {if (!strcmp(devtype, "disk")) {handleDiskChanged(dp, evt);} else {handlePartitionChanged(dp, evt);}} else {SLOGW("Ignoring non add/remove/change event");}return 0;}}errno = ENODEV;return -1;}SDCard挂载卸载事件void VolumeManager::handleSwitchEvent(NetlinkEvent *evt) {const char *devpath = evt->findParam("DEVPATH");const char *name = evt->findParam("SWITCH_NAME");const char *state = evt->findParam("SWITCH_STATE");if (!name || !state) {SLOGW("Switch %s event missing name/state info", devpath);return;}LOGD("ligx ----------- name = %s",name);LOGD("ligx ----------- state = %s",state);bool oldAvailable = massStorageAvailable();if (!strcmp(name, "usb_configuration")) {mUsbConnected = !strcmp(state, "1");SLOGD("USB %s", mUsbConnected ? "connected" : "disconnected");bool newAvailable = massStorageAvailable();if (newAvailable != oldAvailable) {notifyUmsAvailable(newAvailable);}//add by liguxiang 09-15-11 for whether usb available begin}else if(!strcmp(name,"charger_cable")){if(!strcmp(state,"1")){notifyUsbAvailable(true);}else{notifyUsbAvailable(false);}//add by liguxiang 09-15-11 for whether usb available end}else {SLOGW("Ignoring unknown switch '%s'", name);}}void VolumeManager::notifyUmsAvailable(bool available) {char msg[255];snprintf(msg, sizeof(msg), "Share method ums now %s",(available ? "available" : "unavailable"));SLOGD(msg);getBroadcaster()->sendBroadcast(ResponseCode::ShareAvailabilityChange,msg, false); }void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) { pthread_mutex_lock(&mClientsLock);SocketClientCollection::iterator i;for (i = mClients->begin(); i != mClients->end(); ++i) {if ((*i)->sendMsg(code, msg, addErrno)) {SLOGW("Error sending broadcast (%s)", strerror(errno));}}pthread_mutex_unlock(&mClientsLock);}USB插拔事件void VolumeManager::handleUsbCompositeEvent(NetlinkEvent *evt) {const char *function = evt->findParam("FUNCTION");const char *enabled = evt->findParam("ENA BLED");if (!function || !enabled) {SLOGW("usb_composite event missing function/enabled info");return;}if (!strcmp(function, "usb_mass_storage")) {bool oldAvailable = massStorageAvailable();mUsbMassStorageEnabled = !strcmp(enabled, "1");SLOGD("usb_mass_storage function %s", mUsbMassStorageEnabled ? "enabled" : "disabled");bool newAvailable = massStorageAvailable();if (newAvailable != oldAvailable) {notifyUmsAvailable(newAvailable);}}}CommandListener 模块启动流程1)构造CommandListener 对象实例 2)调用startListener 函数启动监听FrameworkListener+mCommands#registerCmd()#onDataAvailable()-dispatchCommand()CommandListener+dumpArgs()SocketListener+mSock +mSocketName +mClients +mClientsLock +mListen +mCtrlPipe +mThread+startListener()+stopListener()+sendBroadcast()#onDataAvailable()-threadStart()-runListener()构造CommandListener 对象CommandListener::CommandListener() :FrameworkListener("vold") {registerCmd(new DumpCmd());registerCmd(new VolumeCmd());registerCmd(new AsecCmd());registerCmd(new ObbCmd());registerCmd(new ShareCmd());registerCmd(new StorageCmd());registerCmd(new XwarpCmd());}FrameworkCommand+mCommand+runCommand()+getCommand()VoldCommandXwarpCmd DumpCmdVolumeCmd ShareCmd AsecCmd ObbCmd StorageCmd构造父类对象FrameworkListenerFrameworkListener::FrameworkListener(const char *socketName) :SocketListener(socketName, true) {//typedef android::List<FrameworkCommand *> FrameworkCommandCollectionmCommands = new FrameworkCommandCollection();}构造父类对象SocketListenerSocketListener::SocketListener(const char *socketName, bool listen) {mListen = listen;mSocketName = socketName;mSock = -1;pthread_mutex_init(&mClientsLock, NULL);//typedef android::List<SocketClient *> SocketClientCollectionmClients = new SocketClientCollection();}命令注册:void FrameworkListener::registerCmd(FrameworkCommand *cmd) {mCommands->push_back(cmd);}启动监听system\core\libsysutils\src\SocketListener.cppint SocketListener::startListener() {if (!mSocketName && mSock == -1) {SLOGE("Failed to start unbound listener");errno = EINVA L;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;}}if (mListen && listen(mSock, 4) < 0) {SLOGE("Unable to listen on socket (%s)", strerror(errno));return -1;} else if (!mListen)mClients->push_back(new SocketClient(mSock));if (pipe(mCtrlPipe)) {SLOGE("pipe failed (%s)", strerror(errno));return -1;}if (pthread_create(&mThread, NULL, SocketListener::threadS tart, 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() {while(1) {SocketClientCollection::iterator it;fd_set read_fds;int rc = 0;int max = 0;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) { FD_SET((*it)->getSocket(), &read_fds);if ((*it)->getSocket() > max)max = (*it)->getSocket();}pthread_mutex_unlock(&mClientsLock);if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) { SLOGE("select failed (%s)", strerror(errno));sleep(1);continue;} else if (!rc)continue;if (FD_ISSET(mCtrlPipe[0], &read_fds))break;if (mListen && FD_ISSET(mSock, &read_fds)) {struct sockaddr addr;socklen_t alen = sizeof(addr);int c;if ((c = accept(mSock, &addr, &alen)) < 0) {SLOGE("accept failed (%s)", strerror(errno));sleep(1);continue;}pthread_mutex_lock(&mClientsLock);mClients->push_back(new SocketClient(c));pthread_mutex_unlock(&mClientsLock);}do {pthread_mutex_lock(&mClientsLock);for (it = mClients->begin(); it != mClients->end(); ++it) { int fd = (*it)->getSocket();if (FD_ISSET(fd, &read_fds)) {pthread_mutex_unlock(&mClientsLock);if (!onDataAvailable(*it)) {close(fd);pthread_mutex_lock(&mClientsLock);delete *it;it = mClients->erase(it);pthread_mutex_unlock(&mClientsLock);}FD_CLR(fd, &read_fds);pthread_mutex_lock(&mClientsLock);continue;}}pthread_mutex_unlock(&mClientsLock);} while (0);}}onDataAvailable 由子类FrameworkListener实现bool FrameworkListener::onDataAvailable(SocketClient *c) {char buffer[255];int len;len = TEMP_FAILURE_RETRY(read(c->getSocket(), buffer, sizeof(buffer)));if (len < 0) {SLOGE("read() failed (%s)", strerror(errno));return false;} else if (!len)return false;int offset = 0;int i;for (i = 0; i < len; i++) {if (buffer[i] == '\0') {/* IMPORTANT: dispatchCommand() expects a zero-terminated string */dis patchCommand(c, buffer + offset);offset = i + 1;}}return true;}void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) { FrameworkCommandCollection::iterator i;int argc = 0;char *argv[FrameworkListener::CMD_ARGS_MAX];char tmp[255];char *p = data;char *q = tmp;char *qlimit = tmp + sizeof(tmp) - 1;bool esc = false;bool quote = false;int k;memset(argv, 0, sizeof(argv));memset(tmp, 0, sizeof(tmp));while(*p) {if (*p == '\\') {if (esc) {if (q >= qlimit)goto overflow;*q++ = '\\';esc = false;} elseesc = true;p++;continue;} else if (esc) {if (*p == '"') {if (q >= qlimit)goto overflow;*q++ = '"';} else if (*p == '\\') {if (q >= qlimit)goto overflow;*q++ = '\\';} else {cli->sendMsg(500, "Unsupported escape sequence", false);goto out;}p++;esc = false;continue;}if (*p == '"') {if (quote)quote = false;elsequote = true;p++;continue;}*q = *p++;if (q >= qlimit)goto overflow;if (!quote && *q == ' ') {*q = '\0';if (argc >= CMD_ARGS_MAX)goto overflow;argv[argc++] = strdup(tmp);memset(tmp, 0, sizeof(tmp));q = tmp;continue;}q++;}*q = '\0';if (argc >= CMD_ARGS_MAX)goto overflow;argv[argc++] = strdup(tmp);#if 0for (k = 0; k < argc; k++) {SLOGD("arg[%d] = '%s'", k, argv[k]);}#endifif (quote) {cli->sendMsg(500, "Unclosed quotes error", false);goto out;}for (i = mCommands->begin(); i != mCommands->end(); ++i) { FrameworkCommand *c = *i;if (!strcmp(argv[0], c->getCommand())) {。
android6.0系统Healthd分析及低电量⾃动关机流程系统平台:android6.0概述Healthd是android4.4之后提出来的⼀种中介模型,该模型向下监听来⾃底层的电池事件,向上传递电池数据信息给Framework层的BatteryService⽤以计算电池电量相关状态信息,BatteryServcie通过传递来的数据来计算电池电量显⽰,剩余电量,电量级别等信息,如果收到过温报警或者严重低电报警等信息,系统会直接关机,保护硬件。
1.主模块处理流程Healthd模块代码是在system/core/healthd/,其模块⼊⼝在healthd的main函数,函数代码如下:1int main(int argc, char **argv) {2int ch;3int ret;4/*代码中开始便是解析参数,healthd_mode_ops是⼀个关于充电状态结构体变量,5 *结构体变量⾥的参数是函数指针,在初始化时指向各个不同的操作函数,6 *当开机充电时变量赋值为&android_ops,关机充电时候变量赋值为&charger_ops。
7*/8 klog_set_level(KLOG_LEVEL);9 healthd_mode_ops = &android_ops; //正常开机充电1011 //charger为该程序的可执⾏⽂件名,该⾏代码主要⽤于区分是命令操作还是正常代码启动12if (!strcmp(basename(argv[0]), "charger")) {1314 healthd_mode_ops = &charger_ops; 15 } else {16while ((ch = getopt(argc, argv, "cr")) != -1) {17switch (ch) { //根据不同的参数赋与不同的操作⽅法18case'c':19 healthd_mode_ops = &charger_ops;20break;21case'r':22 healthd_mode_ops = &recovery_ops;23break;24case'?':25default:26 KLOG_ERROR(LOG_TAG, "Unrecognized healthd option: %c\n",27 optopt);28 exit(1);29 }30 }31 }3233//对需要数据上报的事件进⾏初始化,分别是healthd_mode_ops、wakealarm和uevent三个事件34 ret = healthd_init();3536if (ret) {37 KLOG_ERROR("Initialization failed, exiting\n");38 exit(2);39 }40 healthd_mainloop();41 KLOG_ERROR("Main loop terminated, exiting\n");42return3;43 }1.1healthd_init( )函数分析1static int healthd_init() {2 epollfd = epoll_create(MAX_EPOLL_EVENTS); //创建epoll⽤于事件触发3if (epollfd == -1) {4 KLOG_ERROR(LOG_TAG,5"epoll_create failed; errno=%d\n",6 errno);7return -1;8 }9 healthd_board_init(&healthd_config);10//次处为调⽤android_ops->init进⾏初始化11 healthd_mode_ops->init(&healthd_config);12//对wakealarm进⾏初始化,⽤于周期触发事件上报数据13 wakealarm_init(); 14//对uevent进⾏初始化,⽤于域套节字进⾏数据传输 15 uevent_init(); 1617/*在healthd_init中最后创建BatteryMonitor的对象,并将其初始化。
安卓系统文件夹详细结构及其文件解析Android操作系统是一种基于Linux内核的开源操作系统,它的文件系统也是采用的Linux文件系统结构。
下面我将详细介绍安卓系统文件夹的结构及其文件解析。
1. /system- /bin: 该文件夹存放一些包含Android系统所需的可执行文件,如busybox等。
- /etc: 该文件夹存放一些系统配置文件,如/hosts文件、init.d 文件夹等。
- /lib: 该文件夹存放一些系统库文件,如libc.so、libm.so等。
- /usr: 该文件夹存放一些系统资源文件,如fonts文件夹、keylayout文件夹等。
2. /data- /app: 该文件夹存放已安装的应用程序,每个应用程序都会生成一个以包名命名的子文件夹。
- /cache: 该文件夹存放系统缓存文件,如应用程序缓存、系统临时文件等。
- /data: 该文件夹存放应用程序的数据文件,如数据库文件、SharedPreferences文件等。
- /system: 该文件夹存放一些系统级别的数据文件,如系统配置文件、系统数据库文件等。
- /block: 该文件夹存放块设备文件,如硬盘、U盘等。
- /input: 该文件夹存放输入设备文件,如键盘、鼠标等。
- /graphics: 该文件夹存放图形设备文件,如显示器等。
- /net: 该文件夹存放网络设备文件,如网卡等。
4. /proc- 各个进程的文件夹: 在/proc文件夹下,以进程ID命名的文件夹中存放有关该进程的信息,如进程的状态、资源占用情况等。
5. /sys- 各个设备的文件夹: 在/sys文件夹下,存放了系统的各个设备的相关信息,如CPU、内存、磁盘等设备。
6. /mnt- /sdcard: 该文件夹是外部存储的挂载点,通常被映射为手机的SD 卡。
- /usb: 该文件夹是USB存储的挂载点,用于连接USB存储设备。
7. /root- 该文件夹是Android系统的根目录。
android viewmodel原理Android ViewModel 原理随着 Android 应用不断发展,开发者经常面临着数据管理和存储的问题。
传统上,在 Android 应用中管理数据通常是由 Activity 或 Fragment 完成的。
这样做虽然简单,但是也会带来很多问题。
其中最常见的问题是Activity 和 Fragment 生命周期不可控,可能会导致数据丢失或内存泄漏等问题。
为了解决这些问题,Google 推出了一种新的架构组件:ViewModel。
什么是 ViewModel?ViewModel 是一个 Android 架构组件,目的是将 UI 层和数据层分离。
它可以存储 UI 需要的数据并且可以与UI 生命周期分开管理,这样可以避免由于 Activity 或Fragment 生命周期的变化而导致数据丢失的问题。
ViewModel 还可以存储以及管理 UI 状态信息,比如说网络请求状态,这些状态也可以在 Activity 或 Fragment 生命周期发生变化时保留。
ViewModel 中有哪些东西?ViewModel 功能非常强大,包含以下几个方面:1. 存储数据:ViewModel 可以存储 UI 需要的数据,并且可以随时更新数据。
2. 管理 UI 状态:ViewModel 可以管理 UI 相关的状态信息,比如说网络请求状态。
3. 分离逻辑:ViewModel 可以帮助开发者将 UI 层和业务逻辑层分离,从而使代码更加清晰易懂。
4. 提高应用性能:ViewModel 可以减少内存泄漏和重复代码的情况,提高应用性能。
ViewModel 的实现原理ViewModel 的实现原理其实很简单。
每一个 Activity 或 Fragment 都可以拥有一个 ViewModel 对象。
这个ViewModel 对象会与相应的 Activity 或 Fragment 实例绑定,将 UI 数据存储在其中。
SEAndroid安全机制中的文件安全上下文关联分析SEAndroid安全机制中的文件安全上下文关联分析前面一篇文章提到,SEAndroid是一种基于安全策略的MAC安全机制。
这种安全策略实施在主体和客体的安全上下文之上。
这意味着安全策略在实施之前,SEAndroid安全机制中的主休和客体是已经有安全上下文的。
在SEAndroid安全机制中,主体一般就是进程,而客体一般就是文件。
文件的安全上下文的关联有不同的方式。
本文主要分析文件安全上下文的设置过程,接下来的一篇文章再分析进程安全上下文的设置过程。
在SEAndroid中,文件的安全上下文是在文件的创建过程中设置的。
在Android系统中,文件的产生方式主要分为两种,一种是预置在ROM里面的,另外一种是动态创建的,即在系统在运行的过程中创建的。
对于预置在ROM里面的文件,例如打包在system.img里面的文件,它们的安全上下文在是制作ROM的过程中设置的。
而对于动态创建的文件,它们的安全上下文如果没有特别指定,就与父目录的安全上下文一致。
假设动态创建的文件的安全上下文来自于父目录。
这时候就有一个问题需要解决,就是最开始的父目录的安全上下文是怎么来的呢?如果最开始的父目录是预置在ROM里面的,那么这个问题就很好解决。
但是有一些目录,它们并不是预置在ROM的,而是在系统启动或者运行的过程中动态安装的,即我们平时所说的虚拟文件系统,例如我们在前面一篇文章中提到的selinux文件系统。
这些虚拟文件系统在安装的时候,SEAndroid安全机制会根据安全策略给它们的根目录设置相应的安全上下文,这样以后在里面创建的文件就可以从父目录继承安全上下文了。
此外,有些文件的安全上下文是不适合使用父目录的安全上下文的,例如应用程序数据文件,它们的安全上文需要根据一定的规则来特别指定。
在前面一篇文章中提到,SEAndroid安全机制根据应用程序类型的签名来给其数据文件设置不同的安全上下文,以区分系统应用程序和第三方应用程序的数据文件。
Android的属性系统2011-04-10 17:42每个属性都有一个名称和值,他们都是字符串格式。
属性被大量使用在Android系统中,用来记录系统设置或进程之间的信息交换。
属性是在整个系统中全局可见的。
每个进程可以get/set属性。
在系统初始化时,Android将分配一个共享内存区来存储的属性。
这些是由“init”守护进程完成的,其源代码位于:device/system/init。
“init”守护进程将启动一个属性服务。
属性服务在“init”守护进程中运行。
每一个客户端想要设置属性时,必须连接属性服务,再向其发送信息。
属性服务将会在共享内存区中修改和创建属性。
任何客户端想获得属性信息,可以从共享内存直接读取。
这提高了读取性能。
客户端应用程序可以调用libcutils中的API函数以GET/SET属性信息。
libcutils的源代码位于:device/libs/cutils。
API函数是:int property_get(const char *key, char *value, const char *default_value);int property_set(const char *key, const char *value);而libcutils又调用libc中的__system_property_xxx 函数获得共享内存中的属性。
libc的源代码位于:device/system/bionic。
属性服务调用libc中的__system_property_init函数来初始化属性系统的共享内存。
当启动属性服务时,将从以下文件中加载默认属性:/ default.prop/system/build.prop/system/default.prop/data/local.prop属性将会以上述顺序加载。
后加载的属性将覆盖原先的值。
这些属性加载之后,最后加载的属性会被保持在/data/property中。
Android log系统light2011/11/20Android 系统log抓取,实现原理分析一概述本文档主要是供Android开发人员使用,特别是Framework开发。
因为Framework中95%以上的问题都是靠分析log解决的,所以开发人员必须对android整个log系统十分清楚。
什么问题抓什么log, 使用什么工具抓Log,如何分析log,如何在代码中添加log.二DDMS log关于ddms是如何工作的和ddms的详细功能,见下面android sdk中文档详细介绍:F:\02 Android\01_SDK\Gingerbread2.3\docs-2.3_r01-linux\guide\developing\tools\ddms.htmlDdms 工具中打印log的几个菜单如下:Device -> Show process status…Device -> Dump device state…Device -> Dump app state…Device -> Dump radio state…Device -> Run logcat…1、Show process status…菜单等效于在adb shell下执行adb shell ps –x 命令,该命令打印出进程的详细信息,如下:USER PID PPID VSIZE RSS WCHAN PC NAMEroot 1 0 268 180 c009b74c 0000875c S /init (u:2, s:371) root 2 0 0 0 c004e72c 00000000 S kthreadd (u:0, s:1) root 3 2 0 0 c003fdc8 00000000 S ksoftirqd/0 (u:0, s:0) root 4 2 0 0 c004b2c4 00000000 S events/0 (u:0, s:39) root 5 2 0 0 c004b2c4 00000000 S khelper (u:0, s:0) root 6 2 0 0 c004b2c4 00000000 S suspend (u:0, s:0)USER 用户名,即用户所在组PID 进程ID(Process ID)PPID 父进程的进程ID(Parent Process id)VSZ 进程所使用的虚拟内存的大小(Virtual Size)RSS 进程使用的驻留集大小或者是实际内存的大小,Kbytes字节。
由于Android本身逻辑不支持多个SD卡,如果需要支持多个SD卡,并对SD卡进行操作,建议在Android的基础上进行修改。
对此过程了解,建议参考vold,mountservice机制。
1、修改system/core/rootdir/init.rc,创建目录export EXTERNAL_STORAGE1 /mnt/sdcard/extr_sdmkdir /mnt/sdcard/extr_sd 0000 system systemsymlink /mnt/sdcard/extr_sd /sdcard12、修改system/core/rootdir/etc/vold.fstabdev_mount sdcard /mnt/sdcard auto /devices/platform/goldfish_mmc.0 /devices/platform/msm_sdcc.2/mmc_host/mmc1增加extr_sd,请根据相对应的改写3、修改system/vold/V olumeManager.cpp将函数void V olumeManager::handleBlockEvent(NetlinkEvent *evt)中的break注销,否则找到一个SD卡即停止查找4、frameworks/base/core/java/android/os/Environment.java文件,增加extr_sd的虚拟路径参考private static final File EXTERNAL_STORAGE_DIRECTORY= getDirectory("EXTERNAL_STORAGE", "/sdcard");public static File getExternalStorageDirectory() {return EXTERNAL_STORAGE_DIRECTORY;}public static String getExternalStorageState()此目录下需要添加对外接口,参考sdcard的做法,可能需要更改多处。
Android -- Vold机制简要分析 Vold是用于管理和控制Android外部存储介质的后台进程,这里说的管控,主要包括SDK的插拔、挂载/卸载和格式化等;它是Android平台外部存储系统的管控枢纽。 Vold的整个控制模块主要由三个类模块构成:NetlinkManager、VolumeManager和CommandListener,它们的功能划分大概是: NetlinkManager:用于从kernel中获取SD卡插拔的Uevnet消息 VolumeManager:管理模块,对NetlinkManager转发的消息做一些处理,并通过CommandListener发送给framework(MountService.java);接着framework会通过套接字下发命令,指引VolumeManager对存储设备做下一步的操作,如挂载/卸载等 CommandListener:通过socket,实现MountService.java与Vold之间的消息交换 NetLink是Linux下用户进程和kernel进行信息交互的一种机制,借助这种机制,用户进程(如Vold/Netd)可以接收来自kernel的一些消息,同时也可以向kernel发送一些控制命令。NetlinkManager就是基于此设计的。Uevent也跟Linux系统有关,它与Linux 的设备文件系统有一定关系;这里,我们可以简单的认为,Uevent就是一个字符串,它描述了外部存储设备插入/拔出、挂载/卸载的状态信息。Vold通过Netlink机制,可以得到这些信息,并进行外部存储设备的管理、控制。 由上述介绍,我们可以得到如下的Vold框架图描述:
有了Vold的架构描述,接下来就开始分析Vold进程的整体流程及实现了。 一、Vold进程的声明与创建 Vold进程的声明与创建过程跟zygote一样,在init.rc中声明,在init进程创建: [java] view plain copy 在CODE上查看代码片派生到我的代码片 service vold /system/bin/vold \ --blkid_context=u:r:blkid:s0 --blkid_untrusted_context=u:r:blkid_untrusted:s0 \ --fsck_context=u:r:fsck:s0 --fsck_untrusted_context=u:r:fsck_untrusted:s0 class core socket vold stream 0660 root mount socket cryptd stream 0660 root mount ioprio be 2 在创建Vold进程时,会为它创建两个socket,用于与framework进行信息交互。其他的细节,参考之前zygote进程创建的介绍。 二、进入Vold主程序 Vold的主程序在/system/vold目录中,直接看main.cpp::main()函数: [cpp] view plain copy 在CODE上查看代码片派生到我的代码片 int main(int argc, char** argv) { setenv("ANDROID_LOG_TAGS", "*:v", 1); android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));
LOG(INFO) << "Vold 3.0 (the awakening) firing up"; LOG(VERBOSE) << "Detected support for:" << (android::vold::IsFilesystemSupported("ext4") ? " ext4" : "") << (android::vold::IsFilesystemSupported("f2fs") ? " f2fs" : "") << (android::vold::IsFilesystemSupported("vfat") ? " vfat" : "");
VolumeManager *vm; CommandListener *cl; CryptCommandListener *ccl; NetlinkManager *nm;
parse_args(argc, argv); sehandle = selinux_android_file_context_handle(); 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);//拿到init进程创建的名为vold的socket句柄,并为它设置FD_CLOEXEC标志位 fcntl(android_get_control_socket("cryptd"), F_SETFD, FD_CLOEXEC);//同上
mkdir("/dev/block/vold", 0755);//创建/dev/block/vold目录,存放所有subdisk和sdcard的挂载点信息
/* For when cryptfs checks and mounts an encrypted filesystem */ klog_set_level(6);
/* Create our singleton managers */ //1、创建VolumeManager if (!(vm = VolumeManager::Instance())) { LOG(ERROR) << "Unable to create VolumeManager"; exit(1); }
//2、创建NetlinkManager if (!(nm = NetlinkManager::Instance())) { LOG(ERROR) << "Unable to create NetlinkManager"; exit(1); }
if (property_get_bool("vold.debug", false)) { vm->setDebug(true); }
//3、创建CommandListener、CryptCommandListener cl = new CommandListener(); ccl = new CryptCommandListener(); vm->setBroadcaster((SocketListener *) cl); nm->setBroadcaster((SocketListener *) cl);
//4、启动VolumeManager if (vm->start()) { PLOG(ERROR) << "Unable to start VolumeManager"; exit(1); }
if (process_config(vm)) { PLOG(ERROR) << "Error reading configuration... continuing anyways"; }
//6、启动NetlinkManager,处理来自kernel的usb/sdcard插拔消息 if (nm->start()) { PLOG(ERROR) << "Unable to start NetlinkManager"; exit(1); } //7、应用层往/sys/block目录下的uevent文件写"add\n"指令,触发kernel向上发送Uevent消息,获取设备的当前信息 coldboot("/sys/block"); // coldboot("/sys/class/switch");
/* * Now that we're up, we can respond to commands */ //8、启动CommandListener if (cl->startListener()) { PLOG(ERROR) << "Unable to start CommandListener"; exit(1); }
//9、启动CryptCommandListener if (ccl->startListener()) { PLOG(ERROR) << "Unable to start CryptCommandListener"; exit(1); }
// Eventually we'll become the monitoring thread while(1) { sleep(1000); }
LOG(ERROR) << "Vold exiting"; exit(0); } 从代码中的注释可知,Vold主要创了三个对象:NetlinkManager、VolumeManager和CommandListener。根据Vold的架构图,现分别对它们的创建及启动过程进行分析。 (1)、NetlinkManager 主要的处理过程: nm = NetlinkManager::Instance() nm->setBroadcaster((SocketListener *) cl) nm->start() 现按步骤进行分析。 1、NetlinkManager::Instance(): [cpp] view plain copy 在CODE上查看代码片派生到我的代码片 NetlinkManager *NetlinkManager::Instance() { if (!sInstance) sInstance = new NetlinkManager(); return sInstance; }
NetlinkManager::NetlinkManager() { mBroadcaster = NULL; //type:SocketListener*,用来进行socket通信 } 这里使用了单例模式来构建NetlinkManager对象,构造函数中只是简单地初始化了成员变量。 2、NetlinkManager::setBroadcaster(): [cpp] view plain copy 在CODE上查看代码片派生到我的代码片