Экосистема Android.

SDK

  • Плагины для IDE
  • Инструменты для сборки
  • Инструменты для отладки
  • Библиотеки
  • Образы эмуляторов

Android Studio

  • Представлен в 2013, как замена Eclipse
  • Система сборки gradle
  • Отображение UI
  • Интегрирован c Goole Developer Console
  • Встроенный профайлер памяти, CPU, Network
  • Поддержка систем контроля версий (git, svn и др.)
  • Поддержка нескольких языков программирования
  • Поддержка специфичных конструкций и компонент

Gradle

  • Построена на принципах apache ant и apache maven.
  • DSL использует Groovy (Kotlin) вместо XML
  • Позволяет расширять сборку собственными функциями
  • Использует направленный ацикличный граф для определения порядка выполнения задач
  • Считается более гибким и пригодным для сборки Android приложений

Gradle. Запуск

  • Запуск через файл gradle.
  • Запуск через файл gradlew, где w означает wrapper (обертка).
gradle init				    
				    

Gradle

  • Задача (task) является основным компонентом процесса сборки в файле билда.
  • Задачи представляют собой именованные наборы инструкций билда.
  • По сравнению с традиционными возможностями объявления операций билда, связанных зависимостями, задачи Gradle являются полнофункциональными объектами, которыми вы при желании можете управлять программно.

Gradle. Объявление задачи

task hello				    
				    
Список задач
./gradlew tasks	// все задачи	
./gradlew subprojectName:tasks --all // все задачи для подпроекта, 
				     // в том числе второстепенные
				

Gradle. Объявление задачи

Результат
------------------------------------------------------------
All tasks runnable from root project
------------------------------------------------------------

Build Setup tasks
-----------------
init - Initializes a new Gradle build. [incubating]
wrapper - Generates Gradle wrapper files. [incubating]

Help tasks
----------
dependencies - Displays all dependencies declared in root project '__project'.
dependencyInsight - Displays the insight into a specific dependency in root project '__project'.
help - Displays a help message
projects - Displays the sub-projects of root project '__project'.
properties - Displays the properties of root project '__project'.
tasks - Displays the tasks runnable from root project '__project'.

Other tasks
-----------
hello				    
				    

Gradle. Добавление простейшей операции

task hello << {
    println 'hello, world'
}				    
				    
  • Операторы, такие как << («сдвиг влево» из Java), могут быть перегружены в Groovy для изменения поведения в зависимости от объектов с которыми они работают.
  • В данном случае << перегружен в Gradle для добавления блока кода в список операций, которые выполняет задача.

Gradle. Добавление простейшей операции

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

task hello

hello << {
    print 'hello, '
}

hello << {
    println 'world'
}	

./gradlew hello
:hello
hello, world

BUILD SUCCESSFUL

Total time: 1.916 secs
				    

Gradle. Конфигурация задачи

task initializeDatabase

initializeDatabase << {
    println 'connect to database'
}

initializeDatabase << {
    println 'update database schema'
}

initializeDatabase {
    println 'configuring database connection'
}				

./gradlew initializeDatabase
configuring database connection
:initializeDatabase
connect to database
update database schema

BUILD SUCCESSFUL

Total time: 3.088 secs
				    

Gradle. Конфигурация задачи

  • Для обозначения блока кода между парой фигурных скобок, в Groovy используется термин «замкнутое выражение» или «замыкание» (closure).
  • Функции-замыкания подобны объектам, которые можно передавать методу как параметр или присваивать переменной, с возможностью последующего выполнения.

Gradle. Конфигурация задачи

  • Замыкание, добавленное к имени задачи без оператора сдвиг влево совсем не добавляет новую операцию.
  • Добавился блок конфигурации.
  • Конфигурационный блок задачи выполняется во время конфигурационной фазы жизненного цикла Gradle, которая предшествует фазе выполнения, во время которой выполняются операции задачи.

Gradle. Конфигурация задачи

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

Gradle. Конфигурация задачи

  • Конфигурационный блок — подходящее место для присвоения значений переменных и структур данных, которые используются операцией задачи в дальнейшем
  • Структура конфигурации даёт вам возможность превратить задачи вашего билда в сущности развитой объектной модели, заполненные информацией о билде.
  • В этом и состоит отличие задач Gradle от простого набора операций билда, которые выполняются в определённой последовательности.

Gradle. Конфигурация задачи

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

Процесс загрузки ОС Android

Процесс загрузки ОС Android

  • Bootrom — это небольшой кусочек защищенной от записи флеш-памяти, встроенный в процессорный чип. Он содержит самый первый код, который выполняется процессором при его включении. Далее, он запускает BootLoader.
  • BootLoader выполняет первичный запуск специфичных настроек перед запуском ядра. То есть дословно, копирует файлы в рабочую память устройства и передает управление коду, расположенному в разделе boot, что по сути есть ядро Linux.

