• Binder基本概念流程学习


     

    一 Media Service进程启动

    Init.rc中描述的service对应linux 的进程:

    Media进程定义:

    service media /system/bin/mediaserver
        class main
        user media
        group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc
        ioprio rt 4

    servicemanager 进程定义:

    service servicemanager /system/bin/servicemanager
        class core
        user system
      group system

      Media中有很多Native Service(AudioFlinger MediaPlayerService CameraService 
    AudioPolicyService等),整个Android(native或者framework)的Service都需要加入
    servicemanager中进行统一管理。
      那么Media Process 与ServiceManager Process是如何进行通信的呢——Binder.
    通过Media Process中使用binder进行完成IPC过程,学习Binder的概念和使用方法。

    \frameworks\av\media\mediaserver\ main_mediaserver.cpp:

    int main(int argc, char** argv)
    {
        //创建ProcessState 当前进程属性
        sp<ProcessState> proc(ProcessState::self());
        
        //IServiceManager对象
        sp<IServiceManager> sm = defaultServiceManager();
        
        //初始化MediaPlayerService服务对象
        MediaPlayerService::instantiate();
        ……
        
        //启动进程的线程池
        ProcessState::self()->startThreadPool();
        //执行线程消息循环
        IPCThreadState::self()->joinThreadPool();
    }

      Sp:指针运算符和普通运算符的重载 StrongPointer。

    二 Media Process执行过程

    1 ProcessState对象创建

    当前进程的状态属性,对象创建:

    sp<ProcessState> ProcessState::self()
    {
        Mutex::Autolock _l(gProcessMutex);
        if (gProcess != NULL) {
            return gProcess;
        }
        gProcess = new ProcessState;
        return gProcess;
    }

    ProcessState构造函数:

    ProcessState::ProcessState()
        : mDriverFD(open_driver())    //打开binder驱动设备
        , mVMStart(MAP_FAILED)
        , mManagesContexts(false)
        , mBinderContextCheckFunc(NULL)
        , mBinderContextUserData(NULL)
        , mThreadPoolStarted(false)
        , mThreadPoolSeq(1)
    {
        if (mDriverFD >= 0) {
            //将binder的fd映射到当前进程虚拟空间地址中 与binder进行交互
            mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, 
            MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
        }
    }

    打开binder设备:

    static int open_driver()
    {
        //打开binder设备驱动
        int fd = open("/dev/binder", O_RDWR);
        if (fd >= 0) {
            //bidner最大支持线程数
            size_t maxThreads = 15;
            result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
        }
        return fd;
    }

    ProcessState对象创建过程所做的事:
      打开/dev/binder设备,得到binder设备的fd;
      将bidner设备fd映射到当前进程虚拟地址空间建立交互的通道;

    2 IServiceManager对象创建
      sp<IServiceManager> sm = defaultServiceManager();
    为什么需要一个IServiceManager对象呢,这个类是个抽象提供接口

    class IServiceManager : public IInterface
    {
        virtual sp<IBinder> getService( const String16& name) const = 0;
        virtual status_t addService( const String16& name,
                                 const sp<IBinder>& service,
                                 bool allowIsolated = false) = 0;
        ……                                    
    };

      通过IServiceManager派生对象操作将Service加入到ServiceManager中.

    defaultServiceManager()函数:

    sp<IServiceManager> defaultServiceManager()
    {
        //单例对象
        if (gDefaultServiceManager != NULL) 
            return gDefaultServiceManager;
    
        AutoMutex _l(gDefaultServiceManagerLock);
        if (gDefaultServiceManager == NULL) {
            //创建对象
            gDefaultServiceManager = interface_cast<IServiceManager>(
                    ProcessState::self()->getContextObject(NULL));
        }
        return gDefaultServiceManager;
    } 

    ProcessState::self()->getContextObject(NULL):得到一个IBinder对象

      ProcessState::self()刚才所创建的ProcessState对象。

    sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& caller)
    {
        return getStrongProxyForHandle(0);
    }
    
    sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
    {
        sp<IBinder> result;
        AutoMutex _l(mLock);
        //从表中查询一个handle对应的handle_entry 
        //若没有则创建一个 handle == 0
        handle_entry* e = lookupHandleLocked(handle);
    
        if (e != NULL) {
            IBinder* b = e->binder;
            if (b == NULL || !e->refs->attemptIncWeak(this)) {
                //handle_entry对象成员初始化 创建handle=0的BpBinder 
                b = new BpBinder(handle); 
                e->binder = b;
                if (b) e->refs = b->getWeakRefs();
                result = b;
            }
        }
        return result;
    }

      handle_entry是什么呢?

          struct handle_entry {
                    IBinder* binder;
                    RefBase::weakref_type* refs;
                };

      也就是说ProcessState 有一个表Vector<handle_entry>mHandleToObject;

    表里面的每一项存储了一个binder,每一个binder对应一个handle。

      

      Handle = 0是什么,句柄? 代表谁的句柄——ServiceManager在binder中的资源。
    从ProcessState::self()->getContextObject(NULL)得到一个 IBinder——BpBinder(0);
    于是得到:
      gDefaultServiceManager = interface_cast<IServiceManager>(BpBinder(0));

    使用interface_cast将IBinder实例转化成IServiceManager实例。

    3 interface_cast函数

    \frameworks\native\include\binder\IInterface.h:

    interface_cast是个内联模板函数: 

    template<typename INTERFACE>
    inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
    {
        return INTERFACE::asInterface(obj);
    }

    结合前面就是:

    inline sp<IServiceManager> interface_cast(const sp<IBinder>& obj)
    {
        return IServiceManager::asInterface(obj);
    }

    所以需要到IServiceManager里面去看看是如何实现的

    4 IServiceManager类

    \frameworks\native\include\binder\IServiceManager.h:

    IServiceManager是一个抽象类:

    class IServiceManager : public IInterface
    {
      public:
          //宏声明
        DECLARE_META_INTERFACE(ServiceManager);
        virtual sp<IBinder> getService( const String16& name) const = 0;
        virtual status_t addService( const String16& name,
                                     const sp<IBinder>& service,
                                     bool allowIsolated = false) = 0;
        ……
    }

    DECLARE_META_INTERFACE声明:

    #define DECLARE_META_INTERFACE(INTERFACE)                               \
        static const android::String16 descriptor;                          \
        static android::sp<I##INTERFACE> asInterface(                       \
                const android::sp<android::IBinder>& obj);                  \
        virtual const android::String16& getInterfaceDescriptor() const;    \
        I##INTERFACE();                                                     \
        virtual ~I##INTERFACE();                                            \ 

    替换成IServiceManager:

    //实现时传入:android.os.IServiceManager
    static const android::String16 descriptor; 
    static android::sp<IServiceManager> asInterface( 
    const android::sp<android::IBinder>& obj); 
    virtual const android::String16& getInterfaceDescriptor() const; 
    //构造析构函数
    IServiceManager(); 
    virtual ~IServiceManager(); 

    实现\frameworks\native\include\binder\IServiceManager.cpp:

    IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");

    IMPLEMENT_META_INTERFACE实现:
    看一下asInterface接口:

    #define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \
        android::sp<I##INTERFACE> I##INTERFACE::asInterface(                \
                const android::sp<android::IBinder>& obj)                   \
        {                                                                   \
            android::sp<I##INTERFACE> intr;                                 \
            if (obj != NULL) {                                              \
                intr = static_cast<I##INTERFACE*>(                          \
                    obj->queryLocalInterface(                               \
                            I##INTERFACE::descriptor).get());               \
                if (intr == NULL) {                                         \
                    intr = new Bp##INTERFACE(obj);                          \
                }                                                           \
            }                                                               \
            return intr;                                                    \
    }                                             \

    替换成IServiceManager:

    android::sp<IServiceManager> IServiceManager::asInterface(                
                const android::sp<android::IBinder>& obj)                   
    {   
            //obj BpBinder实例                                                                
            android::sp<IServiceManager> intr;                                
            if (obj != NULL) {
                //返回NULL                                        
                intr = static_cast<IServiceManager*>(                          
                    obj->queryLocalInterface(                               
                            IServiceManager::descriptor).get());              
                if (intr == NULL) {                                         
                    intr = new BpServiceManager(obj);                          
                }                                                           
            }                                                               
            return intr;                                                    
    }

    这里得到IServiceManager 实例:

      BpServiceManager:new BpServiceManager(new BpBinder(0));

    5 BpServiceManager 和 BpInterface类

    \frameworks\native\libs\binder\ IServiceManager.cpp:BpServiceManager

    class BpServiceManager : public BpInterface<IServiceManager>
    {
    public:
          //impl就是 new BpBinder(0)
        BpServiceManager(const sp<IBinder>& impl)
            : BpInterface<IServiceManager>(impl)
        {
        }
    
        virtual sp<IBinder> checkService(const String16& name) const
        {
            ……
            remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
        }
    
        virtual status_t addService(const String16& name, const sp<IBinder>& service,
                bool allowIsolated)
        {
            ……
            remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
        }
    }

    \frameworks\native\include\binder\ IInterface.h:模板类BpInterface

    template<typename INTERFACE>
    class BpInterface : public INTERFACE, public BpRefBase    // INTERFACE IServiceManager
    {
      public:
        BpInterface(const sp<IBinder>& remote);
      protected:
        virtual IBinder* onAsBinder();
    };

    BpInterface构造函数:

    template<typename INTERFACE>
    inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote)
    : BpRefBase(remote)
    {
    }

    BpRefBase构造函数:

    BpRefBase::BpRefBase(const sp<IBinder>& o)
    : mRemote(o.get()), mRefs(NULL), mState(0)
    {
      // IBinder mRemote 指向 o.get() :new BpBinder(0)
    }

      gDefaultServiceManager = interface_cast<IServiceManager>(BpBinder(0));
    实际为:
      gDefaultServiceManager = new BpServiceManager(new BpBinder(0));
    Bn代表Binder Native Bp代表Binder Proxy
    BpServiceManager代理的BpBinder实例 BpBinder代理的handle(0)

    这个关系有些复杂,看一下类继承结构图:

      


      上面这个结构看起来感觉很熟悉——Bridge模式。将Binder数据交互和功能处理桥接起来。

    在Media Process 的main函数中通过:

      sp<IServiceManager> sm = defaultServiceManager();
      我们得到了sm:是BpServiceManager对象。

    三 MediaPlayerService加入到ServiceManager中

    回到main函数中:

    int main(int argc, char** argv)
    {
        //创建ProcessState 当前进程属性
        sp<ProcessState> proc(ProcessState::self());
    
        //IServiceManager对象
        sp<IServiceManager> sm = defaultServiceManager();
    
        //初始化MediaPlayerService服务对象
        MediaPlayerService::instantiate();     //执行到这里
        ……
    
        //启动进程的线程池
        ProcessState::self()->startThreadPool();
        //执行线程消息循环
        IPCThreadState::self()->joinThreadPool();
    }

    1 MediaPlayerService初始化过程

    void MediaPlayerService::instantiate() {
      // defaultServiceManager就是上面所述得到的BpServiceManager对象
      defaultServiceManager()->addService(
        String16("media.player"), new MediaPlayerService());
    }

    BpServiceManager添加Service:

    virtual status_t addService(const String16& name, const sp<IBinder>& service,
                bool allowIsolated)
    {
            //生成数据包Parcel
            Parcel data, reply;
            // Write RPC headers 写入Interface名字 得到“android.os.IServiceManager”
            data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
            //写入Service名字 “media.player”
            data.writeString16(name);
            //写入服务
            data.writeStrongBinder(service);
            data.writeInt32(allowIsolated ? 1 : 0);
            // remote()返回BpBinder对象
            status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
            return err == NO_ERROR ? reply.readExceptionCode() : err;
    }

    remote()->transact 到BpBinder中:

    status_t BpBinder::transact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
    {
    if (mAlive) {
            //到当前进程IPCThreadState中 mHandle=0
            status_t status = IPCThreadState::self()->transact(
                mHandle, code, data, reply, flags);
            if (status == DEAD_OBJECT) mAlive = 0;
            return status;
        }
        return DEAD_OBJECT;
    }

     

    2 IPCThreadState中写入数据到Binder设备过程

    IPCThreadState::self()->transact过程:

    status_t IPCThreadState::transact(int32_t handle,
                                uint32_t code, const Parcel& data,
                                Parcel* reply, uint32_t flags)
    {
        status_t err = data.errorCheck();
    
        flags |= TF_ACCEPT_FDS;
        //将数据转化成binder_transaction_data 写入到Parcel实例mOut中
        err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
        //写入数据
        err = waitForResponse(reply);
        return err;
    } 
    
    status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
    {
        while (1) {
            //将数据写入到Binder设备中
            talkWithDriver();
            ……
        }
        return err;
    }
    
    status_t IPCThreadState::talkWithDriver(bool doReceive)
    {
        //将数据封装成binder_write_read结构
        binder_write_read bwr;
    
        do {
            //将数据写入到所打开的Binder设备中
            ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)
            ……
        
        } while (err == -EINTR);
        return NO_ERROR;
    }

      将MediaPlayerService加入到ServiceManager中,

    这里就通过BpServiceManager的AddService将数据写入到Binder设备传递给ServiceManager。

    继续Media Process过程

    四 Media Process消息循环

    int main(int argc, char** argv)
    {
        //启动进程的线程池    
        ProcessState::self()->startThreadPool();     //走到了这里
    
        //执行线程消息循环
        IPCThreadState::self()->joinThreadPool();
    }


    1 创建工作者线程

    startThreadPool:\frameworks\native\libs\binder\ ProcessState.cpp:

    void ProcessState::startThreadPool()
    {
        spawnPooledThread(true);
    }
    
    void ProcessState::spawnPooledThread(bool isMain)
    {
        //创建PoolThread对象 并run ,非线程
        sp<Thread> t = new PoolThread(isMain);
      t->run(buf);
    }

      PoolThread继承Thread

    执行Thread的run函数:

    status_t Thread::run(const char* name, int32_t priority, size_t stack)
    {
        //创建线程mThread _threadLoop
        bool res;
        res = createThreadEtc(_threadLoop,
        this, name, priority, stack, &mThread);
    
        return NO_ERROR;
    }

    现在有两个线程:主线程和mThread线程

    mThread线程执行:_threadLoop

    int Thread::_threadLoop(void* user)
    {
        Thread* const self = static_cast<Thread*>(user);
        do {
            //调用子类的threadLoop
            result = self->threadLoop();
            ……
        } while(strong != 0);
        return 0;
    }
    
    class PoolThread : public Thread
    {
    protected:
        virtual bool threadLoop()
        {
            IPCThreadState::self()->joinThreadPool(mIsMain);
            return false;
        }
    };

    2 进程间通信消息循环过程

    消息循环:

    void IPCThreadState::joinThreadPool(bool isMain)
    {
        mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
        status_t result;    
        //消息循环
        do {
            int32_t cmd;
            //从binder设备中读取命令
            result = talkWithDriver();
            if (result >= NO_ERROR) {
                cmd = mIn.readInt32();
                //执行命令
                result = executeCommand(cmd);
            }
               ……
        } while (result != -ECONNREFUSED && result != -EBADF);
        
        mOut.writeInt32(BC_EXIT_LOOPER);
        talkWithDriver(false);
    }

    命令执行:

    status_t IPCThreadState::executeCommand(int32_t cmd)
    {
        BBinder* obj;
        RefBase::weakref_type* refs;
        switch (cmd) {
        case BR_DECREFS:
            break;
        case BR_ATTEMPT_ACQUIRE:
            break;
    case BR_TRANSACTION:
      binder_transaction_data tr;
        result = mIn.read(&tr, sizeof(tr));
          if (tr.target.ptr) {
            //将目标对象转化成BBinder
            sp<BBinder> b((BBinder*)tr.cookie);
            //调用BBinder的transact 函数
           const status_t error = b->transact(tr.code, buffer, &reply, tr.flags);
          }
            break;
        ……
        default:
        }
        return result;
    }

      binder_transaction_data.cookie:target object cookie目标对象,这个target object是指那个呢?

    在Media Process里面有几个Service:AudioFlinger、MediaPlayerService、CameraService等。

    这个目标是这其中Service中的一个,假设目标对象为为MediaPlayerService,那为何要转化成BBinder呢?

    3 Service对命令的处理

      线程从binder接收到消息命令,将命令传递给Service处理。将目标对象转化成BBinder,然后调度此命令;

    命令从远端传递到本地端进行处理,每个Service都对应BnXXX对象来处理远端BpXXX传来的命令。
      sp<BBinder> b((BBinder*)tr.cookie);
      const status_t error = b->transact(tr.code, buffer, &reply, tr.flags);
      这里b代表某个Service:假设为MediaPlayerService;弄清楚执行过程,要弄清楚类继承关系。

        


      本地端BnMediaPlayerService消息处理过程:真正的对象是MediaPlayerService实例。
    从BBinder ->transact开始传递:

    status_t BBinder::transact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
    {
        //onTransact是个virtual函数 派生类BnMediaPlayerService重写
        err = onTransact(code, data, reply, flags);
        return err;
    }
    
    status_t BnMediaPlayerService::onTransact(
        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
    {
        switch (code) {
            case CREATE: {
                pid_t pid = data.readInt32();
                sp<IMediaPlayerClient> client =
                    interface_cast<IMediaPlayerClient>(data.readStrongBinder());
                //create是个virtual函数 派生类MediaPlayerService重写
                sp<IMediaPlayer> player = create(pid, client, audioSessionId);
                //创建player写入到数据包中 传回
                reply->writeStrongBinder(player->asBinder());
                return NO_ERROR;
            } break;
            ……
            default:
                return BBinder::onTransact(code, data, reply, flags);
        }
    }

    可以看看Client类继承关系结构图:

        

      看到这个跟上面的MediaPlayerService继承关系非常的相似,

      这个结构也非常的熟悉——Adapter模式;将binder消息交互和命令处理适配到一起。

    五 Client端与Service端交互

      Client对Service进行使用Binder通信,是得到一个Service BnXXX端对象的代理,在Client 为BpXXX代理,

    然后使用此代理进行相关的操作. 前面在使用ServiceManager就是此种方式进行。

      实际上通信的基础是Binder,Proxy不过是在Binder上进行了一层封装,封装了对binder驱动的底层操作,使具有面向对象的特性。

    任意两个进程通过Binder进行通信,就是先得到另一个进程的binder标识,通过此binder进行数据交换。

        

    1 新增加一个服务
    看下面media Palyer类继承结构。
    实现Bn端类继承结构:

        


    实现Bp端类继承结构

        

    可以看到 :

    •   需要定义服务公共接口IMediaPlayerService;
    •   实现服务Bn端 派发消息BnMediaPlayerService;
    •   实现服务的命令处理MediaPlayerService;
    •   实现服务代理BpMediaPlayerService;

    2 Client获取Service服务

      Native Service以及framework Service都是加入到ServiceManger中,

    不管native端还是Framework端得Service 其实都是要满足上面远程对象代理结构。

    native端获取service:

    //获取ServiceManager的代理对象
    sp<IServiceManager> sm = defaultServiceManager();
    //通过ServiceManager获取media Service binder
    binder = sm->getService(String16("media.player"));
    //将binder封装 构造media Service代理对象 BpMediaPlayerService
    sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);

    framework层的service,借助AIDL文件,实现跨进程的通信:

      所有framework端service想要作为公共的服务,被别的应用程序调用,都要实现AIDL文件,服务要继承该AIDL文件内部类Stub。
    其实AIDL文件是对Framework中service作为进程通信的框架的封装,系统自动生成中间需要的代码和步骤,统一结构:还是binder代理,服务代理。

    下面看看PowerManagerService实现。
    PowerManagerService服务:

    \frameworks\base\services\java\com\android\server\PowerManagerService.java

    public class PowerManagerService extends IPowerManager.Stub……
    {
      public void goToSleep(long time){
        ……
      }
    };
    
    AIDL文件:\frameworks\base\core\java\android\os\IPowerManager.aidl
    interface IPowerManager
    {
      void goToSleep(long time);
      ……
    }

    AIDL对应的Java文件:
      AIDL会自动生成一个对应的Java的interface文件,看看这个接口文件。
      AIDL自动生成对应java文件位置:\out\target\common\obj\JAVA_LIBRARIES\framework_intermediates\src\core\java\android\os

    public interface IPowerManager extends android.os.IInterface {
        //IPowerManager 内部类 Stub
        public static abstract class Stub extends android.os.Binder implements
                android.os.IPowerManager {
            public static android.os.IPowerManager asInterface(
                    android.os.IBinder obj)
            {
                //生成一个Proxy对象
                return new android.os.IPowerManager.Stub.Proxy(obj);
            }
            public android.os.IBinder asBinder() {
                return this;
            }
            @Override
            public boolean onTransact(int code, android.os.Parcel data,
                    android.os.Parcel reply, int flags)
            {
                switch (code) {
                    case TRANSACTION_goToSleep:
                    this.goToSleep(_arg0);
                    return true;
                    ……
                }
            }
            //Stub内部类Proxy 
            private static class Proxy implements android.os.IPowerManager {
                private android.os.IBinder mRemote;
                Proxy(android.os.IBinder remote) {
                    mRemote = remote;
                }
                public void goToSleep(long time) 
                {
                    //将数据打包成Parcel
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeLong(time);
                    //传输数据到binder 到相关的Service 进程
                    // IPCThreadState::transact方法中完成
                    mRemote.transact(Stub.TRANSACTION_goToSleep, _data, _reply,0);
                    _reply.readException();
                }
            }
        }
        //goToSleep接口对应的ID
        static final int TRANSACTION_goToSleep = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
        //接口
        public void goToSleep(long time);
    }

    看下其中类结构:

        


    AIDL自动生成对应的java文件,将结构过程进行了统一,自动生成中间代码。

    Application获取用Service:

    IPowerManager m mPowerManagerService;
    //获取service的bingder
    IBinder binder = ServiceManager.getService("power");
    //创建service代理对象
    mPowerManagerService = IPowerManager.Stub.asInterface(binder);
    //调用接口
    mPowerManagerService.goToSleep();

    Native Service和 Framework Service结构方式基本一致的。

     

    进程间通信Linux系统已经提供了很多方式,比如Socket,为什么Android非要另辟蹊径,设计了Binder呢?

      可以阅读一下:http://www.cnblogs.com/bastard/archive/2012/10/17/2728155.html


      Game Over !

    参考文档:
      http://www.cnblogs.com/innost/archive/2011/01/09/1931456.html
      http://blog.csdn.net/maxleng/article/details/5490770

    注:

      “我们其实还一部分没有研究,就是同一个进程之间的对象传递与远程传递是区别的。同一个进程间专递服务地和对象,

      就没有代理BpBinder产生,而只是对象的直接应用了。应用程序并不知道数据是在同一进程间传递还是不同进程间传递,

      这个只有内核中的Binder知道,所以内核Binder驱动可以将Binder对象数据类型从BINDER_TYPE_BINDER修改为

      BINDER_TYPE_HANDLE或者BINDER_TYPE_WEAK_HANDLE作为引用传递。”  ——来自上述地址

      这个可以看到在SystemServer运行的Service之间使用时,直接转化成了对应的对象,而不是通过代理。

     

  • 相关阅读:
    人生中第一份值得纪念的工作
    ZOJ 3829 Known Notation(字符串处理 数学 牡丹江现场赛)
    java基础之内部类
    从计算的本质到编程语言
    【Cocos2dx】资源目录,播放背景音乐,导入外部库
    POJ 3723 Tree(树链剖分)
    hdu 1002 A + B Problem II(大正整数相加)
    时间格式字符串转化为date和时间戳
    深入浅出游戏算法(4)-unity3d算法(1)-球转动
    GeoServer手动发布本地Shapefile地图
  • 原文地址:https://www.cnblogs.com/bastard/p/2766611.html
Copyright © 2020-2023  润新知