9 мая 2016 г.

Android SDK. Тестируем по-настоящему!

    Эта запись — предпоследняя из всего цикла. Пожалуй, она самая скучная, однако она ближе всего к тому, что называется тестированием. И, мне кажется, она ещё и самая длинная. Я попытался разбавить всю эту скукоту наглядными примерами, скриншотами. Книги с картинками читают охотнее? По крайней мере популярные «блоггеры» (а я — популярный, у меня есть минимум 8 читателей, скоро продамся кому-нибудь и работать перестану!) часто ставят всякие картинки, возможно это и работает.
    Как бы то ни было, здесь можно получить минимальное понимание того, что есть в Android SDK и что из этого нужно тестировщику. А главное — зачем. Ещё тут есть море грамматических ошибок, наверное, так как писать большую часть текста приходилось ночью, а я по ночам люблю спать и после 22 часов, как правило, уже сплю.

    Уверен, вам было интересно узнать, во сколько я засыпаю. Читайте дальше, там ещё интереснее!

 Android SDK

    Мы подбираемся всё ближе и ближе к инструментам и методам тестирования. Инструменты для тестирования, а также всякий вспомогательный инструментарий, входит в состави Android SDK. Самые нужные компоненты из состава SDK, конкретно для тестировщиков, это инструменты SDK, они же SDK tools, инструменты сборки, они же Build tools (внезапно, да?) и инструменты платформы, они же Platform tools. Нет никакого смысла запоминать это. Я просто сказал названия папок из установленного пакета Android SDK:
Рис. 1. Содержание папки Android SDK
    В этих папках лежит много чего, но я расскажу про минимальный полезный набор.


SDK Tools

    Здесь лежит набор инструментов, без которых нет смысла и начинать тестирование. Без этих инструментов у вас будет не тестирование, а ловля рыбы в мутной воде. Ключевыми инструментами здесь являются следующие: emulator, monitor, monkeyrunner и, для автоматизваторов, uiautomatorviewer.

Эмулятор

    Вообще называется он «Android Virtual Device» (AVD). Он позволяет создавать виртуальные устройства как из шаблонов, типа Nexus 6, Nexus 4, просто «Устройство с экраном на 7 дюймов», так и совсем кастомные, а также и создавать свои шаблоны. Достоинство и недостаток виртуальных устройств именно в их эмуляции. В отличие от виртуальных машин, где, очень грубо и просто говоря, аппаратные возможности и сами устройства хостовой ОС пробрасываются в гостевую ОС, эмулятор вынужден предоставлять совершенно другую архитектуру — ARM. И от того эмулятор ужасно тормозит. За этого его не любят.
    Впрочем на Intel процессорах хостовой ОС можно установить HAXM (Intel Hardware Accelerated Execution), который также можно найти в SDK (в extras), и получить отличный прирост производительсности эмулятора Intel процессора. Однако это доступно только для владельцев Intel и на процессорах от AMD HAXM не работает. Но в любом случае, x86 эмуляторы побыстрее ARM'овских.

    Вторая, но гораздо более важная проблема, заключается в том, что периодически эмулятор просто отваливается. Вы можете взаимодействовать с ним мышкой и горячими клавишами, но не можете подцепиться через adb (про который я расскажу дальше). Без доступа по adb эмулятор становится просто не нужен. Здесь, кстати, может спасти альтернативный эмулятор — Genymotion, который сделан для исправления типичных проблем штатного эмулятора (и очень популярен!).

    Почему же эмулятор ещё жив, если есть реальные устройства, есть альтернативы? Благодаря эмулятору вы можете, например, посмотреть, как будет выглядеть интерфейс приложения на устройстве, которого у вас нет: вы можете в несколько кликов создать вируальное устройство, задав нужное разрешение, плотность точек, соотношение сторон, и поглядеть на интерфейс. Можно и быстро посмотреть реакцию на типовые ситуации — изменение громкости, поворот экрана, изменение скорости подключения к сети и подобное. К тому же образы Android (кстати, образы Android для эмулятора — практически оригинальный AOSP!) обновляются очень оперативно. У вас может не быть образа для Nexus устройства, но для эмулятора он всегда есть. Эмулятор всегда под рукой.

