Saturday, January 12, 2013

Декомпиляция Android-приложений

В этой статье заметке я хочу рассмотреть два способа "разбора" (reverse engineering'a) Android-приложений.

И так, как мы все знаем, приложения под Android распространяются в виде apk-файлов. Последние в свою очередь являются обычным архивом с скомпилированным кодом (в dex-формате, используемым реализацией JVM для Android - Dalvik) и преобразованными для внутреннего использования ресурсами. Другими словами - "нельзя просто так взять и посмотреть исходники Android-приложения". Однако, способы всё же есть.



Android APK Tool


Первый способ - воспользоваться утилитой apktool. С её помощью можно без труда разобрать, внести некоторые правки и собрать обратно приложение:
apktool decode myapp.apk myapp
apktool build myapp myapp.apk
Однако, есть одно "но". После разбора приложения вы получите не Java-файлы с кодом, а файлы с набором мета-инструкций JVM в формате проекта SMALI. Не смотря на то, что проект SMALI считает себя "human-editable" и "human-readable" - правка байткода есть удовольствие для истинных эстетов. Поэтому данный способ подходит больше для того, что бы выдернуть что-нибудь из ресурсов проекта.


Dex2Jar and JD


Если же ваша цель - исходный код (пусть и восстановленный средствами reverse engineering'a), вам поможет утилита Dex2Jar, которая без труда сделает из вашего apk-файла обычный jar-архив, преобразовав ресурсы и заменив исполняемые файлы Dalvika на обычные классы для JVM.
dex2jar.sh myapp.apk
Теперь, что бы посмотреть код, достаточно воспользоваться любым java-декомпилятором. Например проектом JD-GUI, выгодно отличающимся наличием графического интерфейса.
jd-gui myapp.jar

Read more...

Wednesday, January 2, 2013

Нагрузочное тестирование ВидеоСервера

Пару месяцев назад передо мной встала задача - выяснить, сколько клиентов одновременно может вывезти один видеосервер на основе VLC. В качетсве протоколов вещания предлагалось использовать HLS или HTTP Streaming. Сразу хочу оговориться, что специалистом в тестировании (тем более нагрузочном) я не являюсь. Однако, полученный мною опыт кажется мне весьма интересным.

Теория



Предполагаемая нагрузка


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


Эмуляция нагрузки


Основной особенностью тестирования видеосервера является тот факт, что при проигрывании видео нагрузка ложится не только на сервер, но и на клиент (а так же канал между ними). Отсюда путей для тестирования мне видится два:
  • полная эмуляция клиента (запуск vlc-плеера);
  • частичная эмуляция клиента (скачивание файла через wget);
В любом случае ресурсов одной тестовой машины будет недостаточно для эмуляции рабочей нагрузки. Конкретные цифры зависят от мощности железа и пропускной способности канала между тестовым клиентом и сервером. Однако, в виду предполагаемой нагрузки (см. выше) полная эмуляция клиента технически невозможна, так как потребует неопраданно большого количества машин. Создание же своего маленького botnet'a в благородных целях тестирования в рамках данной статьи мы рассматривать не будем :)


Распределённое тестирование


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

В качестве framework'a для тестирования предлагается использовать JMeter, обладающий всей необходимой нам функциональностью. Идея заключается в том, что бы согласно инструкции развернуть несколько клиентских instance'ов на тестовых машине(ах) (с гигабитным каналом до сервера) и запускать требуемые нам тесты распределённо. Отдельно стоит обратить внимание на то, что на все клиентские машины придётся установить необходимое для тестов ПО: wget или vlc.


Сценарий тестирования


Определися с ценарием, который JMeter будет запускать на каждой тестовой машине.

В случае тестирования с полной эмуляцией сценарии будут сводиться к вызову vlc-плеера (хотя можно использовать и другой, так как у vlc есть некоторые проблемы с проигрыванием HLS):
vlc -Idummy -Vdummy --no-audio http://example.com:8090
или
vlc -Idummy -Vdummy --no-audio http://example.com/streaming/index.m3u8


В случае тестирования с частичной эмуляцией сценарии будут сводиться к вызову wget:
wget -q --limit-rate=128k -O- http://example.com:8090 >/dev/null
или
curl -s http://example.com/streaming/index.m3u8 |grep http |xargs wget -q --limit-rate=128k -O- >/dev/null


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

Важно! При создании задачи на исполнение внешней программы в JMeter параметры необходимо указывать слитно со значением.

Если нагрузка будет эмулироваться с одной машины, то использование JMeter можно заменить на простой bash-скрипт:
#!/bin/bash
for i in {1..КОЛИЧЕСТВО_КЛИЕНТОВ}
do
    nohup КОМАНДА &
done



Практика



При тестировании с частичной эмуляцией клиента (с помощью wget) первым шагом необходимо определить минимальную скорость передачи данных, при которой возможно корректное воспроизведение видео, закодированного в используемом нами формате. Другуми словами необходимо определить скорость, с которой отдаётся поток на сервере вещания: клиенты с более высокой скоростью будут простаивать в ожидании данных, клиенты с более низкой скоростью будут корректировать свою скорость, пропуская части видеопотока. С учётом используемых в моём случае настроек кодирования (video bitrate = 1Mbit/s), скорость отдачи видео потока составляет примерно 128 Kb/s.

Во время запуска тестов необходимо мониоторить нагрузку на процессор и сетевую подсистему.

Загрузка процессора вычисляется с помощью команды ps -p PID -o %cpu, так как "Currently, it is the CPU time used divided by the time the process has been running (cputime/realtime ratio), expressed as a percentage. It will not add up to 100% unless you are lucky.(alias pcpu)." В виду вышесказанного после каждого теста vlc перезапускается.

С помощью утилиты iftop контролируется наличие ожидаемого объёма трафика в сетевой подсистеме. Так же с её помощью необходимо следить за тем, что бы канал не забивался полностью - в противном случае тест стоит остановить, резюмировав, что данное количество клиентов не может быть обработано текущей сетевой подсистемой.

Архиважно контролировать доступность и качество видеопотока, переодически подключаясь N+1 клиентом к серверу.

Перед началом тестирования убедитесь, что на сервере отключены все лимиты по ресурсам и открытым файлам (или же они совпадают с боевыми лимитами). В моём случае, к примеру, по началу не удавалось подключить одновременно более 350 клиентов из-за параметра numtcpsock, отвечающего за максимальное количество открытых TCP соединений в OpenVZ.


Сценарий

  • Отключаем сервер VLC и всех клиентов;
  • Перезапускаем сервер VLС и пул клиентов;
  • Мониторим количество клиентов и трафик на сервере;
  • Оцениваем нагрузку на сервере;


Результат


Подробно на результатах тестирования я останавливаться не буду, так как пос всё же о методике и подходе. Скажу только, что как и ожидалось, в обоих случаях узким местом стала сетевая подсистема тестового сервера, а не ресурсы CPU. Ну и да, барьер в 1000 пользователей был взят :)

Read more...