Перейти к основному содержимому

Среда устройства: что есть, чего нет и что сломает залочка

Страница про то, во что упрётся код на реальной плате. Все факты сняты с живого устройства 2026-09-01, перед тем как плату отключили.

Экран и ввод

Панельодна, 800 × 1280, портрет, 61 Гц
Плотность160 (320 dpi)
Тачgoodix-ts, инвертирован по умолчанию — компенсируется свойством persist.sys.touch.angle=180
Ориентацияактивити объявлена портретной
Компенсация инверсии тача держится на честном слове

Свойство сейчас живёт только в памяти, в build.prop образа его нет. Любое стирание /data вернёт инверсию: человек жмёт «1», нажимается «9». Внести свойство в build.prop — пункт из NATIVE-GATE.md, и правится он в образе, то есть тем же выездом.

Приложение — это рабочий стол

Категории HOME + DEFAULT навешивает плагин plugins/withHomeLauncher.js, роль закреплена как preferred. Кнопка «назад» подавлена — из киоска выйти нельзя.

Практический вывод: уронить киоск некуда. Если он упадёт, пользователь увидит пустоту, а через несколько минут плата перезагрузится сторожевым таймером.

Всё, что правит Android-проект, обязано жить в этом плагине: каталог android/ порождается expo prebuild и при --clean затирается вместе с ручными правками манифеста.

Установка только системная

adb install даст приложение в домене untrusted_app, у которого нет доступа к узлу сторожевого таймера — почему это важно. Приложение запекается в образ как /system/priv-app/Postamat/Postamat.apk.

warning
Копия в /data затеняет запечённую в образ при равном versionCode

Проверяя новую версию, поднимайте versionCode и делайте adb uninstall. Иначе будете тестировать старый код, будучи уверены в обратном. Эта грабля один раз уже сделала заливку холостой.

Чего в системе нет — и не надо туда лезть

  • Камер нет. Возможности android.hardware.camera* в системе отсутствуют: камеры выключены в дереве устройств. Любая библиотека, которой нужна камера, работать не будет. Это цель проекта, а не досадное ограничение.
  • Микрофона в возможностях системы нет, пути захвата вырезаны из политики аудио. 🔒 Но микрофонный тракт на плате физически есть (кодек, контрол в положении «выключено») и включается одной командой из софта. Для проекта, затеянного ради выпиливания камер, включить его из приложения — такая же дыра. Не включать.
  • Телефонии и Bluetooth нет — вырезаны из образа.
  • Есть: Wi-Fi, USB-host, Vulkan / GLES 3.2.

🔴 Сканера QR на плате нет — и не было

Это факт со съёма, а не предположение: на USB нет ни одного устройства, кроме хаба платы; среди устройств ввода только тач, кнопки и детектор гарнитуры — ИК-приёмник из этого списка с тех пор убран; узлы /dev/ttyUSB* и /dev/ttyACM* не создавались.

Что это значит для кода. Интеграцию сканера не на чем было проверить. Всё, что про сканер записано в документах проекта — модель, работа как USB-HID «клавиатура», права на устройства ввода — это сведения из документации и рассуждение, а не измерение.

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

Сканер как клавиатура — путь общий с любым другим устройством ввода

Если киоск будет ловить сканер как клавиатуру, он по построению ловит и всё остальное, что притворяется клавиатурой. Раньше главным таким источником был ИК-пульт; теперь приёмник выключен, но само свойство никуда не делось — любое подключённое HID-устройство пойдёт тем же путём.

ИК-приёмник выключен в образе

На плате был живой инфракрасный приёмник пульта, зарегистрированный как устройство ввода с полной картой клавиш, включая power. Это был единственный беспроводной вход, который не был заглушен: подросток с универсальным пультом за пять евро гасил экран постамата.

Теперь его нет. В дереве устройств узел pwm@fe6e0030 (pwm7, к которому подключён фотоприёмник) переведён в status = "fail".

Проверено на живом, а не выведено рассуждением:

  • драйвер ИК-приёмника не загрузился;
  • устройств ввода стало пять вместо шести — приёмник исчез из списка целиком;
  • подсветки на соседних узлах (pwm4, pwm5) не задеты, экран работает как работал.