Monitor

    Или, как его звали в молодости, DDMS. DDMS теперь (на самом деле давно) деприкейтед, то есть объявлен устаревшим, и эту аббревиатуру можно не запоминать. Расшифровывается она, кстати, Dalvik Debug Monitor Service. Dalvik — это и есть та виртуальная машина, в которой работают Android приложения. Dalvik жил до Android 4.4 включительно, а в Android 5.0 он был заменён на виртуальную машину ART — Android Runtime.
    Одно из ключевых отличий ART от Dalvik, в глазах пользователя, это то, что Dalvik компилировал приложения при первом запуске («кэш Далвика» — это вот они), обеспечивая значительное ускорение при повторных вызовах, а ART — при установке. Впрочем, даже эта JIT, Just In Time, то есть «на лету», компиляция байт-кода в машинный появилась лишь в Android 2.2, а до того всё было на одном интерпретаторе. То есть при Dalvik приложения быстрее устанавливаются, но задают жару системе при первом старте. При ART приложения заметно, прям сильно заметно, дольше устанавливаются, зато запускаются шустрее и не создают таких нагрузок при первом старте. На самом деле различий больше, но нас они особо не касаются. Лично мне знание всех этих различий ни разу не пригодилось в работе.

    Так вот, monitor, который запускается файлом monitor.bat, представляет собой, кроме всего прочего, графическую оболочку для logcat. Что это такое, я расскажу позже. Здесь нам важно, что в этой оболочке мы можем искать нужные строки, фильтровать их, отслеживать поведение продукта, да ещё пусть и с примитивной, но всё-таки подсветкой. Возможностей у monitor больше, но они либо практически бесполезны, если у вас есть более одного устройства, либо слишком хардкорны для ознакомительной лекции.

Monkeyrunner

    Это инструмент, предоставляющий API для взаимодействия с приложениями на устройстве путём отправки на это устройство разных событий. Средствами monkeyrunner можно очень быстро написать скрипт, который будет запускать нужные активити, тыкать в нужные места, вызывать меню, стучать по клавиатуре (включая набор заданных текстов), менять громкость устройства, гасить экран и всё такое прочее. К сожалению, гибко писать тестовые приложения на нём очень трудно, всё же он ориентирован на простоту. Зато с его помощью можно достаточно быстро написать тестовый сценарий, которые будут помогать находить регрессионные ошибки в, скажем, интерфейсе.
    Этот инструмент имеет встроенные методы для снятия скриншотов и даже сравнения их между собой! Не следует путать monkeyrunner и monkey, о котором я расскажу позже.

Uiautomatorviewer

    Это полезный инструмент, облегчающий написание грей бокс автотестов. Что такое White box, Black box и Gray box тестирование?
  • White box — мы знаем о приложении всё, при желании даже в код можем заглянуть. Более того, наше тестовое приложение может обращаться напрямую к тестируемому приложению, топая грязными ногами в его песочнице
  • Black box — мы не знаем о приложении ничего. Мы люди простые — мы видим поле ввода, мы вводим туда данные. Ноль, единицу, огромное число, отрицательное число, число с десятичной точкой, число с десятичной запятой, текст, символы юникода, null’ы, скриптовые сценарии, вставляем из буфера обмена сочинения Льва Толстого, картинки, музыкальные файлы, ставим символ юникода, чтобы текст вводился справа налево… В общем — любимое развлечение при типичном исследовательском тестировании
  • Gray box — мы кое-что знаем о приложении, но особо с этим сделать ничего не можем. К примеру, мы знаем, как и почему текст меняется при нажатии на кнопку, но программно именно на эту кнопку нажать не можем. «Именно на эту» — это обращение уровня findViewById(R.id.btnPressMeButton), а не уровня «кнопка, которая лежит вот на этом экране, но не первая, а вторая». Когда вы пытаетесь своей маме по телефон объяснить, как сделать скриншот, это вот оно. Вы знаете, как это происходит, вы точно знаете, что должно получиться на каждом из шагов, но сами этого сделать не можете

    Так вот когда нужно автоматизировать ввод данных в поле и нажатие на кнопку, то нужно узнать, а что это за ресурсы такие, чтобы обращаться напрямую к ним. Можно, конечно, по координатам тыкать, но это просто смешно — даже одно и тоже устройство может быть в двух положениях, а устройств с разными экранами и разрешениями экранов миллиарды. Здесь на помощь и приходит инструмент uiautomatorviewer.
  • Мы подключаем устройство к компьютеру или же запускаем эмулятор
  • Запускаем приложение и просим этот инструмент собрать данные обо всём, что он «видит»
    Инструмент очень подробно разбирает всё приложение на элементарные элементы и показывает все доступные их свойства. В итоге мы можем своим автотестам обращаться чётко к нужным ресурсам вне зависимости от того, на каком устройстве это приложение было запущено. Что ещё ценно, этот инструмент позволяет сохранить данные о разобранных экранах. Мы можем взять устройство на время, быстро сохранить нужные экраны нужных приложений и вернуть его. А дальше писать сценарий автотеста, посматривая в сохранённые данные.
    Чем же это хуже тестирования белого ящика? Тем, что это всё так сладко только в теории. На практике же графический интерфейс приложения может быть построен таким образом, что на нём будет множество «одинаковых» элементов.
