X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=docs%2F3_Developer_Guides%2F2_Creating_a_New_Service.md;h=7974d002d2fe27e63cd8edfa967808c62af81df6;hb=c72bd577eb1fec884f27f01f3e76875202716e0f;hp=bbaa6092151db2257ec6ee7202c67ea561de93f7;hpb=73d87cf88c657b4f7411d79b3ec9acc742f1ebef;p=AGL%2Fdocumentation.git diff --git a/docs/3_Developer_Guides/2_Creating_a_New_Service.md b/docs/3_Developer_Guides/2_Creating_a_New_Service.md index bbaa609..7974d00 100644 --- a/docs/3_Developer_Guides/2_Creating_a_New_Service.md +++ b/docs/3_Developer_Guides/2_Creating_a_New_Service.md @@ -2,470 +2,144 @@ title: Creating a New Service --- -This tutorial provides instructions on **Creating a New Service** from scratch. - -### 1. Create new project development directory - - ```sh - $ cd ~/agl-app - $ mkdir newservice/ - $ cd newservice/ - ``` - -### 2. Source the SDK environment setup - - ```sh - $ source ~/agl-app/agl-sdk/environment-setup-corei7-64-agl-linux - ``` - -### 3. Copy initial CMAKE configuration templates - - ```sh - $ mkdir -p conf.d/cmake - $ cp ${OECORE_NATIVE_SYSROOT}/usr/share/doc/CMakeAfbTemplates/samples.d/config.cmake.sample conf.d/cmake/config.cmake - $ cp ${OECORE_NATIVE_SYSROOT}/usr/share/doc/CMakeAfbTemplates/samples.d/CMakeLists.txt.sample CMakeLists.txt - ``` - -### 4. Edit CMAKE configuration template - - ```sh - $ vim ~/agl-app/newservice/conf.d/cmake/config.cmake - - ########################################################################### - # Copyright 2020 # INSERT YEAR - # - # author: John Doe # INSERT AUTHOR DETAILS - # - # 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. - ########################################################################### - - # Project Info - # ------------------ - set(PROJECT_NAME hellocount) # INSERT NEW PROJECT NAME - set(API_NAME hellocount) #INSERT NEW API NAME - set(PROJECT_PRETTY_NAME "Example") - set(PROJECT_DESCRIPTION "AGL hellocount application example") # INSERT CONCISE PROJECT DESCRIPTION - set(PROJECT_URL "https://gerrit.automotivelinux.org/gerrit/apps/cmake-apps-module") - set(PROJECT_ICON "icon.png") - set(PROJECT_AUTHOR "John Doe") # INSERT AUTHOR NAME - set(PROJECT_AUTHOR_MAIL "john.doe@example.com") # INSERT AUTHOR EMAIL - set(PROJECT_LICENSE "APL2.0") - set(PROJECT_LANGUAGES "C") - set(PROJECT_VERSION "1.0.0") # INSERT PROJECT VERSION - - # Which directories inspect to find CMakeLists.txt target files - # set(PROJECT_SRC_DIR_PATTERN "*") - - # Where are stored the project configuration files - # relative to the root project directory - set(PROJECT_CMAKE_CONF_DIR "conf.d") - - # Compilation Mode (DEBUG, RELEASE, COVERAGE or PROFILING) - # ---------------------------------- - set(BUILD_TYPE "RELEASE") # SELECT BUILD TYPE - #set(USE_EFENCE 1) - - # Kernel selection if needed. You can choose between a - # mandatory version to impose a minimal version. - # Or check Kernel minimal version and just print a Warning - # about missing features and define a preprocessor variable - # to be used as preprocessor condition in code to disable - # incompatibles features. Preprocessor define is named - # KERNEL_MINIMAL_VERSION_OK. - # - # NOTE*** FOR NOW IT CHECKS KERNEL Yocto environment and - # Yocto SDK Kernel version. - # ----------------------------------------------- - #set (kernel_mandatory_version 4.8) - #set (kernel_minimal_version 4.8) - - # Compiler selection if needed. Impose a minimal version. - # ----------------------------------------------- - set (gcc_minimal_version 4.9) - - # PKG_CONFIG required packages - # ----------------------------- - set (PKG_REQUIRED_LIST - json-c - afb-daemon - ) - - # You can also consider to include libsystemd - # ----------------------------------- - #list (APPEND PKG_REQUIRED_LIST libsystemd>=222) - - # Prefix path where will be installed the files - # Default: /usr/local (need root permission to write in) - # ------------------------------------------------------ - #set(INSTALL_PREFIX /opt/AGL CACHE PATH "INSTALL PREFIX PATH") - - # Customize link option - # ----------------------------- - #list(APPEND link_libraries -an-option) - - # Compilation options definition - # Use CMake generator expressions to specify only for a specific language - # Values are prefilled with default options that is currently used. - # Either separate options with ";", or each options must be quoted separately - # DO NOT PUT ALL OPTION QUOTED AT ONCE , COMPILATION COULD FAILED ! - # ---------------------------------------------------------------------------- - #set(COMPILE_OPTIONS - # -Wall - # -Wextra - # -Wconversion - # -Wno-unused-parameter - # -Wno-sign-compare - # -Wno-sign-conversion - # -Werror=maybe-uninitialized - # -Werror=implicit-function-declaration - # -ffunction-sections - # -fdata-sections - # -fPIC - # CACHE STRING "Compilation flags") - #set(C_COMPILE_OPTIONS "" CACHE STRING "Compilation flags for C language.") - #set(CXX_COMPILE_OPTIONS "" CACHE STRING "Compilation flags for C++ language.") - #set(PROFILING_COMPILE_OPTIONS - # -g - # -O0 - # -pg - # -Wp,-U_FORTIFY_SOURCE - # CACHE STRING "Compilation flags for PROFILING build type.") - #set(DEBUG_COMPILE_OPTIONS - # -g - # -ggdb - # CACHE STRING "Compilation flags for DEBUG build type.") - #set(COVERAGE_COMPILE_OPTIONS - # -g - # -O0 - # --coverage - # CACHE STRING "Compilation flags for COVERAGE build type.") - #set(RELEASE_COMPILE_OPTIONS - # -O2 - # -pipe - # -D_FORTIFY_SOURCE=2 - # -fstack-protector-strong - # -Wformat -Wformat-security - # -Werror=format-security - # -feliminate-unused-debug-types - # -Wl,-O1 - # -Wl,--hash-style=gnu - # -Wl,--as-needed - # -fstack-protector-strong - # -Wl,-z,relro,-z,now - # CACHE STRING "Compilation flags for RELEASE build type.") - - # Location for config.xml.in template file. - # - # If you keep them commented then it will build with a default minimal widget - # template which is very simple and it is highly probable that it will not suit - # to your app. - # ----------------------------------------- - #set(WIDGET_ICON "conf.d/wgt/${PROJECT_ICON}" CACHE PATH "Path to the widget icon") - set(WIDGET_CONFIG_TEMPLATE "${CMAKE_CURRENT_SOURCE_DIR}/conf.d/wgt/config.xml.in" CACHE PATH "Path to widget config file template (config.xml.in)") # UNCOMMENT WIDGET_CONFIG_TEMPLATE - #set(TEST_WIDGET_CONFIG_TEMPLATE "${CMAKE_CURRENT_SOURCE_DIR}/conf.d/wgt/test-config.xml.in" CACHE PATH "Path to the test widget config file template (test-config.xml.in)") - - # Mandatory widget Mimetype specification of the main unit - # -------------------------------------------------------------------------- - # Choose between : - #- text/html : HTML application, - # content.src designates the home page of the application - # - #- application/vnd.agl.native : AGL compatible native, - # content.src designates the relative path of the binary. - # - # - application/vnd.agl.service: AGL service, content.src is not used. - # - #- ***application/x-executable***: Native application, - # content.src designates the relative path of the binary. - # For such application, only security setup is made. - # - set(WIDGET_TYPE application/vnd.agl.service) # UNCOMMENT WIDGET_TYPE - - # Mandatory Widget entry point file of the main unit - # -------------------------------------------------------------- - # This is the file that will be executed, loaded, - # at launch time by the application framework. - # - set(WIDGET_ENTRY_POINT lib/libhellocount.so) # UNCOMMENT WIDGET_ENTRY_POINT - - # Optional dependencies order - # --------------------------- - #set(EXTRA_DEPENDENCIES_ORDER) - - # Optional Extra global include path - # ----------------------------------- - #set(EXTRA_INCLUDE_DIRS) - - # Optional extra libraries - # ------------------------- - #set(EXTRA_LINK_LIBRARIES) - - # Optional force binding Linking flag - # ------------------------------------ - # set(BINDINGS_LINK_FLAG LinkOptions ) - - # Optional force package prefix generation, like widget - # ----------------------------------------------------- - # set(PKG_PREFIX DestinationPath) - - # Optional Application Framework security token - # and port use for remote debugging. - #------------------------------------------------------------ - #set(AFB_TOKEN "" CACHE PATH "Default binder security token") # COMMENT AFB_TOKEN - #set(AFB_REMPORT "1234" CACHE PATH "Default binder listening port") # COMMENT AFB_REMPORT - - # Print a helper message when every thing is finished - # ---------------------------------------------------- - set(CLOSING_MESSAGE "Typical binding launch: cd ${CMAKE_BINARY_DIR}/package \\&\\& afb-daemon --port=${AFB_REMPORT} --workdir=. --ldpaths=lib --roothttp=htdocs --token=\"${AFB_TOKEN}\" --tracereq=common --verbose") - set(PACKAGE_MESSAGE "Install widget file using in the target : afm-util install ${PROJECT_NAME}.wgt") - - # Optional schema validator about now only XML, LUA and JSON - # are supported - #------------------------------------------------------------ - #set(LUA_CHECKER "luac" "-p" CACHE STRING "LUA compiler") - #set(XML_CHECKER "xmllint" CACHE STRING "XML linter") - #set(JSON_CHECKER "json_verify" CACHE STRING "JSON linter") - - include(CMakeAfbTemplates) - ``` - -### 5. Copy WGT configuration template - - ```sh - $ mkdir -p conf.d/wgt - $ cp ${OECORE_NATIVE_SYSROOT}/usr/share/doc/CMakeAfbTemplates/samples.d/config.xml.in.sample conf.d/wgt/config.xml.in - ``` - -### 6. Run CMAKE and Generate autobuild - - ```sh - $ mkdir build/ - $ cd build/ - $ cmake .. - $ make autobuild - ``` - -### 7. Create service directory - - ```sh - $ cd .. - $ mkdir service/ - $ cd service/ - ``` - This `service` directory holds the C code & CMakeLists.txt ; - - - Add `hellocount-service.c` file which contains the functional C code : - - ```sh - $ vim hellocount-service.c - - /* - * Copyright 2020 The Linux Foundation # INSERT YEAR & ORG - * - * 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. - */ - - #define _GNU_SOURCE - #include - #include - #include - - #define AFB_BINDING_VERSION 3 - #include - - static void pingSample(afb_req_t request) - { - static int pingcount = 0; - - afb_req_success_f(request, json_object_new_int(pingcount), "Ping count = %d", pingcount); - - AFB_API_NOTICE(afbBindingV3root, "Verbosity macro at level notice invoked at ping invocation count = %d", pingcount); - - pingcount++; - } - - static void count(afb_req_t request) - { - static int counter = 0; - - afb_req_success_f(request, json_object_new_int(counter), "Counter = %d", counter); - - AFB_API_NOTICE(afbBindingV3root, "Verbosity macro at level notice invoked at count invocation count = %d", counter); - - counter++; - } - - - - static const afb_verb_t verbs[] = - { - /*Without security*/ - {.verb = "ping", .session = AFB_SESSION_NONE, .callback = pingSample, .auth = NULL}, - {.verb = "count", .session = AFB_SESSION_NONE, .callback = count, .auth = NULL}, - {NULL} - }; - - const afb_binding_t afbBindingExport = - { - .api = "count", - .specification = "HelloCount API", - .verbs = verbs, - .preinit = NULL, - .init = NULL, - .onevent = NULL, - .userdata = NULL, - .provide_class = NULL, - .require_class = NULL, - .require_api = NULL, - .noconcurrency = 0 - }; - ``` - -- Add `CMakeLists.txt` file : - - ```sh - $ vim CMakeLists.txt - - ########################################################################### - # Copyright 2020 The Linux Foundation # INSERT YEAR & ORG - # - # 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. - ########################################################################### - - # Add target to project dependency list - PROJECT_TARGET_ADD(hellocount) - # Define project Targets - ADD_LIBRARY(${TARGET_NAME} MODULE hellocount-service.c) - - # Binder exposes a unique public entry point - SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES - PREFIX "afb-" - LABELS "BINDING" - OUTPUT_NAME ${TARGET_NAME} - ) - ``` - -### 8. Build and Package `wgt` using autobuild - - ```sh - $ cd .. - - $ ./autobuild/agl/autobuild build - - make[1]: Entering directory '/home/boron/agl-app/newservice/build' - make[2]: Entering directory '/home/boron/agl-app/newservice/build' - make[3]: Entering directory '/home/boron/agl-app/newservice/build' - make[3]: Leaving directory '/home/boron/agl-app/newservice/build' - [100%] Built target autobuild - make[2]: Leaving directory '/home/boron/agl-app/newservice/build' - make[1]: Leaving directory '/home/boron/agl-app/newservice/build' - - $ ./autobuild/agl/autobuild package - - make[1]: Entering directory '/home/boron/agl-app/newservice/build' - make[2]: Entering directory '/home/boron/agl-app/newservice/build' - make[3]: Entering directory '/home/boron/agl-app/newservice/build' - make[3]: Leaving directory '/home/boron/agl-app/newservice/build' - [100%] Built target autobuild - make[2]: Leaving directory '/home/boron/agl-app/newservice/build' - make[1]: Leaving directory '/home/boron/agl-app/newservice/build' - make[1]: Entering directory '/home/boron/agl-app/newservice/build' - make[2]: Entering directory '/home/boron/agl-app/newservice/build' - make[3]: Entering directory '/home/boron/agl-app/newservice/build' - make[4]: Entering directory '/home/boron/agl-app/newservice/build' - Scanning dependencies of target prepare_package - make[4]: Leaving directory '/home/boron/agl-app/newservice/build' - make[4]: Entering directory '/home/boron/agl-app/newservice/build' - [ 6%] Generating package - [ 12%] Generating package/bin - [ 18%] Generating package/etc - [ 25%] Generating package/lib - [ 31%] Generating package/htdocs - [ 37%] Generating package/var - make[4]: Leaving directory '/home/boron/agl-app/newservice/build' - [ 37%] Built target prepare_package - make[4]: Entering directory '/home/boron/agl-app/newservice/build' - Scanning dependencies of target prepare_package_test - make[4]: Leaving directory '/home/boron/agl-app/newservice/build' - make[4]: Entering directory '/home/boron/agl-app/newservice/build' - [ 43%] Generating package-test - [ 50%] Generating package-test/bin - [ 56%] Generating package-test/etc - [ 62%] Generating package-test/lib - [ 68%] Generating package-test/htdocs - [ 75%] Generating package-test/var - make[4]: Leaving directory '/home/boron/agl-app/newservice/build' - [ 75%] Built target prepare_package_test - make[4]: Entering directory '/home/boron/agl-app/newservice/build' - Scanning dependencies of target populate - make[4]: Leaving directory '/home/boron/agl-app/newservice/build' - [ 75%] Built target populate - make[4]: Entering directory '/home/boron/agl-app/newservice/build' - Scanning dependencies of target widget_files - make[4]: Leaving directory '/home/boron/agl-app/newservice/build' - make[4]: Entering directory '/home/boron/agl-app/newservice/build' - [ 81%] Generating package/icon.png - [ 87%] Generating package/config.xml - make[4]: Leaving directory '/home/boron/agl-app/newservice/build' - [ 93%] Built target widget_files - make[4]: Entering directory '/home/boron/agl-app/newservice/build' - Scanning dependencies of target widget - make[4]: Leaving directory '/home/boron/agl-app/newservice/build' - make[4]: Entering directory '/home/boron/agl-app/newservice/build' - [100%] Generating hellocount.wgt - NOTICE: -- PACKING widget hellocount.wgt from directory /home/boron/agl-app/newservice/build/package - ++ Install widget file using in the target : afm-util install hellocount.wgt - make[4]: Leaving directory '/home/boron/agl-app/newservice/build' - [100%] Built target widget - make[3]: Leaving directory '/home/boron/agl-app/newservice/build' - make[2]: Leaving directory '/home/boron/agl-app/newservice/build' - make[1]: Leaving directory '/home/boron/agl-app/newservice/build' - ``` - - - The `hellocount.wgt` file is packaged and available at `~/agl-app/newservice/build`. - -### 9. Install the service - - - Local System : - ```sh - # Copy hellocount.wgt to remote AGL system - $ scp ~/agl-app/newservice/build/hellocount.wgt root@:/home/0/ - ``` - - - Remote AGL System : - ```sh - # Install using the service using afm-util - $ afm-util install ./hellocount.wgt - # Reboot the system - $ reboot -f - ``` \ No newline at end of file +Services are software running in the background and providing, as their name suggests, +various services to other software: access to specific system hardware, connectivity +management, network servers... They can be split into 2 categories: +- system services: those usually run as a privileged user and make use of shared system + resources which they should have exclusive access to +- user services: such services run as part of an unprivileged user's session and can + only be called by said user + +# Basic requirements + +The only mandatory requirement is that service packages provide a `.service` file +so they can be properly managed by `systemd`. This file must be installed to a specific +location, determined by the service type (system or user): +- `/usr/lib/systemd/system/` for system services +- `/usr/lib/systemd/user/` for user services + +Below is an example of a simple user service, running in a graphical session and +therefore requiring a compositor to be already running before the service starts: + +``` +[Unit] +Requires=agl-compositor.service +After=agl-compositor.service + +[Service] +Type=simple +ExecStart=/usr/bin/homescreen +Restart=on-failure + +[Install] +WantedBy=agl-session.target +``` + +The `WantedBy=agl-session.target` indicates the service is part of the default AGL +user session, as mentioned in the [Application Framework](1_Application_Framework/1_Introduction/#user-session-management) +documentation. + +The `Restart=on-failure` directive ensures the service will be automatically +restarted by `systemd` in case it crashes. + +More details about `systemd` service files can be found in the +[systemd documentation](https://www.freedesktop.org/software/systemd/man/systemd.service.html). + +# D-Bus activation + +Services can also provide a D-Bus interface. In this case, they need not be started +on system boot (or user session startup in the case of user services) but can be +automatically started only when a client sends a request to the D-Bus name the service +registers. + +D-Bus activated services must name their `systemd` service file `dbus-NAME.service` +where `NAME` is the D-Bus name registered by the service. This file must include the +following lines: + +``` +[Service] +Type=dbus +BusName=NAME +ExecStart=/path/to/executable +``` + +In addition, they must provide a D-Bus service file named `NAME.service` and installed +to one of the following locations: +- `/usr/share/dbus-1/system-services` for system services +- `/usr/share/dbus-1/services` for user services + +The contents of the D-Bus service file must be the following: + +``` +[D-BUS Service] +Name=NAME +Exec=/path/to/executable +SystemdService=dbus-NAME.service +``` + +This ensures the service can be safely activated through D-Bus and no conflict will occur +between `systemd` and the D-Bus daemon. + +More details about D-Bus activation can be found in the +[D-Bus specification](https://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-starting-services), +under the "Message Bus Starting Services (Activation)" section. + +# Services startup + +For D-Bus activated services, no additional action is required as those will be automatically +started whenever needed. Other services, however, need a few more steps in order to be +executed on system or session startup. + +## System services + +System services can take advantage of the Yocto `systemd` class which automates the process of +enabling such services. + +1. Ensure the recipe inherits from the `systemd` class: + +``` +inherit systemd +``` + +2. Declare the system services that needs to be enabled on boot: + +``` +SYSTEMD_SERVICE:${PN} = "NAME.service" +``` + +3. Ensure the `FILES` variable includes the systemd service directory the corresponding +file will be installed to: + +``` +FILES:${PN} = "\ + ... + ${systemd_system_unitdir}/* \ +" +``` + +## User services + +The `systemd` class doesn't provide an equivalent mechanism for user services. This must +therefore be done manually as part of the package's install process. + +1. Make the service a part of the user session: + +``` +do_install:append() { + install -d ${D}${systemd_user_unitdir}/agl-session.target.wants + ln -s ../NAME.service ${D}${systemd_user_unitdir}/agl-session.target.wants/NAME.service +} +``` + +This ensures `agl-session.target` depends on `NAME.service`, the latter being therefore +automatically started on session creation. + +2. Ensure the `FILES` variable includes the systemd service directory the corresponding +file will be installed to: + +``` +FILES:${PN} = "\ + ... + ${systemd_user_unitdir}/* \ +" +```