
Если разработку под устройства можно сравнить с тёмным лесом, то как в нём не заплутать?
Привет, путник! Меня зовут Денис Малых, я работаю в Яндексе и руковожу разработкой общих компонент для платформы, на которой работают наши устройства. А ещё — я член программного комитета конференции AppsConf, где мы обсуждаем разработку под мобильные ОС. В этой статье поделюсь опытом разработки под нестандартные устройства: чем она принципиально отличается от привычной мобильной разработки, и что нужно уметь, чтобы разрабатывать «умные вещи».
Кому нужны специалисты по нестандартным устройствам

На рынке есть множество компаний, занимающихся разработкой устройств, в которых в качестве операционной системы используется Android или Linux. Это не только умные колонки, но и:
-
Видеорегистраторы – многие современные модели работают на Android.
-
Системы мультимедиа в автомобилях – кастомизированные прошивки на Android.
-
Домашние умные устройства – камеры видеонаблюдения, умные экраны, шлюзы IoT.
-
Специализированные промышленные решения – кассовые терминалы, медицинское оборудование.
Несмотря на разнообразие устройств, основной стек технологий и принципы работы остаются схожими. Поэтому навыки разработки для устройств востребованы во многих сферах. А с ростом популярности умного железа (IoT, Smart Home, автомобильные технологии) спрос на специалистов растёт. Компании, разрабатывающие свою электронику, нуждаются в инженерах, которые могут не только писать код, но и разбираться в низкоуровневых системах, кастомизации Android и разработке драйверов. В общем, в опытных следопытах, не боящихся темноты и лесных троп.
Чем отличается разработка под устройства

Когда мы говорим о мобильной разработке, в большинстве случаев речь идёт об Android и iOS. Разработчик пишет код в Android Studio или Xcode, тестирует его на телефоне, а затем загружает приложение в Google Play или App Store. Операционная система уже готова, есть встроенные сервисы, API и всё необходимое для работы приложений.
В случае с разработкой под устройства всё гораздо интереснее.
На устройствах нет «привычного» Android, а используется Android Open Source Project (AOSP) 一 это своеобразный «полуфабрикат» Android, который производители дорабатывают под свои нужды. Он требует доварки, обжарки и тщательной приправы в виде драйверов и сервисов. Если мобильный Android – это готовая пицца, то AOSP – это коробка с мукой, томатами и рецептом.
А ещё у устройств часто уникальное железо, требующее написания собственных драйверов и сервисов.

Если мы берём готовый Android для мобильной разработки — этот пирожок нам дают готовым. Если же делаем свою железку, то бОльшую часть слоев надо сделать самим.
Вместо того, чтобы сесть и наслаждаться трапезой, надо засучить рукава и заняться готовкой.
Операционная система и её кастомизация
Мобильные приложения работают на готовой операционной системе с Google-сервисами Google Play Services, Google Maps API, Firebase и другими.
Нестандартные устройства часто используют AOSP (Android Open Source Project) 一 голую версию Android без Google Play, Firebase и других стандартных инструментов. Это значит, что всё необходимо реализовывать самостоятельно 一 начиная от базовой прошивки и заканчивая системными приложениями.
Кроме того, устройство ≠ телефон. Если для телефона разработчику достаточно написать приложение и загрузить его в магазин, то в случае с устройствами перед этим нужно:
-
Собрать прошивку для конкретного железа.
-
Написать драйвера для взаимодействия с аппаратными компонентами.
-
Добавлять системные сервисы и собственные API.
-
Реализовывать базовые системные сервисы (например, работу с громкостью, Wi-Fi, экраном).
И только после этого разрабатывать пользовательские приложения.
Заболоченные тропы: железо и драйвера
В мобильной разработке все драйверы уже предустановлены, а API абстрагируют работу с железом. В устройствах нас поджидают заболоченные тропы. Приходится писать драйверы вручную, особенно если это новый сенсор, регулятор громкости, специфический экран или мультимедиа-кодек.
Каждое устройство уникально. Например, умная колонка может быть как послушный щенок, который выполняет команды, так и дикий енот, который не включается, пищит при загрузке и уходит в boot-loop просто потому, что у него такое настроение. Умная колонка может иметь специальные аппаратные регуляторы громкости, дополнительные микрофоны для шумоподавления, дисплей с кастомным управлением. И со всем этим вам нужно уметь управляться.
Для взаимодействия с такими компонентами разрабатываются драйвера на C/C++, которые обеспечивают работу на низком уровне. Это может показаться непростым, но вы будете вознаграждены за трудности — это вызов, преодолев который вы получите полезный опыт и новые навыки. Например, есть такой репозиторий с огромным количеством полезных инструментов.
Если мобильный разработчик в 99% случаев работает только с Java/Kotlin в Android, то разработчику устройств приходится писать на C++ для работы с железом и системными сервисами. Это требует понимания архитектуры Linux-ядра, поскольку Android базируется на Linux. А ещё знания C/C++ для работы с низкоуровневыми системами и опыт взаимодействия с аппаратурой через I2C, SPI, UART.
Инструменты разработки

