Android app activitythread handlebindapplication

«Холодный» запуск Android-приложения

Всем приветъ! Давно ничего не писал.

Это будет серия постов о процессе «холодного» запуска Android приложения, с момента нажатия на иконку и до создания процесса приложения.

Общая схема

Открывая «окно»…

Перед тем как запустить новый процесс приложения, system_server создает стартовое окно используя метод PhoneWindowManager.addSplashScreen():

Стартовое окно это то, что пользователь будет видеть пока запускается само приложение. Окно будет отображаться до тех пор пока не будет запущена Activity и не будет отрисован первый кадр. То есть пока не будет завершен «холодный» запуск. Пользователь может видеть данное окно длительное время, поэтому постарайтесь сделать его приятным.

Содержимое стартового окна берется из drawable-ресурсов windowSplashscreenContent и windowBackground запускаемого Activity. Банальный пример такого окна:

Если пользователь восстанавливает Activity из режима последнего экрана(Recent screen), при этом на нажимая на иконку приложения, то system_server вызывает метод TaskSnapshotSurface.create(), чтобы создать стартовое окно из уже сделанного скриншота.

Как только стартовое окно показано пользователю, system_server готов запустить процесс приложения и вызывает метод ZygoteProcess.startViaZygote():

В коде видно, что метод ZygoteProcess.zygoteSendArgsAndGetResult() отправляет аргументы запуска через сокет Zygote-процессу.

«Разделение» Zygote-ы

Каждый процесс приложения запускается с помощью форкания(разделения) от существующего Zygote-процесса…

Вкратце об этом я писал в предыдущей статье про запуск Android-а. А теперь давайте посмотрим поглубже на происходящие процессы.

Когда система загружается процесс Zygote стартует и выполняет метод ZygoteInit.main():

Как вы видите метод ZygoteInit.main() делает 2 важные вещи:

  • Подгружает все необходимые системные библиотеки и ресурсы Android-фреймворка. Подобная предзагрузка не только экономит память но еще и экономит время запуска приложений.
  • Далее он запускает метод ZygoteServer.runSelectLoop(), который в свою очередь запускает сокет и начинает слушать вызовы данного сокета.

Когда же на сокет приходит команда на форкинг процесса, метод ZygoteConnection.
processOneCommand() обрабатывает аргументы используя метод ZygoteArguments.parseArgs() и запускает метод Zygote.forkAndSpecialize():

На заметку: Начиная с Android 10 есть оптимизационная фича под названием Unspecialized App Process, которая имеет пул не специализированных Zygote-процессов, для еще более быстрого запуска приложений.

Читайте также:  Как перезагрузить операционную систему андроид

Приложение запустилось!

После форка дочерний процесс запускает метод RuntimeInit.commonInit(), который устанавливает дефолтный UncaughtExceptionHandler. Далее, процесс запускает метод ActivityThread.main():

Тут происходят две интересные вещи:

  • Метод ActivityThread.main() создает новый поток(Thread) и вызывает метод Looper.loop(), в котором будет запущен новый инстанс Looper-а. Он будет привязан к новому потоку(который становится MainThread-ом aka UiThread) и будет работать(теоретически) бесконечно. Looper привязавшись, будет ожидать сообщений для того чтобы поместить их к своему MessageQueue.
  • Далее, метод ActivityThread.attach() делает IPC-запрос к методу ActivityManagerService.attachApplication()system_server-а, тем самым давая понять, что MainThread нашего приложения запущен и готов к работе.

Контроль над приложением

В процессе system_server метод ActivityManagerService.attachApplication() вызывает метод ActivityManagerService.attachApplicationLocked(), который завершает настройку запускаемого приложения:

