原文地址: http://blog.csdn.net/luoshengyang/article/details/6627260
在前面一篇文章浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路中,介绍了Service Manager是如何成为Binder机制的守护进程的。既然作为守护进程,Service Manager的职责当然就是为Server和Client服务了。那么,Server和Client如何获得Service Manager接口,进而享受它提供的服务呢?本文将简要分析Server和Client获得Service Manager的过程。

在阅读本文之前,希望读者先阅读Android进程间通信(IPC)机制Binder简要介绍和学习计划一文提到的参考资料Android深入浅出之Binder机制,这样可以加深对本文的理解。

我们知道,Service Manager在Binder机制中既充当守护进程的角色,同时它也充当着Server角色,然而它又与一般的Server不一样。对于普通的Server来说,Client如果想要获得Server的远程接口,那么必须通过Service Manager远程接口提供的getService接口来获得,这本身就是一个使用Binder机制来进行进程间通信的过程。而对于Service Manager这个Server来说,Client如果想要获得Service Manager远程接口,却不必通过进程间通信机制来获得,因为Service Manager远程接口是一个特殊的Binder引用,它的引用句柄一定是0。

获取Service Manager远程接口的函数是defaultServiceManager,这个函数声明在frameworks/base/include/binder/IServiceManager.h文件中:

[cpp] view plaincopy
  1. sp<IServiceManager> defaultServiceManager();

实现在frameworks/base/libs/binder/IServiceManager.cpp文件中:

[cpp] view plaincopy
  1. sp<IServiceManager> defaultServiceManager()
  2. {
  3. if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
  4. {
  5. AutoMutex _l(gDefaultServiceManagerLock);
  6. if (gDefaultServiceManager == NULL) {
  7. gDefaultServiceManager = interface_cast<IServiceManager>(
  8. ProcessState::self()->getContextObject(NULL));
  9. }
  10. }
  11. return gDefaultServiceManager;
  12. }

gDefaultServiceManagerLock和gDefaultServiceManager是全局变量,定义在frameworks/base/libs/binder/Static.cpp文件中:

[cpp] view plaincopy
  1. Mutex gDefaultServiceManagerLock;
  2. sp<IServiceManager> gDefaultServiceManager;

从这个函数可以看出,gDefaultServiceManager是单例模式,调用defaultServiceManager函数时,如果gDefaultServiceManager已经创建,则直接返回,否则通过interface_cast<IServiceManager>(ProcessState::self()->getContextObject(NULL))来创建一个,并保存在gDefaultServiceManager全局变量中。

在继续介绍interface_cast<IServiceManager>(ProcessState::self()->getContextObject(NULL))的实现之前,先来看一个类图,这能够帮助我们了解Service Manager远程接口的创建过程。


        参考资料Android深入浅出之Binder机制一文的读者,应该会比较容易理解这个图。这个图表明了,BpServiceManager类继承了BpInterface<IServiceManager>类,BpInterface是一个模板类,它定义在frameworks/base/include/binder/IInterface.h文件中:

[cpp] view plaincopy
  1. template<typename INTERFACE>
  2. class BpInterface : public INTERFACE, public BpRefBase
  3. {
  4. public:
  5. BpInterface(const sp<IBinder>& remote);
  6. protected:
  7. virtual IBinder* onAsBinder();
  8. };

IServiceManager类继承了IInterface类,而IInterface类和BpRefBase类又分别继承了RefBase类。在BpRefBase类中,有一个成员变量mRemote,它的类型是IBinder*,实现类为BpBinder,它表示一个Binder引用,引用句柄值保存在BpBinder类的mHandle成员变量中。BpBinder类通过IPCThreadState类来和Binder驱动程序并互,而IPCThreadState又通过它的成员变量mProcess来打开/dev/binder设备文件,mProcess成员变量的类型为ProcessState。ProcessState类打开设备/dev/binder之后,将打开文件描述符保存在mDriverFD成员变量中,以供后续使用。