Мобильный разработчик пишет код, запускает его в эмуляторе или на телефоне и публикует через Google Play. Android Studio 一 стандартная среда разработки для мобильных приложений. Однако для прошивки устройств её недостаточно. Здесь нужны дополнительные утилиты:
-
инструменты сборки AOSP 一 для сборки прошивок.
-
Fastboot 一 для установки и обновления прошивок.
-
adb (Android Debug Bridge) 一 для более углублённого использования устройства.
Кроме того, тестирование на реальном устройстве требует учёта кастомных дополнений (аппаратные регуляторы громкости, LED экраны и тд). Также часто приходится работать не только с Android SDK, но и с низкоуровневыми инструментами для сборки и тестирования прошивок.
Привилегированные приложения и безопасность
Разработчики устройств могут использовать системные привилегии, которые недоступны обычным смертным из Google Play. Но великая сила – это великая ответственность: малейшая ошибка в коде – и устройство превращается в кирпич, а ночной поход в офис – в ритуал воскрешения через Fastboot.
Например:
-
Работа с низкоуровневым доступом к микрофону.
-
Контроль Wi-Fi и Bluetooth на системном уровне.
-
Доступ к «опасным» разрешениям (dangerous permissions), которые обычные приложения не могут получить.
Но есть и обратная сторона: если системное приложение содержит уязвимость, то злоумышленник может получить глобальный доступ к устройству. Именно поэтому в разработке под устройства безопасность играет критически важную роль.
В нашем случае команда информационной безопасности проводит глубокий аудит всех компонентов — анализирует код на уязвимости, проверяет безопасность сетевых соединений и защищает системные сервисы. Служба безопасности защищает нас от голодных волков — критических ошибок, утечек и уязвимостей.
Шаманские ритуалы: симуляторы устройств
Android поставляет базовый комплект эмуляторов, которые помогают тестировать мобильные приложения без реального устройства. Однако, если мы разрабатываем драйверы и низкоуровневые модули, стандартный эмулятор Android недостаточен.
В этом случае необходимо модифицировать симулятор под конкретное железо, чтобы добавлять виртуальные версии аппаратных компонентов (сенсоры, контроллеры, экраны, модули связи). А ещё разрабатывать виртуальные драйвера для корректной эмуляции поведения устройства и создавать API-слои, которые позволят приложениям взаимодействовать с эмулируемыми компонентами.
Создание таких симуляторов 一 чуть более сложная задача, чем стандартная разработка приложений. Причина в том, что при разработке прошивки на базе Android можно столкнуться с багами не только в собственном коде, но и в коде самого Android. Последствия этого 一 плачевны. Это и некорректная работа встроенных сервисов, и устаревшие модули или неожиданные изменения API. При этом нужная документация по поведению ядра Android 一 отсутствует.

Поэтому создание симуляторов для устройств можно сравнить с походом в незнакомый лес. Сам процесс понятен, но можно столкнуться с неожиданностями, требующими глубокого понимания как работает система изнутри.
Прошивки, межпроцессное взаимодействие и интеграция с партнёрами

Разработка прошивки — это командная работа множества специалистов и даже разных компаний. Часто одна компания не делает устройство целиком. Например, аппаратную платформу разрабатывает производитель железа — партнёры из Китая. Драйверы и поддержку модулей могут поставлять отдельные подрядчики. А интеграцией ПО и созданием финальной прошивки занимаются разработчики системы.
Из-за этого отладка проблем становится сложнее, поскольку баг может находиться не в вашем коде, а в чужом модуле. А интеграция разных компонентов порождает сложные системные эффекты. В результате разработчики вынуждены искать ошибки в коде, который им не принадлежит.
Например, если микросхема управления питанием поставляется сторонним производителем, то при сбоях приходится разбираться не только с кодом Android, но и с прошивкой самого модуля.

