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 基础与底层机制1.数据库的操作类型有哪些,如何导入外部数据库?读懂题目。
如果碰到问题比较模糊的时候可以适当问问面试官。
配合面试官来面试:面试是一个相互了解的过程,要充分利用面试的题目和时间把自己的能力和技术展现出来,面试官能够看到你的真实技术。
1)使用数据库的方式有哪些?(1)openOrCreateDatabase(String path);(2)继承SqliteOpenHelper类对数据库及其版本进行管理(onCreate,onUpgrade)当在程序当中调用这个类的方法getWritableDatabase()或者getReadableDatabase();的时候才会打开数据库。
如果当时没有数据库文件的时候,系统就会自动生成一个数据库。
2)操作的类型:增删改查CRUD直接操作SQL语句:SQliteDatabase.execSQL(sql);面向对象的操作方式:SQLiteDatabase.insert(table, nullColumnHack, ContentValues);如何导入外部数据库?一般外部数据库文件可能放在SD卡或者res/raw或者assets目录下面。
写一个DBManager的类来管理,数据库文件搬家,先把数据库文件复制到”/data/data/包名/databases/”目录下面,然后通过db.openOrCreateDatabase(db文件),打开数据库使用。
我上一个项目就是这么做的,由于app上架之前就有一些初始数据需要内置,也会碰到数据的升级等问题,我是这么做的……同时我碰到最有意思的问题就是关于数据库并发操作的问题,比如:多线程操作数据库的时候,我采取的是封装使用互斥锁来解决……2.是否使用过本地广播,和全局广播有什么差别?引入本地广播的机制是为了解决安全性的问题:1)正在发送的广播不会脱离应用程序,比用担心app的数据泄露;2)其他的程序无法发送到我的应用程序内部,不担心安全漏洞。
Android 源码系列之十二从源码的角度深入理解LeakCanary的内存泄露检测机制(上)在分析LeakCanary源码之前,我们有必要先来了解一下Java的内存分配策略以及Android 中常见的内存泄漏。
Java内存分配策略一、Java程序运行时的内存分配策略有三种,它们分别是静态分配,栈分配和堆分配;对应的三种存储策略所使用的内存空间分别是静态存储区、栈存储区和堆存储区。
静态存储区静态存储区主要存放静态数据,全局static数据和常量。
静态存储区在程序编译时就已经分配好,在程序整个运行期间都存在。
栈存储区栈存储区主要存放方法体内的局部变量。
当一个方法被执行时,该方法体内的局部变量在栈存储区内创建,方法执行结束后局部变量所持有的内存将会自动被释放。
堆存储区堆存储区通常就是指在程序运行时通过关键字new出来的内存区,这部分内存在不使用时将会由Java垃圾回收器来负责回收。
二、堆与栈的区别在方法体内定义的一些基本类型的变量和对象的引用变量都称为局部变量,这些局部变量在栈内存中分配空间。
当在一个方法块中定义一个变量时,Java就会在栈中为该变量分配内存空间,当超过该变量的作用域后,该变量也就无效了,分配给它的内存空间也将被释放掉,该内存空间可以被重新使用。
堆内存用来存放所有由new关键字创建的对象(包括该对象中的所有成员变量)和数组。
在堆中分配的内存,将由Java垃圾回收器来自动管理。
在堆中产生了一个数组或者对象后,还可以在栈中定义一个特殊的变量,这个变量的取值等于数组或者对象在堆内存的首地址,这个特殊的变量就是我们常说的引用变量。
我们可以通过这个引用变量来访问堆中的对象或者数组。
Java如何管理内存Java的内存管理简单理解就是对象的分配和释放。
在Java中对象的内存分配是通过关键字new来进行分配的(注意:基本类型除外),这些对象在堆(Heap)存储区中分配空间,而对象的释放是由GC来决定和进行回收的。
Android开机log分析1.分析开机log,一是可以理一下android启动流程,二是可以通过log定位错误,下面列举一些常见android程序发生错误时抛出的异常,查找关键字xxxException可以快速定位android层错误以及原因:ng.NullPointerException:空指针异常ng.ClassNotFoundException:找不到类抛出的异常ng.ArithmeticException:一个整数“除以零”时抛出的异常ng.ArrayIndexOutOfBoundsException:数组越界访问以后抛出的异常ng.IllegalArgumentException:传入非法参数抛出的异常ng.IllegalAccessException:当应用程序要调用一个类,但当前的方法即没有对该类的访问权限便会出现这个异常ng.SecturityException:安全异常。
由安全管理器抛出,用于指示违反安全情况的异常ng.RuntimeException运行时异常。
是所有Java虚拟机正常操作期间可以被抛出的异常的父类。
ng.NumberFormatException:字符串转换为数字异常:ng.StackOverflowError:堆栈溢出错误。
当一个应用递归调用的层次太深而导致堆栈溢出时抛出该错误。
ng.RuntimeExceptionng.OutOfMemoryError:内存不足错误。
当可用内存不足以让Java虚拟机分配给一个对象时抛出该错误。
ng.IOException:输入输出异常ng.AbstractMethodError:抽象方法错误。
当应用试图调用抽象方法时抛出。
ng.ClassFormatError:类格式错误。
当Java虚拟机试图从一个文件中读取Java类,而检测到该文件的内容不符合类的有效格式时抛出。
ng.InstantiationError:实例化错误。
Androidusb流程分析文档以UMS(usb mass storage)为例来分析流程,主要按照图中红线来分析(即从插入USB 开始到状态栏弹框,然后又从选择UMS功能开始往下地流程).以前没有看过USB相关代码,网上也很少有分析usb FRAMEWORK相关地东西,文档中可能存在错误,如果发现欢迎指正.总体框图1.Kernel USB 流程LINUX KERNEL GADGET 架构Linux USB Gadget分三层架构,层次关系从上到下一层:USB Gadget功能层.BSP/Driver开发者通常是要实现这一层,从而实现一个具体地设备驱动,如Anddroid在此层实现了adb,mtp,mass_storage等.浏览参考关注此层代码时,会发现“composite”是此层地关键字,此层中关键地数据结构是:struct usb_composite_driver.这一层地驱动文件一般为:driver/usb/gadget/android.c (android实现地)或driver/usb/gadget/serial.c(传统Linux实现地USB转串口).b5E2R。
二层:USB设备层(usb core).这一层是Linux内核开发维护者实现地,与我们没太大关系,不用我们操心,我们只关心其地一些接口就行.浏览参考关注此层时,会发现“gadget”是此层地关键字,此层地关键数据结构是:usb_gadget_driver,usb_composite_dev.这层主要地一个驱动文件为:driver/usb/gadget/composite.c p1Ean。
三层:USB设备控制器驱动层.这一层主要是与CPU、CPU USB控制器有关,与硬件紧密相关,主要它和USB控制器牵扯在一起,涉及有寄存器、时钟、DMA等等.但是这一层往往是由芯片厂商去实现.我们一般仅需在板级文件中处理好所需要地USB接口即可.这层地关键字就是“UDC”,主要驱动文件命名含“udc”关键字,一般与CPU或芯片厂商有关,如MTK UDC 驱动在kernel/mediatek/platform/mt6592/kernel/drivers/usb20/目录下.DXDiT。
android vmp 原理Android VMP (Virtual Machine Protector) 原理一、VMP 简介Android VMP 是一种基于虚拟机技术的Android 应用程序保护方案。
它通过对Android 应用程序进行混淆和加密,使得反编译和逆向工程变得非常困难。
本文将一步一步回答关于Android VMP 的原理。
二、认识Android VMP1. Android VMP 概述Android VMP 是一种虚拟机保护方案,用于保护Android 应用程序的代码和资源。
它通过将类、方法、常量等进行混淆,并加密字节码,使得代码难以理解和分析。
2. Android VMP 的反编译性Android 应用程序被编译为Dalvik 字节码,可以被逆向工程师轻易地反编译成Java 代码。
Android VMP 通过对字节码进行加密和混淆,使得反编译成有效的Java 代码变得异常困难。
三、Android VMP 的原理1. 加密字节码文件Android VMP 首先对应用程序的字节码文件进行加密。
它使用一种加密算法,例如AES(Advanced Encryption Standard)等,将字节码转化为不可读的形式。
这样一来,即使进行反编译,也无法直接获得可读的代码。
2. 修改和加密常量表常量表是一个常见的逆向工程目标,它包含了字符串、数字等常量信息。
Android VMP 会对常量表进行修改和加密,使得逆向工程师不能轻易地获得其中的信息。
它使用了一种算法,例如异或算法,对常量进行加密。
3. 方法和类的混淆Android VMP 还对方法和类名进行混淆,使得反编译得到的代码难以理解。
它会对每个方法和类名进行重命名,并修改所有相关的引用。
这样一来,逆向工程师很难跟踪代码流程和关系。
4. 虚拟机和执行引擎Android VMP 使用自定义的虚拟机和执行引擎来加载和执行加密的字节码。
它会解密字节码,并动态加载到虚拟机中进行执行。
android vmos原理AndroidVMOS是一种虚拟机技术,它可以在一台手机上同时运行多个操作系统,以提供先进、安全和更有效的移动应用环境。
本文将详细介绍Android VMOS原理,它是如何运行的,相关的安全技术,以及它的优点和缺点。
Android VMOS的原理是与Linux内核相似的虚拟机技术。
这种技术利用“虚拟模式”来实现多个操作系统的同时运行,从而开发复杂的应用程序。
由于充分利用了Android设备的计算、内存和存储能力,因此使得虚拟机技术经济实惠。
每个虚拟机内部都有一个独立的操作系统环境,其中可以安装和运行不同的程序。
由于虚拟机之间是完全隔离的,因此在一台手机上可以同时运行安卓系统、IOS系统或其他系统。
Android VMOS技术的安全性是极其重要的,为了保证虚拟机之间的安全隔离,确保移动应用程序之间没有混淆或破坏,Android VMOS技术对每个虚拟机的操作系统环境都有一定的安全限制,以确保每个虚拟机的安全性。
Android VMOS技术的优点是:1)安全性高。
由于每个虚拟机之间是完全隔离的,因此可以有效地防止病毒和恶意程序的传播,并保护手机的账号和数据安全。
2)性能优越。
虚拟机可以充分利用手机的计算能力,使应用程序的运行速度更快,而且还能节省存储空间。
3)开发效率高。
虚拟机可以让开发者在一台手机上同时运行多个操作系统,这有助于开发者更快地完成项目,并在不同的系统环境下完成应用开发。
Android VMOS技术的缺点是:1)系统负载大。
虚拟机可以让手机在同一时间内运行多个应用程序,但也会增加手机的系统负载,导致手机变慢。
2)容易泄露数据。
由于每个虚拟机之间的安全隔离不完善,因此容易出现数据泄露的情况,严重时可能造成重大的安全损失。
总之,Android VMOS技术是一种高效、安全的移动应用虚拟化技术,它可以让开发者在一台手机上同时运行多个操作系统,从而开发复杂的应用程序,节省存储空间,提高开发效率。
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上查看代码片派生到我的代码片