最近遇到个问题,需要使用共享内存。之前看audioTrack与audioFlinger部份时就看到共存内存的分配与同步,但是没有细研究这部份。这几天细看了下流程,发现使用起来挺简单的。

         ashmem是android封装提供的一种共享内存实现方式。驱动会在/dev/下面注册ashmem字符设备,供上层做文件操作(ashmem驱动后面分析)。

                                       

Android中的Alarm android ashmem_#include

         按照一般理解(如camera videobuffer操作), 既然内核给分配了内存,那上层用户空间要使用的话,要么通过read/write文件操作接口,在用户层与内核层作拷贝;要么就是mmap映射,然后直接使用。ashmem就是直接mmap到用户空间的。大概使用原理就是server、client一端打开/dev/ashmem得到fd句柄,并mmap得到共享内存地址;再把fd与size传到对应的client、server,另一端再mmap下也得到了此地址,这样二边就可以直接操作各自mmap得到的地址就行了。当然从server、client传fd到client、server这里面也包含了binder通信。

                            

Android中的Alarm android ashmem_Android中的Alarm_02

 

         android对ashemem的封装很简单(/system/core/libcutils/Ashmem-dev.c),提供了以下几个接口。一般我们只取ashmem_create_region,得到fd(既然是fd,那必然有close,但android并没有提供,因为只需要close(fd)就行了。那还有一个问题,既然server与client端都是fd,按理解那这2个fd的值应该是不同的,肯定会dup)。

                       

ashmem_create_region
                            ashmem_set_prot_region
                            ashmem_pin_region
                            ashmem_unpin_region
                            ashmem_get_size_region

         完全可以在这几个封装接口的基础上直接使用。除此之外android framework还封了一个IMemory类给上层操作。

 

 

1、直接操作Ashmem-dev.c接口demo

         demo目录如下所示:

                           

Android中的Alarm android ashmem_共享内存_03

                           

Android中的Alarm android ashmem_Android中的Alarm_04

                           

Android中的Alarm android ashmem_共享内存_05

 

       demo由server与client及接口组成,共享内存可由server产生也可由client去申请。为了验证共享内存的使用及正确性,server与client都可以读写此共享内存。这样就产生了同步问题。为了简化起见,弄了个ICallback类,在server、client操作完后,callback对方,这时对方才操作shareMemory,这样就不需要花太多精力与时间去弄同步部份。(典型同步见audioTrack与audioFlinger之间的cblk同步)

 

具体代码如下:

ITestBinder.h

#ifndef _ITESTBINDER_H_
#define _ITESTBINDER_H_
 
#include <binder/IInterface.h>  
#include <utils/String8.h>
#include "ICallback.h"
 
namespace android {
              enum {
                            msg_mem = 0x0000f000,
                            msg_mem_client_not_prepare = msg_mem + 0x01,
                            msg_mem_client_prepared = msg_mem + 0x02,
 
                            msg_mem_client_req_server_alloc = msg_mem + 0x10,
 
                            msg_mem_server_not_prepare = msg_mem + 0x020,
                            msg_mem_server_prepared = msg_mem + 0x021,
                           
                            msg_data = 0x0000f100,
                            msg_data_client_write = msg_data +  0x01,
                            msg_data_server_read = msg_data +  0x02,
                             
                            msg_diconnect = 0x0000ff00,
              };
 
              struct testShareMem
              {
                            int fd;
                            int size;
              };
 
              class ITestBinder : public IInterface
              {
              public:
                            DECLARE_META_INTERFACE(TestBinder);
                            virtual int setCallback(const sp<ICallback>& callback) = 0;
                            virtual int notify(int msg, struct testShareMem *mem) = 0;
              };
 
              class BnTestBinder : public BnInterface<ITestBinder>
              {
              public:
                            virtual status_t onTransact( uint32_t code,
                                                                                                                              const Parcel& data,
                                                                                                                              Parcel* reply,
                                                                                                                              uint32_t flags = 0);
              };
}
 
#endif  //_ITESTBINDER_H_

 

ITestBinder.cpp

#define LOG_NDEBUG 0
#define LOG_TAG "ITestBinder"
#include <utils/Log.h>
 
#include <binder/Parcel.h>
#include <binder/IInterface.h>
#include "ITestBinder.h"
 
namespace android {
              enum {
                            CONNECT = 0,
                            NOTIFY,
                            SET_CALLBACK
              };
 
              class BpTestBinder : public BpInterface<ITestBinder>
              {
              public:
                            BpTestBinder(const sp<IBinder>& impl) : BpInterface<ITestBinder>(impl)
                            {
                            }
 
