tgoop.com/dev_easy_notes/147
Last Update:
Медленно мы подходим к интересным и более хардкорным темам. ZygotеInit каждый видел в стэке вызов функций. Независимо от того, что у вас за приложение стартовать все будет отсюда.
Zygote это термин из биологии, клетка которая возникла при слиянии мужской и женской половых клеток. Zygote после определённого времени начинает делиться клонируя себя. Разработчики назвали этот класс не просто так, потому как в сущности это и происходит каждый раз при старте приложения.
Если кратко погрузится в череду вызов. При старте системы, вот прям с самого начала запускается файл init.rc. Расширение вот такое странное потому как в этом файле используя специальный синтаксис, описывающий инструкции как запускать устройство. Да, разработчики Android сделали систему, которая позволяет при помощи специальных инструкций описать как именно и в каком порядке нужно все запустить.
В init.rc описано как стартовать все демоны, сервисы и остальные элементы системы. Этот же файл запускает AndroidRuntime. В С++ коде он кстати так и называется AndroidRuntime. Этот самый AndroidRuntime в свою очередь запускает JVM и в частности main функцию нашего ZygotеInit.
Что происходит в ZygotInit.main? Для начала подгружаются все классы для работы этой самой JVM и все все Android зависимости необходимые для работы. Если интереснее подробнее разобраться в том, как работают ClassLoader у меня и на это есть серия постов. После загрузки всех необходимых классов, запускается некий ZygoteServer. Этот ZygoteServer запускает бесконечный цикл и чего-то ждет.
Вот тут начинается самое интересное. Эта та магия системного программирования которую практически никогда не увидишь в обычных проектах. Для объяснения нужно написать немного кода на низкоуровневом языке. C++ я жутко не люблю и мне кажется от должен уже отправится на полку истории, поэтому мы черканем пару строк на Rust. Не волнуйтесь сложно не будет, я профессионал. Пример вот такой:unsafe { // unsafe просто позволяет запускать небезопасные штуки
let fork_result = libc::fork(); //вот тут происходит магия
match fork_result {
-1 => println!("Ошибка при попытке сделать fork"),
0 => println!("Бонжур мы в child процессе, pid {}”, libc::getpid()),
_ => {
println!("Тут мы в изначальном процессе, pid {}", libc::getpid());
}
}
}
Сейчас нужно будет на максимум включить абстрактное мышление. Значит есть в Unix такой системный вызов, который называется fork. Все что он делает, копирует процесс и запускает его как отдельный. Еще раз вдумайтесь! Этот системный вызов берет вашу прогу, копирует все состояния переменных, все потоки, все стэки, весь хип все это дело переносит в отдельное место в оперативной памяти и запускает как отдельный процесс.
Забавная вещь в том, что можно легко и просто вызвать этот системный вызов (да вызывать вызов) из любой точки программы. Порой трудно в потоках разобраться, а можно сделать прогу, где у тебя после определенного вызова функции вообще другой процесс будет. Именно это и делает ZygotInit.
ZygotInit запускает ZygoteServer, который просто ждет команду от системы на запуск нового процесса. ZygoteServer запускает бесконечный цикл и вот тут интересно. Когда система дает команду на создание нового процесса, этот новый процесс выходит из этого бесконечного цикла и идет дальше запуская ActivityThread и т.д. Изначальный же процесс так и остается в бесконечном цикле в ожидании новых команд от ОС.
Все скорее всего слышали, что когда стартует приложение, у нас создается копия JVM. Мало кто объясняет как именно создается и зачем копия? Как это происходит мы уже разобрали, остался вопрос зачем? Все просто, Android и так не всегда быстрый, а если бы при каждом старте еще и нужно было каждый раз подгружать все нужные классы было бы вообще грустно. Поэтому разработчики придумали тупо копировать инстанс JVM с уже загруженными классами.
Ну а что там происходит с процессом, который вышел из этого бесконечного цикла мы разберем в следующих постах.
BY Dev Easy Notes
Share with your friend now:
tgoop.com/dev_easy_notes/147