目录:

一、程序实现

参考文件:
frameworks\av\include\media\IMediaPlayerService.h     (IMediaPlayerService,BnMediaPlayerService)
frameworks\av\media\libmedia\IMediaPlayerService.cpp                      (BpMediaPlayerService)
frameworks\av\media\libmediaplayerservice\MediaPlayerService.h
frameworks\av\media\libmediaplayerservice\MediaPlayerService.cpp
frameworks\av\media\mediaserver\Main_mediaserver.cpp   (server, addService)

  之前的代码结构是 test_server 向 service_manager 注册服务,test_client 通过 service_manager 获取服务并使用,服务的实现和数据解析都是在单一的.c文件中实现,接下来对程序框架进行改进,将服务具体函数抽离出来模块化实现,统一由头文件分别定义服务的接口: IHelloService.h 和 IGoodbyeService.h,然后cpp文件实现具体功能:server端为 BnHelloService.cpp 和 BnGoodbyeService.cpp,client端为 BpHelloService.cpp 和 BpGoodbyeService.cpp。

 (1)接口定义:I代表interface)

  ①IHelloService.h

/* 参考: frameworks\av\include\media\IMediaPlayerService.h */
#ifndef ANDROID_IHELLOERVICE_H
#define ANDROID_IHELLOERVICE_H #include <utils/Errors.h> // for status_t
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
#include <binder/IInterface.h>
#include <binder/Parcel.h> #define HELLO_SVR_CMD_SAYHELLO 1
#define HELLO_SVR_CMD_SAYHELLO_TO 2
#define HELLO_SVR_CMD_GET_FD 3 namespace android { class IHelloService: public IInterface
{
public:
DECLARE_META_INTERFACE(HelloService); //宏自动声明必须的接口
virtual void sayhello(void) = ;
virtual int sayhello_to(const char *name) = ;
virtual int get_fd(void) = ;
}; class BnHelloService: public BnInterface<IHelloService>
{
private:
int fd;
public:
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = ); virtual void sayhello(void);
virtual int sayhello_to(const char *name);
virtual int get_fd(void); BnHelloService();
BnHelloService(int fd); };
} #endif

  ②IGoodbyeService.h

/* 参考: frameworks\av\include\media\IMediaPlayerService.h */

#ifndef ANDROID_IGOODBYEERVICE_H
#define ANDROID_IGOODBYEERVICE_H #include <utils/Errors.h> // for status_t
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
#include <binder/IInterface.h>
#include <binder/Parcel.h> #define GOODBYE_SVR_CMD_SAYGOODBYE 1
#define GOODBYE_SVR_CMD_SAYGOODBYE_TO 2 namespace android { class IGoodbyeService: public IInterface
{
public:
DECLARE_META_INTERFACE(GoodbyeService);
virtual void saygoodbye(void) = ;
virtual int saygoodbye_to(const char *name) = ;
}; class BnGoodbyeService: public BnInterface<IGoodbyeService>
{
public:
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = ); virtual void saygoodbye(void);
virtual int saygoodbye_to(const char *name); };
} #endif

 (2)功能实现:B代表binder,n代表native-本地实现,p代表proxy-代理)

  ①BnHelloService.cpp

/* 参考: frameworks\av\media\libmedia\IMediaPlayerService.cpp */

#define LOG_TAG "HelloService"

#include "IHelloService.h"