                            virtual int notify(int msg, struct testShareMem *mem)
                            {
                                          //ALOGD("%s", __func__);
                                          Parcel data,reply;
                                          data.writeInt32(msg);
 
                                          if (msg == msg_mem_client_prepared)
                                          {
                                                        if (mem != NULL)
                                                        {
                                                                      data.writeFileDescriptor(mem->fd);
                                                                      data.writeInt32(mem->size);
                                                        }
                                          }
                                          else if (msg == msg_mem_client_req_server_alloc)
                                          {
                                                        if (mem != NULL)
                                                        {
                                                                      data.writeInt32(mem->size);
                                                        }
                                          }
 
                                          remote()->transact(NOTIFY, data, &reply);
                                          if (msg == msg_mem_client_req_server_alloc)
                                          {
                                                        int ret = reply.readInt32();
                                                        if (!ret)
                                                        {
                                                                      int fd = reply.readFileDescriptor();
                                                                      int size = reply.readInt32();
                                                                      ALOGD("bpTestBinder get: fd=%d, size=%d", fd, size);
                                                                      mem->fd = fd;
                                                                      mem->fd = dup(mem->fd); //why must dup???
                                                                      mem->size = size;
                                                        }
                                                        return ret;
                                          }
                                          else
                                          {
                                                        return reply.readInt32();
                                          }
                            }
 
                            virtual int setCallback(const sp<ICallback>& callback)
                            {
                                          //ALOGD("%s", __func__);
                                          Parcel data, reply;
                                          //data.writeStrongBinder(callback->asBinder());
                                          data.writeStrongBinder(IInterface::asBinder(callback));
                                          remote()->transact(SET_CALLBACK, data, &reply);
                                          return reply.readInt32();
                            }
              };
 
              IMPLEMENT_META_INTERFACE(TestBinder, "android.test.ITestBinder");
 
 
///
              status_t BnTestBinder::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
              {
                            //ALOGD("%s, code=%d\n", __func__, code);
                            switch (code)
                            {
                                          case SET_CALLBACK:
                                          {
                                                        //ALOGD("%s, SET_CALLBACK", __func__);
                                                        sp<ICallback> callback = interface_cast<ICallback>(data.readStrongBinder());
                                                        reply->writeInt32(setCallback(callback));
                                                        return NO_ERROR;
                                          }
 
                                          case NOTIFY:
                                          {
                                                        //CHECK_INTERFACE(ITestBinder, data, reply); 
                                                        //ALOGD("%s, NOTIFY", __func__);
                                                        int msg = data.readInt32();
 
                                                        struct testShareMem *mem = new testShareMem;
 
                                                        if (msg == msg_mem_client_prepared)
                                                        {
                                                                      if (data.dataAvail() > 0)
                                                                      {
                                                                                    mem->fd = data.readFileDescriptor();
                                                                                    mem->size = data.readInt32();
                                                                      }
                                                                      reply->writeInt32(notify(msg, mem));
                                                        }
                                                        else if (msg == msg_mem_client_req_server_alloc)
                                                        {
                                                                      mem->size = data.readInt32();
                                                                      int ret = notify(msg, mem);
                                                                      if (!ret)
                                                                      {
                                                                                    reply->writeInt32(0); //success
                                                                                    reply->writeFileDescriptor(mem->fd);
                                                                                    reply->writeInt32(mem->size);
                                                                      }
                                                        }
                                                        else
                                                        {
                                                                      reply->writeInt32(notify(msg, mem));
                                                        }
                                                        free(mem);
                                                        return NO_ERROR;
                                          }
 
                                          default:
                                          {
                                                        //ALOGD("%s, default onTransact handle\n", __func__);
                                                        return BBinder::onTransact(code, data, reply, flags);
                                          }
                            }
              }
 
}

 

ICallback.h

#ifndef _ICALLBACK_H_   
#define _ICALLBACK_H_
 
#include <binder/IInterface.h>
 
namespace android {
              class ICallback : public IInterface
              {
              public: 
                            DECLARE_META_INTERFACE(Callback);
                            virtual int notifyCallback(int msg) = 0;
              };
 
              class BnCallback : public BnInterface<ICallback>
              {
              public:
                            virtual status_t onTransact( uint32_t code,
                                                                                                                const Parcel& data,
                                                                                                                Parcel* reply,
                                                                                                                uint32_t flags = 0);
              };
}
 
#endif //_ICALLBACK_H_

 

ICallback.cpp

#define LOG_NDEBUG 0
#define LOG_TAG "ICallback"
#include <utils/Log.h>
 
#include <binder/Parcel.h>
#include <binder/IInterface.h>
 
#include "ICallback.h"
 
namespace android{
 
              enum { 
                            NOTIFY_CALLBACK = 0,
              };
 
              class BpCallback : public BpInterface<ICallback>
              {
              public:
                            BpCallback(const sp<IBinder>& impl) : BpInterface<ICallback>(impl)
                            {
                            }
 