理解了这些概念之后,就可以继续分析创建Service Manager远程接口的过程了,最终目的是要创建一个BpServiceManager实例,并且返回它的IServiceManager接口。创建Service Manager远程接口主要是下面语句:

[cpp] view plaincopy
  1. gDefaultServiceManager = interface_cast<IServiceManager>(
  2. ProcessState::self()->getContextObject(NULL));

看起来简短,却暗藏玄机,具体可阅读Android深入浅出之Binder机制这篇参考资料,这里作简要描述。

首先是调用ProcessState::self函数,self函数是ProcessState的静态成员函数,它的作用是返回一个全局唯一的ProcessState实例变量,就是单例模式了,这个变量名为gProcess。如果gProcess尚未创建,就会执行创建操作,在ProcessState的构造函数中,会通过open文件操作函数打开设备文件/dev/binder,并且返回来的设备文件描述符保存在成员变量mDriverFD中。

接着调用gProcess->getContextObject函数来获得一个句柄值为0的Binder引用,即BpBinder了,于是创建Service Manager远程接口的语句可以简化为:

[cpp] view plaincopy
  1. gDefaultServiceManager = interface_cast<IServiceManager>(new BpBinder(0));

再来看函数interface_cast<IServiceManager>的实现,它是一个模板函数,定义在framework/base/include/binder/IInterface.h文件中:

[cpp] view plaincopy
  1. template<typename INTERFACE>
  2. inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
  3. {
  4. return INTERFACE::asInterface(obj);
  5. }

这里的INTERFACE是IServiceManager,于是调用了IServiceManager::asInterface函数。IServiceManager::asInterface是通过DECLARE_META_INTERFACE(ServiceManager)宏在IServiceManager类中声明的,它位于framework/base/include/binder/IServiceManager.h文件中:

[cpp] view plaincopy
  1. DECLARE_META_INTERFACE(ServiceManager);

展开即为:

[cpp] view plaincopy
  1. #define DECLARE_META_INTERFACE(ServiceManager)                              \
  2. static const android::String16 descriptor;                          \
  3. static android::sp<IServiceManager> asInterface(                    \
  4. const android::sp<android::IBinder>& obj);                          \
  5. virtual const android::String16& getInterfaceDescriptor() const;    \
  6. IServiceManager();                                                  \
  7. virtual ~IServiceManager();

IServiceManager::asInterface的实现是通过IMPLEMENT_META_INTERFACE(ServiceManager, "Android.os.IServiceManager")宏定义的,它位于framework/base/libs/binder/IServiceManager.cpp文件中:

[cpp] view plaincopy
  1. IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");

展开即为:

[cpp] view plaincopy
  1. #define IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager")                 \
  2. const android::String16 IServiceManager::descriptor("android.os.IServiceManager");     \
  3. const android::String16&                                   \
  4. IServiceManager::getInterfaceDescriptor() const {                                      \
  5. return IServiceManager::descriptor;                                                    \
  6. }                                                                                      \
  7. android::sp<IServiceManager> IServiceManager::asInterface(                             \
  8. const android::sp<android::IBinder>& obj)                                              \
  9. {                                                                                      \
  10. android::sp<IServiceManager> intr;                                                     \
  11. if (obj != NULL) {                                                                     \
  12. intr = static_cast<IServiceManager*>(                                                  \
  13. obj->queryLocalInterface(                                                              \
  14. IServiceManager::descriptor).get());                                                   \
  15. if (intr == NULL) {                                                                    \
  16. intr = new BpServiceManager(obj);                                                      \
  17. }                                                                                      \
  18. }                                                                                      \
  19. return intr;                                                                           \
  20. }                                                                                      \
  21. IServiceManager::IServiceManager() { }                                                 \
  22. IServiceManager::~IServiceManager() { }

估计写这段代码的员工是从Microsoft跳槽到Google的。这里我们关注IServiceManager::asInterface的实现:

