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 <john.doe@example.com> # 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 <stdio.h>
- #include <string.h>
- #include <json-c/json.h>
-
- #define AFB_BINDING_VERSION 3
- #include <afb/afb-binding.h>
-
- 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@<ip-address>:/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, and network servers. Services 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}/* \
+"
+```