                            virtual int notifyCallback(int msg)
                            {
                                          //ALOGD("%s", __func__);
                                          Parcel data,reply;
                                          data.writeInt32(msg);
                                          remote()->transact(NOTIFY_CALLBACK, data, &reply);
                                          return reply.readInt32();
                            }
              };
 
              IMPLEMENT_META_INTERFACE(Callback, "android.test.ICallback");
 
 

              status_t BnCallback::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
              {
                            //ALOGD("%s, code=%d\n", __func__, code);
                            switch (code)
                            {
                                          case NOTIFY_CALLBACK:
                                          {
                                                        //CHECK_INTERFACE(ICallback, data, reply);                                     
                                                        reply->writeInt32(notifyCallback((int) data.readInt32()));
                                                        return NO_ERROR;
                                          }
 
                                          default:
                                          {
                                                        return BBinder::onTransact(code, data, reply, flags);
                                          }
                            }
              }
}

 

Android.mk

include $(call all-subdir-makefiles)

 

TestService.cpp

#define LOG_NDEBUG 0
#define LOG_TAG "TestService"
#include <utils/Log.h>
 
#include <sys/mman.h>
#include <cutils/ashmem.h>
 
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/Parcel.h>
#include <utils/String8.h>
#include "TestService.h"
 
 
namespace android {
              TestService::TestService()
              {
                            mShareClient.mShareMem.fd = -1;
                            mShareClient.mShareMem.size = 0;
                            mShareClient.mMapAddr = MAP_FAILED;
 
                            mShareMemHost.mShareMem.fd = -1;
                            mShareMemHost.mShareMem.size = 0;
                            mShareMemHost.mMapAddr = MAP_FAILED;
              }
 
              TestService::~TestService()
              {
                            if (mShareClient.mShareMem.fd > 0)
                            {
                                          close(mShareClient.mShareMem.fd);
                            }
                            if (mShareClient.mMapAddr != MAP_FAILED)
                            {
                                          munmap(mShareClient.mMapAddr, mShareClient.mShareMem.size);
                            }
 
              //free host
                            if (mShareMemHost.mShareMem.fd > 0)
                            {
                                          close(mShareMemHost.mShareMem.fd);
                            }
                            if (mShareMemHost.mMapAddr != MAP_FAILED)
                            {
                                          munmap(mShareMemHost.mMapAddr, mShareMemHost.mShareMem.size);
                            }
              }
             
              int TestService::setCallback(const sp<ICallback>& cb)
              {
                            //ALOGD("%s", __func__);
                            mCallback = cb;
                            return 0;
              }
             
              int TestService::notify(int msg, /*const*/ struct testShareMem *mem)
              {
                            //ALOGD("%s", __func__);
 
                            switch (msg)
                            {
                            case msg_mem_client_prepared:
                                          {
                                                        ALOGD("get client share mem: fd=%d, size=%d", mem->fd, mem->size);
                                                        //int fd = dup(mem->fd);
                                                        int fd = mem->fd;
                                                        mShareClient.mShareMem.size = mem->size;
                                                        mShareClient.mMapAddr = mmap(0, mShareClient.mShareMem.size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
                                                        if (mShareClient.mMapAddr == MAP_FAILED)
                                                        {
                                                                      ALOGE("mmap fail!!");
                                                                      close(fd);
                                                                      //return -1;
                                                        }
                                                        else
                                                        {
                                                                      mShareClient.mShareMem.fd = fd;
                                                        }
                                                        ALOGD("mmaped mem: %p", mShareClient.mMapAddr);
                                          }
                                          break;
                           
                            case msg_data_client_write:
                                          {
                                                        ALOGD("get client data msg:");
                                                        if (mShareClient.mMapAddr != MAP_FAILED)
                                                        {
                                                                      ALOGD("                        %s", (char *)mShareClient.mMapAddr);
                                                                      sprintf((char *)mShareClient.mMapAddr, "%s", "service write: 1234567890");
                                                        }
                                                        else if (mShareMemHost.mMapAddr != MAP_FAILED)
                                                        {
                                                                      ALOGD("                        %s", (char *)mShareMemHost.mMapAddr);
                                                                      sprintf((char *)mShareMemHost.mMapAddr, "%s", "2018 123456789");
                                                        }
 
                                                        sp<ICallback> cb = mCallback;
                                                        if (cb != 0)
                                                        {
                                                                      cb->notifyCallback(msg_data_server_read);
                                                        }
                                          }
                                          break;
 
                            case msg_mem_client_req_server_alloc:
                                          {
                                                        if (mem == NULL || mem->size <=0)
                                                        {
                                                                      ALOGW("client must send right param go get share mem fd!!");
                                                                      return -1;
                                                        }
                                                        ALOGD("client request server to alloc share mem, size:%d!!", mem->size);
 
                                                        int size = mem->size;
                                                        int fd = ashmem_create_region("test_ash_mem_share_host", size);
                                                        mShareMemHost.mShareMem.fd = fd;
                                                        mShareMemHost.mMapAddr = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
                                                        if (mShareMemHost.mMapAddr == MAP_FAILED)
                                                        {
                                                                      ALOGE("mmap(fd=%d, size=%u) failed (%s)", fd, uint32_t(size), strerror(errno));
                                                                      close(fd);
                                                                      mShareMemHost.mShareMem.fd = -1;
                                                                      return -errno;
                                                        }
                                                        mShareMemHost.mShareMem.size = size;
                                                        ALOGD("malloc share_mem, fd=%d, size=%d", fd, mShareMemHost.mShareMem.size);
                                                        ALOGD("mmap addr: %p", mShareMemHost.mMapAddr);
                                                       
                                                        /*sp<ICallback> cb = mCallback;
                                                        if (cb != 0)
                                                        {
                                                                      cb->notifyCallback(msg_mem_server_prepared);
                                                        }*/
 
                                                        mem->fd = mShareMemHost.mShareMem.fd;
                                                        mem->size = mShareMemHost.mShareMem.size;
                                          }
                                          break;
                                         
                            case msg_diconnect:
                                          {
                                                        ALOGD("client disconnect!!");
                                          }
                                          break;
 
                            default:
                                          break;
                            }
                           
                            return 0;
              }
}

 

TestService.h

#ifndef _TEST_SERVICE_H_
#define _TEST_SERVICE_H_
 
#include <binder/BinderService.h>
#include "../ITestBinder.h"
#include "../ICallback.h"
 
namespace android {
              typedef struct shareMemory
              {
                            void *mMapAddr;
                            struct testShareMem mShareMem;
              }severShareMemory_t;
 