Фильтр клавиш в приложении писать не нужно

Раньше в списке нативных задач стоял фильтр, отсекающий нажатия с пульта, — и его нельзя было ни написать заранее, ни проверить. Теперь фильтровать нечего: события не приходят вовсе, потому что устройства ввода больше не существует.

Это как раз тот случай, когда задача решена не кодом, а тем, что источник убран.

⚠️ В COMMISSIONING.md остаётся отдельный шаг «заклеить фотоприёмник непрозрачной лентой». Он писался до этой правки образа и теперь дублирует программное выключение. ❓ Оставлять его или убрать — решение владельца; аргумент за то, чтобы оставить: лента продолжает работать и на плате, залитой старым образом, а стоит она тридцать секунд.

Чего в приложении сейчас нет — и чинится это только выездом

Пункты из NATIVE-GATE.md, которые легко принять за мелочь. Каждый стоит поездки, если про него забыть при единственной нативной заливке.

Экран может погаснуть. Разрешения WAKE_LOCK в манифесте нет, удержания экрана тоже. Погасший экран на уличном постамате неотличим от сломанного: человек уходит.

Приложению нечем издать звук. Динамик подключён и оставлен намеренно, но системные звуки в образе выключены — своих звуковых файлов у приложения нет. Последствия конкретные: нажатие цифры в перчатке на морозе ничем не подтверждается (человек жмёт дважды и попадает в антибрут); щелчок замка через дверцу не слышен; и главное — некому крикнуть «закройте дверцу». Это единственный исполнительный механизм, которым можно вернуть уже уходящего человека, и он не задействован.

Яркость не управляется. Днём на солнце экран нечитаем, ночью светит жильцам в окна.

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

Порты и разъёмы, которые важны коду

РазъёмКуда идётЗачем нам
RS485 (клеммник)/dev/ttyS0🔴 плата замков, главный рабочий интерфейс
UART (клеммник)консоль отладки, 1 500 000 бодединственный путь из кирпича, снаружи корпуса
Type-CUSB-OTGadb и заливка образа; ⚠️ только USB 2.0
RJ45eth0, PHY 10/100проводной путь обслуживания
USB ×5хаб платына съёме не подключено ничего

⚠️ Пин «5V» на задних клеммниках — это выход питания платы, а не вход. Питание переходника к нему не подключать.

Сеть

В проде связь по Wi-Fi, на роутере фильтр — только до нашего backend. Фильтр работает по именам, и в него заносятся ровно два: api (эндпоинты устройства) и ota (обновления). Панель оператора и документация живут на других именах и постамату недоступны вовсе — зачем так сделано. Ethernet остаётся проводным путём обслуживания: если через 45 секунд после загрузки DHCP ничего не дал, на eth0 встаёт запасной адрес 169.254.1.1/16 — воткнутый напрямую ноутбук достучится без единой настройки со своей стороны.

Плату нельзя подключать к боевой сети

Пока на ней отладочная сборка, SELinux в permissive и adb по TCP:5555 — любой, кто дотянется по сети, получает root одной командой. Это осознанное временное состояние на время разработки, решение владельца.

Что сломает залочка

Залочка — это перевод SELinux в enforcing, отключение отладочной сборки и выключение сетевого adb. Список того, что перестанет работать, снят с живого: в permissive система пишет в лог всё, что запретила бы. Собрано 274 отказа.

Что случится
🔴 кормление сторожевого таймерабудет отклонено молча, плата уйдёт в цикл «пять минут — сброс». Нужна своя политика
🟡 оверлей температуры / CPU / GPU в киоскепокажет «—». Приложение не упадёт: каждое чтение в try/catch, любое поле может быть null. Не добавлять сюда «упасть, если не прочиталось»
✅ работа с платой замковне пострадает: среди 274 отказов нет ни одного на устройство порта
Список отказов неполон, и это надо понимать

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

Обратима ли залочка — да, пока цел загрузчик и есть физический доступ к клеммнику UART: путь восстановления идёт мимо Android. Разбор — docs/ROOT-AND-LOCKDOWN.md в репозитории прошивки.