Запуск приложений в Android Virtual Device на удаленном Linux-сервере

В процессе работы над одним проектов возникла ситуация, когда необходимо проводить в автоматическом режиме ряд операций из мобильного приложения. Поскольку набор входных данных, которые вводит пользователь для работы приложения меняется, была необходима реализация, которая позволила бы имитировать действия пользователя. Более того, необходимо было, чтобы приложение запускалось автоматически на удаленном linux-сервере, выполняло действия и сохраняло результаты. О том, как решал данную задачу, я и хочу рассказать читателям.

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

Требования и инструменты


Главным требованием было то, что приложение должно запускаться на linux-сервере. Для меня это значило, что привычного мне, заядлому «виндузятнику», графического интерфейса не будет со всеми вытекающими из этого сложностями. Также среди полезных пожеланий была возможность вести отладку все на том же сервере при необходимости.

Для реализации использовались:
  1. Среда разработки — IntelliJ IDEA;
  2. Удаленный сервер linux — Debian 7;
  3. Android SDK;
  4. Putty — для реализации удаленной отладки.


Шаг 1. Разворачиваем SDK


Сам Android SDK можно взять отсюда. Для его работы, разумеется, необходим предустановленный JDK, у меня это была версия 1.7. Ранее была необходима именно х86 версия, но начиная с некоторых последних версий данная проблема отпала. После того как Android SDK у нас есть, начинаем его устанавливать и настраивать:
  1. Копируем архив на нашу linux-машину и распаковываем в нужный каталог;
  2. Далее обновляем наш SDK.
    Тут два варианта. Первый, когда вы точно знаете, что вам необходимо, тогда получаем список доступных библиотек:

    ./android list sdk –all
    

    В результате получим длинный список доступных для скачивания пакетов, выбираем нужные и даем команду для из загрузки:

    ./android update sdk --no-ui –filter<порядковый номер пакета из списка пакетов или имя категории>
    

    Второй вариант скачать все, что доступно на текущий момент. Мне он оказался ближе, потому что сам я не разработчик Android и не был уверен, что выберу все, что нужно:

    ./android update sdk --no-ui
    

    Обе эти команды описаны на официальном сайте в разделе документации, но почему-то описание ключа --no-ui, который указывает на запуск без графического интерфейса, я там не нашел, возможно, плохо искал.
  3. Ждем окончания загрузки пакетов.

Далее для простоты управления можно добавить утилиты adb, android, emulator из каталогов platform-tools и tools в системные переменные, но я запускал их просто из каталога.

Шаг 2. Создаем и запускаем Android Virtual Device


Теперь нам необходимо создать наше виртуальное устройство, тут тоже ничего сложного, команда для этого стандартная:

./android create avd --name <имя устройства> --target <порядковый номер версии ОС Android> –b <набор инструкций процессора>

Имя устройства — ну тут все и так понятно.
Порядковый номер версии ОС Android — его можно увидеть в списке доступных версий для создания устройства. Сам список можно получить командой:

./android list target

Набор инструкций процессора — какой процессор эмулировать, если для версии Android использовался только один вариант процессора, то данный параметр можно проигнорировать, иначе в ответ на команду утилита выдаст сообщение о необходимости явно указать набор инструкций, а также укажет возможные варианты. Например, у меня значение этого параметра было default/armeabi.

После этого создает папку с набором файлов виртуального устройства, расположен он в каталоге */.android/avd, который находится или в директории root, или в директории, где расположен сам SDK (зависит от прав пользователя). Имя каталога с файлами совпадает с именем виртуального устройства.

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

./emulator -avd <имя устройства> -no-window

-no-window — указывает на запуск с отключенным экраном.
Имя устройства — имя, которое мы указали при создании устройства выше.
Более подробное описание и другие ключи для запуска можно найти здесь.

Теперь нужно дождаться, пока устройство загрузится:

./adb wait-for-device

Теперь нам осталось только установить наши приложения: основное, которое обращается к серверу, и robotium-приложение, которое умеет обращаться к основному и выполнять действия:

./adb install -r <имя приложения>