namespace android {

BnHelloService::BnHelloService()
{
} BnHelloService::BnHelloService(int fd)
{
this->fd = fd;
} status_t BnHelloService::onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags)
{
/* 解析数据,调用sayhello/sayhello_to */ switch (code) {
case HELLO_SVR_CMD_SAYHELLO: {
sayhello();
reply->writeInt32(); /* no exception */
return NO_ERROR;
} break; case HELLO_SVR_CMD_SAYHELLO_TO: { /* 从data中取出参数 */
int32_t policy = data.readInt32();
String16 name16_tmp = data.readString16(); /* IHelloService */ String16 name16 = data.readString16();
String8 name8(name16); int cnt = sayhello_to(name8.string()); /* 把返回值写入reply传回去 */
reply->writeInt32(); /* no exception */
reply->writeInt32(cnt); return NO_ERROR;
} break; case HELLO_SVR_CMD_GET_FD: {
int fd = this->get_fd();
reply->writeInt32(); /* no exception */ /* 参考:
* frameworks\base\core\jni\android_view_InputChannel.cpp
* android_view_InputChannel_nativeWriteToParcel
*/
reply->writeDupFileDescriptor(fd);
return NO_ERROR;
} break; default:
return BBinder::onTransact(code, data, reply, flags);
}
} void BnHelloService::sayhello(void)
{
static int cnt = ;
ALOGI("say hello : %d\n", ++cnt); } int BnHelloService::sayhello_to(const char *name)
{
static int cnt = ;
ALOGI("say hello to %s : %d\n", name, ++cnt);
return cnt;
} int BnHelloService::get_fd(void)
{
return fd;
} }

  ②BnGoodbyeService.cpp

/* 参考: frameworks\av\media\libmedia\IMediaPlayerService.cpp */

#define LOG_TAG "GoodbyeService"

#include "IGoodbyeService.h"

namespace android {

status_t BnGoodbyeService::onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags)
{
/* 解析数据,调用saygoodbye/saygoodbye_to */ switch (code) {
case GOODBYE_SVR_CMD_SAYGOODBYE: {
saygoodbye();
reply->writeInt32(); /* no exception */
return NO_ERROR;
} break; case GOODBYE_SVR_CMD_SAYGOODBYE_TO: { /* 从data中取出参数 */
int32_t policy = data.readInt32();
String16 name16_tmp = data.readString16(); /* IGoodbyeService */ String16 name16 = data.readString16();
String8 name8(name16); int cnt = saygoodbye_to(name8.string()); /* 把返回值写入reply传回去 */
reply->writeInt32(); /* no exception */
reply->writeInt32(cnt); return NO_ERROR;
} break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
} void BnGoodbyeService::saygoodbye(void)
{
static int cnt = ;
ALOGI("say goodbye : %d\n", ++cnt); } int BnGoodbyeService::saygoodbye_to(const char *name)
{
static int cnt = ;
ALOGI("say goodbye to %s : %d\n", name, ++cnt);
return cnt;
} }

  ③BpHelloService.cpp

/* 参考: frameworks\av\media\libmedia\IMediaPlayerService.cpp */

#include "IHelloService.h"

namespace android {

class BpHelloService: public BpInterface<IHelloService>
{
public:
BpHelloService(const sp<IBinder>& impl)
: BpInterface<IHelloService>(impl)
{
} void sayhello(void)
{
/* 构造/发送数据 */ Parcel data, reply;
data.writeInt32();
data.writeString16(String16("IHelloService")); remote()->transact(HELLO_SVR_CMD_SAYHELLO, data, &reply);
} int sayhello_to(const char *name)
{
/* 构造/发送数据 */
Parcel data, reply;
int exception; data.writeInt32();
data.writeString16(String16("IHelloService")); data.writeString16(String16(name)); remote()->transact(HELLO_SVR_CMD_SAYHELLO_TO, data, &reply); exception = reply.readInt32();
if (exception)
return -;
else
return reply.readInt32();
} int get_fd(void)
{
/* 构造/发送数据 */
Parcel data, reply;
int exception; data.writeInt32();
data.writeString16(String16("IHelloService")); remote()->transact(HELLO_SVR_CMD_GET_FD, data, &reply); exception = reply.readInt32();
if (exception)
return -;
else
{ /* 参考:
* frameworks\base\core\jni\android_view_InputChannel.cpp
* android_view_InputChannel_nativeReadFromParcel
*/
int rawFd = reply.readFileDescriptor();
return dup(rawFd);
}
} }; IMPLEMENT_META_INTERFACE(HelloService, "android.media.IHelloService"); }

  ④BpGoodbyeService.cpp