              class TestService : public BinderService<TestService>,  public BnTestBinder
              {
                            friend class BinderService<TestService>;
              public:
                            TestService();
                            virtual ~TestService();
 
                            static char const* getServiceName()
                            {
                                          return "test.ITestService";
                            }
 
                            virtual int notify(int msg, /*const*/ struct testShareMem *mem);
                            virtual int setCallback(const sp<ICallback>& callback);
 
              private:
                            severShareMemory_t mShareClient;
                            sp<ICallback> mCallback;
                            severShareMemory_t mShareMemHost;
              };
}
 
#endif  //_TEST_SERVICE_H_

 

main.cpp

#define LOG_NDEBUG 0
#define LOG_TAG "server_main"
#include <utils/Log.h>
 
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
 
#include "TestService.h"
 
using namespace android;
 
 
int main(int argc, char** argv)
{
              sp<ProcessState> proc(ProcessState::self());
              sp<IServiceManager> sm = defaultServiceManager();
 
              ALOGI("ServiceManager: %p", sm.get());
              TestService::instantiate();
 
              ProcessState::self()->startThreadPool();
              IPCThreadState::self()->joinThreadPool();
              return 0;
}

 

Android.mk

LOCAL_PATH:= $(call my-dir)
 
include $(CLEAR_VARS) 
 
LOCAL_SRC_FILES:= \
    main.cpp \
    TestService.cpp \
    ../ITestBinder.cpp \
    ../ICallback.cpp
 
LOCAL_SHARED_LIBRARIES := \
    libcutils \
    libutils \
    liblog \
    libbinder
 
LOCAL_MODULE:= test_mem_server_4
LOCAL_MODULE_TAGS := eng
include $(BUIL

D_EXECUTABLE)

 

TestClient.cpp

#define LOG_NDEBUG 0
#define LOG_TAG "TestClient"
#include <sys/mman.h>
#include <utils/Log.h>
#include <binder/IServiceManager.h>
#include <cutils/ashmem.h>
#include "TestClient.h"
 
namespace android {
              int TestClient::Callback::notifyCallback(int msg)
              {
                            switch (msg)
                            {
                            case msg_data_server_read:
                                          ALOGD("get service read echo back:");
                                          ALOGD("                        %s", (char *)(tc->getCurShareMemory()->mMapAddr));
                                          break;
 
                            default:
                                          break;
                            }
                            return 0;
              }
 
              sp<ITestBinder> TestClient::gTestService = NULL;
 
              const sp<ITestBinder>& TestClient::get_test_service()
              {
                            if (gTestService == NULL)
                            {
                                          sp<IServiceManager> sm = defaultServiceManager();
                                          sp<IBinder> binder;
                                          do {
                                                        binder = sm->getService(String16("test.ITestService"));
                                                        if (binder != 0)
                                                                      break;
                                                        ALOGD("testbinder not published, waiting...");
                                                        usleep(500000); // 0.5 s
                                          } while (1);
                                          gTestService = interface_cast<ITestBinder>(binder);
                            }
 
                            if(gTestService == NULL)
                            {
                                          ALOGE("connetct no testbinder!");
                            }
                            return gTestService;
              }
 