-r — данный ключ показывает, что если приложение уже существует, то перезаписать его.
Имя приложения — имя вашего apk-файла с расширением.

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

Шаг 3. Запуск приложений


Запустить robotium-приложение достаточно просто (я приведу конкретный пример для наглядности):

./adb -s emulator-5554 shell am instrument -w -e class com.example.robotium.Kernel com.example/android.test.InstrumentationTestRunner

emulator-5554 – имя эмулятора, обычно оно стандартно, если эмулятор запущен в системе один, но посмотреть список доступных запущенных устройство можно командой:

./adb devices

e class com.example.robotium.Kernel – имя класса в robotium-приложении, непосредственно выполняющего тесты.
com.example– имя package из файла AndroidManifest.xml для robotium-приложения.

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

./adb shell input keyevent 82

Тест на своей windows-машине показал, что это работает, причем независимо от того запущен эмулятор с параметром –no-window, и без него. А вот запуск на debian-е не дал ничего, ошибка повторялось, а значит причина в другом, предположил я. Долгие поиски не дали ничего конкретного, видимо, мало кому приходит в голову гонять тесты для GUI на терминальном сервере. В основном встречались комментарии, что поскольку тесты эти для gui, то и работать они при отключенном экране не могут, мол, нет GUI отображающегося, нет и тестов для них. Но у меня ситуация была из разряда «партия сказала надо» и придти с таким ответом к своему teamlead-у я не мог, поэтому я взял за аксиому, что экран просто не разблокировался, к сожалению проверить визуально как оно было на самом деле я не смог, сервер терминальный все-таки. Добавил дополнительные проверки на состояние экрана в момент запуска и действительно оказалось, что экран мало того, что не разблокирован, но и еще выключен – подвела-таки команда.

Проблему решить помогла программная разблокировка. Для этого в robotium-приложении добавляем код:

PowerManager.WakeLock wl;
PowerManager pm = (PowerManager) solo.getCurrentActivity().getApplicationContext().getSystemService(Context.POWER_SERVICE);
wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK
        | PowerManager.ACQUIRE_CAUSES_WAKEUP
        | PowerManager.ON_AFTER_RELEASE, "INFO");
wl.acquire();
KeyguardManager km = (KeyguardManager) solo.getCurrentActivity().getApplicationContext().getSystemService(Context.KEYGUARD_SERVICE);
KeyguardManager.KeyguardLock kl;
kl = km.newKeyguardLock("name");
kl.disableKeyguard();

Чтобы данный код заработал в файл AndroidManifest.xml необходимо добавить следующие строчки:

<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />

Следует отметить, что добавлять нужно не в файл robotium-приложения, а в файл тестируемого приложения, потому что вся работа с ОС Android ведется именно через него, а значит ему и нужны все права на доступ.

После этого еще раз выполняем описанную ранее команду — ура, все запустилось все работает.

Шаг 4. Настройка удаленной отладки


К сожалению, с нуля, ни сама Android SDK, ни IDEA не умеют работать с виртуальными устройствами на удаленных серверах, а значит заставим их думать, что устройство здесь, рядом. Для этого настроим в Putty туннель к нашему серверу. Для этого надо добавить два порта — для устройства emulator-5554 это будут порты 5554 и 5555. Для уточнения на всякий случай пример на изображении:

image

Теперь на удаленном сервере выключаем сервис ADB:

./adb kill-server

А на локальной машине запускаем или перезапускаем (сразу выключив):

./adb start-server

Теперь если выполнить команду ./adb devices — мы увидим удаленные запущенные устройства. К сожалению, запускать эмуляторы удаленно мы не можем, только видеть уже запущенные, ну и работать с ними. Теперь, при запуске robotium-приложения непосредственно из IDEA в диалоге выбора устройства мы увидим и наш удаленный эмулятор (см. изображение). С ним можно работать точно так же как и с локальным.

image

Спасибо за внимание, надеюсь данный пост будет полезен еще кому-то, потому что мне его в свое время очень не хватало.
  • +7
  • 8,8k
  • 6
Поделиться публикацией
Похожие публикации
Ой, у вас баннер убежал!

