Develop and Configure

Version added 07-Mar-2018| Modified 24-Jun-2018

To create a native service, you must define the source code and define the required configuration files.

For easier understanding, the process to create a native service is explained using the example of a service named "com.example.service.native" that has method named "hello" that responds with the string "Hello, Native Service!!".

The directory structure of com.example.service.native must be as follows:

com.example.service.native
├── CMakeLists.txt
├── README.md
├── files
│   ├── sysbus
│   │   ├── com.example.service.native.api.json
│   │   ├── com.example.service.native.perm.json
│   │   ├── com.example.service.native.role.json.in
│   │   └── com.example.service.native.service.in
│   └── systemd
│       └── com.example.service.native.service.in
├── main.cpp

 

Setup Development Environment

Before starting development, you must do the following:

  1. Clone the build-webos repository.

    $ git clone https://github.com/webosose/build-webos.git
  2. Install all required components (on Ubuntu).

    $ sudo scripts/prerequisites.sh
  3. Configure the build.

    $ ./mcf -p 0 -b 0 raspberrypi3
  4. Build the webOS image.

    $ source oe-init-build-env  
    $ bitbake webos-image 

This is only a list of the main steps. For detailed information, see Building webOS OSE and Flashing webOS OSE.

 

Define Source Code

Define the functionality of the native service.

For the sample native service (com.example.native.service), you must:

  • Create and update the file : main.cpp

  • Directory : com.example.service.native 

#include <glib.h>
#include <string>
#include <luna-service2/lunaservice.h>

static bool cbHello(LSHandle *sh, LSMessage* message, void* ctx)
{
    std::string answer = "{\"returnValue\": true, \"answer\": \"Hello, Native Service!!\"}";
    LSError lserror;

    if (!LSMessageReply(sh, message, answer.c_str(), &lserror))
    {
        g_print("Message reply error!!\n");
        LSErrorPrint(&lserror, stdout);

        return false;
    }
    return true;
}

static LSMethod serviceMethods[] = {
    { "hello", cbHello }
};

int main(int argc, char* argv[])
{
    g_print("Start com.example.service.native\n");

    LSError lserror;
    LSErrorInit(&lserror);

    GMainLoop* mainLoop = g_main_loop_new(nullptr, false);
    LSHandle *m_handle = nullptr;   

    if(!LSRegister("com.example.service.native", &m_handle, &lserror))
    {
        g_print("Unable to register to luna-bus\n");
        LSErrorPrint(&lserror, stdout);

        return false;
    }

    if (!LSRegisterCategory(m_handle, "/", serviceMethods, NULL, NULL, &lserror))
    {
        g_print("Unable to register category and method\n");
        LSErrorPrint(&lserror, stdout);

        return false;
    }

    if(!LSGmainAttach(m_handle, mainLoop, &lserror))
    {
        g_print("Unable to attach service\n");
        LSErrorPrint(&lserror, stdout);

        return false;
    }

    g_main_loop_run(mainLoop);

    if(!LSUnregister(m_handle, &lserror))
    {
        g_print("Unable to unregister service\n");
        LSErrorPrint(&lserror, stdout);

        return false;
    }

    g_main_loop_unref(mainLoop);
    mainLoop = nullptr;

    return 0;
}

A brief explanation of the above file:

  • Line(3) : Include a header file to use LS2.

  • Line(5~18) : Implement the cbHello callback function when com.example.service.native/hello is called. The third argument of LSMessageReply() should be in json format.

  • Line(20~22) : Register the hello method and cbHello callback function in the LSMethod array.

  • Line(28~29) : Declare and initialize LSError.

  • Line(31~32) : Declare GMainLoop and LSHandle variables.

  • Line(34) : Register com.example.service.native service using LSRegister().

  • Line(42) : Register the hello method and the callback function in LSHandle(m_handle).

  • Line(50) : Attach com.example.service.native service to GMainLoop.

  • Line(58) : Run an iteration loop.

  • Line(60) : After stopping the iteration loop, unregister the service.

  • Line(68~69) : Release GMainLoop.

 