[cpp] view plaincopy
  1. android::sp<IServiceManager> IServiceManager::asInterface(const android::sp<android::IBinder>& obj)
  2. {
  3. android::sp<IServiceManager> intr;
  4. if (obj != NULL) {
  5. intr = static_cast<IServiceManager*>(
  6. obj->queryLocalInterface(IServiceManager::descriptor).get());
  7. if (intr == NULL) {
  8. intr = new BpServiceManager(obj);
  9. }
  10. return intr;
  11. }

这里传进来的参数obj就则刚才创建的new BpBinder(0)了,BpBinder类中的成员函数queryLocalInterface继承自基类IBinder,IBinder::queryLocalInterface函数位于framework/base/libs/binder/Binder.cpp文件中:

[cpp] view plaincopy
  1. sp<IInterface>  IBinder::queryLocalInterface(const String16& descriptor)
  2. {
  3. return NULL;
  4. }

由此可见,在IServiceManager::asInterface函数中,最终会调用下面语句:

[cpp] view plaincopy
  1. intr = new BpServiceManager(obj);

即为:

[cpp] view plaincopy
  1. intr = new BpServiceManager(new BpBinder(0));

回到defaultServiceManager函数中,最终结果为:

[cpp] view plaincopy
  1. gDefaultServiceManager = new BpServiceManager(new BpBinder(0));

这样,Service Manager远程接口就创建完成了,它本质上是一个BpServiceManager,包含了一个句柄值为0的Binder引用。

在Android系统的Binder机制中,Server和Client拿到这个Service Manager远程接口之后怎么用呢?

对Server来说,就是调用IServiceManager::addService这个接口来和Binder驱动程序交互了,即调用BpServiceManager::addService 。而BpServiceManager::addService又会调用通过其基类BpRefBase的成员函数remote获得原先创建的BpBinder实例,接着调用BpBinder::transact成员函数。在BpBinder::transact函数中,又会调用IPCThreadState::transact成员函数,这里就是最终与Binder驱动程序交互的地方了。回忆一下前面的类图,IPCThreadState有一个PorcessState类型的成中变量mProcess,而mProcess有一个成员变量mDriverFD,它是设备文件/dev/binder的打开文件描述符,因此,IPCThreadState就相当于间接在拥有了设备文件/dev/binder的打开文件描述符,于是,便可以与Binder驱动程序交互了。

对Client来说,就是调用IServiceManager::getService这个接口来和Binder驱动程序交互了。具体过程上述Server使用Service Manager的方法是一样的,这里就不再累述了。

IServiceManager::addService和IServiceManager::getService这两个函数的具体实现,在下面两篇文章中,会深入到Binder驱动程序这一层,进行详细的源代码分析,以便更好地理解Binder进程间通信机制,敬请关注。

老罗的新浪微博:http://weibo.com/shengyangluo,欢迎关注!

43
4
  • 上一篇浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路
  • 下一篇Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析

我的同类文章

Android(175)
  • •Chromium扩展(Extension)的页面(Page)加载过程分析2016-09-19阅读967
  • •Chromium扩展(Extension)机制简要介绍和学习计划2016-09-05阅读14606
  • •Chromium为视频标签<video>渲染视频画面的过程分析2016-08-22阅读2328
  • •Chromium视频标签<video>简要介绍和学习计划2016-08-08阅读2510
  • •Chromium网页滑动和捏合手势处理过程分析2016-07-11阅读5373
  • •Chromium网页输入事件处理机制简要介绍和学习计划2016-06-27阅读5352
  • •Chromium扩展(Extension)加载过程分析2016-09-12阅读3707
  • •Chromium为视频标签<video>全屏播放的过程分析2016-08-29阅读2486
  • •Chromium为视频标签<video>创建播放器的过程分析2016-08-15阅读6431
  • •Chromium分发输入事件给WebKit处理的过程分析2016-07-25阅读3490
  • •Chromium网页输入事件捕捉和手势检测过程分析2016-07-04阅读7027

更多文章

参考知识库

猜你在找
Android底层技术:Java层系统服务(Android Service)
Android开发—Bmob云服务
Android平台的崩溃捕获机制及实现
Android移植基础
PHP单例模式视频
浅谈Android系统进程间通信IPC机制Binder中的Server和Client获得Service Manager接口之路
浅谈Android系统进程间通信IPC机制Binder中的Server和Client获得Service Manager接口之路
浅谈Android系统进程间通信IPC机制Binder中的Server和Client获得Service Manager接口之路
Binder2 浅谈Android系统进程间通信IPC机制Binder中的Server和Client获得Service Manager接口之路
那两年炼就的Android内功修养
查看评论
24楼 qq_23565697 前天 14:17发表 [回复]
罗老师,这个群130112760加不了了啊。
23楼 默默9518 2015-07-29 17:30发表 [回复]
这是哪个安卓版本呢,文件位置貌似不对吧。

frameworks/native/libs/binder/IServiceManager.cpp

22楼 小桥流水__人家 2015-05-25 10:48发表 [回复]
在这里,请教一个问题,罗老师说"Client如果想要获得Service Manager远程接口,却不必通过进程间通信机制来获得,因为Service Manager远程接口是一个特殊的Binder引用,它的引用句柄一定是0",问题是: 按道理,client和Service Manager都分别是一个独立的进程,他们要实现数据传递,也应该要实现数据共享哈,或者要遵循进程间通信,才能够把数据传到另一个进程中去,为什么说
"一个特殊的Binder引用,它的引用句柄为0“,就可以实现进程间数据的传递了?

举个例子:
在调用defaultServiceManager()函数获得gDefaultServiceManager变量时,Client和Service Manager两个进程都应该有一个自己独立的gDefaultServiceManager变量吧,为什么在这里,感觉这个变量就在两个进程中共享了呢?
非常感谢哪位大虾能帮我解答一下这个疑问,谢谢!

Re: 罗升阳 2015-05-25 11:17发表 [回复]
回复小桥流水__人家:这里说的只是Service Manager远程接口(代理接口)的获取方式,IPC是获得了远程接口之后的事情,这个是当然是跨进程的。

Re: 小桥流水__人家 2015-05-26 11:25发表 [回复]
回复罗升阳:回复Luoshengyang:非常感谢罗老师的回答,多个client进程会共享gDefaultServiceManager变量吗? 假设有多个client端来调用defaultServiceManager()函数,它里面的gDefaultServiceManager变量是同一个吗?如果不是同一个,那每一个client进程都会调用interface_cast<IServiceManager>(new BpBinder(0))一次; 按道理,每一个进程都会有自己独立的变量,也就是每一个client,都会有一个变量gDefaultServiceManager?谢谢!
21楼 _Caij 2015-05-12 18:32发表 [回复]
Bp和Bn之间通信是通过发送数据 这个通信也是Binder吗?
20楼 xingfeng2010 2014-12-19 10:10发表 [回复]
学习了
19楼 ctsiuser 2014-08-11 22:00发表 [回复]
有段时间没看android了,回头看看,还真有点忘了
18楼 plgg0814 2014-06-26 15:17发表 [回复]
为什么BINDER_VM_SIZE是1*1024*1024 - 4096*2, 为什么要减去8k?
17楼 jltxgcy 2014-05-25 19:54发表 [回复]
罗老师,我想了很久,为什么BpBinder(0)不会被析构呢?sp<Ibinder>也是局部变量,出了作用域就会被析构。

Re: mandagod 2015-08-11 14:10发表 [回复]
回复jltxgcy:请研究只能智能指针,其中包括弱指针和强指针。
Re: 罗升阳 2014-05-26 09:54发表 [回复]
回复jltxgcy:在你拿到这个BpBinder之前,很多地方引用了它,所以不会被析构。

Re: jltxgcy 2014-05-26 20:47发表 [回复]
回复罗升阳:终于明白了,是在构造BpRefBase时,if (mRemote) { mRemote->incStrong(this); mRefs = mRemote->createWeak(this); } 所以不会被析构。
Re: jltxgcy 2014-05-26 16:22发表 [回复]
回复罗升阳:但是,在FregServer.cpp中defaultServiceManager()只调用了一次getStrongProxyForHandle(0),在这个进程中没有其他地方调用getStrongProxyForHandle(0),也就是BpBinder只在这个位置引用了。你回答,在你拿到这个BpBinder之前,很多地方引用了它,是其他进程调用了这个函数么,但与这个进程无关啊?想不明白,请指教。
16楼 test_impeller 2014-04-11 09:36发表 [回复]
罗老师,请教一个问题。你这篇文章讲的是C++层获取Server Manager接口的方法。如果在JAVA层获取Server Manager接口,那么就是另一套机制了,对吧?
15楼 ccnuxieshuo 2014-01-03 11:44发表 [回复]
由此可见,在IServiceManager::asInterface函数中,最终会调用下面语句:
能帮忙讲下这个由此可见是从什么地方来的? 因为我一直在追同一进程内的Process Binder IPC是否要走Binder Driver

Re: 罗升阳 2014-01-03 13:58发表 [回复]
回复ccnuxieshuo:不走

Re: ccnuxieshuo 2014-01-03 14:25发表 [回复]
回复罗升阳:大概想结论肯定是这样,但这件事情是怎么做到的?

Re: 罗升阳 2014-01-03 14:29发表 [回复]
回复ccnuxieshuo:很简单,Client透过Binder驱动向Server请求一个Binder代理对象时,Binder驱动发现它们是同一个进程,就向Client进程返回一个Binder本地对象,而不是Binder代理对象。

Re: ccnuxieshuo 2014-01-03 19:59发表 [回复]
回复罗升阳:后来看了下Driver,然后Userspace应该是在unflatten_binder用type做了区分,但是就IMPLEMENT_META_INTERFACE这个Macro来说,obj->queryLocalInterface(IServiceManager::descriptor)这个东西如果说是对Bp来说,那应该一定是NULL,后面的.get() 怎么跑为好,还是说我什么地方看漏了,Orz...
14楼 rickystudio 2013-05-07 17:25发表 [回复]
罗老师,是不是每个进程都有唯一个defaultServiceManager?

Re: 罗升阳 2013-05-08 09:27发表 [回复]
回复rickystudio:是的,调用defaultServiceManager获得的是Service Manager的代理对象,用来访问Service Manager。
13楼 yyfei3212 2013-03-08 10:53发表 [回复]
hi, laoluo, 您知不知道binder的ProcessState对象是在哪儿delete的?我找了半天没找到,有点疑惑,望能帮助。

Re: 罗升阳 2013-03-08 11:46发表 [回复]
回复yyfei3212:ProcessState是在进程内全局唯一的,进程在它就会在,没有必要delete。

Re: yyfei3212 2013-03-09 16:28发表 [回复]
回复罗升阳:但是我看log,ProcessState会构造很多次,这个是什么原因呢?比如像mediaserver进程里构造的ProcessState应该不会被delete才对吧?可能我基础不太好,不是很理解

Re: 罗升阳 2013-03-09 17:39发表 [回复]
回复yyfei3212:每次新建一个应用程序进程,都会创建一个ProcessState,所以ProcessState的构造函数被调用多次是正常的。
12楼 woluzhi 2013-01-20 15:31发表 [回复]
当进程调用函数open打开设备文件/dev/binder之后,内核就会返回一个文件描述符给进程,看到这个一直有个疑问,是不是不同的进程打开/dev/binder都会得到不同的文件描述符?如果是,那为什么打开的是同一个设备,会得到不同的描述符呢?

Re: 罗升阳 2013-01-20 23:04发表 [回复]
回复woluzhi:文件描述符是在进程内有效的,换句话说,在不同进程中的数值相等的文件描述符指向的文件是可以不同的。
11楼 woluzhi 2013-01-17 22:52发表 [回复]
还有一个问题:IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");
展开后是
const android::String16 IServiceManager::descriptor("android.os.IServiceManager");
…………
IServiceManager::IServiceManager() { } 
展开这段代码 没有位于某个函数体内,这样这个宏是怎么起作用的? 即是说怎么被调用的?

Re: 罗升阳 2013-01-18 10:12发表 [回复]
回复woluzhi:连同前一个问题,你得先去学学C++的语法。。。

Re: woluzhi 2013-01-20 15:17发表 [回复]
回复罗升阳:呵呵,C++确实不过关,为了看你的这个文章 用了一个星期看的,还好多不懂。看来只能再去看看了,顺便问一下,这个是跟C的区别么?
10楼 woluzhi 2013-01-17 22:05发表 [回复]
罗哥,android::sp<IServiceManager> intr;
这个sp<IServiceManager> intr; 我能理解,前面这个android::是什么意思啊? 是不是有android这个类?
9楼 hongbog_cd 2012-10-29 11:35发表 [回复]
这个图画得不错。
精辟
8楼 qinpengtaiyuan 2012-07-23 16:05发表 [回复]
向大神鞠躬!
7楼 zhenhaiyoulong 2012-07-23 13:59发表 [回复]
罗老师,想请教一个问题,我刚刚接触android framework层,想问一下,需要什么基础知识,比方说,罗老师是先把linux内核看一遍才研究的framework层的哈?我应该从什么方面入手,推荐两本书之类的,我现在基础比较薄弱,想先把基础夯实一些,然后等十月份再看罗老师的书,哈,谢谢了

Re: 罗升阳 2012-07-23 17:05发表 [回复]
回复zhenhaiyoulong:对的,在看Android系统代码之前,我先看了Linux内核相关的书,可以参考一下这篇文章:http://blog.csdn.net/luoshengyang/article/details/6557518
6楼 hqd_2008 2012-07-22 21:27发表 [回复]
老罗的书是哪一本?有空去看看,牛人啊。

Re: 罗升阳 2012-07-23 13:16发表 [回复]
回复hqd_2008:还没出来,估计要10月底的样子。
5楼 Ocean2006 2012-03-27 12:08发表 [回复]
请教一个问题:Android中ServiceManager管理的服务都在同一进程中还是不同的进程中,比如telephony service、media service等,

Re: zhongyuanceshi 2012-07-11 14:51发表 [回复]
回复Ocean2006:telephony service、media service等应该是不同的进程吧,不同服务,不同进程,不知道是不是这样?

Re: 罗升阳 2012-07-11 16:51发表 [回复]
回复zhongyuanceshi:系统的关键服务一般都是运行在System进程中,不过有些会运行在一个独立的线程中。

Re: zhongyuanceshi 2012-07-15 10:47发表 [回复]
回复罗升阳:哦,学习了,老罗新书讲些进程操作系统的知道呗,打算买你的书作为第一本android书籍,现在还没买书呢

Re: 罗升阳 2012-07-15 11:03发表 [回复]
回复zhongyuanceshi:书还没有出来,大概10月底吧
4楼 最后一个菜鸟 2011-12-19 18:08发表 [回复]
软件设计真是博大精深阿
3楼 yang105 2011-09-29 11:24发表 [回复] [引用] [举报]
好文章啊,虽然我没有c c++,语言的功能 我还是能大概看懂你所说的,建议给java学习者把c++,c代码的换成大概意思描述就可以了

Re: 罗升阳 2011-09-29 12:52发表 [回复] [引用] [举报]
回复yang105:后面有一篇文章是针对Java层的Binder机制的,参考《Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析》,不过Java层的Binder接口最终还是通过C++这一层来实现的

浅谈Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路相关推荐

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

    原文地址: http://blog.csdn.net/luoshengyang/article/details/6629298 在前面一篇文章浅谈Android系统进程间通信(IPC)机制Binder ...

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

    在前面一篇文章浅谈Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路中,介绍了在Android系统中Binder进程间通信机 ...

  3. 《浅谈-Android系统越用反应越慢的问题》

    <浅谈-Android系统越用反应越慢的问题> android应用程序和iphone应用程序不一样,用过iphone的都知道,点击图标进入程序后,如果还想用其他程序,必须先按返回退出然后进 ...

  4. 浅谈SpaceBuilder系统的缓存机制_缓存思想

    在前面的文章中也提及到为了提高系统的性能,SpaceBuilder在内部做了大量的工作,而数据缓存就是其中非常高效的处理方式. 我们知道SpaceBuilder采用了多层架构的处理模式,数据通过业务实 ...

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

    Service Manager被唤醒之后,就进入while循环开始处理事务了.这里wait_for_proc_work等于1,并且proc->todo不为空,所以从proc->todo列表 ...

  6. 浅谈Android系统开发中LOG的使用【转】

    本文转载自:http://blog.csdn.net/luoshengyang/article/details/6581828 在程序开发过程中,LOG是广泛使用的用来记录程序执行过程的机制,它既可以 ...

  7. 浅谈Android系统开发中LOG的使用

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6581828 在程序开发过程中,LOG是广泛使用 ...

  8. 问渠哪得清如许,唯有源头活水来-浅谈android 系统

    古人学问无遗力,少壮功夫老始成,纸上得来终觉浅,绝知此事要躬行 android系统是基于Linux平台的开源移动操作系统的名称,该平台由操作系统.中间件.用户界面和应用软件组成. 底层以Linux内核 ...

  9. 读进程和写进程同步设计_浅谈unix进程进程间通信IPC原理

    什么是进程进程间通信 进程间通信即为不同进程之间通信,进程同步是进程间通信的一种 unix进程间通信的分类有哪些 System V进程间通信方式包含: System V消息队列 System V信号量 ...

最新文章

  1. SQL分页语句(转)
  2. 2018-2019-2 20165315 《网络对抗技术》Exp2+ 后门进阶
  3. c语言 图的存储邻接矩阵,数据结构之---C语言实现图的数组(邻接矩阵)存储表示...
  4. 【Python学习教程】推导式与生成器
  5. python基础(part11)-作用域LEGB
  6. 保护 .NET Core 项目的敏感信息
  7. apm java_非Java专家的APM:什么泄漏?
  8. 双电阻差分电流采样_小小的采样电阻,还真有点门道!
  9. 三段式状态机_FPGA笔试题——序列检测(FSM状态机)
  10. 在网页输入框输入角标_这个免费插件能帮我们把Excel内容快速填充到网页表单?...
  11. javascript无限弹窗_解决下javascript无限弹窗的问题
  12. 最流行的十大开源云监控工具
  13. 大学高数常微分方程思维导图_思维导图_2016考研数学:高数中六种常见题型归纳_沪江英语...
  14. 量化感知训练_《量化健身 动作精讲》:专业解读健美身材的秘密
  15. ZBrush笔刷属性栏简介
  16. iOS混合开发之uni-app本地打包集成到iOS原生项目
  17. 如何将某一文件添加到信任列表?
  18. 怎么制作出领导喜欢的移动端报表?
  19. You do not have sufficient permissions to access the inventory ‘/u01/app/oraInventory‘.
  20. 安装Microsoft.UI.Xaml.2.6(WSA安卓子系统安装缺失)

热门文章

  1. The Joy of Clojure – Clojure philosophy(1)
  2. Python PycURL 网络编程
  3. 转载:独立思考能力吞噬
  4. R学习笔记:运行时间记录
  5. malloc 不能返回动态内存
  6. 科大星云诗社动态20210327
  7. matlab句柄函数@和C++ 中的引用 很像
  8. VS2010 不能将参数 2 从“char [20]”转换为“LPCWSTR”的错误解决
  9. [计算机视觉:算法与应用]学习笔记一:图像形成
  10. SqlDataAdapter隐式打开关闭connection