Overview

The BrowserPlus ServiceAPI allows you to write native plugins that can be loaded by BrowserPlus. These plugins (or "services") are primarily designed to expose a scriptable interface to Javascript running in a web browser.

A service consists of a directory which contains a single required file, manifest.json, which is json text that points to the shared library (.dll or .so) that implements the service. The manifest.json also includes other information, such as localized end-user visible strings identifying at a high level what the service does, and any explicit permissions that should be requested from the user. Here is a sample manifest file for a service that displays desktop notifications:

{
  "type": "standalone",
  "ServiceLibrary": "notify.dll",
  "strings": {
    "en": {
      "title": "Notify",
      "summary": "A service to deliver desktop notifications."
    }
  },
  "permissions": [
    "DisplayNotifications"  
  ]
}

The other entities in the service's directory are the dynamic library itself, and whatever else the service author wishes to include.

Overview

As this API allows for native services to be authored, the first question that may arise is how do we support multiple platforms? At the time services are published, they may be marked platform specific, or platform independent. To support multiple platforms, the only requirement is that the same service with the same version exports the same API. It is up to the service author whether and how they wish to share code between implementations.

Finally, because services may be written in high level languages (Ruby and Python are two languages supported today), it is possible to implement a service as Ruby on one platform, and native code on another.

File Overview

The ServiceAPI is a header only SDK. No libraries are required.

These C header files compose the lowest level "ServiceAPI", however it is worth noting that several libraries and frameworks exist which simplify the process of writing a service. These frameworks can be found on github at http://github.com/browserplus

Design Requirements

The design of the BrowserPlus ServiceAPI was motivated by the following goals:

  1. It must be possible to dynamically map a services interface into a high level laguage (usually JavaScript).
  2. non-responsive services should not render the whole system non-responsive.
  3. The entire interface should be asynchronous to prevent unresponsiveness.
  4. Complex return values from services must be supported.
  5. The data representation must allow serialization into different formats, and must be bindable into different languages.
  6. The API should not preclude cross platform services.
  7. The API should be flexible enough to allow for interpreter services to be authored, which allows for the authoring of other services in high level languages.
  8. The API should be designed with versioning and binary compatibility in mind. A version of a service may be in production for a Long Time.

Service Types

There are three different types of services, this type is specified in the service manifest (manifest.json)

  1. 'standalone' - Binary services implemented as a shared library
  2. 'provider' - Binary services implemented as a shared library that can run 'dependent' services
  3. 'dependent' - Services (not necessarily binary) that require the existence of another service to function.

Symbol Spelunking

Exactly one symbol is the contract between services and BrowserPlusCore. This symbol is "BPPGetEntryPoints", a symbol that returns a function which takes no arguments and returns a structure. The first member of that structure is a 32bit integer which holds the service api version against which the service was written. All function pointers from service to BrowserPlus or vice versa are passed in structures, which means that no import libraries are required, and only one symbol must be exported from a service.

Service Loading Procedure

BPP* functions are provided by the service and are called by BPCore. The service loading procedure is thus:

  1. The dynamic library is loaded.
  2. The "BPPGetEntryPoint" symbol is extracted and called to get a BPPFunctionTable pointer. This table contains the version of the service API to which the service was written.
  3. if the service hasn't been loaded since it was installed, BPInstall() will be invoked.
  4. BPPInitialize() is called which passes control to the service to attain a description of the supported functions and deliver a function table which may be used to call back into BrowserPlus.
  5. BPPAllocate may be invoked any number of times.
  6. BPPInvokePtr may be called from the "main" thread on different allocated instances of the service.
  7. BPPDestroy will be called once per allocated instance.
  8. BPPShutdown will be called after the last BPPDestroy call.
  9. if the service is going to be removed after unload, BPUninstall() will be invoked.
  10. the service library will be unloaded from memory
  11. the hosting process will shut down.

Memory Management

Anything that the service allocates, the service must free. Anything that BrowserPlus allocates, BrowserPlus must free. All pointers passed into a function traveling either direction are valid only for the duration of the function, the caller may free immediately after the function returns.

Threading Model

The threading model for services is intended to minimize complexity and maximize flexibility, leaving as much up to the service author as possible. All functions invoked by BrowserPlus on the service will be invoked from the "main" or "primordeal" thread of execution. On platforms where pertinent, there will be a OS provided "runloop" running on this thread (a Cocoa runloop or a Win32 message pump).

The service may allocate and run as many threads as it likes, and may call into BrowserPlus on any of them.

Defining your service

After loading a service, BrowserPlus will want to know what functions the service supports and what arguments those functions accept, and the name and version of the service, etc. All of this information is conveyed through C structures documented in bpdefinition.h.

Data Binding

A main purpose of services is usually to get data back to the execution environment that invoked the service. Before crossing the service <-> BrowserPlus boundary, data must be mapped into an intermediate format. Our solution to this problem is very similar to that of NPAPI. bptypes.h defines a set of structures capable of holding all of the different data types we support.

Working with the structures directly is supported, but leads to complex code. As mentioned above, there are ongoing efforts to develop service frameworks to simplify the authoring of native services, especially in the area of data binding. All pertinent projects are available on github: http://github.com/browserplus

File System Paths

Paths in the system are passed around as operating system native paths. That is, on unix, all paths are forward slash delimited, UTF8. On windows, paths are windows style UTF16.

In bptypes.h, the pertinent type is BPNativePath where you'll see that the type is either a wchar_t * or a char * -- depending on the platform.

Provider Services

A "provider" service is one that can be required by a "dependent" service. This mechanism minimally affects the authors of "standalone" services while making it possible to enable services written in high level languages. Finally, while the design motivation for this mechanism was to support interpreter services, it's conceivable that it could be applied to other use cases.

A provider service will be loaded any time a dependent service that requires it is loaded. At the time BPPInitialize() is called on the provider service, the path to the dependent service will be provided, and also any content in the manifest.json of the dependent service under the 'arguments' key will be parsed and passed into the provider. This mechanism allows the dependent service to provide arguments to the provider, and leaves the decision of the structure and content of those arguments up to the implementor of the provider service.


Generated by  doxygen 1.6.2