Android Linux

  • Ядро Linux обеспечивает такие низкоуровневые вещи, как управление памятью
  • Защиту данных
  • Поддержку мультипроцессности и многопоточности
  • Здесь нет ничего от проекта GNU, не используется X.Org, ни даже systemd
  • Все эти компоненты заменены аналогами, более приспособленными для использования в условиях ограниченной памяти, низкой скорости процессора и минимального потребления энергии

Android Linux

  • Модификации ядра:
  • добавлено несколько небольших компонентов
  • ashmem (anonymous shared memory)
  • Binder driver
  • wakelocks (управление спящим режимом)
  • low memory killer

Android Linux

Процесс загрузки ОС Android

  • Ядро запускает настройку кэша, защищенную память, планировщик задач и загружает драйверы. Когда ядро завершит настройку и запуск своих подсистем, он первым делом запустить корневой и самый главный процесс init(). Все процессы запускаемые после него являются дочерними.

Процесс загрузки ОС Android

  • init()
  • подключает директории /sys, /dev, /proc
  • запускает службы(daemon), которые указаны в файле init.rc
  • Например, Service Manager, Media Server.
  • Формат init.rc достаточно простой и по сути представляет собой набор команд, разделенных на блоки.
  • Запуск среды выполнения Android путем запуска службы Zygote

Процесс загрузки ОС Android

  • Zygote ответственен за инициализацию, старт системных служб, запуск и остановку пользовательских приложений и многие другие задачи.
  • запускается с помощью приложения /system/bin/app_process
  • код которой располагается в разделяемой библиотеке /system/lib/libandroid_runtime.so
  • Zygote получит управление, он начинает формирование среды исполнения Java-приложений с помощью загрузки всех Java-классов фреймворка.

Процесс загрузки ОС Android

  • system_server
  • Включает в себя большинство высокоуровневых (написанных на Java) системных сервисов.
  • В том числе Window Manager, Status Bar, Package Manager и, что самое важное, Activity Manager.

Процесс загрузки ОС Android

  • Activity Manager
  • Zygote открывает сокет /dev/socket/zygote и уходит в сон.
  • Запущенный ранее Activity Manager посылает широковещательный интент Intent.CATEGORY_HOME, чтобы найти Launcher-приложение, отвечающее за формирование рабочего стола.
  • Zygote, в свою очередь, форкается и запускает Launcher-приложение поверх виртуальной машины.
  • На экране появляется рабочий стол, найденный Activity Manager и запущенный Zygote, и статусная строка, запущенная system_server в рамках службы Status Bar.

Запуск «своего» приложения.

Запуск «своего» приложения.

  • После нажатия по иконке приложения Launcher пошлет интент с именем этого приложения, его примет Activity Manager и передаст команду на старт приложения демону Zygote.
  • Zygote получает запрос на старт приложения от Activity Manager, он не запускает новую виртуальную машину, а просто форкается, то есть копирует самого себя и затем запускает поверх полученной копии виртуальной машины нужное приложение.
  • Копия ART/Dalvik VM создаёт главный поток приложения (MainThread).

APK файл (Android Package)

  • Manifest
  • Resources
  • Classes.dex

APK файл (Android Package)

  • Java код (.java).
  • Байт код (.class). Получаем с помощью javac.
  • Другие байт коды используемых библиотек.
  • Соединяем в файл classes.dex (Dalvik executable). Получаем с помощью утилиты dex.
  • Соединяем AndroidManifest.xml, classes.dex и ресурсы (изображения, аудио файлы, видео файлы и др) в файл apk.
  • С помощью утилиты aapt.

Dalvik

  • Dalvik Virtual Machine (DVM) — виртуальная Java машина, разработанная как часть мобильной платформы Android.
  • Cреда для выполнения компонентов операционной системы Android и пользовательских приложений.
  • Каждый процесс выполняется в своём, изолированном адресном пространстве.
  • Когда пользователь запускает приложение (либо операционная система запускает один из своих компонентов), ядро виртуальной машины Dalvik (Zygote Dalvik VM) создает отдельный, защищенный процесс в общей памяти, в котором непосредственно разворачивается VM, как среда для запуска приложения.
  • Android выглядит как набор виртуальных машин Dalvik, в каждой из которых исполняется приложение.

Dalvik

  • Использует архитектуру на основе регистров: структура данных, куда помещаются методы, основана на регистрах процессора. За счет отсутствия операций POP и PUSH, команды в регистровой виртуальной машине выполняются быстрее аналогичных команд стековой виртуальной машины.
  • Исполняет байт-код собственного формата: Android dexer преобразует class-файлы в формат .dex, оптимизированные для выполнения на Dalvik VM. В отличие от class-файла, dex-файл содержит сразу несколько классов.

jvm vs dvm

Android Dexer

  • Процесс преобразования Java байткода в .dex байткод для Android Runtime является ключевым шагом в создании APK.
  • Напрямую влияет на время сборки приложения, на размер файла .dex и производительность во время выполнения.
  • dex-файл содержит сразу несколько классов.
  • Изначально, class-файлы преобразовывались в dex-файлы с помощью встроенного DX-компилятора.
  • Далее, компилятором по умолчанию стал D8.
  • По сравнению с DX-компилятором, D8 компилирует быстрее и выводит dex-файлы меньшие по размеру, при этом обеспечивая более высокую производительность приложения во время исполнения.
  • Полученный таким образом байт-код dex подвергается минификации с помощью open-source утилиты ProGuard.