              TestClient::TestClient()
                            : mCb(NULL)
                            , curShareMemType(SHAREMEM_CREATE_BY_CLIENT)
              {
                            mShareMemLocal.mShareMem.fd = -1;
                            mShareMemLocal.mShareMem.size = 0;
                            mShareMemLocal.mMapAddr = MAP_FAILED;
 
                            mShareMemServer.mShareMem.fd = -1;
                            mShareMemServer.mShareMem.size = 0;
                            mShareMemServer.mMapAddr = MAP_FAILED;
              }
 
              TestClient::~TestClient()
              {
                            if (mCb.get() != NULL)
                            {
                                          mCb.clear();
                            }
                            if (mShareMemLocal.mMapAddr != MAP_FAILED)
                                          munmap(mShareMemLocal.mMapAddr, mShareMemLocal.mShareMem.size);
                            if (mShareMemLocal.mShareMem.fd > 0)
                                          close(mShareMemLocal.mShareMem.fd);
 
                            if (mShareMemServer.mMapAddr != MAP_FAILED)
                                          munmap(mShareMemServer.mMapAddr, mShareMemServer.mShareMem.size);
                            if (mShareMemServer.mShareMem.fd > 0)
                                          close(mShareMemServer.mShareMem.fd);
              }
 
              int TestClient::init(int shareMemType)
              {
                            sp<ITestBinder> ts = get_test_service();
                            if (ts == NULL)
                                          return -1;
 
                            mCb = new Callback(this);
                            ts->setCallback(mCb);
 
                            if (shareMemType == SHAREMEM_CREATE_BY_CLIENT)
                                          curShareMemType = SHAREMEM_CREATE_BY_CLIENT;
                            else
                                          curShareMemType = SHAREMEM_CREATE_BY_SERVER;
 
                            return allocShareMemory(curShareMemType);
              }
 
              shareMemory_t* TestClient::getCurShareMemory()
              {
                            if (curShareMemType == SHAREMEM_CREATE_BY_SERVER)
                            {
                                          return &mShareMemServer;
                            }
                            else
                            {
                                          return &mShareMemLocal;
                            }
              }
 
              int TestClient::localAlloc(int size)
              {
                            ALOGD("%s, local alloc share memory", __func__);
 
                            if (size <= 0)
                                          return -1;
                           
                            int fd = ashmem_create_region("test_ash_mem_share", size);
                            mShareMemLocal.mShareMem.fd = fd;
                            mShareMemLocal.mMapAddr = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
                            if (mShareMemLocal.mMapAddr == MAP_FAILED)
                            {
                                          ALOGE("mmap(fd=%d, size=%u) failed (%s)", fd, size, strerror(errno));
                                          close(fd);
                                          mShareMemLocal.mShareMem.fd = -1;
                                          return -errno;
                            }
                            mShareMemLocal.mShareMem.size = size;
 
                            ALOGD("fd: %d, size: %d", mShareMemLocal.mShareMem.fd, mShareMemLocal.mShareMem.size);
                            return 0;
              }
 
              int TestClient::serverAlloc(int size)
              {
                            sp<ITestBinder> ts = get_test_service();
                            ALOGD("%s, server alloc share memory", __func__);
 
                            if (ts == 0)
                                          return 0;
 
                            struct testShareMem mem;
                            mem.size = size;
                            int ret = ts->notify(msg_mem_client_req_server_alloc, &mem);
                            if (!ret)
                            {
                                          mShareMemServer.mShareMem = mem;
                                          mShareMemServer.mMapAddr = mmap(0, mem.size, PROT_READ|PROT_WRITE, MAP_SHARED, mem.fd, 0);
                                          if (mShareMemServer.mMapAddr == MAP_FAILED)
                                          {
                                                        ALOGE("mmap(fd=%d, size=%u) failed (%s)", mem.fd, size, strerror(errno));
                                                        close(mem.fd);
                                                        mShareMemServer.mShareMem.fd = -1;
                                                        return -errno;
                                          }
                                          mShareMemServer.mShareMem.size = size;
                            }
 
                            ALOGD("fd: %d, size: %d", mShareMemServer.mShareMem.fd, mShareMemServer.mShareMem.size);
                            return ret;
              }
 
              int TestClient::allocShareMemory(int type)
              {
                            int ret;
 
                            switch(type)
                            {
                            case SHAREMEM_CREATE_BY_BOTH:
                                          {
                                                        ALOGD("not realize yet!!!");
                                          }
                                          break;
 
                            case SHAREMEM_CREATE_BY_SERVER:
                                          {
                                                        ret = serverAlloc(2018);
                                          }
                                          break;
 
                            case SHAREMEM_CREATE_BY_CLIENT:
                                          {
                                                        ret = localAlloc(2018);
 
                                                        sp<ITestBinder> ts = get_test_service();
                                                        ts->notify(msg_mem_client_prepared, &mShareMemLocal.mShareMem);
                                          }
                                          break;
 
                            default:
                                          ALOGD("error type!!!");
                                          break;
                            }
 
                            return ret;
              }
 