Поскольку прошивка разрабатывается внутри компании, а не выкладывается в открытый доступ, то требуется локальный сервер для хранения версий кода. В отличие от мобильных приложений, где можно использовать GitHub, GitLab или Bitbucket 一 Google рекомендует использовать репозиторий на базе Gerrit. Gerrit 一 это специализированная система контроля версий, разработанная для управления большими проектами, такими как Android. Она включает код-ревью с обязательными проверками перед коммитами, раздельное хранение кода для разных модулей, что удобно при интеграции с партнёрами, а также управление мерджами и тестированием перед внесением изменений.
Большинство компаний, работающих с AOSP, используют Gerrit для контроля версий, и разработчикам прошивок необходимо знать, как с ним работать.
Для настройки системы контроля версий нужны специалисты DevOps, которые развернут и поддержат репозиторий. Также придётся составить грамотную политику доступа, чтобы избежать утечек кода. А процессы сборки нужно автоматизировать, чтобы каждое изменение в коде тестировалось перед встраиванием в прошивку.
Тестирование прошивки также сложнее тестирования обычного мобильного приложения. Для разработчиков устройств это дополнительный навык, который не требуется при создании обычных Android-приложений.
Оно включает три уровня проверки:
Тестирование прошивки |
Тестирование API прошивки |
Тестирование встроенных приложений |
Проверка драйверов и их совместимости с железом |
Сторонние приложения могут работать с сервисами прошивки (например, управлять громкостью, воспроизводить звук) |
В прошивке есть базовые приложения, такие как видео- и аудиоплееры, настройки устройства |
Тестирование базовых системных сервисов, таких как обработка звука, управление экраном, если он есть, взаимодействие с сенсорами |
API должны быть протестированы и должна обеспечиваться их плавная эволюция |
Они должны корректно работать во всех режимах |
Когда мы говорим о тестировании обычного мобильного приложения, самый неприятный сценарий — это его падение. В худшем случае приложение зависает или теряет пользовательские данные. Но проблему можно решить путём перезапуска и/или переустановкой.
Но если баги появляются на уровне системного кода устройства и в системном приложении возникает критическая ошибка, устройство может уйти в boot-loop — бесконечную перезагрузку. Пользователь не сможет ничего сделать, даже если перезагрузит устройство вручную. В некоторых случаях даже сброс к заводским настройкам не помогает и приходится перепрошивать устройство.
Избежать критических ошибок помогут:
Автоматизированные тесты прошивки. Стараемся внедрять автоматизированное тестирование даже на уровне прошивки. Это позволяет заранее выявлять ошибки, которые могут привести к нестабильности системы.
Жёсткие требования к системному коду. Код, связанный с ядром ОС, драйверами, загрузчиком, проходит многоуровневую проверку. Любая ошибка может привести к неработоспособности устройства, поэтому тестированию уделяется особое внимание. Например, если в процессе обновления прошивки что-то пойдёт не так, повреждён файл обновления или возникает ошибка во время записи, устройство может превратиться в «кирпич». В таком случае его придётся восстанавливать вручную через инженерные инструменты.
Контроль безопасности. Системные компоненты устройства работают с привилегиями, недоступными обычным приложениям. Поэтому ошибки в их коде могут привести не только к сбоям, но и к уязвимостям в безопасности.
В мобильных приложениях всё изолировано — каждое приложение работает в своём окружении. Но разработка прошивки для устройств — это не только работа с железом, но и поддержка совместимости между разными компонентами системы. Устройство состоит из нескольких сервисов и приложений, которые должны взаимодействовать друг с другом. Разные процессы взаимодействуют между собой. Есть системные API, к которым приложения обращаются.
Например, аудиосистема общается с сервисом обработки команд. Графическая система взаимодействует с API управления экраном. Фоновый процесс обновлений должен поддерживать совместимость с предыдущими версиями системы.
Если при обновлении не следить за совместимостью, могут возникнуть конфликты:
-
Приложение А использует один формат данных, а приложение Б — другой.
-
Один процесс ожидает одни параметры, а другой процесс их больше не отправляет.
-
Некоторые сервисы могут перестать корректно взаимодействовать.
В итоге, система перестаёт корректно работать, так как разные её части не понимают друг друга. Это можно сравнить с ситуацией, когда русский и китаец пытаются общаться, не зная общего языка.
Решить проблему совместимости помогут:
Чёткие контракты между сервисами. Мы заранее определяем структуру данных и протоколы взаимодействия, которые не должны меняться без обратной совместимости.
Механизмы версионирования API. Если необходимо изменить формат данных, реализуем механизмы поддержки старых версий, чтобы система могла работать без сбоев.
Гибкие механизмы обновлений. Мы разрабатываем процедуры отката в случае неудачного обновления, чтобы избежать ситуации, когда устройство становится неработоспособным.
Android предоставляет несколько способов межпроцессного взаимодействия (IPC), но каждый из них требует более сложной архитектуры взаимодействия, чем в обычных приложениях.
Эти механизмы требуют более сложной архитектуры кода по сравнению с обычными мобильными приложениями.
Особенности обработки звука и роль C++
Звук — одна из ключевых составляющих работы умных устройств, особенно голосовых ассистентов и колонок. В отличие от телефонов, которые пользователь держит в руках или у уха, колонки стационарны, и их микрофоны должны улавливать команды из любого места комнаты.
При этом возникает ряд сложностей, которые нужно решать на уровне прошивки. У колонок больше микрофонов, чем у телефонов, что позволяет определять направление источника звука. Вокруг может быть много фонового шума — работающий телевизор, разговаривающие люди, шум улицы, лай собаки. А ещё колонка должна отличать музыку, которую она воспроизводит, от команд пользователя.