/* 参考: frameworks\av\media\libmedia\IMediaPlayerService.cpp */

#include "IGoodbyeService.h"

namespace android {

class BpGoodbyeService: public BpInterface<IGoodbyeService>
{
public:
BpGoodbyeService(const sp<IBinder>& impl)
: BpInterface<IGoodbyeService>(impl)
{
} void saygoodbye(void)
{
/* 构造/发送数据 */ Parcel data, reply;
data.writeInt32();
data.writeString16(String16("IGoodbyeService")); remote()->transact(GOODBYE_SVR_CMD_SAYGOODBYE, data, &reply);
} int saygoodbye_to(const char *name)
{
/* 构造/发送数据 */
Parcel data, reply;
int exception; data.writeInt32();
data.writeString16(String16("IGoodbyeService")); data.writeString16(String16(name)); remote()->transact(GOODBYE_SVR_CMD_SAYGOODBYE_TO, data, &reply); exception = reply.readInt32();
if (exception)
return -;
else
return reply.readInt32();
} }; IMPLEMENT_META_INTERFACE(GoodbyeService, "android.media.IGoodbyeService"); }

(3)测试代码:

  ①test_server.cpp

/* 参考: frameworks\av\media\mediaserver\Main_mediaserver.cpp */

//#define LOG_NDEBUG 0