'README.md' File

This file provides general information of the native service.

For the sample native service (com.example.native.service), you must:

  • Create and update the file : README.md 

  • Directory : com.example.service.native 

Non-availability of the README.md file can result in an error at build time.
Make sure the 'Summary' subsection is a single line. Even a blankspace before the 'Description' section is considered a part of the summary and can cause the build to fail. 
Here is a snippet of the README.md file that shows the blankspace that can cause the error:

Summary
-------
native service sample
(no blankspace)
Description
-----------
Summary
-------
native service sample

Description
-----------
native service sample

How to Build on Linux
---------------------

## Dependencies

Below are the tools and libraries (and their minimum versions) required to build sample program:

* cmake (version required by cmake-modules-webos)
* gcc
* glib-2.0
* make
* cmake-modules-webos

## Building

    $ cd build-webos
    $ source oe-init-build-env
    $ bitbake com.example.service.native

Copyright and License Information
=================================
Unless otherwise specified, all content, including all source code files and
documentation files in this repository are:
 
Copyright (c) 2018 LG Electronics, Inc.
 
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
 
http://www.apache.org/licenses/LICENSE-2.0
 
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
 
SPDX-License-Identifier: Apache-2.0

 

LS2 Configuration Files

The list of configurations files required for the LS2 bus.

 

Service Configuration File

This file contains description of the service type and launch command.

  • Create and update the file : <native-service-name>.service.in

  • Directory : <native-service-name>/files/sysbus

where <native-service-name> is the name of the native service. For the sample native service, <native-service-name> to be replaced by 'com.example.service.native'.

[D-BUS Service]
Name=com.example.service.native
Exec=@WEBOS_INSTALL_SBINDIR@/com.example.service.native
Type=static

A brief explanation of the above file:

  • Line(1) : Write [D-BUS Service] on the first line. 

  • Line(2) : Set com.example.service.native to service name.

  • Line(3) : Write the full path of the executable file. @WEBOS_INSTALL_SBINDIR@ stands for '/usr/sbin' directory.

  • Line(4) : Type can be set to 'static' and 'dynamic'. In this example, it is set as static service.

 

Role File

This file contains allowed service names for each component and inidivdual security settings for each service name.

  • Create and update the file : <native-service-name>.role.json.in

  • Directory : <native-service-name>/files/sysbus

where <native-service-name> is the name of the native service. For the sample native service, <native-service-name> to be replaced by 'com.example.service.native'.

{
    "exeName":"@WEBOS_INSTALL_SBINDIR@/com.example.service.native",
    "type": "regular",
    "allowedNames": ["com.example.service.native"],
    "permissions": [
        {
            "service":"com.example.service.native",
            "outbound":[
                "*"
            ]
        }
    ]
}

A brief explanation of the above file:

  • Line(2) : exeName - Specifies the full path to the binary for a native service. Must be of the form: /path/to/binary 

  • Line(3) : type - Indicates whether the app is privileged (can change its role) or regular. Possible values are privileged or regular.

  • Line(4) : allowedNames - Names that this service is allowed to register. It can be an array of any valid service name strings, empty array [] for none, and empty string "" for an unnamed service.

  • Line(5-12) : The permissions for the service.

    • outbound - Array of services that this service is allowed to send to. It can be any valid service names strings, "*" for all, empty array [] for none, and empty string "" for unnamed services.

 

Client Permission File

This file defines what groups are required for this component to function properly. In this example, the service is set to "public" to give it permission to call the public methods.

  • Create and update the file : <native-service-name>.perm.json

  • Directory : <native-service-name>/files/sysbus

where <native-service-name> is the name of the native service. For the sample native service, <native-service-name> to be replaced by 'com.example.service.native'.

{
    "com.example.service.native": [
        "public"
    ]
}

 

API Permission File