D8

R8

  • Следом за D8 пришел R8, который, по сути, является тем же D8, только с дополнениями.
  • Proguard больше не используется для оптимизации кода во время компиляции.
  • Вместо этого плагин работает по умолчанию с R8, который сам выполняет Code shrinking, Optimisation и Obfuscation.

R8 и сокращение кода

  • приложения используют сторонние библиотеки, такие как Jetpack, Gson, Google Play Services.
  • Когда мы используем одну из этих библиотек, часто в приложении используется только малая часть каждой отдельной библиотеки.
  • Без Code shrinking, весь код библиотеки сохраняется в вашем приложении.
  • для улучшения читаемости и удобства поддержки приложения разработчики используют подробный код.
  • Например, могут быть использованы значимые имена переменных и шаблон проектирования для того, чтобы другим было удобнее разобраться в коде.
  • R8 позволяет существенно уменьшить размер приложения, оптимизируя размер даже того кода, который действительно используется приложением.

R8 и сокращение кода

ART vs DVM в Android

  • DVM была спроектирована именно для мобильных устройств
  • использовалась как виртуальная машина для запуска андроид приложений вплоть до Android 4.4 Kitkat.
  • Начиная с этой версии, ART был представлен как среда выполнения
  • в Android 5.0 (Lollipop) ART полностью заменил Dalvik.
  • Основное явное отличие ART от DVM состоит в том, что ART использует AOT компиляцию, а DVM — JIT компиляцию.
  • Не так давно ART начал использовать гибрид AOT и JIT.

DVM

  • Использует JIT компиляцию: всякий раз при запуске приложения,
  • компилируется та часть кода, которая необходима для выполнения приложения. Остальная часть кода компилируется динамически. Это замедляет запуск и работу приложений, но уменьшает время установки.
  • Ускоряет загрузку устройства, поскольку кеш приложения создается во время выполнения.
  • Приложения, работающие на DVM, требуют меньше памяти, чем те, которые работают на ART.
  • Уменьшает резерв батареи, увеличивая нагрузку на CPU.
  • Dalvik является “устаревшим” и не используется на андроид версиях выше 4.4.

DVM

ART

  • Использует AOT компиляцию, то есть компилирует весь код во время установки приложения. Это ускоряет запуск и работу приложений, но требует большего времени установки.
  • Замедляет загрузку устройства, так как кеш создается во время первой загрузки.
  • Ввиду использования подхода AOT компиляции, требует больше памяти в сравнении с приложениями на DVM.
  • Увеличивает резерв батареи, сокращая работу процессора из-за отсутствия компиляции при выполнении приложений.
  • Улучшенная Garbage Collection или сборка мусора. Во времена использования Dalvik, сборщики мусора должны были осуществить 2 прохода по куче (heap), что и приводило к плохому UX. В случае с ART, такой ситуации нет: он чистит кучу один раз для консолидации памяти.

ART

DVM vs ART

AndroidManifest.xml

  • Разрешения
  • Описание всех компонент: application, activity, service, receiver.
  • Дополнительная информация.
  • Activity: визуальная часть приложения, точка входа
  • Application: класс приложения, используется как глобальный синглтон.
  • Service: нет интерфейса, работает в фоне.
  • Receiver: системные и пользовательские оповещения.

manifest

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="string"
    android:versionCode="string"
    android:versionName="string"
    android:installLocation=[ "auto" | "internalOnly" | "preferExternal" ]
    >
</manifest>				    
				    

manifest

  • package - имя пакета приложения в стиле Java, должно быть уникальным
  • android:versionCode - версия приложения, нужна для обновления
  • android:versionName - версия приложения, которая показывается пользователя
  • android:installLocation - куда ставить приложение.

permission

<permission
    android:description="string"
    android:icon="string"
    android:label="string"
    android:name="string"
    android:protectionLevel="string"
    />
				    

permission

  • android:name - "android.permisstion.INTERNET"
  • android:icon - иконка, для пользователя
  • android:label - название, для пользователя
  • android:description - описание, для пользователя
  • android:protectionLevel - описание риска

application

  • Большое количество настроек.
  • android:name - Название приложения
  • android:theme - набор параметров, которые применяются ко всему приложению, содержит базовые цвета приложения, стили для отрисовки всех компонентов приложения и различные настройки.
  • android:icon - иконка приложения.

activity

  • Описывает параметры к экрану (Activity подкласс). Все экраны должны быть представлены в манифесте.
  • android:name - название класса (например, com.example.project.ExtracurricularActivity)
  • android:screenOrientation - ориентация экрана (например, портретная или альбомная).
  • android:lauchMode - описание, как экран должен запускаться (например, singleTop).
  • android:label - надпись над экраном.