Парочка ключевых выводов:

  • Процесс system_server делает IPC-запрос к методу ActivityThread.bindApplication() в процессе нашего приложения, который направляет запрос к методу ActivityThread.handleBindApplication() в MainThread-е приложения.
  • Сразу после этого, system_server планирует запуск Pending Activity, Service и BroadcastReciever-ов нашего приложения.
  • Метод ActivityThread.handleBindApplication() загружает APK-файл и компоненты приложения.
  • Разработчики имеют возможность немного повлиять на процессы перед запуском метода ActivityThread.handleBindApplication(), так что именно здесь должен начаться мониторинг холодного запуска приложения.

Давайте немного подробно разберем 3-ий пункт и узнаем что и как происходит при загрузке компонентов и ресурсов приложения. Порядок шагов такой:

  • Загрузка и создание инстанса класса AppComponentFactory.
  • Вызов метода AppComponentFactory.instantiateClassLoader().
  • Вызов метода AppComponentFactory.instantiateApplication() для загрузки и создания инстанса класса Application.
  • Для каждого объявленного ContentProvider-а, в порядке приоритета, вызов метода AppComponentFactory.instantiateProvider() для загрузки его класса и создания инстанса, после вызов метода ContentProvider.onCreate().
  • И наконец, вызов метода Application.onCreate().

Эпилог

Мы начали изучать «холодную» загрузку с очень обще-абстрагированного уровня:

Теперь мы знаем, что происходит «под капотом»:

Ну что же, это был длинный пост. Но это не все! В следующих постах мы продолжим глубокое погружение в процесс запуска Android-приложения. Оставайтесь с нами!

Источник

Отрисовка первого кадра Android-приложения

Всем приветЪ! Этот пост является продолжением поста про глубокое погружение в процесс загрузки-запуска Android-приложения. Сегодня мы пойдем чуть дальше и обсудим момент когда главная Activity приложения запущена и система должна отрисовать первый кадр. Прошу под кат.

Следуя официальной документации запущенный процесс приложения отвечает за выполнение следующих шагов:

  1. Создание объекта класса Application.
  2. Запуск основного потока(MainThread aka UiThread).
  3. Создание стартового Activity, который указан в манифесте.
  4. Расширение(раздутие, inflating) вьюшек. То есть создание вьюшек, которые прописаны в xml-файле.
  5. Планировка размеров(View.measure()) и размещения(View.layout()) вьюшек на экране.
  6. Выполнение начальной отрисовки.
Читайте также:  Cent browser для android

После того как был отрисован первый кадр, системный процесс заменяет отображаемое фоновое окно, заменяя его на Activity приложения. Теперь пользователь может взаимодействовать с приложением.

А теперь давайте поподробнее обо всех шагах.

Старт главного потока

В предыдущем посте мы узнали:

  • Когда запускается процесс приложения, он вызывает метод ActivityThread.main(), который делает блокирующий IPC-запрос к методу ActivityManagerService.attachApplication() в процессе system_server.
  • system_server делает IPC-вызов в процессе приложения метода ActivityThread.bindApplication(), который ставит в очередь сообщение BIND_APPLICATION в MessageQueue главного потока.
  • Когда IPC-вызов метода ActivityManagerService.attachApplication() завершен, ActivityThread.main() вызывает Looper.loop(), который будет зациклен навсегда(пока приложение работает) и будет обрабатывать сообщения поступающие в MessageQueue.
  • Первое сообщение, которое будет обработано это BIND_APPLICATION. В этот момент будет вызван метод ActivityThread.handleBindApplication(), который загрузит APK и другие компоненты приложения.

Важный момент: ничего не происходит в главном потоке процесса приложения пока не выполнится IPC-вызов метода ActivityManagerService.attachApplication().

Планируем запуск Activity

Давайте посмотрим что происходит в процессе system_server после вызова метода ActivityThread.bindApplication():

Строка которая релевантна запуску Activity — mAtmInternal.attachApplication(. ). Метод вызывает ActivityTaskManagerService.attachApplication(), который в свою очередь вызывает метод RootActivityContainer.attachApplication():

