Binder Inspect() Details

< pidgen | Binder Kit | Storage Kit >

The IBinder::Inspect() API is the Binder's mechanism for performing interface casts. (If you are familiar with COM, this is similar to the IUnknown::QueryInterface() method found there.)

Interfaces are identified by an interface descriptor. This is a string SValue, where the string is a unique name of that interface. We use Java-style naming conventions for interfaces to ensure they have unique names; all system-level interfaces are in the org.openbinder.* namespace, and all of our application-level interfaces should be in the com.palmsource.* namespace.

You will not normally write these strings yourself. Instead, pidgen generates them for you from the IDL file. Given an interface IFoo, pidgen will generate a method IFoo::Descriptor() that returns the descriptor for that interface.

Casting Interfaces

When working in C++, you will not normally call Inspect() yourself. Instead, you will use the template function interface_cast<INTERFACE>(), which will call Inspect() for you and return the result as the requested C++ interface. For example:

SValue v;
sptr<IBinder> b;

sptr<IFoo> foo(interface_cast<IFoo>(v));
sptr<IFoo> foo(interface_cast<IFoo>(b));

You can also call Inspect() yourself directly for special situations. The API is:

virtual SValue
Inspect(const sptr<IBinder>& caller,
        const SValue &which,
        uint32_t flags = 0);

The caller is the IBinder you are calling Inspect() on, which is the interface descriptor(s) you desire, and flags is currently not used (must always be 0).

For example, here is a call to inspect to get the IView interface binder:

sptr<IBinder> origBinder;
sptr<IBinder> newBinder(origBinder->Inspect(origBinder, IView::Descriptor()));

Like other places where we use SValue operations, the which parameter can also be a set of SValue mappings to retrieve multiple interfaces in one call, or B_WILD_VALUE to retrieve all interfaces. (Note that currently due to IPC limitations, in some cases B_WILD_VALUE will fail because it returns too many IBinder objects.)

Here is an example of retrieving two interfaces:

sptr<IBinder> origBinder;

SValue which(IView::Descriptor(), IView::Descriptor());
which.JoinItem(IViewManager::Descriptor(), IViewManager::Descriptor());
SValue result = origBinder->Inspect(origBinder, which);

sptr<IBinder> viewBinder(result[IView::Descriptor()].AsBinder());
sptr<IBinder> viewManagerBinder(result[IViewManager::Descriptor()].AsBinder());

Note that for C++ programming this is not a very useful technique, since to get the C++ interface you still need to do interface_cast<>(), which will itself do its own IBinder::Inspect() call. You can get around this using IFoo::AsInterfaceNoInspect(), but unless there is some very clear performance critical section for which it makes sense, you are best off just sticking with interface_cast<>().

Implementing Interface Casts

With a binder object of only one interface, there is usually no need for you to do anything. Pidgen will generate for you a standard implementation of Inspect() in the BnFoo class, which returns the interface being implemented. By deriving from BnFoo as normal, you will get this implementation and everything will work as expected.

When you implement an object with multiple interfaces, you will often need to allow the user to cast between them. By default you are not able to cast from one interface to another. To allow this, you need to re-implement Inspect() so that calling the method on one IBinder will also return the information for the other interfaces.

C++ background: when writing an object with multiple interfaces, you have multiple BBinder objects (via multiple inheritance), one for each of those interfaces. Each of these BBinder objects has its own Inspect() method. If the deriving class does not itself implement Inspect(), then they remain separate, and a call to Inspect() on one will just use that one's original implementation.
To implement Inspect(), all you need to do is merge the inspect result of all of your base classes. For example, here is the implementation from the Application Manager service, which implements both IApplication and IApplicationManager:

SValue
BApplicationManager::Inspect(
    const sptr<IBinder>& caller, const SValue &which, uint32_t flags)
{
    SValue result(BnApplication::Inspect(caller, which, flags));
    result.Join(BnApplicationManager::Inspect(caller, which, flags));
    return result;
}

Restricting Interface Access

Sometimes you want to restrict the ways the clients can cast between interfaces. For example, in the view hierarchy, a layout manager implements the interfaces IView, IViewParent, and IViewManager. We want to set these casting policies:

This essentially defines a hierarchy of capabilities holding an IViewParent gives you no other capabilies, while an IView gives you access to all other view capabilities.

In order to accomplish this, we need to look at the caller parameter of Inspect() to determine which interface the call is coming from, and use that to decide which of the base classes we will call. Here is an example implementation of BViewGroup::Inspect() that implements the casting policy described above:

SValue
BViewGroup::Inspect(
    const sptr<IBinder>& caller, const SValue& v, uint32_t flags)
{
    // Figure out which interfaces to inspect.
    uint32_t which = 0;
    if (caller == (BnViewParent*)this) which |= 1;
    if (caller == (BnViewManager*)this) which |= 2|1;
    if (caller == (BnView*)this) which |= 4|2|1;

    SValue result;
    if (which&1) result.Join(BnViewParent::Inspect(caller, v, flags));
    if (which&2) result.Join(BnViewManager::Inspect(caller, v, flags));
    if (which&4) result.Join(BnView::Inspect(caller, v, flags));

    return result;
}

One thing it is very important to note is that this implementation of Inspect() will only return results when the caller is one of the interfaces it provides. This is different than the default implementation, which will return the interface regardless of the caller allowing casts to that interface from any other interface.

Because of this difference in semantics, when you write a subclass that is implementing this kind of Inspect(), you should clearly document in the header file that you are doing and what casting rules it uses. Any subclass of your own class that wants to implement a new interface needs to know about your Inspect() implementation, so that it can call it correctly to implement its own desired casts.

For example, BListView derives from BViewGroup and implements a new interface, IListView. It would like to allow casts from IListView to any of the BViewGroup interfaces. Just calling BViewGroup::Inspect() will not do this, because our implementation only allows casts from its known interfaces. Thus the implementation of BListView::Inspect() will look something like this:

SValue
BListView::Inspect(
    const sptr<IBinder>& caller, const SValue &which, uint32_t flags)
{
    SValue result;

    // IListView and IView get access to the IListView interface.
    if (caller == (BnListView*)this || caller == (BnView*)this)
        result.Join(BnListView::Inspect(caller, which, flags));

    // If inspecting from IListView, we give full access to the object &mdash;
    // that is, the same permissions as if inspecting from IView.
    if (caller == (BnListView*)this)
        result.Join(BViewGroup::Inspect((BnView*)this, which, flags));
    else
        result.Join(BViewGroup::Inspect(caller, which, flags));

    return result;
}

The trick here is that if the caller is inspecting from IListView, we call up to BViewGroup::Inspect() with the caller changed to the IView binder, so that it will return all interfaces.