#include <fcntl.h>
#include <sys/prctl.h>
#include <sys/wait.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <cutils/properties.h>
#include <utils/Log.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h> #include "IHelloService.h"
#include "IGoodbyeService.h" #define SOCKET_BUFFER_SIZE (32768U) using namespace android; /* 参考:
* http://blog.csdn.net/linan_nwu/article/details/8222349
*/
class MyThread: public Thread {
private:
int fd;
public:
MyThread() {}
MyThread(int fd) { this->fd = fd; } //如果返回true,循环调用此函数,返回false下一次不会再调用此函数
bool threadLoop()
{
char buf[];
int len;
int cnt = ; while()
{
/* 读数据: test_client发出的数据 */
len = read(fd, buf, );
buf[len] = '\0';
ALOGI("%s\n", buf); /* 向 test_client 发出: Hello, test_client */
len = sprintf(buf, "Hello, test_client, cnt = %d", cnt++);
write(fd, buf, len);
} return true;
} }; /* usage : test_server */
int main(void)
{ int sockets[]; socketpair(AF_UNIX, SOCK_SEQPACKET, , sockets); int bufferSize = SOCKET_BUFFER_SIZE;
setsockopt(sockets[], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
setsockopt(sockets[], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
setsockopt(sockets[], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
setsockopt(sockets[], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)); /* 创建一个线程, 用于跟test_client使用socketpiar通信 */
sp<MyThread> th = new MyThread(sockets[]);
th->run(); /* addService */ /* while(1){ read data, 解析数据, 调用服务函数 } */ /* 打开驱动, mmap */
sp<ProcessState> proc(ProcessState::self()); /* 获得BpServiceManager */
sp<IServiceManager> sm = defaultServiceManager(); sm->addService(String16("hello"), new BnHelloService(sockets[]));
sm->addService(String16("goodbye"), new BnGoodbyeService()); /* 循环体 */
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool(); return ;
}

  ②test_client.cpp

//#define LOG_NDEBUG 0

#include <fcntl.h>
#include <sys/prctl.h>
#include <sys/wait.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <cutils/properties.h>
#include <utils/Log.h>
#include <unistd.h> #include "IHelloService.h"
#include "IGoodbyeService.h" using namespace android; /* ./test_client <hello|goodbye>
* ./test_client <readfile>
* ./test_client <hello|goodbye> <name>
*/
int main(int argc, char **argv)
{
int cnt; if (argc < ){
ALOGI("Usage:\n");
ALOGI("%s <readfile>\n", argv[]);
ALOGI("%s <hello|goodbye>\n", argv[]);
ALOGI("%s <hello|goodbye> <name>\n", argv[]);
return -;
} /* getService */
/* 打开驱动, mmap */
sp<ProcessState> proc(ProcessState::self()); /* 获得BpServiceManager */
sp<IServiceManager> sm = defaultServiceManager(); if (strcmp(argv[], "hello") == )
{ sp<IBinder> binder =
sm->getService(String16("hello")); if (binder == )
{
ALOGI("can't get hello service\n");
return -;
} /* service肯定是BpHelloServie指针 */
sp<IHelloService> service =
interface_cast<IHelloService>(binder); /* 调用Service的函数 */
if (argc < ) {
service->sayhello();
ALOGI("client call sayhello");
}
else {
cnt = service->sayhello_to(argv[]);
ALOGI("client call sayhello_to, cnt = %d", cnt);
}
}
else if (strcmp(argv[], "readfile") == )
{ sp<IBinder> binder =
sm->getService(String16("hello")); if (binder == )
{
ALOGI("can't get hello service\n");
return -;
} /* service肯定是BpHelloServie指针 */
sp<IHelloService> service =
interface_cast<IHelloService>(binder); /* 调用Service的函数 */
int fd = service->get_fd(); ALOGI("client call get_fd = %d", fd); char buf[];
int len;
int cnt = ; while ()
{
/* 向 test_server 进程发出: Hello, test_server */
len = sprintf(buf, "Hello, test_server, cnt = %d", cnt++);
write(fd, buf, len); /* 读取数据(test_server进程发回的数据) */
len = read(fd, buf, );
buf[len] = '\0';
ALOGI("%s\n", buf); sleep();
}
}
else
{ sp<IBinder> binder =
sm->getService(String16("goodbye")); if (binder == )
{
ALOGI("can't get goodbye service\n");
return -;
} /* service肯定是BpGoodbyeServie指针 */
sp<IGoodbyeService> service =
interface_cast<IGoodbyeService>(binder); /* 调用Service的函数 */
if (argc < ) {
service->saygoodbye();
ALOGI("client call saygoodbye");
}
else {
cnt = service->saygoodbye_to(argv[]);
ALOGI("client call saygoodbye_to, cnt = %d", cnt);
}
} return ;
}

(4)Android.mk:

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
BnHelloService.cpp \
BpHelloService.cpp \
BnGoodbyeService.cpp \
BpGoodbyeService.cpp \
test_server.cpp LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
liblog \
libbinder LOCAL_MODULE:= test_server
LOCAL_32_BIT_ONLY := true include $(BUILD_EXECUTABLE) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \
BpHelloService.cpp \
BpGoodbyeService.cpp \
test_client.cpp LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
liblog \
libbinder LOCAL_MODULE:= test_client
LOCAL_32_BIT_ONLY := true include $(BUILD_EXECUTABLE)

二、内部机制

1.回顾binder框架关键点

  test_server向service_manager添加服务,test_client通过service_manager获取服务,具体流程如下:

①add_service:
  a.test_server为每个服务构造 struct flat_binder_object 结构体,其中void *binder 或 void* cookie 对应不同服务;
  b.调用ioctl发送数据:
    b1. 数据:flat_binder_object + 服务名称;
    b2.数据中含有"目的地":handle=0,则代表 service_manager;
  c.驱动程序对每一个flat_binder_object构造一个binder_node结构体,其中 void __user *ptr 和 void __user *cookie即来自flat_binder_object;
  d.驱动程序根据handle=0找到service_manager,把数据发送给service_manager并且创建一个 struct binder_ref结构体到链表,其中node指针指向binder_node结构体;
  e.service_manager中记录服务名(“hello”、“goodbye”)称和desc值(binder_ref结构体中的desc值);

②get_service: 
  a.test_client构造数据:名称 + "目的"(handle=0);
  b.调ioctl发送数据;
  c.驱动程序根据handle=0找到service_manager把数据给service_manager;
  d.service_manager从service list中找到对应项,比如根据服务名"hello"找到第一项,handle=1;
  e.service_manager调用ioctl返回数据(flat_binder_object);
  f.驱动发现数据中含有flat_binder_object,且type为引用,从service_manager的binder_ref表中找到对应项(传入的handle=binder_ref.desc)再找到binder_node,最后为test_client建立binder_ref,即对应service_manager里构造的binder_ref链表;

③test_client使用服务: hello->sayhello(code=1), hello->sayhello_to(code=2)
  a.构造数据,code定义要执行的函数、参数、目的(handle=1);
  b.使用ioctl发送数据;
  c.驱动从数据中取出handle=1,根据handle找到binder_ref,根据binder_ref找到binder_node,再根据binder_node找到目的进程(.proc->test_server),最后把数据传给test_server,并且在数据中设置.ptr/.cookie 等于binder_node的.ptr/.cookie;
  d.test_server根据.ptr/.cookie获知test_client想调用的服务,再根据code等参数调用具体的函数操作;

小结:

  server注册服务时, 对每个服务都提供不同的ptr/cookie,在驱动程序里对每个服务都构造一个binder_node, 它也含有ptr/cookie,client使用服务前要先getService,在驱动程序里对该服务构造一个binder_ref,binder_ref含有desc, node成员, desc是整数, node指向对应服务的binder_node,使用服务时, client调用ioctl发送构造数据,数据里含有handle,驱动程序根据handle找到binder_ref(desc==handle), 再通过binder_ref找到binder_node, 再根据binder_node找到对应server,最后从binder_node取出ptr/cookie连同那些数据发给server,server根据数据中的ptr/cookie信息调用对应服务,再根据code调用对应函数。

Binder系统最核心的函数: ioclt;

client最核心的数据:handle;

server最核心的数据:.ptr/.cookie

2.代理类BpXXX分析

  test_server向service_manager添加服务时,首先获得BpServiceManager(handle=0)成为一个client与之通信,test_client同样获得BpServiceManager和service_manager通信,然后test_client再获得BpHelloService(handle=BpServiceManager->getService("Hello")==1)和test_server通信。

 UML展示BpServiceManager的继承关系

                                (1)

                                (2)

                                (3)

   2.1 获得BpServiceManager对象的过程:
    defaultServiceManager构造了一个BpServiceManager对象(派生自BpRefBase,含有IBinder *mRemote, mRemote指向BpBinder对象,它含有mHandle),
 其中它的mRemote = new BpBinder(0); // mRemote->mHandle=0

 defaultServiceManager // IServiceManager.cpp
                               // 把BpBinder(mHandle=0)对象转换为IServiceManager接口(BpServiceManager)                           
    gDefaultServiceManager = interface_cast<IServiceManager>(
                ProcessState::self()->getContextObject(NULL));
 分析:
 ProcessState::self()->getContextObject(NULL)
     getStrongProxyForHandle(0);
         b = new BpBinder(handle);   // mHandle=handle=0

 interface_cast<IServiceManager>(new BpBinder(0))  // IInterface.h
     IServiceManager::asInterface(obj);
            return new BpServiceManager(obj); // mRemote=obj=new BpBinder(0);

   2.2 获得BpHelloService对象的过程:
    调用BpServiceManager的getService函数获得一个flat_binder_object,
    从中取出handle, 创建一个BpBinder(handle),
    然后使用interface_cast使用这个BpBinder创建一个BpHelloService对象

 // binder是BpBinder对象, 里面含有HelloService的handle
 sp<IBinder> binder =
        sm->getService(String16("hello")); // IServiceManager.cpp
                    // 构造数据: 数据中肯定含有"hello"
                    // 发送数据: 给handle 0, 即 service_manager进程
                    // 从收到的回复中取出HelloService的handle
                             return reply.readStrongBinder();
                                                     unflatten_binder(ProcessState::self(), *this, &val);
                                                             *out = proc->getStrongProxyForHandle(flat->handle);
                                                                                 new BpBinder(handle);  //handle来自service_manager进程的回复
        
                            // 把binder转换为IHelloService接口(BpHelloService对象)
                            // binder是BpBinder对象, 里面含有HelloService的handle
 sp<IHelloService> service = interface_cast<IHelloService>(binder);

   2.3 代理类如何发送数据: ioctl, 数据里含有handle, 含有其他构造的参数
        构造好数据之后,调用:
        remote()->transact(...)  //addService、checkService、getService 以及sayhello/sayhello_to等函数最终都会调用这里,remote()返回一个BpBinder对象,其中实现了transact;
             IPCThreadState::self()->transact(mHandle, code, data, reply, flags); //该线程中实现了waitForResponse()、talkWithDriver(其中通过mDriverFD句柄进行ioctl操作) 等函数。

3.数据传输:ProcessState 和 IPCThreadState 类 (单例模式)

 ProcessState::self()->startThreadPool(); //创建子线程,最终执行:IPCThreadState ::self()->joinThreadPool();

 IPCThreadState ::self()->joinThreadPool(); //循环,读取数据、解析、处理、回复。

   3.1 addService
    前面介绍过,对于不同服务构造的flat_binder_object结构体,里面的.binder/.cookie对于不同的服务它的值不一样
                                                        
 sm->addService(String16("hello"), new BnHelloService());
            data.writeStrongBinder(service);  // service = new BnHelloService();
                            flatten_binder(ProcessState::self(), val, this); // val = service = new BnHelloService();
                                    flat_binder_object obj;  // 参数 binder = val = service = new BnHelloService();
                                    IBinder *local = binder->localBinder(); // =this = new BnHelloService();
                        obj.type = BINDER_TYPE_BINDER;
                        obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
                        obj.cookie = reinterpret_cast<uintptr_t>(local);  // new BnHelloService();
                                   
   3.2 server如何分辨client想使用哪一个服务?
    server收到数据里含有flat_binder_object结构体,
    它可以根据.binder/.cookie分析client想使用哪一个服务
    
    把.cookie转换为BnXXXX对象,然后调用它的函数:
            // 根据cookie构造了一个BBinder指针, 实际上是指向某个BnXXX对象
            sp<BBinder> b((BBinder*)tr.cookie);
            // 然后调用它的transact函数
            error = b->transact(tr.code, buffer, &reply, tr.flags);
                                        err = onTransact(code, data, reply, flags);  // 就会调用到BnXXX里实现的onTransact
                                // 它就会根据code值来调用不同的函数

-end-

Android : 跟我学Binder --- (5) C++实现的更多相关文章

  1. Android : 跟我学Binder --- (6) JAVA实现

    目录: Android : 跟我学Binder --- (1) 什么是Binder IPC?为何要使用Binder机制? Android : 跟我学Binder --- (2) AIDL分析及手动实现 ...

  2. Android : 跟我学Binder --- (4) 驱动情景分析

    目录: Android : 跟我学Binder --- (1) 什么是Binder IPC?为何要使用Binder机制? Android : 跟我学Binder --- (2) AIDL分析及手动实现 ...

  3. Android : 跟我学Binder --- (3) C程序示例

    目录: Android : 跟我学Binder --- (1) 什么是Binder IPC?为何要使用Binder机制? Android : 跟我学Binder --- (2) AIDL分析及手动实现 ...

  4. Android : 跟我学Binder --- (2) AIDL分析及手动实现

    目录: Android : 跟我学Binder --- (1) 什么是Binder IPC?为何要使用Binder机制? Android : 跟我学Binder --- (2) AIDL分析及手动实现 ...

  5. Android : 跟我学Binder --- (1) 什么是Binder IPC?为何要使用Binder机制?

    目录: Android : 跟我学Binder --- (1) 什么是Binder IPC?为何要使用Binder机制? Android : 跟我学Binder --- (2) AIDL分析及手动实现 ...

  6. 写给 Android 应用工程师的 Binder 原理剖析

    写给 Android 应用工程师的 Binder 原理剖析 一. 前言 这篇文章我酝酿了很久,参考了很多资料,读了很多源码,却依旧不敢下笔.生怕自己理解上还有偏差,对大家造成误解,贻笑大方.又怕自己理 ...

  7. Android native进程间通信实例-binder篇之——HAL层访问JAVA层的服务

    有一天在群里聊天的时候,有人提出一个问题,怎样才能做到HAL层访问JAVA层的接口?刚好我不会,所以做了一点研究. 之前的文章末尾部分说过了service call 可以用来调试系统的binder服务 ...

  8. 【Android - IPC】之Binder机制简介

    参考资料: 1.<Android开发艺术探索>第二章2.3.3 Binder 2.[Android Binder设计与实现-设计篇] 3.[Android Binder机制介绍] 1. 什 ...

  9. Android 看源码学 Binder

    参考:https://jekton.github.io/2018/04/07/binder-why-RemoteListenerCallback-works/ 参考:https://jekton.gi ...

随机推荐

  1. beego 初体验 - 基础模块 - config, httplibs, logs

    beego 的基础模块支持了一些web开发常用的功能. 配置,http操作库,日志 配置模块: 这是我的配置文件 如何读取: httplibs:这是一个利用 httplibs 发起 get 请求的示例 ...

  2. AWS是怎么改写 MySQL的?

    五倍吞吐量的提升,跨可用区的六副本,低于一分钟的宕机恢复,兼容 MySQL协议,这是 AWS 推出 Aurora 数据库时给出的数据. 这种量级的提升不可能是小修小补,大都是在架构上有了变革性的突破才 ...

  3. mecacheq的配置

    在处理业务逻辑时有可能遇到高并发问题,例如商城秒杀.微博评论等.如果不做任何措施可能在高瞬间造成服务器瘫痪,如何解决这个问题呢?队列是个不错的选择.队列(Queue)又称先进先出(First In F ...

  4. 0004-20180422-自动化第五章-python基础学习笔记

    内容回顾:1.数据类型 2.for和while循环 continue break #如下循环将怎么打印结果? for i in range(1,10): print(i) for i in range ...

  5. js获取本月最后一天

    function getLastDay() {      var seperator1 = "-";      var date=new Date;      var new_mo ...

  6. js实现复制内容到剪切板,兼容pc和手机端,支持Safari浏览器

    Javascript原生有一些事件:copy.paste.cut, 这些事件可以作用的目标元素: 能获得焦点的元素 (如contentEditable内容能编辑或者可以选中的元素),或者是<bo ...

  7. Python Redis list

    List操作,redis中的List在在内存中按照一个name对应一个List来存储. 注:列表存入 从右到左 如图: lpush(name,values) # 在name对应的list中添加元素,每 ...

  8. Linux 组管理、权限

    权限说明 1. 组涉及到两个配置文件,组文件/etc/group,组密码管理员/etc/gshadow/,GID500往后的算普通组. 2.主组与附属组,当创建一个用户,没有制定,用户会默认创建一个与 ...

  9. Shell 实践、常用脚本进阶

    1.备份单个文件 #!/bin/bash #备份单个文件 DATE=`/bin/date +%y%m%d` /bin/tar -czpf /backup/$1.$DATE.tar.gz /backup ...

  10. kmp匹配详解

    字符串算法都是毒瘤的 一.kmp算法的用处 在文本串中查找模式串的位置,数量 文本串:要在这个字符串查找模式串 模式串:在文本串中查找的字符串 全是废话 二.kmp算法的思想 话说kmp好像是3个发明 ...