Всем хорош Sailfish, но что делать, если Вам захочется помяукать модемом?
Ладно, далее, в этой статье, я расскажу как создать плагин для офоно, в нём создать кастомный dbus интерфейс и покажу как обрабатывать входные данные, добро пожаловать под кат.
Итак, сразу начнём всё по взрослому, как в настоящем плагине! Да чтобы с конфигурацией и пакетами! Весь код будет располагаться тут
https://github.com/neochapay/ofono-example-plugin и разбит коммитами по частям этой статьи. Так что приступаем!
Часть первая: Всё по взрослому!
Мы работаем с коммитом с хешем f6a8a2424987aad9d864be099161e61a3684d7e5 он же первый коммит Для создания Makefile и последующей сборки мы будем использовать automake. Почему? Потому что я стар и видел смерти и рождения галактик вот почему!
Для начала создаём папку ofono-example-plugin в котором создаём папки rpm и src. По названию можно понят, что в rpm будут файлы, относящиеся к пакетированию, а в src собственно исходники нашего плагина.
В rpm кладём файл следующего содержания:
Код SPEC:Name: ofono-example-plugin
Version: 0.0.1
Release: 1
Summary: Ofono example plugin
Group: Development/Libraries
License: BSD
URL: https://github.com/neochapay/ofono-example-plugin
Source: %{name}-%{version}.tar.bz2
Requires: ofono
BuildRequires: ofono-devel
%description
Implements some examples for ofono plugin
%prep
%setup -q -n %{name}-%{version}
%build
./autogen.sh
%configure
make %{_smp_mflags}
%install
rm -rf %{buildroot}
%make_install
#libtool don't like lib without version
rm %{buildroot}/usr/lib/ofono/plugins/exampleplugin.so.0
rm %{buildroot}/usr/lib/ofono/plugins/exampleplugin.so
mv %{buildroot}/usr/lib/ofono/plugins/exampleplugin.so.0.0.0 %{buildroot}/usr/lib/ofono/plugins/exampleplugin.so
%files
%defattr(-,root,root,-)
%{_libdir}/ofono/plugins/exampleplugin.so
Если Вы собирали когда либо RPM файлы - Вам всё понятно, за исключением одной мелочи, о которой позже. Если же нет, то стоит сперва почитать о создании rpm из исходников, но в этой статье, я решил, что всё уже всё знают. О странном коде в секции install: я так и не понял, как сказать libtool создать библиотеку без версионирования - поэтому, всё, что не нужно удаляем и переносим с нужным именем.
Далее нам понадобятся файлы AUTHORS ChangeLog README NEWS значение которых, я думаю понятно по их названию. Я их оставил пустыми, потому что вот почему.
Далее нам понадобится autogen.sh - файл, который вызывает различные утилиты и формирует нам ./configure и Makefile. У меня он до боли прост:
Код BASH:#!/bin/sh
autoreconf --install --force
Да вот так всё просто
Далее нам нужен файл configure.ac из которого уже получится необходимый нам ./configure
Код AUTOCONF:AC_INIT([example-plugin], [0,1])
AC_CONFIG_SRCDIR(src/example-plugin.c)
AM_INIT_AUTOMAKE
AC_PROG_CC
AC_PROG_INSTALL
AC_PROG_LIBTOOL
AC_ENABLE_SHARED
AC_DISABLE_STATIC
libdir=/usr/lib/ofono/plugins
AC_OUTPUT(Makefile src/Makefile)
Разберём его построчно:
1 - инициализация autoconf - объявляем название библиотеки и её версию
2 - говорим, где у нас исходники
3 - говорим, что будем собирать automake
4 - говорим, что мы используем C
5 - говорим, что нам нужна будет утилита install
6 - говорим, что мы собираем shared библиотеку
7 - говорим, что мы не собираем static библиотеку
8 - обявляем переменную, где у нас хранятся плагины ofono
9 - говорим, что нам нужно на выходе.
Далее, для формирования Makefile нам нужны Makefile.am файлы, аж 2 штуки - одна в корне исходников:
Код AUTOMAKE:SUBDIRS = src
Он нам просто говорит, что смотри в папку src не отвлекайся. А вот в папке src Makefile.am будет чуть сложнее:
Код AUTOMAKE:lib_LTLIBRARIES = exampleplugin.la
exampleplugin_la_LDFLAGS=-module -lglibutil -lglib-2.0 -lgobject-2.0
exampleplugin_la_SOURCES = example-plugin.c
Опять таки, разберём по строчкам:
1 - говорим, что собираем библиотеку с именем examplepulgin
2 - сообщаем файлы линковки
3 - сообщаем, где лежат исходники самой библиотеки
И тут ты спросишь: "А где собственно плагин то?"
Ну всё до этого, было подготовкой, теперь встречайте сам код плагина
Код C:define OFONO_API_SUBJECT_TO_CHANGE
#include <ofono/plugin.h>
#include <ofono/log.h>
#Функция при старте
static int example_plugin_init()
{
ofono_info("Hello example ofono plugin.");
return 0;
}
#Функция при выходе
static void example_plugin_exit()
{
ofono_info("Bye bye example ofono plugin");
}
#обозночаем плагин
OFONO_PLUGIN_DEFINE(example, "example plugin",
OFONO_VERSION, OFONO_PLUGIN_PRIORITY_DEFAULT,
example_plugin_init, example_plugin_exit)
Код, достаточно простой, для понимания за исключением макроса OFONO_PLUGIN_DEFINE
у него входные параметры:
Названия плагина
Описание плагина
Версия ofono, для которого он был создан
Приоритет запуска - у нас стандартный
Функция вызываемая при инициализации
Функция вызываемая при завершении
Теперь можно собрать пакет, установить его на свой телефон и при запуске ofono увидеть строчку "Hello example ofono plugin.", а при остановке "Bye bye example ofono plugin"
Часть 2: Пытаемся поговорить
Но просто включаться и выключаться нам не очень то и интересно, хочется и поговорить с плагином, чтобы он нам отвечал на наши просьбы и мольбы - для этого ofono использует DBUS. Что это за монстр, я не буду рассказывать в рамках этой статьи, но попробуем в данной части зарегистрировать наш кастомный интерфейс.
Используем тот же репозиторий, но коммит 43fec818746984d90265911ced75b131d0cf78ef Кому лень читать, а сразу посмотреть изменения, то смотрим тут:
https://github.com/neochapay/ofono-example-plugin/commit/43fec818746984d90265911ced75b131d0cf78ef Первое, что нам понадобится - добавить в configure.ac опрос системы, на наличие библиотек dbus glib dbus-glib - делается это так:
Код AUTOCONF:PKG_CHECK_MODULES(DBUS, dbus-1 >= 1.4, dummy=yes,
AC_MSG_ERROR(D-Bus >= 1.4 is required))
AC_SUBST(DBUS_CFLAGS)
AC_SUBST(DBUS_LIBS)
Для поиска библиотек нам поможет pkgconfig, который нам подскажет есть ли библиотеки нужной нам версии и добавит нам флаги компиляции (DBUS_CFLAGS) и флаги линковки(DBUS_LIBS) которые понадобятся нам при сборке нашего плагина.
Так же добавляем для glib и dbus-glib
Код AUTOCONF:PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.32, dummy=yes,
AC_MSG_ERROR(GLib >= 2.32 is required))
AC_SUBST(GLIB_CFLAGS)
AC_SUBST(GLIB_LIBS)
PKG_CHECK_MODULES(DBUS_GLIB, dbus-glib-1, dummy=yes,
AC_MSG_ERROR(dbus-glib is required))
AC_SUBST(DBUS_GLIB_CFLAGS)
AC_SUBST(DBUS_GLIB_LIBS)
Чтобы эти флаги применялись при компиляции, добавим в src/Makefile.am некоторые изменения:
Строчку
Код AUTOMAKE:exampleplugin_la_LDFLAGS=-module -lglibutil -lglib-2.0 -lgobject-2.0
Меняем на
Код AUTOMAKE:exampleplugin_la_LDFLAGS=-module @GLIB_LIBS@ @DBUS_GLIB_LIBS@
И добавляем строку
Код AUTOMAKE:exampleplugin_la_CFLAGS=@DBUS_CFLAGS@ @GLIB_CFLAGS@ @DBUS_GLIB_CFLAGS@
Думаю понятно, откуда взялись переменные и зачем. Если нет - спрашивай в комментариях.
Теперь нам нужно создать 2 файлика: src/dbus-iface.c и src/dbus-iface.h , где собственно и будет реализация создания интерфейса dbus для нашего плагина.
В src/dbus-iface.h объявляем 2 функции - создание и удаление интерфейса
Код C:#ifndef DBUS_EXAMPLE_H
#define DBUS_EXAMPLE_H
static int register_example_dbus();
static void free_example_dbus();
#endif
register_example_dbus будет нам возвращать 1 если зарегистрировал интерфейс и нолик если нет. Напишем его реализацию в src/dbus-iface.c
Код C:/*Подключаем необходимые заголовки*/
#include <ofono/dbus.h>
#include <ofono/gdbus.h>
//Определяем где у нас будет интерфейс
#define EXAMPLE_DBUS_INTERFACE "org.nemomobile.ofono.Example"
//Болванки, которые нам понадобятся позже
static const GDBusMethodTable example_dbus_methods[] = {};
static const GDBusSignalTable example_dbus_signals[] = {};
//Регистрируем интерфейс
int register_example_dbus() {
//Вызываем главный интерфейс dbus ofono - мы же всё же плагин, а не отдельное приложение
DBusConnection *connection = dbus_connection_ref(ofono_dbus_get_connection());
/*
connection - наш основной интерфейс ofono
/Example - путь отосительно которого мы коннектимся. Должен быть уникальным
EXAMPLE_DBUS_INTERFACE - наш личный плагиновый интерфейс
example_dbus_methods - методы, которые мы представляем
example_dbus_signals - сигналы, которые мы можем слать
*/
if (g_dbus_register_interface(connection, "/Example",
EXAMPLE_DBUS_INTERFACE,
example_dbus_methods,
example_dbus_signals,
NULL, NULL, NULL)) {
// Если соединение проходит возвращаем 1
return 1;
}
//Если нет - то возвращаем ноль
return 0;
}
//А это домашнее задание - написать код освобождения интерфейса
void free_example_dbus() {
}
Прописываем вызовы при создании и удалении интерфейса в src/example-plugin.c
Теперь он будет выглядеть так:
Код C:
#define OFONO_API_SUBJECT_TO_CHANGE
#include <ofono/plugin.h>
#include <ofono/log.h>
#include "dbus-iface.h"
static int example_plugin_init()
{
ofono_info("Hello example ofono plugin.");
if(register_example_dbus() != 0) {
ofono_info("Register example dbus interface.");
} else {
ofono_warn("Fail register dbus interface.");
}
return 0;
}
static void example_plugin_exit()
{
free_example_dbus();
ofono_info("Bye bye example ofono plugin");
}
OFONO_PLUGIN_DEFINE(example, "example plugin",
OFONO_VERSION, OFONO_PLUGIN_PRIORITY_DEFAULT,
example_plugin_init, example_plugin_exit)
Собираем, устанавливаем и в консоли от рута запускаем
Код BASH:dbus-send --system --print-reply --dest=org.ofono / org.freedesktop.DBus.Introspectable.Introspect
Ура у нас появился интерфейс! Мы можем к нему обратится! Но как? Увы у нас нет методов.
Ну котикам грустить не стоит! Давайте в следующей части создадим интерфейсы и поговорим с ними через dbus!
Часть 3: Продолжаем пытаться говорить
Далее мы будем работать с коммитом da495d6b068a4522cdfcf6ecd21f55e817a5e92b . Изменения смотреть тут :
https://github.com/neochapay/ofono-example-plugin/commit/da495d6b068a4522cdfcf6ecd21f55e817a5e92b Для начала, в файле src/dbus-iface.c создадим функцию example_meow
Код C:static DBusMessage *example_meow(DBusConnection *conn, DBusMessage *msg, void *data) {
ofono_info("Some cat say meow!");
return dbus_message_new_method_return(msg);
}
При вызове которой в логе ofono будет отображаться сообщение "Some cat say meow!" далее, добавим эту функцию в нашу таблицу методов, теперь он будет выглядеть так:
Код C:static const GDBusMethodTable example_dbus_methods[] = {
{ GDBUS_METHOD("SayMeow", GDBUS_ARGS({"path", "s"}), NULL, example_meow) },
{ }
};
Метод зовётся SayMeow и принимает параметр "s" - string и при его вызове запускается функция example_meow.
Собираем, и прочее и при вызове в консоли от рута
Код BASH:dbus-send --system --print-reply --dest=org.ofono /Example org.nemomobile.ofono.Example.SayMeow string:""
Мы получим в логе офоно сообщение "Some cat say meow!"
А что, если нам нужно, чтобы котик не только мяукал например, а мурчал? Добро пожаловать в
следующую часть.
Ну и где доказательства про 18 запусков у маска в 2018 году? Или ты предпочтешь и тут...