Поэтому разработка для таких устройств включает сложную обработку аудиосигнала, которая требует высокой производительности.
Для повышения точности распознавания команд применяется целый набор алгоритмов обработки звука. Самые распространённые из них:
Acoustic Echo Cancellation (AEC) — подавление эха. Если колонка воспроизводит музыку, её микрофоны тоже её слышат. AEC позволяет вычитать воспроизводимый звук из входного сигнала, оставляя только голос пользователя. Это снижает вероятность ложных срабатываний голосового ассистента.
Noise Reduction (NR) — фильтрация шумов. Различает полезные сигналы (речь) и шум (гул улицы, звук кондиционера, лай собаки). Позволяет отделять голос от окружающего фона и передавать в систему чистый сигнал.
Beamforming — пространственная обработка звука. Использует несколько микрофонов для определения, откуда пришёл звук. Позволяет «фокусироваться» на голосе говорящего и игнорировать посторонние шумы.
Dereverberation — устранение эха и отражений. Компенсирует отражённый звук, который может исказить команду. Особенно важно в больших помещениях с голыми стенами.
Каждый из этих алгоритмов требует быстрой обработки аудиопотока в реальном времени, что делает C++ (а иногда и язык ассемблера) незаменимым инструментом.
Аудиообработка — это реальное время, и здесь важны оптимизация и производительность. C++ позволяет работать с низкоуровневыми операциями быстрее, чем интерпретируемые языки вроде Java или Python.
А ещё благодаря С++ можно оптимизировать использование CPU, SIMD-инструкций и DSP (цифровых сигнальных процессоров). Ведь обработка аудиопотока требует минимального времени реакции, иначе голосовой ассистент будет тормозить. При этом для встроенных устройств важно, чтобы программы занимали минимум памяти. И тут снова выигрывает С++.
В некоторых случаях оптимизация идёт ещё дальше — критические части алгоритмов пишут на ассемблере, особенно если используется DSP (Digital Signal Processor).
Если вас интересует разработка аудиосистем и голосовых интерфейсов, стоит прокачать такие знания:
-
Основы цифровой обработки сигналов (DSP) – фильтрация, свёртки, оконные функции.
-
Библиотеки для работы со звуком:
-
FFmpeg – обработка аудиопотоков.
-
PortAudio – низкоуровневый доступ к аудиоустройствам.
-
Speex, Opus – кодеки для сжатия речи.
-
-
Работу с микрофонными массивами и Beamforming.
-
Оптимизацию кода на C++ с использованием SIMD (AVX, SSE).
Производительность: как добиться стабильной работы на ограниченном железе
Одна из ключевых особенностей разработки для нестандартных устройств — ограниченность доступных вычислительных ресурсов. Если современные смартфоны комплектуются мощными процессорами и большим объемом оперативной памяти, то такие устройства, как умные колонки, видеорегистраторы, телевизоры и даже фотоаппараты на Android, зачастую обладают менее производительным железом.
Но эти устройства, несмотря на относительно слабую аппаратную начинку, должны работать надёжно и непрерывно. Например, видеорегистратор должен записывать видео до тех пор, пока его физически не отключат или пока из-за сбоя в последствии аварии он не утратит способность функционировать. А умная колонка — реагировать на голосовые команды 24/7, причём с минимальной задержкой. Если время отклика слишком велико, пользователь просто перестанет ей пользоваться.
На умных устройствах одновременно работают различные параллельные процессы:
-
Распознавание ключевого слова ("Алиса", "Окей, Google").
-
Вывод информации на экран — например, заставки, анимации, фильмы.
-
Аудио- и видеовоспроизведение — музыка, стриминг видео.
-
Фоновые процессы — синхронизация, обновления, работа сенсоров и датчиков.
Все эти задачи конкурируют за ограниченные ресурсы устройства, поэтому важно уметь эффективно управлять их выполнением.
Как работать с производительностью:
Оптимизация работы с памятью. Для этого используем минимально возможное количество оперативной памяти. Избегаем утечек памяти и неконтролируемого роста потребления ресурсов. Учитываем влияние кэширования и предзагрузки данных.
Управление нагрузкой на процессор. Для этого ограничиваем фоновую активность, чтобы основные процессы получали нужное время на исполнение. Используем оптимизированные алгоритмы обработки звука, графики и вычислений. Работаем с энергоэффективными режимами процессора.
Снижение энергопотребления. Ограничиваем избыточное использование CPU и GPU. Оптимизируем время запуска сервисов и их работу в спящем режиме. Тестируем и контролируем нагрузку на аккумулятор для устройств с автономным питанием.
Если не учитывать производительность, можно столкнуться с ситуацией, когда устройство просто не справляется с нагрузкой. В таком случае либо процессор перегружается, и система зависает. Либо некоторые задачи «выпадают» из очереди и не выполняются. В наихудшем случае устройство перезагружается или просто перестаёт реагировать.
Выводы
Разработка для умных устройств, будь то колонки, видеорегистраторы, автомобильные мультимедиа-системы или IoT-решения, требует совершенно иного подхода, чем мобильная разработка. Если в мире Android-приложений разработчик получает готовую операционную систему и сервисы, то в случае с устройствами он сам становится частью команды, которая создаёт ОС и инфраструктуру с нуля. Это путешествие по полному чудес лесу, но без карты, компаса и опытного проводника.
Главные вызовы, с которыми сталкивается разработчик устройств:
-
Отсутствие готовой экосистемы.
Работая с Android Open Source Project (AOSP), разработчик должен самостоятельно создавать многие вещи, которые в обычных смартфонах обеспечивают сервисы Google (Google Play, Firebase, Play Services). -
Работа с железом и драйверами.
Устройства имеют уникальные аппаратные модули — сенсоры, аудиочипы, экраны, мультимедийные контроллеры. Чтобы заставить их работать, приходится разрабатывать драйверы на C++ и разбираться в низкоуровневом взаимодействии. -
Производительность на слабом железе.
В отличие от флагманских смартфонов, которые обладают избыточными ресурсами, умные устройства часто работают на ограниченных вычислительных мощностях.
Неоптимизированный код может перегрузить процессор, вызвать утечки памяти и затормозить всю систему, поэтому разработчик обязан следить за эффективностью каждого компонента. -
Безопасность и привилегированные сервисы.
Системные сервисы устройств имеют доступ к критически важным данным, управляют Wi-Fi, Bluetooth, микрофонами, камерами. Ошибки в их коде могут привести к взлому системы, поэтому защита прошивки и аудит безопасности становятся приоритетными задачами. -
Тестирование и обновления.
Разработка прошивки и её обновлений намного сложнее, чем деплой мобильных приложений. Любая ошибка в системном коде может привести к boot-loop'у (бесконечной перезагрузке) или "окирпичиванию" устройства.
Поэтому тестирование должно включать не только проверку функциональности, но и анализ совместимости, стабильности и возможности отката на предыдущие версии.
Спрос на специалистов растёт. Рынок IoT, умных домов, автомобильных решений, носимых устройств и встраиваемых систем стремительно развивается.
Компании ищут разработчиков, которые умеют работать на стыке высокоуровневого кода (Android, Kotlin, Java) и низкоуровневых технологий (C++, драйверы, ядро Linux, аппаратные протоколы). Это сложная, но востребованная область, где специалист получает конкурентное преимущество и может участвовать в уникальных проектах, которых в мире не так много.
Разработка под устройства — это не просто программирование, а исследовательская работа, требующая инженерного
Разработка прошивки – это не просто кодинг, а настоящее приключение. Вам предстоит идти по неведомым тропам, собирать артефакты (драйвера, тесты, симуляторы), избегать ловушек (boot-loop'ов и зависаний) и, возможно, найти старый манускрипт с документацией по вашему железу. Если у вас есть дух первооткрывателя – добро пожаловать в лес разработки под устройства. Главное – не забывайте оставлять метки на деревьях (логи и бэкапы), чтобы не заблудиться!
Приходите на AppsConf в июне в Москве: сможем обсудить как стандартную мобильную разработку, так и разработку под нестандартные устройства. Поговорим про технологии, инфраструктуру, процессы, финансы и юридические вопросы.
Автор: olegbunin