Рис. 2. Так uiautomatorviewer «видит» экран настроек режима разработчика (правая верхняя треть) и данные конкретного переключателя, по которым его можно попытаться найти программно (правая нижняя треть)
    На скриншоте типичный пример, когда обратиться к конкретному элементу можно, но это уже выходит за рамки «охохо, сейчас мы тут всё быстренько автоматизируем». У переключателя тот же айди ресурса, что и у всех других переключателей. Нет, в R.java (в этом файле перечислены вообще все ресурсы, какие они есть в приложении) у них разные айди, но снаружи этого не видно.
    Теперь, чтобы переключить конкретно этот переключатель, нужно рекурсивно перебирать лайауты (это, грубо говоря, форма с пазами, в которые все элементы интерфейса вставляются, а форма уже «следит», чтобы из пазов ничего не уезжало) и по косвенным признакам находить нужный, чтобы уже в нём забраться внутрь и щёлкнуть тумблером. Либо же сразу обратиться к нужному лайауту по его индексу (здесь он имеет индекс 6), внутри которого выбрать дочерний с индексом 1, внутри которого щёлкнуть тумблером.

    В первом случае кода будет намного больше, зато небольшие перетасовки интерфейса не сломают автотест, потому что ориентируется он по косвенным признакам (скажем, читает текст и сравнивает с эталонным), однако это уже слабо подходит для тестирования локализаций (потому что в локализациях тексты, понятное дело, меняются). Во втором случае кода совсем мало, можно даже в пару строк уложиться, зато просто перестановка двух вьюх (View здесь — это каждый из элементов интерфейса: каждая кнопка, каждая надпись, каждый переключатель — всё это самостоятельные вьюхи) относительно друг друга полностью сломает автотест. Зато этот метод идеален для тестирования локализаций, потому что для локализаций интерфейс меняют очень редко и нужно, как правило, проверять именно влезание надписей и что эти надписи вообще правильные. А это, между прочим, uiautomatorviewer умеет! Просто потому что он получает ровно те строки, которые видны. То есть если строка вылезает за пределы экрана, вылезшую часть он не «прочтёт».

Build Tools

    Вообще здесь находятся инструменты для сборки горстей текста, картинок, музыки, кода, библиотек и волшебной пыльцы в единый apk файл и около того. Но для тестировщика здесь есть полезный инструмент, который пригодится для быстрого получения некоторых данных из apk.

    Прежде чем о нём рассказать, я скажу в общих чертах о структуре apk файла. Хотя бы для того, чтобы вы не растерялись, когда заглянете в него сами. Как уже было сказано ранее, apk — это просто zip архив. Внутри него нам чаще всего интересны следующие папки:
  • assets. Здесь, обычно, лежат различные ресурсы, которые используются не для правильного отображения интерфейса на правильных языках, а просто вспомогательные, нужные для нормальной работы. Например, ini файлы, собственные шрифты, открытые криптографические ключи и всякое такое
  • lib. Здесь у людей, которые ещё не лишились остатков разума, хранятся библиотеки функций
  • META-INF. Место хранения подписи. Все apk файлы подписаны электронной цифровой подписью, подтверждающей целостность файла и принадлежность приложения владельцу. Любое изменение внутри apk файла делает подпись не валидной. Android откажется установить такое приложение, выбросив соответствующее исключение. Также Android откажется установить одно приложение поверх другого, если у них одинаковое внутреннее имя, но разные подписи. Если же внутренние имена пакетов (их, кстати, можно найти в AndroidManifest.xml) и подписи совпадают, то только тогда возможен апгрейд. Это позволяет избежать ситуации, когда поддельное приложение пытается подменить собою настоящее. Так как модифицировать приложение в тестовых целях приходится десятки раз в день, то приходится постоянно переподписывать итоговые apk. В тестовых целях «боевые» подписи использовать строго не рекомендуется!
  • res. Здесь хранятся все ресурсы приложения — картинки, звуки, тексты, оффлайн справки. Текстовые ресурсы сгруппированы по языкам, графические — по видам экранов
  • AndroidManifest.xml. Об этом файле рассказывалось раньше. Сейчас нам нужно узнать другое. Этот файл представляет собой бинарный XML. То есть его нельзя просто взять и открыть в Notepad++ и с удобством читать на ночь
  • classes*.dex. Здесь находится весь программный код продукта. Под декомпиляцией apk файла подразумевается декомпиляция именно этого файла. Обычно файл classes.dex всего один. Но в Android есть некоторые ограничения на количество используемых методов — максимум шестьдесят пять тысяч пятьсот… Кто догадается про последние две цифры? В общем, максимум 65536 методов на один dex файл. Что важно. Речь не об определённых вами методах, а о тех, на которые вы можете сослаться. То есть вы можете подключить библиотеку ради одного метода «сделать хорошо», а она с собой тянет ещё 50 тысяч, которые вы никогда не используете и вообще вам не нужны. Однако счётчик они накрутят! Бест практикс говорит, что нечего подключать библиотеки почём зря. Но кто же их слушает, правда? Кто такие Google с их бест практикс? Вместо этого можно использовать больше файлов classes.dex, нумеруя их. Android обрабатывает эту ситуацию и не спотыкается. Ещё есть обфускаторы, которые для своих целей дробят classes.dex на кучу файлов по своим причинам. Dex, кстати, это привет из прошлого и означает «Dalvik executable», то есть формат, исполняемый виртуальной машиной Dalvik. С переходом на ART никто ничего не переименовывал во имя обратной совместимости
  • resources.arsc. Здесь можно найти ссылки на все ресурсы приложения, которые живут в res. Здесь же можно найти все текстовые строки, надписи с кнопок и подобное. Не особо то это нужно в повседневности, но пусть будет. Этот файл также нельзя прочесть как текст, но получить из него и из AndroidManifest.xml данные можно похожим образом, одним и тем же инструментом — aapt.