This file defines what methods are included into security groups this component provides. In this example, the hello method is included the "public" group.

  • Create and update the file : <native-service-name>.api.json

  • Directory : <native-service-name>/files/sysbus

where <native-service-name> is the name of the native service. For the sample native service, <native-service-name> to be replaced by 'com.example.service.native'.

{
    "public": [
        "com.example.service.native/hello"
    ]
}

 

Systemd Configuration File

This file is required to run the services provided by systemd.

  • Create and update the file : <native-service-name>.service.in

  • Directory : <native-service-name>/files/systemd

where <native-service-name> is the name of the native service. For the sample native service, <native-service-name> to be replaced by 'com.example.service.native'.

This file will be installed to target as com.example.service.native.service.

Normally, this config file is in webos-initscripts. However, for ease-of-use we have defined it in the local source directory.
[Unit]
Description=webos - "%n"
Requires=ls-hubd.service
After=ls-hubd.service
 
[Service]
Type=simple
OOMScoreAdjust=-500
EnvironmentFile=-/var/systemd/system/env/com.example.service.native.env
Environment=CHARSET=UTF-8
ExecStart=/usr/sbin/com.example.service.native
Restart=on-failure

A brief explanation of the above file:

  • Line(3) : Describe the dependency of service execution. If the dependent unit is normal, the unit is started. The example allows the ls-hubd.service unit to run and then run the service.

  • Line(11) : Set the path to the executable file.

Please see systemd official site for more details.

 

'CMakeLists.txt' File

This file is required to build the source code using CMake.

For the sample native service (com.example.native.service), you must:

  • Create and update the file : CMakeLists.txt

  • Directory : com.example.service.native

cmake_minimum_required(VERSION 2.8.7)
project(com.example.service.native CXX)
set(CMAKE_BUILD_TYPE Debug)
 
include(webOS/webOS)
webos_modules_init(1 6 3)
webos_component(0 0 1)
 
include(FindPkgConfig)
 
pkg_check_modules(GLIB2 REQUIRED glib-2.0)
include_directories(${GLIB2_INCLUDE_DIRS})
webos_add_compiler_flags(ALL ${GLIB2_CFLAGS_OTHER})
 
pkg_check_modules(LUNASERVICE2 REQUIRED luna-service2)
include_directories(${LUNASERVICE2_INCLUDE_DIRS})
webos_add_compiler_flags(ALL ${LUNASERVICE2_CFLAGS_OTHER})
 
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(SRCS main.cpp)
 
add_executable(${PROJECT_NAME} ${SRCS})
 
SET (EXT_LIBS
    ${GLIB2_LDFLAGS}
    ${LUNASERVICE2_LDFLAGS}
)
 
target_link_libraries(${PROJECT_NAME} ${EXT_LIBS})
 
install(TARGETS ${PROJECT_NAME} DESTINATION ${WEBOS_INSTALL_SBINDIR})
 
webos_build_system_bus_files()
webos_build_configured_file(files/systemd/com.example.service.native.service SYSCONFDIR systemd/system)

A brief explanation of the above file:

  • Line(2) : Specify the project name and the file extension type. In this tutorial, we use "com.example.service.native" as the project name for indicating various filenames and pathnames. The file extension type allows CMake to skip unnecessary compiler checks.

  • Line(5) : Include webOS OSE modules for the build.

  • Line(6) : Specify the "cmake-modules-webos" version.

  • Line(7) : Specify "webos_component" with the component version to use webOS variables for the standard system paths. It commonly follows three digit versioning scheme.

  • Line(9~29) : Add GLib and LS2 dependencies, and add options to use C++11.

    • Line(20) : Set SRCS variable as main.cpp.

    • Line(22) : Specify the command to build more than one project.

  • Line(31) : Installs the executable in /usr/sbin.

  • Line(33) : Installs the LS2 configuration files (/files/sysbus) to target.

  • Line(34) : Installs the systemd configuration file on target (etc/systemd/system).

Except as noted, this content is licensed under Creative Commons Attribution 4.0 and sample code is licensed under Apache License 2.0.