ElfPack2: различия между версиями
(+ Shared Libraries, API, Config, Postlinker) | Andy51 (обсуждение | вклад) (Различия в исходниках) | ||
Строка 13: | Строка 13: | ||
*Добавлена полноценная система импортов функций по их именам. Если ранее для этой цели использовались механизмы сомнительной надёжности, что не раз приводило к различным проблемам, то теперь процедура загрузки эльфа стала гораздо более надёжной. Это в том числе означает, что для каждого загружаемого эльфа проверяется наличие в библиотеках всех требуемых им функций, и выводится сообщение об ошибке, если обнаружены несоответствия. | *Добавлена полноценная система импортов функций по их именам. Если ранее для этой цели использовались механизмы сомнительной надёжности, что не раз приводило к различным проблемам, то теперь процедура загрузки эльфа стала гораздо более надёжной. Это в том числе означает, что для каждого загружаемого эльфа проверяется наличие в библиотеках всех требуемых им функций, и выводится сообщение об ошибке, если обнаружены несоответствия. | ||
+ | |||
*Добавлена "Консоль" - встроенное в ElfPack средство для вывода текстовой информации на дисплей. В основном используется для вывода информации самим ElfPack-ом, но ещё позволяет выводить информацию и эльфам. Консоль будет полезна для фоновых эльфов. | *Добавлена "Консоль" - встроенное в ElfPack средство для вывода текстовой информации на дисплей. В основном используется для вывода информации самим ElfPack-ом, но ещё позволяет выводить информацию и эльфам. Консоль будет полезна для фоновых эльфов. | ||
+ | |||
*Система callback-ов для вывода на дисплей средствами [[AHI]] ''параллельно'' с [[UIS]]. Таким, например, образом работает и Консоль. | *Система callback-ов для вывода на дисплей средствами [[AHI]] ''параллельно'' с [[UIS]]. Таким, например, образом работает и Консоль. | ||
+ | |||
*Shared libraries - так называют аналог DLL в [[Linux|линуксе]]. Это такие модули, содержащие функции, которые будучи однажды загружены в память, могут быть подлинкованы к различным эльфам. И также, как и с DLL, есть два варианта их подгрузки - статический и динамический. Первый подразумевает, что библиотека будет найдена и загружена в память в момент запуска эльфа. Второй означает, что эльф может загрузить любую библиотеку "на лету". Это позволяет вынести общий код, используемый сразу во множестве эльфов в отдельный модуль, который будет подгружен лишь единожды - получаем экономию памяти. Второе применение библиотек - возможность реализации полноценной системы плагинов. Shared libraries имеют расширение .so | *Shared libraries - так называют аналог DLL в [[Linux|линуксе]]. Это такие модули, содержащие функции, которые будучи однажды загружены в память, могут быть подлинкованы к различным эльфам. И также, как и с DLL, есть два варианта их подгрузки - статический и динамический. Первый подразумевает, что библиотека будет найдена и загружена в память в момент запуска эльфа. Второй означает, что эльф может загрузить любую библиотеку "на лету". Это позволяет вынести общий код, используемый сразу во множестве эльфов в отдельный модуль, который будет подгружен лишь единожды - получаем экономию памяти. Второе применение библиотек - возможность реализации полноценной системы плагинов. Shared libraries имеют расширение .so | ||
+ | |||
*Для предоставления своей функциональности эльфам, в ElfPack2 предусмотрен API - набор интерфейсных функций. Их описание можно посмотреть в файле loader2.h SDK. | *Для предоставления своей функциональности эльфам, в ElfPack2 предусмотрен API - набор интерфейсных функций. Их описание можно посмотреть в файле loader2.h SDK. | ||
+ | |||
*Для настройки возможностей ElfPack2 есть конфигурационный файл, который находится в стандартном билде в /b/Elf2/elfpack.cfg | *Для настройки возможностей ElfPack2 есть конфигурационный файл, который находится в стандартном билде в /b/Elf2/elfpack.cfg | ||
+ | |||
*В версии для E398 предусмотрена кнопка для пропуска обработки auto.run (настраивается в конфиге) - полезно в случае добавления нерабочего эльфа в авторан. Для других моделей - возможность ещё в разработке. Но, в любом случае, необходимо проверять эльфы на работоспособность запуском вручную, прежде чем добавлять их в автозапуск. | *В версии для E398 предусмотрена кнопка для пропуска обработки auto.run (настраивается в конфиге) - полезно в случае добавления нерабочего эльфа в авторан. Для других моделей - возможность ещё в разработке. Но, в любом случае, необходимо проверять эльфы на работоспособность запуском вручную, прежде чем добавлять их в автозапуск. | ||
+ | |||
*В процесс сборки эльфа добавилось ещё одно звено - postlinker. Основная функция этой программы - подготовить эльф для загрузки в ElfPack2. Эльфы, не прошедшие такую обработку, запускаться не будут. Также postlinker создаёт стандартные библиотеки функий из sym-файлов. | *В процесс сборки эльфа добавилось ещё одно звено - postlinker. Основная функция этой программы - подготовить эльф для загрузки в ElfPack2. Эльфы, не прошедшие такую обработку, запускаться не будут. Также postlinker создаёт стандартные библиотеки функий из sym-файлов. | ||
== SDK == | == SDK == | ||
+ | Процесс разработки эльфов имеет ряд отличий от предыдущей версии. Это касается как исходного кода, так и процесса сборки. | ||
+ | |||
+ | С различиями можно наглядно ознакомиться на примере helloworld из репозитория svn://svn.vilko.ru/elfs2/hw - важные участки кода отмечены #ifdef-ами. | ||
+ | |||
+ | <br> | ||
+ | === Больше всего изменения касаются функции - точки входа в эльф === | ||
+ | <br> | ||
+ | |||
+ | <ul> | ||
+ | <li>'''Необходимо объявить ''глобальную'' переменную типа ldrElf: | ||
+ | <ul><pre> | ||
+ | ldrElf elf; | ||
+ | </pre></ul> | ||
+ | </li> | ||
+ | |||
+ | <li>'''Точка входа в эльф теперь имеет следующий вид (раньше называлась Register): | ||
+ | <ul><pre> | ||
+ | ldrElf* _start( WCHAR *uri, WCHAR *params ) | ||
+ | </pre></ul> | ||
+ | :Обратите внимание также на то, что параметры теперь передаются в неё как WCHAR*, что позволяет избежать проблем с путями, содержащими символы кроме латиницы, и на то, что reserve не передаётся. | ||
+ | </li> | ||
+ | |||
+ | <li>'''При необходимости, можно добавить проверку на то, был ли уже запущен эльф с таким именем: | ||
+ | <ul><pre> | ||
+ | if ( ldrIsLoaded( (char*)app_name ) ) | ||
+ | { | ||
+ | ... | ||
+ | // Если возвращаем NULL из _start - эльф удаляется из памяти | ||
+ | return NULL; | ||
+ | } | ||
+ | </pre></ul> | ||
+ | </li> | ||
+ | |||
+ | <li>'''Вместо reserve, evcode_base можно получить так: | ||
+ | <ul><pre> | ||
+ | evcode_base = ldrRequestEventBase( ); | ||
+ | </pre></ul> | ||
+ | </li> | ||
+ | |||
+ | <li>'''В ElfPack2 важные константы берутся из библиотеки функций. К ним также относятся и все коды ивентов. | ||
+ | :А конкретно механизм выглядит так - на этапе компиляции в таблицы ивентов (any_state_handlers, например) заносятся не сами значения ивентов, а их идентификаторы. С точки зрения кода в этом месте ничего не меняется - подмена никак не отражается. А вот чтобы идентификаторы заменились на реальные значения, необходимо вызвать для каждой таблицы функцию ldrInitEventHandlersTbl ДО вызова APP_Register. | ||
+ | <ul><pre> | ||
+ | // Функция не модифицирует evcode_base, но возвращает новое значение базы - поэтому присваивание | ||
+ | evcode_base = ldrInitEventHandlersTbl( any_state_handlers, evcode_base ); | ||
+ | </pre></ul> | ||
+ | </li> | ||
+ | |||
+ | <li>'''Вместо LdrStartApp используется ldrSendEvent: | ||
+ | <ul><pre> | ||
+ | ldrSendEvent( evcode_base ); | ||
+ | </pre></ul> | ||
+ | </li> | ||
+ | |||
+ | <li>'''Необходимо поместить в объявленную ранее переменную типа ldrElf имя текущего эльфа и возвратить указатель на неё: | ||
+ | <ul><pre> | ||
+ | elf.name = (char*)app_name; | ||
+ | return &elf; | ||
+ | </pre></ul> | ||
+ | </li> | ||
+ | </ul> | ||
+ | |||
+ | <br> | ||
+ | === Также обратите внимание на следующие общие изменения === | ||
+ | <br> | ||
+ | |||
+ | <ul> | ||
+ | <li>'''В функции старта приложения (в примере - HelloWorldStart) необходимо записать в структуру elf указатель на созданное [[Application|приложение]]. | ||
+ | :Этим мы сообщаем эльфпаку, что эльф начал свою работу как приложение. | ||
+ | <ul><pre> | ||
+ | elf.app = app; | ||
+ | </pre></ul> | ||
+ | </li> | ||
+ | |||
+ | <li>'''Функции выгрузки эльфа из памяти теперь не требуются какие-либо параметры: | ||
+ | <ul><pre> | ||
+ | // Название сменилось - теперь с маленькой буквы! | ||
+ | ldrUnloadElf(); | ||
+ | </pre></ul> | ||
+ | </li> | ||
+ | |||
+ | <li>'''Никаких структур вроде APP_HELLOWORLD_T (в helloworld_snd.h) объявлять не нужно. | ||
+ | :В прошивке это - необходимая особенность приложений, работающих прямо из ROM-памяти. В этой структуре размещаются глобальные переменные для приложения. А так как эльфы выполняются из RAM - они могут создавать обычные глобальные переменные. | ||
+ | </li> | ||
+ | |||
+ | <li>'''В обработчиках сообщений вторым параметром вместо void *app передаётся APPLICATION_T *app, что позволяет избавиться от ненужных преобразований типов, сравните: | ||
+ | <ul><pre> | ||
+ | // EP1: | ||
+ | UINT32 HandleUITokenGranted( EVENT_STACK_T *ev_st, void *app ) | ||
+ | { | ||
+ | APPLICATION_T *papp = (APPLICATION_T*) app; | ||
+ | status = APP_ExitStateAndApp( ev_st, app, 0 ); | ||
+ | ... | ||
+ | |||
+ | // EP2: | ||
+ | UINT32 HandleUITokenGranted( EVENT_STACK_T *ev_st, APPLICATION_T *app ) | ||
+ | { | ||
+ | status = APP_ExitStateAndApp( ev_st, app, 0 ); | ||
+ | ... | ||
+ | </pre></ul> | ||
+ | </li> | ||
+ | </ul> | ||
[[Категория:Эльфостроение]] | [[Категория:Эльфостроение]] |
Версия 16:58, 31 октября 2009
ElfPack2 — это развитие предыдущей версии ElfPack-а для Motorola, где учтён опыт его использования как со стороны конечного пользователя, так и со стороны разработчика эльфов, исправлено множество моментов, досаждавших ранее, а также значительно расширена функциональность.
Содержание
Отличия от предыдущей версии
ElfPack2 является улучшенной и полностью переработанной версией своего предшественника. Достаточно упомянуть, что объём кода увеличился почти в 4 раза, и при этом они не имеют общего кода.
- Для сборки эльфов используется компилятор GCC вместо ADS
Переход на GCC позволил реализовать полноценную систему импортов и динамических библиотек - Основная библиотека функций имеет более сложный формат, при этом в ней хранится её версия и версия прошивки, для которой библиотека предназначена. При этом библиотека может быть перезагружена в любой момент - для этого более не требуется перезагружать телефон.
- Исправлена недоработка, связанная с передачей параметров в эльф в виде char вместо WCHAR
- Более совершенный обработчик auto.run
Нововведения
- Добавлена полноценная система импортов функций по их именам. Если ранее для этой цели использовались механизмы сомнительной надёжности, что не раз приводило к различным проблемам, то теперь процедура загрузки эльфа стала гораздо более надёжной. Это в том числе означает, что для каждого загружаемого эльфа проверяется наличие в библиотеках всех требуемых им функций, и выводится сообщение об ошибке, если обнаружены несоответствия.
- Добавлена "Консоль" - встроенное в ElfPack средство для вывода текстовой информации на дисплей. В основном используется для вывода информации самим ElfPack-ом, но ещё позволяет выводить информацию и эльфам. Консоль будет полезна для фоновых эльфов.
- Система callback-ов для вывода на дисплей средствами AHI параллельно с UIS. Таким, например, образом работает и Консоль.
- Shared libraries - так называют аналог DLL в линуксе. Это такие модули, содержащие функции, которые будучи однажды загружены в память, могут быть подлинкованы к различным эльфам. И также, как и с DLL, есть два варианта их подгрузки - статический и динамический. Первый подразумевает, что библиотека будет найдена и загружена в память в момент запуска эльфа. Второй означает, что эльф может загрузить любую библиотеку "на лету". Это позволяет вынести общий код, используемый сразу во множестве эльфов в отдельный модуль, который будет подгружен лишь единожды - получаем экономию памяти. Второе применение библиотек - возможность реализации полноценной системы плагинов. Shared libraries имеют расширение .so
- Для предоставления своей функциональности эльфам, в ElfPack2 предусмотрен API - набор интерфейсных функций. Их описание можно посмотреть в файле loader2.h SDK.
- Для настройки возможностей ElfPack2 есть конфигурационный файл, который находится в стандартном билде в /b/Elf2/elfpack.cfg
- В версии для E398 предусмотрена кнопка для пропуска обработки auto.run (настраивается в конфиге) - полезно в случае добавления нерабочего эльфа в авторан. Для других моделей - возможность ещё в разработке. Но, в любом случае, необходимо проверять эльфы на работоспособность запуском вручную, прежде чем добавлять их в автозапуск.
- В процесс сборки эльфа добавилось ещё одно звено - postlinker. Основная функция этой программы - подготовить эльф для загрузки в ElfPack2. Эльфы, не прошедшие такую обработку, запускаться не будут. Также postlinker создаёт стандартные библиотеки функий из sym-файлов.
SDK
Процесс разработки эльфов имеет ряд отличий от предыдущей версии. Это касается как исходного кода, так и процесса сборки.
С различиями можно наглядно ознакомиться на примере helloworld из репозитория svn://svn.vilko.ru/elfs2/hw - важные участки кода отмечены #ifdef-ами.
Больше всего изменения касаются функции - точки входа в эльф
- Необходимо объявить глобальную переменную типа ldrElf:
ldrElf elf;
ldrElf* _start( WCHAR *uri, WCHAR *params )
- Обратите внимание также на то, что параметры теперь передаются в неё как WCHAR*, что позволяет избежать проблем с путями, содержащими символы кроме латиницы, и на то, что reserve не передаётся.
if ( ldrIsLoaded( (char*)app_name ) ) { ... // Если возвращаем NULL из _start - эльф удаляется из памяти return NULL; }
evcode_base = ldrRequestEventBase( );
- А конкретно механизм выглядит так - на этапе компиляции в таблицы ивентов (any_state_handlers, например) заносятся не сами значения ивентов, а их идентификаторы. С точки зрения кода в этом месте ничего не меняется - подмена никак не отражается. А вот чтобы идентификаторы заменились на реальные значения, необходимо вызвать для каждой таблицы функцию ldrInitEventHandlersTbl ДО вызова APP_Register.
// Функция не модифицирует evcode_base, но возвращает новое значение базы - поэтому присваивание evcode_base = ldrInitEventHandlersTbl( any_state_handlers, evcode_base );
ldrSendEvent( evcode_base );
elf.name = (char*)app_name; return &elf;
Также обратите внимание на следующие общие изменения
- В функции старта приложения (в примере - HelloWorldStart) необходимо записать в структуру elf указатель на созданное приложение.
- Этим мы сообщаем эльфпаку, что эльф начал свою работу как приложение.
elf.app = app;
// Название сменилось - теперь с маленькой буквы! ldrUnloadElf();
- В прошивке это - необходимая особенность приложений, работающих прямо из ROM-памяти. В этой структуре размещаются глобальные переменные для приложения. А так как эльфы выполняются из RAM - они могут создавать обычные глобальные переменные.
// EP1: UINT32 HandleUITokenGranted( EVENT_STACK_T *ev_st, void *app ) { APPLICATION_T *papp = (APPLICATION_T*) app; status = APP_ExitStateAndApp( ev_st, app, 0 ); ... // EP2: UINT32 HandleUITokenGranted( EVENT_STACK_T *ev_st, APPLICATION_T *app ) { status = APP_ExitStateAndApp( ev_st, app, 0 ); ...