AAPT

    Aapt.exe — утилита, которая используется для выковыривания некоторых данных из приложения. То есть это тестировщики используют её для разбора, а вообще это Android Asset Packing Tool и с её помощью код и ресурсы собираются в единый apk файл. Но у этой утилиты есть параметры запуска, которыми можно и модифицировать apk файлы без привлечения внешних архиваторов и, что важно, получать некоторую информацию. Узнать, какие пермишены использует приложение, проверить, что строка «Папа у Васи силён в математике» была удалена, узнать минимальную версию API, посмотреть внутреннее имя пакета и его версию и всё такое прочее можно сделать одной командой, прочитав нужный файл AndroidManifest.xml или resources.arsc (и не только их можно читать, понятное дело). На выходе вы получите не зашифрованный текст, с которым можете работать.

    Каковы реальные пример использования этой утилиты?
  • Вам нужно убедиться, что новая версия приложения не может быть затёрта более старой версией при установке поверх. Этим занимается сам Android, отслеживая внутренний номер версии, который вообще никакого отношения к версии продукта, к его билду, не имеет. Значение параметра version code отслеживается инсталлятором приложений Android. Если между файлами A.apk и B.apk этот параметр имеет одно и тоже значение, то версии могут быть установлены друг поверх друга в любом порядке. Если у B.apk значение числа в этом параметре будет больше, то B можно будет установить поверх A, а наоборот — нет. Если параметра вообще не будет, то в Маркет приложение залить будет нельзя. Впрочем, Market вообще хорошо следит за этим параметром и не даст залить ту же самую версию или версию ниже, только на повышение
  • Вы получили на тестирование чёрный ящик. Так как это Android, то довольно много всего полезного вы всё равно можете получить, сделав из чёрного ящика такой, мутно-серый. Много чего полезного с приложением можно сделать из командной строки через adb. Но почти всегда для этого нужно знать внутреннее имя приложения, оно же package name (это имя уникально для Play Store и самого устройства) и названия операций (активити) этого приложения. Например, зная имя пакета и названия операций, вы можете сделать прямой вызов любого из них (ну, не любого, а тех, у которых установлен флаг exported, который по умолчанию всё-таки установлен) и посмотреть, что же получится. Если это, скажем, приложение программы лояльности KFC, то его падение тут не является какой-то проблемой. Если это защитное приложение (антивирус, антивор, родительский контроль и всё в таком духе), то ни о каких падениях говорить недопустимо, потому что стороннее приложение точно также сможет обратиться к «больному» месту (использовать эту точку входа) и уронить продукт
  • Вам нужно убедиться, что для приложения убрали некий пермишен. Можно посмотреть информацию об установленном приложении, а можно отфильтровать вывод команды утилиты aapt в поисках того, что нужно.
  • Вам нужно убедиться, что некая строка заменена на другую. Безусловно, нужно её вызвать в продукте по сценарию. Но если весь продукт не менялся и изменение было строго в ресурсах и заключалось в исправлении опечатки, можно отфильтровать вывод этой утилиты, запущенной с нужными параметрами, и посмотреть, что вернёт фильтрация.

zipalign

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

Platform Tools

    И, это случилось. Мы дошли до тестирования, наконец! Здесь я расскажу, что такое и для чего используется adb — лучший друг Android тестировщика.

Что такое ADB

    Adb — Android Debug Bridge — это консольная многофункциональная утилита, которая позволяет подключаться к запущенному эмулятору или подключенному в режиме отладки устройству и взаимодействовать с ним. Состоит adb из трёх компонентов:
  • Клиент. Это сам exe файл, если речь о Windows, который мы запускаем с нужными командами и ключами команд, получая в ответ некоторый результат. То есть клиент выполняет операцию разово
  • Сервер. Сервер также работает на вашей машине. Клиент взаимодействует с устройством или эмулятором через сервер. Чтобы каждый раз не поднимать сервер и не тушить его на каждую команду, первый запуск клиента автоматически запускает сервер, который будет работать, пока вы руками его не остановите. Остановить можно как штатной командой adb kill-server так и просто отстрелив его системным диспетчером задач или командой taskkill. Если сервер остановлен и вы хотите, чтобы команды исполнялись сразу в вашем тестовом сценарии, то сделайте предварительный запуск сервиса командой adb start-server. Запуск monitor также поднимает сервер. Потому что получение системных логов с устройства идёт в реальном времени и тут стартом-стопом приложения просто не обойтись
  • Демон, который работает на устройстве или эмуляторе. Вы сами не имеете к нему никакого отношения, он является частью прошивки
    Одна из прелестей сервера в том, что он может одновременно работать с несколькими устройствами. Вообще сервер ожидает устройства в диапазоне портов 5555-5585. Запоминать эти цифры бессмысленно, во-первых потому что всё несколько сложнее (например, сервер сканирует только нечётные номера из диапазона), во-вторых вы всё равно не будете использовать больше десяти устройств одновременно в худшие из времён. Мой максимум — тестирование на восьми устройствах одновременно:
Рис. 3. Приёмочное тестирование Kaspersky Phound! одновременно на восьми устройствах
    Это не значит, что больше десятка устройств одновременно у вас никогда не будет. Это я про тестирование из консоли сказал. А вообще, одновременная проверка какой-то проблемы на нескольких десятках устройств — это не что-то невероятное, такое случается:
Рис. 4. Воспроизведение проблемы с быстрым разрядом батареи. К счастью, этим занимался не я
     К слову, если у вас подключено одновременно более одного устройства, то выполнение «adb command» вернёт ожидаемую ошибку о том, что не понятно, к какому из устройств обращаются. Потому, кроме прочего, у adb есть команда devices, которая возвращает список устройств по их серийникам (что берётся в качестве SerialId нам не важно, пусть хоть случайно генерируется от солнечных вспышек), указывая для каждого из них, доступно ли оно, реальное ли это устройство или эмулятор. Но о командах ниже.

Включение отладки через adb

    Возможности управления устройством через adb очень широки и многие из них опасны. К примеру, ни одно приложение в AOSP и в тех кастомах, которые не сильно испорчены производителями, не имеет привилегий из своей песочницы взять и перезагрузить устройство. А команда adb reboot мгновенно отправит устройство на перезагрузку, не запрашивая никаких подтверждений. Через adb можно останавливать приложения, а не только прибивать их. В AOSP и не сломанных кастомах остановка приложений дозволена только пользователю через графический интерфейс. Возможностей, которые даёт adb, очень много. И так как с точки зрения безопасности это большая дырка, то Google делает некоторые усложнения для бездумного включения режима отладки.

Android 2.1-2.3

    Эти версии Android уже практически никто не поддерживает, так что просто историческая справка. Нужно было зайти в настройки, пункт «Приложения» и там поставить галку разрешения отладки через USB. Что это такое — нигде особо не пояснялось.

Android 3.0-4.1

    Включение режима отладки по USB вынесли в отдельный пункт в настройках, который называется «Developer options» или «Инструменты разработчика». Именно во множественном числе, так как появилась возможность не только разрешать отладку через USB (и, кстати, по Wi-Fi), но и включать специальные режимы работы Android, которые по умолчанию выключены, но сюда были вынесены для тех разработчиков, которые понимают, что пункты эти появились не просто так, что в будущем они станут настройками по умолчанию, а сейчас есть возможность протестировать поведение продукта. К примеру, появилась возможность использовать графичекий ускоритель для отрисовки интерфейса. А в Android 4.4 здесь появился пункт, позволяющий перейти на конкретном устройстве с Dalvik на ART, за несколько месяцев до появления Android 5.

Android 4.2-4.2.1

    Первое из двух серьёзных улучшений для безопасности. Если ранее Developer options был виден любому человеку и любой мог его включить, открыв таким образом дырку в безопасности (шутка про «хоть что-то у нас в безопасности»), то в 4.2 пункт «Инструменты разработчика» исчез. Его не было в интерфейсе. Чтобы он появился, нужно зайти в настройки системы, выбрать пункт «Об устройстве», найти там строку «Версия сборки» и несколько раз тапнуть по ней. На тапы будут появляться сообщения, что осталось столько то раз, а потом «Вы уже разработчик». Только после этого пункт «Инструменты разработчика» появлялся на старом месте и можно было разрешить отладку по USB. Прямого метода скрытия пункта нет. Предполагается, что раз уж человек сделал такой путь, то он понимает, что делает.

Android 4.2.2

    Второе и самое важное изменение в системе безопасности. Теперь, кроме прочего, нужно разрешить конкретному компьютеру подключаться к этому устройству. Как только adb сервер попытается установить подключение к демону на устройстве, система покажет запрос, можно ли внешнему устройству подключаться для отладки:
Рис. 5. Запрос доверия компьютеру
    Если устройство имеет пароль блокировки, то этот запрос системы возникнет под экраном блокировки. То есть если в Android 4.2.1 и ниже пользователь включил режим отладки, то любой злоумышленник, получив физический доступ к устройству, мог работать с ним через adb, минуя блокировку. Начиная с Android 4.2.2 это стало невозможно сделать.

Android 6

    Если устройство заблокировано, то по умолчанию к нему нельзя подключиться, так как демон просто не будет отвечать на запросы, потому что все подключения по USB считаются зарядным устройством и adb сервер снаружи никто не ждёт. Нужно перевести устройство в режим MTP для начала.

Ключи, команды и параметры запуска adb

    И вот оно, самое-самое. Я расскажу о некоторых, самых популярных командах и ключах команд для adb. Они используются с частотой от несколько раз в месяц до несколько раз в час.

Ключи adb

    Сам adb можно запустить с ключами -d, -e и -s <id>. Это полезно, если у вас подключены либо реальное устройство и эмулятор одновременно, либо больше чем одно устройство или/и эмулятор.
  • Ключ -d означает «device» и сообщает adb, что команда, которая идёт далее, должна быть выполнена на реальном устройстве, а не на эмуляторе. То есть если у вас подключено одно реальное устройство и сколько угодно эмуляторов, то adb -d command отправит command на реальное устройство
  • Ключ -e, наоборот, говорит, что между устройством и эмулятором нужно выбрать эмулятор
  • Ключом -s можно указать конкретное устройство. Если у вас их подключено одновременно 10 штук и вам нужно перезагрузить конкретный LG, у которого его id, скажем, 12345, то выполните команду adb -s 12345 reboot. У эмуляторов коды тоже есть и они выглядят как emulator-55XX, где 55XX — это порт подключения эмулятора для adb. Как узнать id? Читайте ниже

Команды adb

Основные

    Основных команд три: devices, help и version. Вам частно нужна будет команда devices. Команда adb devices возвращает список устройство по id и их состояние.
Рис. 6. Результат выполнения adb devices
    На скриншоте выше 036969c40935bf1a device означает, что это реальное устройство (device) и его id — 036969c40935bf1a. Состояние emulator означало бы, что это эмулятор. Состояние offline обычно означает, что устройство подключено, но подключение этого компьютера не разрешено ещё на самом устройстве, см. рис. 5. Хотя иногда это означает, что подключение зависло — adb сервер на компьютере и демон на устройстве не могут установить связь между собой. Зная id вы можете использовать ключ -s для запуска adb: adb -s 036969c40935bf1a reboot
    Что значат help и version я понятия не имею. Думаю, вы можете посмотреть это в справке, но я не знаю, как её вызвать. Также в новых версиях могут добавляться новые команды, но как посмотреть версию adb я тоже не знаю. Парам-парам-пам, фью!

Отладочные

    Важных команд здесь две: logcat и bugreport.
  • adb logcat. Выводит системный лог в реальном времени в stdout. Прям бери и перенаправляй вывод в файл, чтобы предоставить лог разработчику (ниже покажу, как правильно это сделать), или парси сам в поисках ключевых строк. Утилита monitor показывает именно вывод logcat. Практически всё тестирование завязано на чтение логов, если это не тестирование графического интерфейса. Хотя и тут тоже лог часто нужен
    Так как в лог может попадать приватная информация, показ которой не допустим, то запись в лог делают только дебажные версии продуктов. В коде обычно есть явная проверка флага debug и, если это истина, действия логгируются. Безусловно, если в конкретных участках кода вообще добавлено логгирование. Следовательно, очень большой кусок функционального и регрессионного тестирования проводится на дебажных сборках, а приёмочное — только на боевых. Каждая строчка продукта в logcat для боевой сборки — причина оформить баг в багтрекер. Вплоть до блокирования релиза, если это реально очень критичная в плане приватности строка! Здесь проблема в том, что читать системный лог могут приложения, установленные на самом устройстве (к счастью, только на не современных версиях Android). Троян может парсить лог и искать там интересные записи.
    Логгирование — процесс, в общем-то, бесконечный. Потому его нужно вручную прерывать при воспроизведении проблемы. Что очень хорошо, логи хранятся в буфере до его заполнения. Если баг воспроизвёлся, а устройство не было подключено, то можно сразу подключить его и перенаправить лог в файл. Информация соберётся не с момента выполнения команды, а ещё и за последние несколько минут (или даже часов!). Потому у logcat есть полезный ключ -d, который выводит содержимое буфера и выполнение команды завершается, ждать ничего не нужно.
    К сожалению простое выполнение adb logcat даёт не так много информации, как хотелось бы. Нет PIDов процессов, например, не тот уровень логгирования. Потому, если хотите собрать максимально полезный лог, используйте подобные команды:
adb logcat -v threadtime *V > file.txt
adb logcat -f /sdcard/file.txt -v threadtime *V
    Они обе будут сохранять одинаковый лог, только первая — на вашем компьютере (так что после > напишите полный путь к файлу), а вторая — на карте памяти. Вторая полезна, если вы подключены к устройству через, скажем, ssh.
  • adb bugreport выводит сборную информацию от команд dumpsys, dumpstate и logcat. Полезно, если устройство не ваше, вам его принесли со словами «вот, только что опять». Вы собираете эту информацию и возвращаете устройство владельцу

Работа с данными

    Вообще работа с файловой системой устройства через adb реализована довольно нудно и проще установить плагин к файловому менеджеру, который даст возможность работать с устройством, будто это флешка подключена. Но для автоматизации или быстрых операций командная строка предпочтительнее. Здесь всего три нужных команды:
  • adb install file.apk. Команда install устанавливает apk на устройство и возвращает Success, если всё нормально и текст ошибки, если что-то не так. Чаще всего «не так» бывают «приложение уже установлено» и значит нужно либо его удалить, либо использовать ключ -r (install -r), чтобы сделать upgrade (или даже -d, чтобы сделать даунгрейд; но такое не нужно почти никогда), «не валидная цифровая подпись» и значит приложение нужно переподписать, «цифровые подписи не совпадают», когда вы пытаетесь сделать install -r, но у уже установленного приложения и этой apk разные подписи, или, уже очень редко на современных устройствах, «нет места»
  • adb uninstall packagename. Чтобы деинсталлировать установленное приложение, нужно знать его внутреннее имя, packagename (которое легко узнасть, имея в руках утилиту aapt)
  • adb push local_file remote_file. Команда push отправляет local_file с вашего компьютера на устройство. Скажем, adb push d:\test\qqq.tmp /sdcard/demo.app скопирует файл qqq.tmp в корень карты памяти устройства под именем demo.app. Управлять файлами внутри устройства таким образом нельзя, это делается иначе, через шелл, о чём я расскажу дальше
  • adb pull remote_file local. Команда pull, напротив, копирует файл с устройства вам на компьютер

Скриптовые

    Для упрощения написания сценариев автоматизации есть три команды:
  • adb get-serialno. Если к компьютеру подключено одно устройство, то команда вернёт его id. В любой другой ситуации будет возвращена ошибка. Это то, что написано в первом столбце для команды adb devices, но только для одного устройства
  • adb get-state возвращает состояние устройства, если оно одно подключено и ошибку в иных случаях. Это то, что написано во втором столбце для команды adb devices. Можно их обе и не использовать, а парсить только вывод adb devices, но ситуации бывают разные.
Рис. 7. Результаты выполнения команд devices, get-serialno и get-state
  • adb-wait-for-device other_command ожидает, пока adb серверу не ответит хотя бы один демон и тут же выполнит other_command. Скажем, вам нужно установить приложение на все подключаемые устройства. Вы пишите бесконечный цикл, который содержит только одну важную строку: adb wait-for-device install application.apk

Управление сервером

    Здесь всего две команды и я говорил про них выше. Они нужны, потому что подключение между сервером и демоном нет-нет, а зависает, особенно на не очень качественных прошивках. adb kill-server останавливает adb сервер, а adb start-server запускает его.
Рис. 8. Реакция на команды остановки и запуска сервера, когда сервер работает или не работает

    Главная сложность в том, что остановка сервера означает отвал всех устройств и прерывание записи лога, если у вас выполнялась всё это время adb logcat. И никакой adb -s <id> не поможет, так как перезапускается весь сервис, так что помните это.

    Впервые мне пришлось использовать перезапуск сервиса на каждой итерации автотеста, когда устройство One Plus One стало мгновенно проходить автотест, причём проваливая его. При отладке своего скрипта, суть которого сводилась к парсингу вывода adb logcat, выяснилось, что команда logcat вываливала содержимое буфера за последние несколько часов, а не с момента старта. Вообще, чтобы затирать старые записи и писать лог строго с текущего момента, у команды logcat есть ключ -c, от clear. Проверил руками — и действительно, adb logcat -c просто не отрабатывала, не возвращая никаких ошибок. После перезапуска сервиса всё заработало, поработало и сломалось точно также на очередной итерации. Пришлось вносить изменения в автотест, добавив перезапуск сервиса.

Shell

    Команды, которые должны быть выполнены внутри самого Android, выполняются из шелла. Этих команд довольно много и без них жить трудно. Скажем, напечатать текст в поле ввода, если там стоит курсор, можно командой input text, выполненной в шелле. А скопировать файл из места А в место Б можно средствами cp.

    Строго говоря, сама команда shell — это команда adb. Таким образом можно работать в шелле, будто бы подключившись по ssh или telnet, выполнив adb shell и нажав Enter, а можно выполнять по одной команде shell’а, делая это из adb. В первом случае вам доступны инструменты и возможности Linux и Android, во втором — инструменты и возможности консоли, в которой вы работаете. В Windows это cmd или, скажем, PowerShell.

    Я приведу в пример несколько команд, доступных из shell, но их гораздо больше. Нужно просто понимать, что примерно можно делать в шелле.

Monkey

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

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