              int TestClient::write(String8 &str)
              {
                            //ALOGD("%s", __func__);
                            sp<ITestBinder> ts = get_test_service();
                            if (ts == NULL)
                                          return -1;
 
                            char *mem;
                            size_t size;
                            if (curShareMemType == SHAREMEM_CREATE_BY_CLIENT)
                            {
                                          mem = (char *)mShareMemLocal.mMapAddr;
                                          size = mShareMemLocal.mShareMem.size;
                            }
                            else
                            {
                                          mem = (char *)mShareMemServer.mMapAddr;
                                          size = mShareMemServer.mShareMem.size;
                            }
                            memset((void *)mem, 0, (unsigned int)size);
                            memcpy((void *)mem, str.string(), str.length());
 
                            ts->notify(msg_data_client_write, NULL);
                            return 0;
              }
 
              int TestClient::exit()
              {
                            ALOGD("%s", __func__);
                            sp<ITestBinder> ts = get_test_service();
                            if (ts == NULL)
                                          return -1;
                            ts->notify(msg_diconnect, 0);
 
                            return 0;
              }
}

 

TestClient.h

#ifndef _TEST_CLIENT_H_
#define _TEST_CLIENT_H_
 
#include "../ITestBinder.h"
#include "../ICallback.h"
 
namespace android {
              enum{
                            SHAREMEM_CREATE_BY_CLIENT = 0,
                            SHAREMEM_CREATE_BY_SERVER = 1,
                            SHAREMEM_CREATE_BY_BOTH = 2, //reserve, two share memory for test
              };
 
              typedef struct shareMemory
              {
                            void *mMapAddr;
                            struct testShareMem mShareMem;
              }shareMemory_t;
 
              class TestClient
              {
              public:
                            static const sp<ITestBinder>& get_test_service();
                            static sp<ITestBinder> gTestService;
 
              public:
                            TestClient();
                            ~TestClient();
 
                            int init(int);
                            int write(String8 &str);
                            int exit();
                           
              protected:
                            class Callback : public BnCallback
                            {
                                          friend class TestClient;
                            public:
                                          Callback(TestClient *tclient)
                                                        : tc(tclient)
                                          {}
                                         
                                          virtual ~Callback()
                                          {}
                                         
                                          virtual int notifyCallback(int msg);
 
                            private:
                                          TestClient *tc;
                            };
 
              public:
                            shareMemory_t* getCurShareMemory();
 
              private:
                            int localAlloc(int size);
                            int serverAlloc(int size);
                            int allocShareMemory(int type);
 
              private:
                            shareMemory_t mShareMemLocal;
                            sp<Callback> mCb;
                            shareMemory_t mShareMemServer;
                            int curShareMemType; //client or server alloc sharemem
              };
}
 
#endif //_TEST_CLIENT_H_

 

main.cpp

#define LOG_NDEBUG 0
#define LOG_TAG "client_main"
#include <utils/Log.h>
 
#include "TestClient.h"
 
using namespace android;
 
int main(int argc, char* argv[])
{
              int cnt = 0;
 
              TestClient* myclient = new TestClient();
              if(myclient == NULL)
              {
                            return 0;
              }
 
              myclient->init(/*SHAREMEM_CREATE_BY_CLIENT*/SHAREMEM_CREATE_BY_SERVER);
 
              while(cnt++ < 5)
              {
                            String8 str("binder mem test");
                            myclient->write(str);
              }
             
              myclient->exit();
              delete myclient;
              return 0;
}

 

 

Android.mk

LOCAL_PATH:= $(call my-dir)
 
include $(CLEAR_VARS) 
 
LOCAL_SRC_FILES:= \
    TestClient.cpp \
    main.cpp \
              ../ITestBinder.cpp \
              ../ICallback.cpp
 
LOCAL_SHARED_LIBRARIES := \
    libcutils \
    libutils \
    liblog \
    libbinder
 
LOCAL_MODULE:= test_mem_client_4
LOCAL_MODULE_TAGS := eng
include $(BUILD_EXECUTABLE)

 

 

1.1、由client申请共享内存

                              

Android中的Alarm android ashmem_android_06

         fd与size是怎样传到server端的。BpTestBinder直接写fd与size到BnTestBinder。

                             

Android中的Alarm android ashmem_Android中的Alarm_07

         bn端的处理:

                                

Android中的Alarm android ashmem_Android中的Alarm_08

                                  

Android中的Alarm android ashmem_共享内存_09

         可以说是直接传了fd与size,server端直接拿来就mmap了。

