`
isiqi
  • 浏览: 16044603 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

Binder Frequently Asked Questions

阅读更多
= Binder Frequently Asked Questions =

'''Note: this material comes from internal documentation at PalmSource, and still contains references to things that are not a part of OpenBinder.'''

[[TOC(BinderFAQ)]]

= Binder Basics =

== What are the "key" elements of binder? ==

Component Model, Cross-language/process "scripting" ability, data flow, and threading model. Data flow allows you to "hook things up and let them run".

== How do I use "the binder"? ==

The binder is not like, for example, libc, where there is a library with a given API. The binder is the object model used for components in a system. To use the binder, you either just use an existing component or you write your own components. See [wiki:BinderFAQ#Whatisacomponent What is a component?].

== How do I write a Binder object? ==
The details are given later, but you select an interface for what you want to do (or often a more convenient base implementation of an interface, for example BView for the IView interface), then derive from it and implement it in C++.

If you are "one of ''those'' people" (you know the ones we're talking about) you may also write your own interface and compile it with pidgen.

== What is a normal object hierarchy? ==
{{{
#!graphviz
digraph 
{
edge [arrowsize=.75, color=blue, arrowtail=none];
node [shape=box width=1.0, fontsize=9, height=.2];
 rankdir = "BT";
 { rank = same; IBinder IInterface node0; }
 { rank = same; BBinder IPerson BpAtom; }
 { rank = same; BnPerson BpPerson BpBinder; }
 { rank = same; Person; }

 subgraph
 {
 Person -> BnPerson -> BBinder -> IBinder ;
 }
 subgraph
 {
 BnPerson -> IPerson -> IInterface;
 }
 
 BpPerson -> BpAtom;
 BpPerson -> IPerson; 

 IBinder -> SAtom;
 IInterface -> SAtom;


 node0 [label = "IBinder" ];
 BpBinder -> node0;

 subgraph
 {
 BpPerson -> BpBinder [ style=dotted, fontsize=9, arrowhead=none, headlabel="Works with a", labeldistance=4.0, minlen=4, labelangle=10.0, labelfloat=true];
 }
}
}}}
Pidgen generates: IPerson, !BnPerson, !BpPerson

System: [[DoxyClass(SAtom)]], [[DoxyClass(IBinder)]], [[DoxyClass(IInterface)]], [[DoxyClass(BBinder)]]

Don't worry too much about the details if you don't want to, you usually won't care a whole lot.

== How do I derive? ==

Remember that interfaces are like Java interfaces, there is no
implementation. (They are "pure virtual" in the C++ parlance.) If you simply want to implement
an existing interface (''interface'' inheritance), derive from the "Bn" class that
pidgen generated:
{{{
#!cpp
class Person : public BnPerson
}}}
The "Person" class is a normal C++ class, so you can also derive from that
for ''implementation'' inheritance:
{{{
#!cpp
class Manager : public Person
}}}
Note that in this case a Manager is a variation of Person '''functionality'''
but provides no new Binder APIs (i.e., API that can be accessed across
processes or languages) of its own.

If you want to add a formal manager
interface, there are two basic approaches you can take. The first is to use
inheritance in the IDL like this:
{{{
#!cpp
interface IManager : IPerson
}}}
This means your Manager object must derive from the more-specific IManager
interface, and can not share any implementation with Person:
{{{
#!cpp
class Manager : public BnManager
}}}
The second, more common approach, is to define IManager as a separate
autonomous interface, and use C++ multiple inheritance to create a class
that implements it along with the other interface. Given the existing
Person C++ class and a new IManager interface, the final Manager would
look like this:
{{{
#!cpp
class Manager : public Person, public BnManager
}}}
There are some subtleties to be aware of when implementing a class with
multiple interfaces like this. You will need to override the IBinder
Inspect() method (see [[DoxyFile(BinderInspect,Inspect)]]) if you want to allow casting (via interface_cast<>)
between them. It also means your class contains multiple BBinder object
instances, so in the Binder world it has multiple identities depending
on which interface one is using.

== How do I deal with multiple interfaces on an object? ==

As an example, look at these two shell examples:
{{{
// Example 1
$ invoke /services/window AddView $ClockSlip
// Example 2
$ A=$[inspect /services/surface palmos.services.IErrAlert]
$ invoke $A ShowAlert "This is a test"
}}}
IBinder is the language-neutral interface. IInterface is the C++ binding. When you do an `Inspect()` on an IBinder (see [[DoxyFile(BinderInspect, Inspect)]]), it returns to you a (possibly different) IBinder for the object corresponding to the requested interface. In C++, that means that a C++ Binder component can have multiple BBinder objects, one for each interface the component implements. In these examples, in the first case the `/services/window` IBinder that is published in the catalog is the IBinder for the IViewManager of the window manager. So invoke is called on the IViewManager. In the second case, the published `/services/surface` is some other IBinder (then the IErrAlert interface), so you need to `Inspect()` to get to the one you want.

== What is the identity of a Binder object? ==

IBinder address is the identity of an object. Do not compare interface addresses. Interface proxies are created on-demand by the system, so the interface address is not a unique identity.

Every C++ interface (such as IPerson) has an IBinder associated with it. The IBinder provides it with a unique identity across the entire system as well as the basic Binder mechanisms like inspect, put, get, and invoke. You can have an IBinder without an IInterface; you can not have an IInterface without an IBinder.

== How do I pass Binder objects to functions? ==

Normally you always want to pass a "const sptr&" as the argument. You don't want a BFoo, because that constrains your function to only working with objects created in C++. Other languages or processes cannot create the object that is then passed to the function. When you get an object back from the package manager or another process, all you'll have access to is an IFoo. Functions should normally return sptr objects.

Notice that there is nothing prohibiting you from writing the following:
{{{
SomeFunction(const sptr&) { ... }
...
sptr a = new BFoo
SomeFunction(a);
}}}

But that means you can not use it with objects retrieved from the package manager or another process; once you no longer have the BFoo concrete class, SomeFunction() is no longer available. That is generally a very extreme limitation to impose on a function, though if in some situation it makes sense there is no reason not to do it. 

== How do I store binder objects? ==

You can't use `sptr` because that doesn't provide object identity that is needed for comparisons. So we need to compare IBinder pointers, but you still want to use smart pointers, so use `sptr` and add the items as `item->AsBinder()`. If you are going to be making calls on the interface for these IBinder objects, you might also want to carry around a sptr to that interface so that you don't have to look it up every time:
{{{
#!cpp
SKeyedVector, sptr > vec;
}}}

Note that if you don't care about object identity (you won't be comparing pointers), you are better off just using a pointer to the interface
(such as `sptr`) that you are interested in.

== What are the different ways to use a binder object? ==

There are three ways:
 1. Local calls
 2. Remote calls - IPC (used to use scripting, but now more efficient) uses "!AutoBinder" with optimized marshalling code
 3. Scripting using IBinder - put/get/invoke. Notice that the scripting interface doesn't use the !BpClass at all. It calls directly on the binder (IBinder::Invoke, which if it is an !BpBinder calls invoke on !BnBinder, which translates into an Effect call on the !BnClass.)

== How do I get from a binder or value to Interface? ==

Use the following:
{{{
#!cpp
sptr v = interface_cast(b);
// deprecated but still widely used: IClass::AsInterface(b)
}}}

See [[DoxyFile(BinderInspect, Inspect)]] for more details.

== What is this interface_cast<>/AsInterface and AsBinder? ==

You have a class hierarchy (simplified) like so:
{{{
BView
 BnView
 IView
 BBinder
 IBinder
}}}

If you have an IView, but need the IBinder, you use `AsBinder()`. If you have a binder object, but need the interface, (or an alternative interface), then you use `interface_cast<>()` (or the old form, `AsInterface()`). Suppose you implement both IView and IWidget so that you have two interfaces, you would need to do something like:
{{{
#!cpp
sptr myWidget;
sptr asView(interface_cast(myWidget->AsBinder()));
// if you need to call Link (a method of BBinder)
asView->AsBinder()->Link(...);
}}}

Note that as long as you have a valid IInterface (for example the IView above), you are guaranteed that AsBinder() will return a valid object and do not need to check for NULL.

== Why do I see BnClass::AsBinder, IClass::AsBinder, and BClass::AsBinder? ==

Just going far enough up the tree to disambiguate the correct binder object wanted with multiple inheritance.

== If I hit bugs with wrong binders being used, what should I do? ==

Look for code like this:
{{{
#!cpp
return this->BnWidget::Link(to, mappings, flags);
}}}
ADS has a bug where the pointer additions don't happen correctly if this includes multiple inheritance. Use the following style instead.
{{{
#!cpp
return static_cast(this)->Link(to, mappings, flags);
}}}

== How do I convert my this pointer to the right interface? ==

If you have a raw pointer, for example the "this" pointer, it's just C++. So code like these are completely unnecessary:

{{{
#!cpp
sptr me = IView::AsInterface(this->IInterface::AsBinder())
}}}
or:
{{{
#!cpp
sptr me = IView::AsInterface(this->IView::AsBinder())
}}}

Write this instead:
{{{
#!cpp
sptr me = this;
}}}

= Binder Components =

== What is a component? ==

A Binder component corresponds closely to a C++ class. It is the implementation of Binder-based functionality, from which you can make instances as desired. Every Binder component implements one or more Binder interfaces.

You instantiate components by name. Unlike C++, Binder components are dynamically bound -- the system locates and loads the correct code at runtime from the name that is provided. You can ask the [http://www.openbinder.org/docs/html/BinderTerminology.html#ContextDefn Binder Context] (retrieved by calling [[DoxyClass(BBinder)]]'s `Context()` method) to create a component with {{{SContext::New()}}}.

== What is a service? ==
There are many parts of the system implemented as components that must be instantiated once and shared by all clients. These are generally referred to as services. After being instantiated with {{{SContext::New()}}}, these active objects are published in the [http://www.openbinder.org/docs/html/BinderTerminology.html#ContextDefn Binder Context] using {{{SContext::PublishService()}}}. You can find these objects using {{{SContext::LookupService()}}}.

(Note that `PublishService()` and `LookupService()` are simply synonyms for doing a normal publish or lookup within the `/services` tree of the context.)

== How is my component created? ==

`SContext::New()` or `SContext::RemoteNew()` calls the package manager which calls [[DoxyClass(IProcess)]]'s `InstantiateComponent()` to create the component. 

(To create a component in a different language (and therefore which is not implemented in compiled C++) there is a VM (virtual machine) attribute in the component Manifest XML. `New()` will instantiate the VM interface---which could be a Java VM or other runtime---and hand it information about which package needs to be instantiated; the VM is in charge of returning a Binder.)

== What is the difference between a component and a C++ object that derives from BBinder? ==

A component is included in a manifest file. You instantiate it through SContext::New() which goes through the package manager. You can also lookup an existing component by name. The component need not be implemented in C++.

A C++ object (which could be derived from BBinder) is created with "new" and just directly creates the object. This doesn't require any facilities except the C++ runtime and BBinder in libbinder.

== What do I need to do to create a component? ==

 1. Select an existing interface (or write a new one in IDL).
 2. Write the implementation
 3. Name the implementation class in the manifest.xml file
 4. Write (or add to) an !InstantiateComponent. !InstantiateComponent is passed the "suffix" after the package name, so the name for the component corresponding to the package itself is just "".

(For a complete example, see [source:/depot/openbinder/main/samples/SampleComponent].)

== Why do some implementations of InstantiateComponent use a static cast, and others don't? ==
Some classes, such as XXX, derive from multiple IBinder interfaces. These classes need to use a static cast disambiguate ''which'' IBinder to return as the result of the function. If there is only 1 ancestral IBinder, then no static cast is needed and you can directly return the result of the call to new.

== How do I list all the components from the shell? ==

{{{
ls packages/components
}}}

== How do I instantiate a component in the Binder Shell? ==

Use the `new` command. The first argument is the full name of a
component; the optional second argument is an [[DoxyClass(SValue)]] to be passed to
the component's constructor. The return value of the
`new` command is a Binder, which you can store in a variable or pass to
another command or method invocation. Example:

{{{
MyView=$[new palmos.kits.widgets.RadioButtonTestView]
invoke /services/window AddView $MyView
}}}

`new` corresponds to `SContext::New()`, and
`new -t` is equivalent to `SContext::RemoteNew()`; see [wiki:BinderFAQ#Whatisacomponent What is a component?].


== What is new -p (in the Binder Shell) ==

Objects get published into directories with Publish call. "new -p" is shorthand for new and then publish.
You will usually want to publish under /services, so that others will be able to
find it with {{{SContext::LookupService()}}}; see [wiki:BinderFAQ#Whatisaservice What is a service?].

== I want to create a Person interface, what do I do? ==

I write IPerson.idl. The tool chain looks like:
{{{
IPerson.idl -> Pidgen -> IPerson.h + IPerson.cpp
}}}
 
IPerson.h defines IPerson and !BnPerson

IPerson.cpp implements !BnPerson and !BpPerson. !BnPerson translates Transact into calls to Person. !BpPerson bundles up calls to transmit across IPC. (The Bn signifies native, and Bp signifies proxy.)

To write my code, I write class Person : public !BnPerson
Local calls are just virtual calls to !SetName.

Detailed information on pidgen is at [http://www.openbinder.org/docs/html/pidgen.html].

== What is SPackageSptr? ==

An [[DoxyClass(SPackageSptr)]] is a strong pointer (`sptr`) to your .so's [[DoxyClass(SPackage)]] so that it isn't unloaded until last reference goes away. Constructor is in [source:/depot/openbinder/main/libraries/libbinder_glue/binder_glue.cpp]. Once a class derives from `SPackageSptr`, then any classes derived from that do not have to (if they are in the same .so). If you have a class in a public header, often just have `SPackageSptr` as a member variable.

= Binder Links =

== What is the data flow model? ==

Properties between binder objects can be linked so that when a property in binder1 is changed, a Put is called on a property in binder2. In C++ implementations, this means that when binder1 pushes property foo, binder2->SetFoo() will be called. Pidgen generates some helper methods for you, but the implementations are in charge of pushing changes to their properties and in setting up any desired links.

Suppose you have an interface that contains a text property.

{{{
#!cpp
interface ITextData {
properties: 
 SString text; 
}
}}}

Because you have a text property, Pidgen will generate two pure virtual methods:
{{{
#!cpp
 virtual void SetText(const SString& value) = 0;
 virtual SString Text() = 0;
}}}

As you implement SetText, you will want to push the property when it is changed. You could do this like so:
{{{
#!cpp

TextData::SetText(const SString& value) 
{
 if (m_text != text) {
 m_text = text;
 PushText(text);
 }
}
}}}

`PushText()` is a helper method automatically generated by Pidgen. It checks if a link exists and if so, calls through to `Push()`. In this case, it would result in: `Push("text", m_text)`. Notice that the text is only pushed when it is actually changed. Pushing unchanged properties is considered bad form.

Now you want to display an ITextData in a view, so you create a text viewer interface:
{{{
#!cpp
interface ITextViewer {
properties:
 SString contents;
methods:
 void Invalidate();
}
}}}

When you go to display the text, you get the text from the ITextData and display it. However, you want to know when others change the data so you can update your display. This is when you would set up a link.

You would set up a link like so:
{{{
#!cpp
 textdata->Link(viewer, SValue(SValue::String("text"), SValue::String("contents"));
}}}

This says that when the "text" property is pushed by the textdata object, that the "contents" property will be put on the viewer. In C++ terms, SetContents() will be called.

The implementor of an ITextViewer does the following:
{{{
#!cpp

TextViewer::SetContents(const SString& newContents)
{
 m_contents = newContents;
 Invalidate();
}
}}}

Now when anyone changes the textdata, the TextViewer will be notified, Invalidate() will be called, and the new text will be displayed in the viewer.

Notice that SetContents() can't tell who updated the text. If needed, this could be added with an event/method link.

== What are events? ==

Events are a second type of linking. The convention is that properties link to properties and events link to methods. Events are really syntactic surgar and convention, but they also codify what is pushed from an interface.

Events are described in IDL with a syntax that looks like a method:
{{{
#!cpp
events:
 void EntryCreated(INode who, SString name, IBinder entry);
}}} 

An implementation would then call the pidgen generated helper method `PushEntryCreated` when they wanted to push that event.

Objects who are interested would set up a method with the signature of the event. When the event is pushed, their method will be called with those parameters.

The link would be set up like this:

{{{
#!cpp
 aNode->Link(aViewer, SValue(SValue::String("EntryCreated"),
 SValue::String("HandleEntryCreated"));
}}}

This specifies `HandleEntryCreated` as the name of the method that gets called when the `EntryCreated` event is pushed.

== What are the key methods for data flow? ==

Set up with Link(). Pidgen generates a helper method for each interface named `Link()`.
Trigger data flow with Push(). Pidgen generates a helper method for each property named `Push()`. Normally you would call the helper method. The implementation will then go through and see if there are any linked objects and call put on that object.

On the observer side, a common idiom to use is to inherit from [[DoxyClass(BObserver)]]. This gives you a single hook function `Observed()` to handle all the properties/events you are linked to. Using `BObserver`, you don't need an interface property or method, you can just specify a key in the link binding to be used in the call to `Observed()`.

== What are the link flags? ==
 
 * `B_NO_TRANSLATE_LINK` - don't translate the value
 * `B_WEAK_BINDER_LINK` - use a `wptr<>` rather than a `sptr<>` to the target of the link
 * `B_SYNC_BINDER_LINK` - the link is pushed synchronously.

Normally the value that is pushed is put on the linked property. `B_NO_TRANSLATE_LINK` can be used when you don't care about the value, just the event/property change.
{{{
#!cpp
 binder1->Link(binder2, {"a"->"b"->50}, NO_TRANSLATE)
 binder1->Push({"a"->100}) ---> binder2.Effect({"b"->50}) // 100 is ignored
}}}

Normally when a property or event is being pushed, the push is performed asynchronously -- it is dispatched to another thread, allowing the caller to return while the new thread takes care of calling all the targets. You can use `B_SYNC_BINDER_LINK` to avoid this asynchronicity, having your object called directly from Push(). You must be very careful when using this to avoid acquiring locks in a way that may cause deadlocks.

== Why isn't Push called automatically in property put implementation? ==

Because it really is implementation dependent. Perhaps the set function ignores the value. Also, you can call the set function directly.

== Why is my Push not seeming to do anything? ==

Is the [[DoxyClass(SValue)]] you are pushing mapping to undefined accidentally? Print the SValue participating in the push.

= Binder Threading =

== How do I create new threads? ==

[[DoxyClass(BHandler)]], [[DoxyClass(SMessage)]] - handle the threading, so that you never need to create a thread for this type of thing, just create a BHandler and feed it SMessages. See [http://www.openbinder.org/docs/html/SHandlerPatterns.html SHandler Patterns] for examples.

== What is the object threading model? ==

Threads are not bound to objects. The Binder has a thread pool from it dispatches threads to objects as needed, and calls between objects are executed as direct function calls from the calling thread. In COM terms, you would say the Binder is free-threaded. As such, you generally must assume that your public API is completely multi-threaded and perform any locking of your state as needed. However, you are guaranteed that only one thread will be executing in your object during its constructor, destructor, and InitAtom() method.

In general our approach to thread safety is "fine-grained locking". Locking is never exposed outside of the implementation; each class has its own lock for its state, which it acquires when accessing that state and ensures it is not holding the lock any time it makes a call outside of its own implementation. Because you never call outside with a lock held, you can not cause deadlocks.

You can avoid acquiring a lock if the operation you are protecting is atomic -- which for a variable of 32 bits or smaller, should always be the case for a read. For writes, variables of exactly 32 bits will be atomic; others are not, because the variable may be packed with other members.

See [http://www.openbinder.org/docs/html/BinderThreading.html Threading Conventions] for more information.

= Binder Implementation Details =

== How is a BpPerson created? ==
First, you really don't care. But if you just need to know how things work internally:
{{{
process A:
 RemoteNew(IPerson, procB)
process B:
 Instantiates a new Person, returns the Binder associated with it to process A
process A:
 Gets the binder returned from Process B, does an AsInterface
 AsInterface - hey, I don't have the C++ class, so I'll create an BpPerson
}}}

By the way, when archiving binder objects into a parcel, if the binder is local, the pointer is stored, if the binder is remote, then m_handle is stored. (I think m_handle is a kernel object for the remote binder passable through IPC.)
{{{
#!cpp
if (!local) {
 BpBinder *proxy = binder->RemoteBinder();
 const int32_t handle = proxy->Handle();
}
}}}

== What is the code path for remote/scripting calls? ==

For remote procedure calls, !AutoBinder is used...
{{{
BpClass::Method
 Remote()->AutobinderInvoke(...)
 Class_invoke_Method_auto_hook
 autobinder_from_parcel
 this->Method(...)
}}}

For script call to invoke, get, put (or Link to property/method)...
{{{
Effect
 BnClass::HandleEffect
 Class_invoke_Method
}}} 

== What do AsBinder and AsInterface really do? ==

 * {{{AsBinder}}} returns a pointer to the {{{IBinder}}} associated with the interface. 
 * {{{AsInterface}}} returns a pointer to the IInterface for the desired interface descriptor, and will create a proxy (see [source:/depot/openbinder/main/libraries/libbinder/support/Binder.cpp] for details) if the local object does not have the C++ interface (for example if it is in a remote process or another language). 

But {{{AsInterface}}} can be much more complex in case of multiple {{{IBinders}}}. For example, 
{{{
#!cpp
BViewLayout : public BView, public BnViewCollection
}}}
!AsInterface calls Inspect, which will return all interfaces. ie:
{{{
{"palmos.view.IView" -> IBinder_a, "palmos.view.IViewManager" -> IBinder_b}
}}}
Then {{{AsInterface}}} will look up the corresponding {{{IBinder}}} based on key.

Be careful about the use of "interface" here: a Binder interface (also called an
interface descriptor) is identified by a string using Java-style naming
conventions (like {{{palmos.view.IViewManager}}} above). Pidgen generates a C++
representation of this interface for easy use in C++. However, that C++
representation may not be available even if the object itself implements
the interface descriptor (for the reasons mentioned above, the object being
remote or in another language), in which case we must create a C++ proxy of
the interface ({{{BpViewManager}}}) that converts C++ method calls into low-level
Binder operations (get, put, invoke).

== How does a call on IApplication::Start turn into a shell function Start()? ==

For example, calling IApplication::Start can turn into the binder interpreting the code for a start method like so:
{{{
INTERFACE=@{palmos.app.IApplication->$SELF}
function Start()
{
 # Create the calculator
 obj=$[new com.palmsource.test.BRD.View]
 ...
}
function Stop()
{
}
}}}

The binder shell is set up in the manifest like this...
{{{

 vm="org.openbinder.tools.BinderShell.VM"
 restype="[shel]"
 resid="1000">
}}}

In C++ code we create the IApplication object and ask for the IApplication interface
{{{
#!cpp
sptr b = context->New("application");
sptr app = IApplication::AsInterface(b);
}}}
This calls inspect and looks for the C++ implementation. When it can't find the c++ implementation, it creates an !BpApplication, which will then turn all the calls into scripting calls that are passed over to the Binder Shell. The Binder Shell can then do a lookup, and interprete the approprate code based on the name of the call coming in.

= Interfaces, IDL and marshalling =

== Does an IDL reference document exist? ==

Yes, see the [http://openbinder.org/docs/html/pidgen.html Pidgen] section of the [http://openbinder.org/docs/html/index.html online documentation].

== Can I should pass a C++ structure or class in an interface? ==

You can pass a C++ class if you define a constructor taking an SValue, and an AsValue method. For example:
{{{
 SValue AsValue();
 BFont BFont(SValue o);
}}}
(see Font.idl and Font.h/Font.cpp for an example of doing this for the font_height type.)

== Is there a way for a component to define a custom marshalling implementation? ==

Hopefully you don't need to do custom marshalling, but yes, you can do your own marshalling if you want. If you find a reason that you think you need to write custom marshalling, please talk to John. For example, the IRender interface has its own custom marshalling code for improved performance. (But you don't want to use that one as an example, because it brings along a lot of "gotcha's".)

= Components =

== Is there a way to implement a singleton so that always the same instance of a component is returned when I call the Binder new method? ==

No, but you can implement a singleton by doing a LookupService, followed by a new + Publish if not found. There will also probably be some higher-level features for this introduced in Rome (called Daemons).

== How do I find a specific component instance from the Binder? Is the singleton model the only way? ==

Use LookupService. The Binder is based on a capability model—that is, you can't know about an object unless someone explicitly gives you access to it. Most of the Binder objects created have very limited access, for example a view that is only seen by its parent. For more general access one usually accomplishes this by publishing in the namespace.

== How to handle component persistence? Is there a standard interface to implement or do I need to define my own persistence scheme? ==

Nothing is currently defined. When we find we need to, we can do so.

== Each class must have a unique identifier so that I can instantiate the right component when I read from a persistent storage. Which identifier should I use? ==

The component name. It is the same as the interface GUID in COM.

== How to dynamically discover components capabilities, such as supported interfaces? Should I try multiple interface cast and check the resulting pointers, or is there a standard RTTI mechanism? ==

The standard usage is to know the capabilities of the binder object you are dealing with. However, you can use {{{Inspect()}}} to find all interfaces. An alternative is to do an interface_cast and check the result if needed. Inspect() is basically the equivalent to !QueryInterface() on COM. There is currently no way to discover the capabilities (properties, methods, events) of a particular interface at run time, as we have not yet had a strong need for it.

== What are the recommendations when I want to add functionalities to an existing component? Extend the interface, or add a new interface? ==

Depends on what you are adding. If you are adding an orthogonal capability, you should add a new interface. If you are enhancing a capability, then extend the existing interface. Please notice that when we go public with the APIs, we will have some ability to extend, but not unlimited. We are generally leaning towards the COM approach of versioning—fixed interfaces, and extending through the introduction of new interfaces.

== Is there a standard versioning scheme that applies when a component evolves? (I am thinking about persistence issues also) ==

Yes, in the manifest you can specify the version of a component. When there are multiple components with the same name, the system picks the one with the highest version.

== When long operations occur, how to notify the client about the processing progress and, eventually, cancel the operation? ==

Implement [[DoxyClass(IProgress)]], and pass the [[DoxyClass(IProgress)]] to the operation.

== Is there a standard way to handle notifications / callbacks between components? ==

Links in general, and [[DoxyClass(BObserver)]] specifically. (See Link section.) An interface can declare events that are generated from it and other can link with. There is also a higher-level service called the Informant for performing notifications between servers and clients that are do not directly know about each other.
Binder context / namespace

== My object implements two interfaces, IFoo and IBar, why doesn't interface_cast (AsInterface) work? ==

Your implementation must override Inspect, and then call Inspect for each IBinder base class.

= Binder context / namespace =

== Is there a formal document describing the Binder namespace tree hierarchy so I can plug information at the right place? ==

We have not yet formalized where things go in the namespace.

== What is BCatalogMirror and ICatalogPermissions ==

They are the foundation for multiple contexts. A catalog mirror combines an ICatalogPermissions with an ICatalog. Essentially it is a surrogate for a catalog with the following potential changes.
 1. The catalog can be made read-only
 2. Entries can be hidden
 3. Entries can be overridden
For example, the {{{services/surface}}} object normally is an {{{ISurface}}}, but we override that entry in the user services catalog by publishing it as an {{{IPlane}}}. Here is an example of a simple text entry wher contexts/user is a BCatalogMirror for the root catalog.
{{{
$ lookup who_am_i
Result: "System Context"
$ lookup contexts/user/who_am_i
Result: "User Context"
}}}

== How to address security issues within the namespace? ==

For instance I want a particular value be updated only by my application. Or accessing a particular node requires a user interaction, such as providing a login and password.

Limited security with the system and user context. However, you can hide interfaces in a binder object so that only your application can get to an interface. For example, the window manager only publishes the ISurface interface, and not the IWindowManager interface. Another way of solving the security issue is to not publish the component. We need to add more here.
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics