[recovery mode] Изучаем принципы взаимодействия Ubuntu Touch и Android

22 мая 2013 г., 18:06:06
Упомянутые аппараты

[recovery mode] Изучаем принципы взаимодействия Ubuntu Touch и Android
Привет, хабр.

Пару месяцев назад я занимался портированием Ubuntu Touch на платформу Allwinner A10, в процессе делал заметки себе на память. Сейчас, на мой взгляд, они всё ещё актуальны, пока Ubuntu Touch окончательно не переехала на свой графический сервер Mir и так далее.

Данная статья поможет заинтересованным лицам найти стартовую точку, с которой можно начать близкое знакомство с UT.

Стиль изложения далёк от технического, но если вы не против, то приглашаю под кат.

Введение

Что такое libhybris libhybris — прослойка, позволяющая подгружать в Glibc userspace библиотеки из библиотека)">Bionic userspace, на лету заменяя некоторые символы вариантами из Glibc. Проще говоря, данное решение позволяет использовать проприетарные библиотеки для Android в Linux-пространстве. Наибóльшая польза, конечно же, в возможности использовать проприетарные GPU-драйвера, собранные производителем только под Android.

Что такое surfaceflinger surfaceflinger — нативный сервис андроида, композитный менеджер графических слоёв.

[recovery mode] Изучаем принципы взаимодействия Ubuntu Touch и Android

Более подробно про Binder IPC и SurfaceFlinger:

Ubuntu Touch Ubuntu Touch Developer Preview сама по себе основана на , заимствует необходимые сервисы для работы с железом. Общий обзор зависимости можно почитать здесь — Ubuntu Touch Porting или в заметке на OpenNet.

В качестве базовой операционной системы используется обычный JB 4.2, а точнее CyagenMod-10.1 (репозиторий подпроектов CM — phablet.ubuntu.com/gitweb). Из него удалено всё что связано с dalvik и java — оставлена только нативная часть, состоящая из системных сервисов и HAL. При желании можно использовать AOSP 4.1, но будьте готовы к адаптации под нативное API от 4.1, оно не покрыто никакой документацией и тем более спецификацией и меняется от релиза к релизу.

Компоненты UT располагаются в chroot, используется самописная утилита uchroot, отрывок:

static int ubuntum(void *a) {
    /* Chroot */
    chroot("/data/ubuntu");
    chdir("/");

    /* Set basic env variables */
    char *const envp[8] = {
        "container=aal",
        "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 
        "SHELL=/bin/bash", 
        "HOME=/root",
        "USER=root",
        "USERNAME=root",
        "LOGNAME=root", 
        NULL
    };

    /* Exec shell */
    execle("/sbin/init", "/sbin/init", "--verbose", NULL, envp);

    return 0;
}

Для взаимодействия Android-окружения и chroot-окружения Ubuntu задействован механизм libhybris. [recovery mode] Изучаем принципы взаимодействия Ubuntu Touch и Android

Компоненты Ubuntu Touch

Суп из различных компонентов UT можно наблюдать в lanchpad-репозитории ~phablet-team. Нас интересуют следующие два компонента, отвечающие за работу платформы на Android устройствах:

Скачаем последнюю версию исходников:

bzr branch lp:platform-api
bzr branch lp:qtubuntu

Ubuntu Platform API Ubuntu platform API — низкоуровневый API для выполнения базовых операций с использованием возможностей платформы (Android).

Примеры методов:

  • ubuntu_application_ui_show_surface
  • ubuntu_application_ui_hide_surface
  • ubuntu_application_ui_move_surface_to
  • ubuntu_application_ui_resize_surface_to

Из файла документации doc/mainpage.md узнаём, что дерево исходников platform-api можно разбить на две части:

  • include — абстрактная декларация platform API
  • android — реализация platform API под Android (я бы уточнил — под Android 4.2)

И то единственное, на что может полагаться сторонний разработчик при работе с этим API — это заголовки из директории includes/ubuntu/application, а всё остальное предполагает изменяться со временем.

Из файла debian/control узнаём, что:

Package: libplatform-api1-hybris
Depends: libhybris
Description:
Hybris implementation of the Platform API (runtime)
This package provides the hybris implementation of the Platform API.
  
The produced library should be used via libhybris, to communicate with the
Android userspace, which is where the Ubuntu Application Manager lives.

Ага, значит, судя по android/hybris/Android.mk, реализация platform API собирается в виде библотеки libubuntu_application_api с линковкой с нативными либами андроида и помещается в android userspace:

LOCAL_SRC_FILES := \
    ubuntu_application_api_for_hybris.cpp \
    ubuntu_application_gps_for_hybris.cpp \
    ubuntu_application_sensors_for_hybris.cpp \
    ../default/default_ubuntu_application_sensor.cpp \
    ../default/default_ubuntu_application_ui.cpp \
    ../default/default_ubuntu_ui.cpp \
    application_manager.cpp

LOCAL_MODULE := libubuntu_application_api

LOCAL_SHARED_LIBRARIES := \
    libandroidfw \
    libbinder \
    libutils \
    libgui \
    libEGL \
    libGLESv2 \
    libhardware \
    libhardware_legacy

Без внимания осталась директория platform-api/src/android, рассмотрим её в деталях. Судя по наличию файла CMakeLists.txt, сборка идёт уже для glibc.

Есть один-единственный файл с кодом — ubuntu_application_api.cpp, заглянув в которой мы увидим:

extern void *android_dlopen(const char *filename, int flag);
extern void *android_dlsym(void *handle, const char *symbol);

— использование процедур libhybris для динамической загрузки символов из shared-либы из android userspace.

struct Bridge {
    static const char* path_to_library() {
        return "/system/lib/libubuntu_application_api.so";
    }
    Bridge() : lib_handle(android_dlopen(path_to_library(), RTLD_LAZY)) {
        assert(lib_handle && "Error loading ubuntu_application_api");
    }

.......

    void* resolve_symbol(const char* symbol) const {
        return android_dlsym(lib_handle, symbol);
    }
    void* lib_handle;
};

— нехитрый мост для подгрузки символов из libubuntu_application_api.so, которая ладит с нативными сервисами андроида, и которую мы совсем недавно мысленно «собрали» с помощью android/hybris/Android.mk.

#define IMPLEMENT_VOID_FUNCTION3(symbol, arg1, arg2, arg3)      \
    void symbol(arg1 _1, arg2 _2, arg3 _3) {                    \
        static void (*f)(arg1, arg2, arg3) = NULL;              \
        DLSYM(&f, #symbol);                                     \
        f(_1, _2, _3); }
.......

IMPLEMENT_VOID_FUNCTION2(ubuntu_application_ui_init, int, char**);
IMPLEMENT_FUNCTION0(StageHint, ubuntu_application_ui_setup_get_stage_hint);
IMPLEMENT_FUNCTION0(FormFactorHint, ubuntu_application_ui_setup_get_form_factor_hint);
IMPLEMENT_VOID_FUNCTION1(ubuntu_application_ui_start_a_new_session, SessionCredentials*);
IMPLEMENT_VOID_FUNCTION2(ubuntu_application_ui_set_clipboard_content, void*, size_t);
.......

— куча обёрток для символов API, реализованных в libubuntu_application_api.so.

Итак, во избежание путаницы:

  • libubuntu_application_api.so — библиотека под bionic, живёт в android userspace;
  • libubuntu_application_api.so — библиотека под glibc, живёт в linux userpace (chroot), грузит символы из первой через libhybris.

Разработчики решили уменьшить энтропию вселенной путём создания одноимённых библиотек. Если посмотреть их дебаты по поводу именования компонентов merge-153874 discussion, то уши вянут.

Ubuntu Application Manager В platform-api/android/hybris помимо реализации Ubuntu platform API находятся исходники ubuntuappmanager — сервиса приложений Ubuntu, он живёт в android userspace и, судя по Android.mk, активно использует libubuntu_application_api и общается через Binder IPC с сервисами андроида.

LOCAL_SRC_FILES:= \
    application_manager.cpp \
    default_application_manager.cpp \

LOCAL_MODULE:= ubuntuappmanager
LOCAL_MODULE_TAGS := optional

LOCAL_SHARED_LIBRARIES := \
    libbinder \
    libinput \
    libgui \
    libskia \
    libandroidfw \
    libutils \
    libEGL \
    libGLESv2 \
    libubuntu_application_api

Решает кучу задач управления приложениями и сессиями, быстрый взгляд на default_application_manager.h:

    void update_app_lists();
    void binderDied(const android::wp<android::IBinder>& who);
    void register_a_surface(...);
    void request_fullscreen(...);
    int get_session_pid(const android::sp<android::IApplicationManagerSession>& session);
    void focus_running_session_with_id(int id);
    void unfocus_running_sessions();
    int32_t query_snapshot_layer_for_session_with_id(int id);
    android::IApplicationManagerSession::SurfaceProperties query_surface_properties_for_session_id(int id);
    void switch_focused_application_locked(size_t index_of_next_focused_app);
    void switch_focus_to_next_application_locked();
    void kill_focused_application_locked();

    void start_a_new_session(
        int32_t session_type,
        int32_t stage_hint,
        const android::String8& app_name,
        const android::String8& desktop_file,
        const android::sp<android::IApplicationManagerSession>& session,
        int fd);

QtUbuntu Разбираемся с частью UT, отвечающей за взаимодействие между Ubuntu platform API и Qt/QML приложениями.

Если вы не знакомы с Qt Platform Abstraction, то, в кратце, это возможность абстрагироваться от платформы, на которой запускаются приложения Qt с помощью специально написанных QPA-плагинов.

В QPA-плагине реализуются базовые методы вроде createPlatformWindow, а затем Qt приложение, когда захочет создать окошко, использует символ createPlatformWindow из плагина абстракции и в ус не дует, куда оно там дальше пошло.

В данном случае мы будем иметь дело с QPA плагином для работы с Ubuntu application API.

~/ubuntu/qtubuntu $ tree
.
├── qtubuntu.pro
├── src
│   ├── modules
│   │   ├── application   <------------------ QML plugin для общения с
│   │   │   ├── application.cc               | Ubuntu Application Manager
│   │   │   ├── application.h                | из QtQuick
│   │   │   ├── application.pro              |
│   │   │   ├── application_image.cc         |
│   │   │   ├── application_image.h          |
│   │   │   ├── application_list_model.cc    |
│   │   │   ├── application_list_model.h     |
│   │   │   ├── application_manager.cc       |
│   │   │   ├── application_manager.h        |
│   │   │   ├── application_window.cc        |
│   │   │   ├── application_window.h         |
│   │   │   ├── input_filter_area.cc         |
│   │   │   ├── input_filter_area.h          |
│   │   │   ├── logging.h                    |
│   │   │   ├── plugin.cc                    |
│   │   │   └── qmldir                       |
│   │   ├── ----------------------------------
│   │   └── modules.pro
│   ├── platforms
│   │   ├── base
│   │   ├── platforms.pro
│   │   └── ubuntu   <-------------- QPA платформа абстракции
│   │         ├── clipboard.cc
│   │         ├── clipboard.h
│   │         ├── input.cc
│   │         ├── input.h
│   │         ├── integration.cc <-- здесь реализован `createPlatformWindow` например
│   │         ├── integration.h
│   │         ├── main.cc
│   │         ├── screen.cc
│   │         ├── screen.h
│   │         ├── ubuntu.json
│   │         ├── ubuntu.pro
│   │         ├── window.cc
│   │         └── window.h
│   └── src.pro
└── tests

Судя по содержимому ubuntu.pro, платформа линкуется с glibc-версией libubuntu_application_api.so Обратим на следующие вызовы методов из набора platform API, использованные в integration.cc и window.cc:

#include <ubuntu/application/ui/ubuntu_application_ui.h>

ubuntu_application_ui_start_a_new_session(&credentials);
ubuntu_application_ui_destroy_surface(surface_);
ubuntu_application_ui_create_surface(&surface_, "QUbuntuWindow", geometry.width(), geometry.height(), static_cast<SurfaceRole>(role), flags, eventCallback, this);
ubuntu_application_ui_move_surface_to(surface_, geometry.x(), geometry.y());
ubuntu_application_ui_request_fullscreen_for_surface(surface_);
ubuntu_application_ui_move_surface_to(surface_, rect.x(), rect.y());
ubuntu_application_ui_resize_surface_to(surface_, rect.width(), rect.height());
ubuntu_application_ui_request_fullscreen_for_surface(surface_);
ubuntu_application_ui_show_surface(surface_);
ubuntu_application_ui_hide_surface(surface_);

Теперь понятно, что когда наше Qt приложение захочет создать окошко, то оно вызовет метод из QPA платформы qubuntu — QUbuntuIntegration::createPlatformWindow из файла integration.cc:

QPlatformWindow* QUbuntuIntegration::createPlatformWindow(QWindow* window) {
.......
  // Create the window.
  QPlatformWindow* platformWindow = new QUbuntuWindow(.......);
.......
}

Заглядывая в конструктор QUbuntuWindow в файле window.cc, находим вызов метода QUbuntuWindow::createWindow():

void QUbuntuWindow::createWindow() {
.......
  ubuntu_application_ui_create_surface(
      &surface_, "QUbuntuWindow", geometry.width(), geometry.height(),
      static_cast<SurfaceRole>(role), flags, eventCallback, this);
.......
  ubuntu_application_ui_move_surface_to(surface_, geometry.x(), geometry.y());
.......
}

Это крайне урезанный код, но суть ясна — делаются вызовы к Ubuntu platform API, которое у нас реализовано в glibc-версии libubuntu_application_api.so, которая, на самом деле, является мостом к bionic-версии libubuntu_application_api.so, код которой лежит в platform-api/android.

Прыгаем?

Прыгнув с помощью grep в нужный файл, попадаем в platform-api/android/default/default_ubuntu_application_ui.cpp:

// Это в ubuntu_application_ui_create_surface
  ubuntu::application::ui::Surface::Ptr surface = session->create_surface(props,
         ubuntu::application::ui::input::Listener::Ptr(new CallbackEventListener(cb, ctx)));

// Это в ubuntu_application_ui_move_surface_to
  auto s = static_cast<Holder<ubuntu::application::ui::Surface::Ptr>*>(surface);
  s->value->move_to(x, y);

Нам осталось открыть матрёшку и найти, как же реализованы ubuntu::application::ui::Session и, соответственно, ubuntu::application::ui::Surface. А реализованы они в этом файле — ubuntu_application_api_for_hybris.cpp:

namespace android {
.......
struct Session : public ubuntu::application::ui::Session, public UbuntuSurface::Observer {
   .......
    Session(.....) {
    ......
    ubuntu::application::ui::Surface::Ptr create_surface(
        const ubuntu::application::ui::SurfaceProperties& props,
        const ubuntu::application::ui::input::Listener::Ptr& listener) {
        .......

        // О, а вот и вызов конструктора. Осталось только перемотать вверх и найти реализацию UbuntuSurface
        UbuntuSurface* surface = new UbuntuSurface(client, client_channel, looper,
            props, listener,this);

         .......

         // 100% это наш клиент, теперь нужно смотреть UbuntuSurface
         return ubuntu::application::ui::Surface::Ptr(surface);
         .......

Перематываем, находим UbuntuSurface:

struct UbuntuSurface : public ubuntu::application::ui::Surface {
    .......
    UbuntuSurface(const sp<SurfaceComposerClient>& client, .......)
    : ubuntu::application::ui::Surface(listener)
    {
        // Вот это место - прямое обращение к Android API
        surface_control = client->createSurface(
                              String8(props.title),
                              props.width,
                              props.height,
                              PIXEL_FORMAT_RGBA_8888,
                              props.flags & .......);

        surface = surface_control->getSurface();
        .......

Получаем некий объект типа android::SurfaceControl, который является результатом вызова android::SurfaceComposerClient()->createSurface(). Через него проходят все обращения к android::SurfaceComposerClient (frameworks/native/libs/gui/Surface.cpp), такие как: изменение размеров, перемещение, изменение порядка слоёв и так далее.

Возвращаясь назад по цепочке, понимаем, что же на самом деле происходит, когда мы запускаем очередное Qt приложение с QPA платформой Ubuntu. Начался реверс-инжиниринг процессора PlayStation 1: безумству храбрых поём мы песню!

Заключение

На этом моменте я вынужден себя остановить, поскольку, на мой взгляд, рассмотренный принцип взаимодействия Ubuntu Touch и Android является самодостаточным. Дальнейшие рассуждения могут идти уже в отрыве от всего вышеописанного. Нерасмотренными остались вопросы взаимодействия qmlscene и ubuntuappmanager, принцип контроля ввода с помощью сервисов SurfaceFlinger и InputDispatcher и другие вопросы из уголков этой простороной темы. Но это уже совсем другая история.

Через неделю приедет телефон на , распотрошу его…



Sony Ericsson Xperia Play (PlayStation Phone) Review
Sony Ericsson Xperia Play (PlayStation Phone) Review Hi guys, back with my second review. It is on the Sony Ericsson Experia Play (PlayStation Phone). I hope this helped you a lot :) & don't forget to subscribe for more videos Thanks Dean PT11M57S

Похожие новости

15 февраля 2016 г., 16:10:39 EdgeUpdate_Main_1.5

Компания Samsung анонсировала обновление Android 6.0.1 для Galaxy S6 edge и S6 edge+, которое приносит не только только свежую ОС, но и более продвинутые приложения для изогнутого дисплея. Больше лучше Грани Dual Edge умели работать с приложениями, но эти программы ограничивались шириной 260 пикселей....

5 февраля 2016 г., 16:29:54 Android Wear

Последний раз Google обновляла Android Wear в ноябре 2015 года. Тогда часы с сотовым модулем научились звонить. В ближайшем будущем владельцы «умных» часов получат более масштабное обновление версии 1.4 на базе Android Marshmallow. Huawei Watch, Asus ZenWatch 2 (49 мм) и LG Watch Urbane 2nd Edition...

31 января 2016 г., 19:09:24 DSC_0047 (2)

Свет, камера, мотор! Фраза, известная даже тем, кто никак не связан с киноиндустрией, означающая начало съемки. Она также может относиться и к BlackBerry, когда речь идет о работе с профессиональной качественной камере. Кеннет Орескович – независимый кинооператор. Его сфера деятельности очень разнообразна:...

30 января 2016 г., 22:31:25 lenovo_p70_08

Компания Lenovo стремительно развивается на рынке смартфонов. С её шильдиками не выходят уберфлагманы (эта роль отведена недавно приобретенной Motorola), а вот недорогие аппараты бренда можно встретить практически в любом магазине. Особого внимания заслуживают устройства с литерой P в названии, которые...

28 января 2016 г., 22:23:56 Live Demo Unit на примере Samsung Galaxy S6 edge+

    В этом видео я хочу подробно рассказать Вам про Live Demo Unit образцы от Samsung на примере смартфона Samsung Galaxy S6 edge+. Основной плюс Demo-версииэто его цена, но есть и минусы.   ...


Похожие обзоры

21 января 2016 г., 0:23:00 Обзор смартфона Meizu MX4 Ubuntu Edition

Слухи о том, что китайская компания Meizu планирует выпустить коммуникатор на базе Ubuntu Touch, появились еще в начале прошлого года. В течении 2014 г. компания периодически демонстрирует прототип устройства на выставках и осенью объявляет, что Meizu MX4 на Ubuntu Touch выйдет в декабре, сообщает некоторые...

20 января 2016 г., 19:45:31 Хабраобзор Highscreen Explosion или недорогого аналога Samsung Galaxy 3

Большинство Android-телефонов, с которыми я имел дело, отвечали простому требованию – максимум функциональности за минимум денег. Поэтому, когда появилась возможность пощупать вроде как аналог Samsung Galaxy S3, при этом стоимостью всего 13 тысяч (на самом деле 12990, но это маркетинговые уловки), я...

20 января 2016 г., 19:45:20

Недели две назад мне прислали на тест коммуникатор Highscreen PP5420. Я долго не собирался о нем написать. Но тут мне позвонили и попросили сделать это. Это второй коммуникатор Highscreen, который попал мне в руки. Первый был Zeus.Технические характеристики Операционная система:: Android OS...

20 января 2016 г., 18:46:00 Обзор смартфона Highscreen Omega Prime S – новый цвет каждый день

Российский бренд Highscreen имеет в своем арсенале большое количество моделей на любой вкус и кошелек, как бы шаблонно это ни звучало. Девайс, о котором мы поговорим сегодня, относится к бюджетному сегменту (7-8 тысяч рублей). При этом обладает симпатичным тонким корпусом (6,9 мм) и комплектным набором...

16 января 2016 г., 21:16:12 Планшет Amazon Fire 7 (2015)

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


Похожие отзывы

10 ноября 2015 г., 18:23:56 verge-2015-11-06_15-55-52.0

В конце прошлой недели, BlackBerry открыла продажи нового смартфона BlackBerry Priv, первого смартфона, работающего на базе операционной системы Android. Мы опубликовали перевод обзора от наших коллег из CrackBerry, а теперь, вместе с блогом INSIDE BlackBerry предлагаем вам взглянуть на отзывы в прессе...

7 ноября 2015 г., 20:15:56 Blackberry-Priv-G02

Вчера, BlackBerry открыла продажи нового смартфона BlackBerry Priv, первого смартфона, работающего на базе операционной системы Android. Мы опубликовали перевод обзора от наших коллег из CrackBerry, а теперь, вместе с блогом INSIDE BlackBerry предлагаем вам взглянуть на первые отзывы в прессе о запуске...

3 ноября 2015 г., 22:55:25 priv-by-blackberry-slide-out-keyboard

По мере того, как мы приближаемся к тому дню, на который запланирован запуск первого безопасного смартфона BlackBerry на базе Android — BlackBerry PRIV, люди становятся все более взволнованными. И почему бы и нет? Это флагманское устройство, оснащенное всем необходимым для достижения успеха — прекрасным...

12 июня 2015 г., 16:26:05 Apple айфон 5 с отзывы, его характеристики, плюсы и минусы

Apple айфон 5 с отзывы, его характеристики, плюсы и минусы от Артур · Июн 12, 2015 12:12 В данной статье рассмотрим Apple айфон 5 с отзывы, его характеристики, плюсы и минусы. Дизайн, материалы корпуса. Айфон 5 c выглядит красивым и аккуратным. Пластик...

30 апреля 2015 г., 19:05:20 image

Здравствуйте, меня зовут Мурат и я смартфонозависим. *хором* «Здравствуй, Мурат». Везде и в любое время при мне находится смартфон. Не то, чтобы от его непосредственного нахождения вблизи зависит моя работа или личная жизнь, но этот аппарат значительно облегчает оба этих аспекта. На сегодняшний день...


Похожие инструкции

28 декабря 2015 г., 12:53:14 Прошивка Android 6.0.1 Marshmallow beta для Galaxy S5

Отличная новость для всех энтузиастов — владельцев смартфонов Samsung Galaxy. Сегодня в сети оказалась новейшая прошивка Android 6.0.1 Marshmallow для этого смартфона и попала она по «ошибке» в качестве обновления «по воздуху». Разумеется сейчас она уже недоступна для официальной установки, но в сети...

18 декабря 2015 г., 20:33:02 Лучшие кастомные прошивки для Galaxy S6

Пока мы ждем официального обновления Android 6.0 Marshmallow для Galaxy S6, я решил найти на этот гаджет лучшие кастомные прошивки, чтобы скоротать время. Есть много преимуществ использования кастомизированного ПО. Во-первых, это чистый от “мусора” и улучшенный TouchWiz, а во-вторых лучшая автономная...

16 декабря 2015 г., 17:10:49 Разработчик заявил об «официальном джейлбрейке» PS4

Если у вас есть игровая консоль PS4 и вы ждете ее взлома, то есть немного хороших новостей. На днях разработчик, известный под ником CTurt, объявил о выходе «официального джейлбрейка PS4». Для того, чтобы добиться поставленной цели, CTurt решил использовать эксплоит для ядра FreeBSD. Сам взломщик является...

11 ноября 2015 г., 23:15:21 lg g watch r прошивка

Подробная пошаговая инструкция по установке кастомной прошивки на умные часы LG G Watch R при помощи программы FastBoot. Скачиваем архив Watch.zip, с набором программ для прошивки умных часов LG G Watch R (Если вы вдруг линуксовод — то в стандартных репозиториях имеются пакеты с ADB и Fastboot, Их...

3 ноября 2015 г., 3:41:00 How to flash firmware on Samsung Galaxy S6 SM-G920F

Instructions for firmware on smartphone Samsung Galaxy S6 SM-G920F a new official firmware Android, as well as obtaining Root access on the phone Samsung Galaxy S6 SM-G920F. Before starting the firmware phone Samsung Galaxy S6 SM-G920F, you must first download the necessary programs and files on your...

Упомянутые аппараты
vk.com/analogindex_ru
"Analog Index" © 2014 - 2015