Activity Manager

    Для управления активити приложений используется команда am. То есть, если мы говорим о выполнении отдельных команд из adb, то целиком строка будет adb shell am command.
  • Можно запустить активити или сервис вашего приложения, послав нужный Intent
  • Можно остановить, то есть сделать Force Stop, приложение. Это очень полезно, когда вы работаете с реальными вредоносами, к примеру. Можно остановить так выполнение любой заразы, если антивирус провалил тест. Конечно, из шелла можно и kill сделать, но это обычно бесполезно
  • Можно послать бродкаст

Package Manager

    Для работы с пакетами, то есть с конечными приложениям, а не их модулями, используется команда pm. Package Manager используется в повседневности даже чаще, чем активити менеджер.
  • Можно получить список всех установленных приложений. Самое простое — я фильтрую выдачу по тем, которые принадлежат нам, чтобы проверить, нужно ли их удалять
  • Можно получить путь к установленному приложению, зная его имя пакета. И затем, например, скопировать командой обычным cp -r. Я использую эту возможность именно чтобы получить нужное приложение с целевого устройства. Скажем, человек подозревает, что у него установлено вредоносное приложение. Я даю ему скрипт, который собирает приложения с телефона и он отдаёт мне их
  • Установить и деинсталлировать приложение. Так как в целом писать adb shell pm install и adb shell pm uninstall дольше, чем просто adb install и adb uninstall, то эта возможность почти не используется. С другое стороны, если вы уже в шелле, то можно не запускать другой сеанс cmd. Также через pm install можно немного рулить пермишенами для Android 6
  • Можно чистить данные приложения. Очень полезная операция, недоступная без root привилегий на самом устройстве. Если вы тестируете приложение, которое защищается от удаления правами Администратора устройства, то это уже само по себе создаёт неудобства, так как деинсталлировать через adb его нельзя. А если оно ещё и блокирует устройство паролем, при попытке забрать права, то это вообще нудно. Когда-то я тестировал такое приложение (это оно на рис. 3 и есть). Причём код блокировки был случайным и генерировался на каждой инсталляции. Тогда я написал скрипт из пары строк, который останавливал приложение и чистил его данные. Дальше руками снимал права Администратора устройства и никаких блокировок не происходило, так как с точки зрения приложения его только что установили и оно не было настроено. Полезно это ещё для длинных автотестов, где требуется, чтобы приложение запускалось будто только после инсталляции. У меня есть скрипт для тестирования производительности, который, конкретно в этом случае, в цикле запускает приложение, считает время, за которое оно запустилось, останавливает его, чистит ему данные и запускает снова. Ещё это очень полезно, если есть активное заражение системы и нужно приструнить вредонос. В статье «Спасаемся от Androidлокеров (Trojan-Ransom)» часть работы приходится на am и pm
  • Сделать скриншот, сохранив файл под желаемым именем на устройстве. Забрать с устройства его можно командой adb pull. Можно заскриптовать это дело и сделать скринкаст
  • Сделать захват видео с экрана
    Возможности shell гораздо богаче. На моём Nexus 5 с Android 6 без рутования и, что важно, без установки buzybox, то есть без добавления сторонних утилит, поддерживается больше 250 команд. Получить их список можно выполнением команды adb shell ls /system/bin. То есть просто посмотреть содержимое директории bin внутри директории system.

    Завершить эту запись я решил демонстрацией того, что подразумевалось под словами «В первом случае вам доступны инструменты и возможности Linux и Android, во втором — инструменты и возможности консоли, в которой вы работаете.» Вы читали эти слова буквально несколько минут назад, должны вспомнить. На скриншоте ниже я проделаю одно и тоже — получу список установленных приложений через пакетный менеджер и отфильтрую вывод по названиям, в которых есть явное упоминание LG. В cmd у меня есть findstr, а в shell — grep.
Рис. 9. Поиск строки с заданным вхождением в cmd и в shell
    З.Ы.: (лол, как в старые добрые, когда мы писали «ЗЫ» и «йа креведко» и это было ещё смешным!) Просыпаюсь я где-то в 7 утра.

9 комментариев:

  1. Спасибо большое! Вы талантливый тестировщик.

    ОтветитьУдалить
  2. Пост уже староват, и я хз, увидишь ли ты этот коммент, автор, но статья действительно информативная и моментами очень орная, я пару раз прям в голос заржал)

    ОтветитьУдалить
  3. сейчас изучаю adb и ваще охреневаю сколько там возможностей. Главная проблема в том, что информация с сайта гугл, из кучи обучалок, и из adb [имяфункции] -help вообще отличается, и приходится протыкивать все как раз из кривого -help

    ОтветитьУдалить
    Ответы
    1. У самого adb не так уж много возможностей, если уж на то пошло. А вот у встроенных в Андроид утилит — много. То есть adb shell — это не adb'ные фичи уже. В итоге одним только am (adb shell am) можно кучу всякого делать с приложениями, к примеру.

      Удалить
  4. Прекрасная статья! Спасибо!

    ОтветитьУдалить