Binder in Android are used for Inter Process Communication. In Android code base, interface_cast
and asBinder
function are used at multiple places in context of Binder. This article tries to explain the interpretation of these API.
interface_cast
Let’s analyze it based on the following ICameraClient example:
// https://android.googlesource.com/platform/frameworks/av/+/refs/heads/master/camera/ICamera.cpp sp<ICameraClient> cameraClient = interface_cast<ICameraClient>(data.readStrongBinder());
Look at the implementation of interface_cast, the code is in IInterface.h
// Code snippet: https://android.googlesource.com/platform/frameworks/native/+/refs/heads/master/libs/binder/include/binder/IInterface.h /** * If this is a local object and the descriptor matches, this will return the * actual local object which is implementing the interface. Otherwise, this will * return a proxy to the interface without checking the interface descriptor. * This means that subsequent calls may fail with BAD_TYPE. */ template<typename INTERFACE> inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj) { return INTERFACE::asInterface(obj); }
This is a template function, which is expanded as:
inline sp<ICameraClient> interface_cast(const sp<IBinder>& obj) { return ICameraClient ::asInterface(obj); }
asInterface
Lets look at the implementation of asInterface of ICameraClient. ICameraClient.h and ICameraClient.cpp have only the following two definitions:
// https://android.googlesource.com/platform/frameworks/av/+/refs/heads/master/camera/ICameraClient.cpp IMPLEMENT_META_INTERFACE(CameraClient, "android.hardware.ICameraClient"); // https://android.googlesource.com/platform/frameworks/av/+/refs/heads/master/camera/include/camera/android/hardware/ICameraClient.h DECLARE_META_INTERFACE(CameraClient);
The DECLARE_META_INTERFACE
and IMPLEMENT_META_INTERFACE
functions are the macro definitions of its parent class IInterface. Below illustrate the code snippet of the same.
//Declare the asInterface function #define DECLARE_META_INTERFACE(INTERFACE) static const android::String16 descriptor; //Declare the asInterface function static android::sp<I##INTERFACE> asInterface( const android::sp<android::IBinder>& obj); virtual const android::String16& getInterfaceDescriptor() const; I##INTERFACE(); virtual ~I##INTERFACE(); //Implement asInterface function #define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) const android::String16 I##INTERFACE::descriptor(NAME); const android::String16& I##INTERFACE::getInterfaceDescriptor() const { return I##INTERFACE::descriptor; } 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);//Expansion is intr = new BpServiceManager(obj); } } return intr; } I##INTERFACE::I##INTERFACE() {} I##INTERFACE::~I##INTERFACE() {}
When used with the above example, above will expand to
// Expand to #define DECLARE_META_INTERFACE(CameraClient) //Add a descriptor static const android::String16 descriptor; //Declare the asInterface function static android::sp<ICameraClient> asInterface( const android::sp<android::IBinder>& obj); //Get the descriptor function virtual const android::String16& getInterfaceDescriptor() const; //Constructor and folding function ICameraClient(); virtual ~ICameraClient(); // Expand to #define IMPLEMENT_META_INTERFACE(CameraClient, "android.hardware.ICameraClient") //Define the descriptor of ICameraClient as "android.hardware.ICameraClient" const android::String16 ICameraClient ::descriptor("android.hardware.ICameraClient"); //Get the descriptor "android.hardware.ICameraClient" const android::String16& ICameraClient ::getInterfaceDescriptor() const { return ICameraClient ::descriptor; } //Implement asInterface function android::sp<ICameraClient> ICameraClient::asInterface( const android::sp<android::IBinder>& obj) { android::sp<ICameraClient> intr; if (obj != NULL) { intr = static_cast<ICameraClient*>( //queryLocalInterface is defined in IBinder and returns NULL by default, but in BBinder's subclass BnInterface, this method is overloaded and returns this, while BpBinder is not overloaded, using the default implementation of IBinder, returning NULL obj->queryLocalInterface( ICameraClient::descriptor).get()); if (intr == NULL) { //Build INTERFACE's Bp-side proxy object intr = new BpCameraClient(obj); } } return intr; } ICameraClient::ICameraClient() {} ICameraClient::~ICameraClient() {}
To summarize, if the parameter obj of interface_cast
is BnInterface
, it returns itself. If the parameter obj is BpInterface
, then a new Bp proxy object is returned. Here we use the ICameraClient example to explain, it returns BpCameraClient.
asBinder
Below code shows the snippet of asBinder
API.
// https://android.googlesource.com/platform/frameworks/native/+/refs/heads/master/libs/binder/IInterface.cpp // static sp<IBinder> IInterface::asBinder(const IInterface* iface) { if (iface == nullptr) return nullptr; return sp<IBinder>::fromExisting(const_cast<IInterface*>(iface)->onAsBinder()); } // static sp<IBinder> IInterface::asBinder(const sp<IInterface>& iface) { if (iface == nullptr) return nullptr; return sp<IBinder>::fromExisting(iface->onAsBinder()); }
BnInterface
The onAsBinder
method of BnInterface
returns itself directly, because BnInterface
inherits from BBinder
, and BBinder
inherits from IBinder
.
// https://android.googlesource.com/platform/frameworks/native/+/refs/heads/master/libs/binder/include/binder/IInterface.h template<typename INTERFACE> class BnInterface : public INTERFACE, public BBinder { public: virtual sp<IInterface> queryLocalInterface(const String16& _descriptor); virtual const String16& getInterfaceDescriptor() const; protected: typedef INTERFACE BaseInterface; virtual IBinder* onAsBinder(); };
BpInterface
The onAsBinder
method of BpInterface
calls the remote()
method and returns.
// https://android.googlesource.com/platform/frameworks/native/+/refs/heads/master/libs/binder/include/binder/IInterface.h template<typename INTERFACE> class BpInterface : public INTERFACE, public BpRefBase { public: explicit BpInterface(const sp<IBinder>& remote); protected: typedef INTERFACE BaseInterface; virtual IBinder* onAsBinder(); }; // Implementation of remote in BpRefBase inline IBinder* remote() { return mRemote; }
The mRemote
variable passes the remote variable to its parent class BpRefBase
when creating the BpInterface
object.
// https://android.googlesource.com/platform/frameworks/native/+/refs/heads/master/libs/binder/Binder.cpp BpRefBase::BpRefBase(const sp<IBinder>& o) : mRemote(o.get()), mRefs(nullptr), mState(0) { extendObjectLifetime(OBJECT_LIFETIME_WEAK); if (mRemote) { mRemote->incStrong(this); // Removed on first IncStrong(). mRefs = mRemote->createWeak(this); // Held for our entire lifetime. } }