Код делает следующее:

  • Обходит каждый дисплей.
  • Получает стек сфокусированных Activity для этого дисплея.
  • Проходит по каждому Activity целевого стека Activity.
  • Если Activity принадлежит к запущенному процессу, то вызывается метод ActivityStackSupervisor.realStartActivityLocked(). Обратите внимание, что параметр andResume будет иметь значение true если Activity находится на вершине стэка.

Вот как выглядит метод ActivityStackSupervisor.realStartActivityLocked():

Все вызовы методов, которые мы просмотрели происходят в системном процессе system_server. Метод ClientLifecycleManager.scheduleTransaction() делает IPC-вызов ActivityThread.scheduleTransaction() в процессе приложения, который вызывает ClientTransactionHandler.scheduleTransaction(), чтобы положить в очередь сообщение EXECUTE_TRANSACTION:

При обработке сообщения EXECUTE_TRANSACTION происходит вызов метода TransactionExecutor.execute().

Теперь можно обновить диаграмму:

Фактический запуск Activity

Метод TransactionExecutor.execute() вызывает TransactionExecutor.
performLifecycleSequence(), который в свою очередь делает коллбэк в ActivityThread для создания(create), запуска(start) и продолжения(resume) Activity:

Первый кадр

Давайте взглянем на последовательность вызовов методов, которые ведут к отрисовке первого кадра:

  • ActivityThread.handleResumeActivity()
  • WindowManagerImpl.addView()
  • WindowManagerGlobal.addView()
  • ViewRootImpl.setView()
  • ViewRootImpl.requestLayout()
  • ViewRootImpl.scheduleTraversals()
  • Choreographer.postCallback()
  • Choreographer.scheduleFrameLocked()
Читайте также:  Это самые лучшие шахматы для андроид

Метод Choreographer.scheduleFrameLocked() ставит в очередь сообщение MSG_DO_FRAME:

При обработке сообщения MSG_DO_FRAME происходит вызов метода Choreographer.doFrame(), который в свою очередь вызывает ViewRootImpl.doTraversal(), который осуществляет проходы measure pass и layout pass, и наконец проход the first draw pass по иерархии вьюшек:

Заключение

Мы начали с высокого уровня понимания того, что происходит, когда система создает процесс приложения:

Теперь мы знаем что именно происходит «под капотом»:

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

Теперь, когда у нас есть полная картина, мы можем начать разбираться в том, как правильно контролировать холодный запуск. Следующий пост будет именно об этом! До встречи.

Источник

Why app crash after building to Android? #393

Comments

aidanikuz02 commented Feb 19, 2020

Hello. I am using Unity 2019.3.0f3, Windows10, version 7.18.0.

I created a project that successfully built and run. Then i exported it as a package and imported it into another project that uses EasyAR camera function. I created a new app in the console so i got a new ID and entered the package name as per the new project. Updated the app id in unity facebook settings like attached images 3 and 4. but when building to my Samsung s10 it crashes with errors : Didnt get provider and didnt find class com.facebook.FacebookContentProvider like attached images 1 and 2. The AndroidManifest is as image 5. the generated hash key for android i did like this from the previous project, so its still the same. Please help.




The text was updated successfully, but these errors were encountered:

aidanikuz02 commented Feb 19, 2020

I also added -keep class com.facebook.internal.* <*;>and -keep class com.facebook.* <*;>in proguard-user.txt file (as suggested in this closed issue ) which was created when i checkmarked user proguard file at Player Settings > Publishing Settings > Build : User Proguard File.

But i still got the same error as above.

aidanikuz02 commented Feb 19, 2020

run «/Assets/Play Service Resolver/Android Resolver/Delete Resolved Libraries»

run «/Assets/Play Service Resolver/Android Resolver/Resolve»

Still got the error

aidanikuz02 commented Feb 19, 2020

Okay, so what i did was delete the PlayServicesResolver in Assets. Then I imported play-services-resolver-1.2.135.0.unitypackage which can be downloaded here : https://github.com/googlesamples/unity-jar-resolver

then Assets > Play Services Proivider > Android Resolver > Resolve

Источник

Оцените статью