Ну. И что?
Реклама
Комментарии 6
  • 0
    Я бы для выяснения причин ошибок временно пробросил «иксы» на свою машину и включил графику в эмуляторе. В винде можно поставить, например, Xming и средствами того же putty включить X11 Forwarding. В линуксе и так всё заработает. При этом не обязательно на удалённой машине включать графику, достаточно наличия установленной базовой подсистемы X11 (libX11, Xorg и т.п.).
    Либо можно использовать VNC, но это несколько посложнее (хотя и работать будет побыстрее). Если интересно, расскажу.
    • 0
      Да, думаю, будет полезно знать об этом. Но там главная заморочка была в том, что «в бою» не будет графических библиотек, причем никак и никогда, и это уже зависит только от заказчика.
      • 0
        Я и говорю, что для отладки можно, а на боевом сервере это действительно ни к чему.

        Для VNC используется пакет Xvnc (его разрабатывает так же команда, что и TightVNC). Он есть во всех популярных репозиториях, так что описание установки опущу.
        На клиенте можно установить TightVNC (он с Xvnc по очевидным причинам работает эффективнее всего) или какой-нибудь другой VNC-клиент.
        Далее есть два варианта: xinetd и ssh.

        В первом случае надо настроить и включить inetd или xinetd (у кого что в системе стоит). У меня (openSuSE) после установки Xvnc в каталоге /etc/xinetd.d сразу образовался файл с отключёнными (строка «disable=yes») образцами сервисов. Надо их настроить сообразно своим требованиям, (пере)запустить xinetd и можно коннектиться на выбранный порт своим клиентом. Выводится рабочий стол и т.п, можно запускать все нужные программы стандартным образом.

        Второй случай предусматривает проброс порта через SSH. Это гораздо безопаснее, хоть и немного ухудшает производительность. К тому же позволяет запустить только ту программу, которая нужна, а не грузить весь рабочий стол. Понадобится лишь простейший менеджер окон openbox (тоже есть во многих репозиториях).
        В каталог пользователя помещается исполняемый файл «VNC» следующего содержания:
        #!/bin/sh
        
        export DISPLAY=:[YOUR_DISPLAY]
        
        vncserver $DISPLAY -localhost -geometry 1280x800 -depth 16 -query localhost -once securitytypes=none
        [YOUR_COMMAND]
        vncserver -kill $DISPLAY
        

        где [YOUR_DISPLAY] — номер дисплея, произвольное целое число желательно более 10 (например, 21), а [YOUR_COMMAND] — команда, которую надо запустить (например, xterm). Разумеется, вместо 1280x800 можно указать любое другое желаемое разрешение.
        В каталоге пользователя создаётся подкаталог ".vnc", где создаётся исполняемый файл «xstartup» следующего содержания:
        #!/bin/sh
        
        xrdb $HOME/.Xresources
        xsetroot -solid grey
        openbox &
        

        Процесс соединения в putty несколько усложняется:
        * Пробрасываем локальный порт 5900 на удалённый порт 5900+YOUR_DISPLAY (то есть 5921, если в скрипте указали DISPLAY=:21).
        * В разделе SSH указываем запуск команды "./VNC".
        * Отключаем сжатие (оно в данном случае только вредит)
        После установки соединения в putty на клиенте соединяемся с localhost. Получаем окно, где уже запущена указанная программа.
        Если надо запускать не отдельную программу, а рабочий стол целиком, то надо убрать openbox из xstartup и в качестве YOUR_COMMAND указать запуск сессии вашего любимого DE (он должен быть установлен) — kde-session, gnome-session, openbox-session, lxde-session и т.п.
        Таким образом, например, я раздаю 1С 8.3 из-под линукса с сервера в центральном офисе по удалённым рабочим местам, разбросанным по области.

        Вот написал сейчас это всё и думаю, а не запилить ли хабрапост на эту тему… Пойду поищу, не писали ли уже такого.
  • 0
    Осталось только нормальный клиент для вайбера запилить на этой базе
    • 0
      Спасибо автору за статью.
      Очень ксати)

      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

      Самое читаемое