         关闭时也是各自关闭各自的fd。

                         

Android中的Alarm android ashmem_共享内存_10

                          

Android中的Alarm android ashmem_共享内存_11

       

         操作起来相当简单。我们看打印2个fd的值。fd=5、fd=7果然是不一致。是否是ashmem驱动帮我们dup了??

                          

Android中的Alarm android ashmem_#include_12

                  

 

1.2、由server申请共享内存


Android中的Alarm android ashmem_共享内存_13

                       

Android中的Alarm android ashmem_#include_14

         跟前面client端申请内存一样的,注意下面的,传fd、size值。在bp端读取bn端的fd时,必须得dup下,这点有些不懂,其实不dup的话,打印fd值,驱动是有帮dup的,这里为什么要再dup下,实在是想不通。如果这里不dup,那就会出现mmap fail。

                       

Android中的Alarm android ashmem_#include_15

 

                       

Android中的Alarm android ashmem_共享内存_16

                       

Android中的Alarm android ashmem_android_17

 

         在bp那里没有加dup(),mmap fail:

                        

Android中的Alarm android ashmem_#include_18

 

2、IMemory分析

         通常我们调用IMemory去分配共享内存时,一般都如下面操作:

            

sp<MemoryHeapBase> mMemHeap = new MemoryHeapBase(sndDataSize, 0, "AudioTrack Heap Base");
                            sp<MemoryBase> mMemBase = new MemoryBase(mMemHeap, 0, sndDataSize);
                            memcpy(mMemHeap->getBase(), sndDataBuffer, sndDataSize);

              由BnMemoryHeapBase转换到BnMemory,再通过IMemory类去实现进程间的共享内存通信。

         IMemory是framework层在ashmem-dev.c接口上封的一个共享内存类。Bn端是memoryHeapBase与memoryBase。与直接调用ashmem-dev.c接口基本相同,memoryHeapBase也是对open与mmap封装了下。

                       

Android中的Alarm android ashmem_共享内存_19

                      

Android中的Alarm android ashmem_Android中的Alarm_20

        BpMemopry端,我们看常见的getBase()接口。

                           

Android中的Alarm android ashmem_Android中的Alarm_21

         fd、size、offset对应Bn端mmap()操作的参数。同样可以看到BpMemory端的dup()操作,这也验证了上面demo只有加dup()才会正常。

                         

Android中的Alarm android ashmem_android_22

 

 

         所以可以看到,IMemory类的操作与直接调用ashmem-dev.c接口也是大同小异。

         用一个简单的audioTrack demo来说明IMemory接口的使用。

test.cpp

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <binder/Parcel.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/MemoryHeapBase.h>
#include <binder/MemoryBase.h>
#include <media/AudioTrack.h>
 
 
#define uint32_t unsigned int
#define uint16_t unsigned short
 
#define ID_RIFF 0x46464952
#define ID_WAVE 0x45564157
#define ID_FMT  0x20746d66
#define ID_DATA 0x61746164
 
struct riff_wave_header {
    uint32_t riff_id;
    uint32_t riff_sz;
    uint32_t wave_id;
};
 
struct chunk_header {
    uint32_t id;
    uint32_t sz;
};
 
struct chunk_fmt {
    uint16_t audio_format;
    uint16_t num_channels;
    uint32_t sample_rate;
    uint32_t byte_rate;
    uint16_t block_align;
    uint16_t bits_per_sample;
};
 
static char *sndDataBuffer;
static uint32_t sndReadSize;
static uint32_t sampleRate;
static uint32_t audioFormat;
 
using namespace android;
 
#define TEST_FILE_PATH  "/data/audio/test_ringtone.wav"
 
int loadSoundFile(const char *path)
{
              struct riff_wave_header riff_wave_header;
    struct chunk_header chunk_header;
    struct chunk_fmt chunk_fmt;
    int more_chunks = 1;
 
              int file_pos_cur,file_pos_end;
              int buffer_size;
 
              FILE *sndFile;
 
    sndFile = fopen(path, "rb");
    if (!sndFile) {
        ALOGE("Unable to open file '%s'\n", path);
        return -1;
    }
             
              fread(&riff_wave_header, sizeof(riff_wave_header), 1, sndFile);
    if ((riff_wave_header.riff_id != ID_RIFF) ||
        (riff_wave_header.wave_id != ID_WAVE)) {
        ALOGE("Error: '%s' is not a riff/wave file\n", path);
        fclose(sndFile);     
        return -1;
    }
 
    do {
        fread(&chunk_header, sizeof(chunk_header), 1, sndFile);
 
        switch (chunk_header.id) {
        case ID_FMT:
            fread(&chunk_fmt, sizeof(chunk_fmt), 1, sndFile);
            /* If the format header is larger, skip the rest */
            if (chunk_header.sz > sizeof(chunk_fmt))
                fseek(sndFile, chunk_header.sz - sizeof(chunk_fmt), SEEK_CUR);
            break;
        case ID_DATA:
            /* Stop looking for chunks */
            more_chunks = 0;
            break;
        default:
            /* Unknown chunk, skip bytes */
            fseek(sndFile, chunk_header.sz, SEEK_CUR);
        }
    } while (more_chunks);
 
              if (chunk_fmt.bits_per_sample == 32)
              {
                            audioFormat = AUDIO_FORMAT_PCM_32_BIT;
              }
    else if (chunk_fmt.bits_per_sample == 16)
    {
                            audioFormat = AUDIO_FORMAT_PCM_16_BIT;
    }
              sampleRate = chunk_fmt.sample_rate;
              file_pos_cur = ftell(sndFile);
              fseek(sndFile, 0, SEEK_END);
              file_pos_end = ftell(sndFile);
 
              buffer_size = file_pos_end - file_pos_cur;
              if (sndDataBuffer) {
                            free(sndDataBuffer);
                            sndDataBuffer = NULL;
              }
    sndDataBuffer = (char*)malloc(buffer_size);
    if (!sndDataBuffer) {
        ALOGE("Unable to allocate %d bytes\n", buffer_size);
                            fclose(sndFile);
        return -1;
    }
              fseek(sndFile, file_pos_cur, SEEK_SET);
              sndReadSize = fread(sndDataBuffer, 1, buffer_size, sndFile);
              if(sndReadSize <= 0) {
        ALOGE("Unable to allocate %d bytes\n", buffer_size);
                            fclose(sndFile);
        return -1;
    }  
              fclose(sndFile);
              return 0;
}
 
int playSound(char *sndDataBuffer, unsigned int sndDataSize, uint32_t sampleRate, uint32_t format)
{
              int res;
              sp<AudioTrack> audioTrack = NULL;
              if ((sndDataBuffer == NULL) || !sndDataSize)
                            return -1;
 
              ALOGD("samplerate: %d, format: %d\n", sampleRate, format);
              sp<MemoryHeapBase> mMemHeap = new MemoryHeapBase(sndDataSize, 0, "AudioTrack Heap Base");
              sp<MemoryBase> mMemBase = new MemoryBase(mMemHeap, 0, sndDataSize);
              memcpy(mMemHeap->getBase(), sndDataBuffer, sndDataSize);
                                                                                     
              audioTrack = new AudioTrack();
              res = audioTrack->set(AUDIO_STREAM_MUSIC,
                                                                      sampleRate,
                                                                      (audio_format_t)format,
                                                                      AUDIO_CHANNEL_OUT_STEREO,
                                                                      0,
                                                                      AUDIO_OUTPUT_FLAG_PRIMARY,
                                                                      NULL,
                                                                      NULL,
                                                                      0,
                                                                      mMemBase   //sp<IMemory>& sharedBuffer
                                                                      );
 
    ALOGD("audioTrack->set() res=%d\n", res);
 
              audioTrack->setVolume(1.0, 1.0);
              audioTrack->start();
             
#if 0     
              while(!audioTrack->stopped()) //怎样获取停止状态的???没用.....
              {
                            sleep(1);
              }
#endif
 
              sleep(5);
              audioTrack.clear();
              return 0;
}
 
int main(int argc, char **argv)
{
              char file_path[128] = {0};
              sndDataBuffer = NULL;
 
              strcpy(file_path, TEST_FILE_PATH);
              if (argc > 1)
                            strcpy(file_path, (char *)(argv[1]));
              ALOGD("file: %s", file_path);
              if (!loadSoundFile(file_path))
              {
                            playSound(sndDataBuffer, sndReadSize, sampleRate, audioFormat);
              }
             
              if (sndDataBuffer != NULL)
              {
                            free(sndDataBuffer);
                            sndDataBuffer = NULL;
              }
              return 0;
}

 

Android.mk

LOCAL_PATH:= $(call my-dir)
 
include $(CLEAR_VARS) 
LOCAL_C_INCLUDES := \
    frameworks/av/include/
 
LOCAL_SRC_FILES:= test.cpp
 
LOCAL_SHARED_LIBRARIES := \
    libcutils \
    libutils \
              libbinder \
    libmedia \
              liblog
 
 
LOCAL_MODULE_TAGS := eng
LOCAL_MODULE:= audiotrack_sharebuffer_test
include $(BUILD_EXECUTABLE)

 

         可以看到,真正的使用接口就是下面的:

                         

Android中的Alarm android ashmem_共享内存_23

         从字面上理解是先分配堆内存,再在堆内存上分配实现内存,但是实际代码的操作明显就是一样的操作。为什么这样写接口,而不是一步封出来??而要有个BnMemoryHeap ->BnMemory的转换??