Android application to process

Android Application Launch explained: from Zygote to your Activity.onCreate()

Apr 30, 2018 · 6 min read

This article explains how Android launches your application when a user clicks an app icon. The Android system does a lot of heavy lifting behind the curtains to make your launch activity visible to a user. This article covers this process in detail by highlighting the important phases and call sequences.

Android applications are unique in two ways:

  1. Multiple Entry points: Android apps are composed of different components and they can invoke the components owned by other apps. These components roughly correspond to multiple entry points for any application. Hence, they differ from traditional applications which have a single entry point like main() method.
  2. Own Little World: Every Android application lives in its own world, it runs in a separate process, it has its own Dalvik VM instance and is assigned a unique user ID.

When does Android process start?

An Android process is started whenever it is required.

Any time a user or some other sys t em component requests a component (could be a service, an activity or an intent receiver) that belongs to your application be executed, the Android system spins off a new process for your app if it’s not already running. Generally processes keep running until killed by the system. Application processes are created on demand and a lot of things happen before you see your application’s launch activity up and running.

Every app runs in its own process: By default, every Android app runs in its own Android process which is nothing but a Linux process which gets one execution thread to start with. For example, when you click on a hyper-link in your e-mail, a web page opens in a browser window. Your mail client and the browser are two separate apps and they run in their two separate individual processes. The click event causes Android platform to launch a new process so that it can instantiate the browser activity in the context of its own process. The same holds good for any other component in an application.

Zygote : Spawning new life, new process

Let’s step back for a moment and have a quick look on system start-up process. Like the most Linux based systems, at startup, the boot loader loads the kernel and starts the init process. The init then spawns the low level Linux processes called “daemons” e.g. android debug daemon, USB daemon etc. These daemons typically handle the low level hardware interfaces including radio interface.

Init process then starts a very interesting process called ‘ Zygote ’.

As the name implies it’s the very beginning for the rest of the Android application. This is the process which initializes a very first instance of Dalvik virtual machine. It also pre-loads all common classes used by Android application framework and various apps installed on a system. It thus prepares itself to be replicated. It stats listening on a socket interface for future requests to spawn off new virtual machines (VM)for managing new application processes. On receiving a new request, it forks itself to create a new process which gets a pre-initialized VM instance.

Читайте также:  Android applications app store

After zygote, init starts the runtime process.

The zygote then forks to start a well managed process called system server. System server starts all core platform services e.g activity manager service and hardware services in its own context.

At this point the full stack is ready to launch the first app process — Home app which displays the home screen also known as Launcher application.

When a user clicks an app icon in Launcher …

The click event gets translated into startActivity(intent) and it is routed to ActivityManagerService via Binder IPC. The ActvityManagerService performs multiple steps

  1. The first step is to collect information about the target of the intent object. This is done by using resolveIntent() method on PackageManager object. PackageManager.MATCH_DEFAULT_ONLY and PackageManager.GET_SHARED_LIBRARY_FILES flags are used by default.
  2. The target information is saved back into the intent object to avoid re-doing this step.
  3. Next important step is to check if user has enough privileges to invoke the target component of the intent. This is done by calling grantUriPermissionLocked() method.
  4. If user has enough permissions, ActivityManagerService checks if the target activity requires to be launched in a new task. The task creation depends on Intent flags such as FLAG_ACTIVITY_NEW_TASK and other flags such as FLAG_ACTIVITY_CLEAR_TOP.
  5. Now, it’s the time to check if the ProcessRecord already exists for the process.If the ProcessRecord is null, the ActivityManager has to create a new process to instantiate the target component.

As you saw above many things happen behind the scene when a user clicks on an icon and a new application gets launched. Here is the full picture :

There are three distinct phases of process launch :

  1. Process Creation
  2. Binding Application
  3. Launching Activity / Starting Service / Invoking intent receiver …

ActivityManagerService creates a new process by invoking startProcessLocked() method which sends arguments to Zygote process over the socket connection. Zygote forks itself and calls ZygoteInit.main() which then instantiates ActivityThread object and returns a process id of a newly created process.

Every process gets one thread by default. The main thread has a Looper instance to handle messages from a message queue and it calls Looper.loop() in its every iteration of run() method. It’s the job of a Looper to pop off the messages from message queue and invoke the corresponding methods to handle them. ActivityThread then starts the message loop by calling Looper.prepareLoop() and Looper.loop() subsequently.

The following sequence captures the call sequence in detail —

The next step is to attach this newly created process to a specific application. This is done by calling bindApplication() on the thread object. This method sends BIND_APPLICATION message to the message queue. This message is retrieved by the Handler object which then invokes handleMessage() method to trigger the message specific action — handleBindApplication(). This method invokes makeApplication() method which loads app specific classes into memory.

This call sequence is depicted in following figure.

Launching an Activity:

After the previous step, the system contains the process responsible for the application with application classes loaded in process’s private memory. The call sequence to launch an activity is common between a newly created process and an existing process.

Читайте также:  Как настроить call recorder для андроида

The actual process of launching starts in realStartActivity() method which calls sheduleLaunchActivity() on the application thread object. This method sends LAUNCH_ACTIVITY message to the message queue. The message is handled by handleLaunchActivity() method as shown below.

Assuming that user clicks on Video Browser application. the call sequence to launch the activity is as shown in the figure.

The Activity starts its managed lifecycle with onCreate() method call. The activity comes to foreground with onRestart() call and starts interacting with the user with onStart() call.

Thanks for reading through 🙌🏼. If you found this post useful, please applaud using the 👏 button and share it through your circles.

This article was initially published as two part series (Part 1 and Part 2) on my blog ./ mult-core-dump in 2010. These articles have been cited in multiple documents including the very famous Introduction to the Android Graphics Pipeline

Источник

Процессы и потоки в Android: пишем AsyncTask правильно

Продолжаю свои повествования об Android. И в этот раз хочу поделиться ценной информацией о процессах и потоках, которая должна быть хорошо усвоена и всегда оставаться под рукой во избежании ошибок и недопонимания при написании приложений. В конце статьи приведу пример реализации AsyncTask, который загружает в ImageView картинку по нажатию на кнопку.

Прежде всего отмечу, что подробнее о данной теме можно прочесть в данном руководстве — developer.android.com/guide/topics/fundamentals/processes-and-threads.html

На заметку о процессах и потоках в Android

Когда запускается компонент приложения и приложение не имеет других запущенных компонентов, Android создает новый процесс для приложения с одним потоком исполнения. По умолчанию все компоненты одного приложения запускаются в одном процессе, в потоке называемом «главный». Если компонент приложения запускается и уже существует процесс для данного приложения(какой-то компонент из приложения существует), тогда компонент запущен в этом процессе и использует его поток выполнения. Вы можете изменить данное поведение, задав разные процессы для разных компонентов вашего приложения. Кроме того вы можете добавить потоки в любой процесс.

Задать отдельный процесс для компонента можно с помощью файла манифеста. Каждый тег компонента(activity, service, receiver и provider) поддерживает атрибут android:process. Данный атрибут позволяет задать процесс, в котором будет выполняться компонент. Также вы можете задать процесс в котором будут выполняться компоненты разных приложений. Также данный атрибут поддерживается тегом application, что позволяет задать определенный процесс для всех компонентов приложения.

Android пытается поддерживать процесс приложения как можно дольше, но когда потребуются ресурсы старые процессы будут вытеснены по иерархии важности.

Существует 5 уровней иерархии важности: (процессы первого уровня из списка будут удалены последними)

1.Процесс с которым взаимодействует пользователь(Foreground process)
К таким процессам относится например: активити с которым взаимодействует пользовать; сервис(экземпляр Service), с которым взаимодействует пользователь; сервис запущенный методом startForeground(); сервис, который выполняет один из методов своего жизненного цикла; BroadcastReceiver который выполняет метод onReceive().

2.Видимый процесс
Процесс, в котором не выполнены условия из пункта №1, но который влияет на то, что пользователь видит на экране. К примеру, вызван метод onPause() активити.

3.Сервисный процесс
Служба запущенная методом startService()

4.Фоновый процесс
Процесс выполняемый в фоновом режиме, который невиден пользователю.

Отмечу, что в компонентах приложения существует метод onLowMemory(), но полагаться на то, что данный метод будет вызван нельзя, также как нельзя на 100% полагаться на метод onDestroy(), поэтому логику сохранения данных или каких-либо настроек можно осуществить в методе onStop(), который(как уверяют) точно вызывается.

Когда запускается приложение, система создает «главный» поток выполнения для данного приложения, который также называется UI-потоком. Этот поток очень важен, так как именно в нем происходит отрисовка виджетов(кнопочек, списков), обработка событий вашего приложения. Система не создает отдельный поток для каждого экземпляра компонента. Все компоненты, которые запущенны в одном процессе будут созданы в потоке UI. Библиотека пользовательского интерфейса Android не является потоково-безопасной, поэтому необходимо соблюдать два важных правила:

Читайте также:  Сколько всего комбинаций графического ключа android

1) Не блокировать поток UI
2) Не обращаться к компонентам пользовательского интерфейса не из UI-потока

Теперь, предположим, что у нас возникла задача — загрузить картину в ImageView из сети и тут же ее отобразить. Как мы поступим? По логике: мы создадим отдельный поток, который и сделает всю нашу работу, примерно так:

Выглядит правдоподобно, так как мы вынесли операцию загрузки картинки в отдельный поток. Проблема в том, что мы нарушили правило №2. Исправить эту проблему можно с помощью следующих методов:

Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)

К примеру, воспользуемся первым из них:

Теперь реализация потоково-безопасная: сетевая операция выполняется в отдельном потоке, а к ImageView обращаемся из потока UI.
К счастью, данные операции можно объединить с помощью наследования класса Handler и реализации нужной логики, но лучшее решение — наследовать класс AsyncTask.

AsyncTask позволяет выполнить асинхронную работу и делать обновления пользовательского интерфейса.
Для обновления реализуйте метод onPostExecute(), а всю фоновую работу заключите в метод doInBackground(). После того, как вы реализуете свою собственную задачу, необходимо ее запустить методом execute().

Привожу обещанный пример AsyncTask, в котором реализована задача загрузки и отображения картинки(вариант с аннотациями и отклонением от применения стандартного протокола диалогов):

А теперь рассмотрим самый правильный вариант с точки зрения работы с диалогами:

Кода стало побольше, но лучше использовать стандартный протокол работы с диалогами.
Также я убрал все аннотации, чтобы новичкам было проще попробовать данный код.

Не забудьте добавить в свою разметку кнопочки атрибут с указанным значением: android:onClick=«runButtonHandler»

И добавлю: в оффициальном документе(Тыц ) также, как и в моем случае, не используется preExecute(), но если вам понадобится выполнить какие-то действия с вашим пользовательским интерфейсом до начала выполнения задачи, то смело используйте данный метод.

Параметры передаваемые в AsyncTask:
1. Параметры(в нашем случае адрес URL).
2. Прогресс (единицы задающие ход изменения задачи). В нашем случае не используется.
3. Результат выполнения задачи(в нашем случае объект Bitmap)

Код довольно прост: всю фоновую работу мы выполняем в методе doInBackGround(), вызывая метод publishProgress(), чтобы во время загрузки картинки крутился наш ProgressDialog при вызове метода onProgressUpdate(). После выполнения фоновой работы вызывается метод onPostExecute() в который передается результат работы метода doInBackGround(), в нашем случае это объект Bitmap и тут же мы его загружаем в ImageView.
Отмечу пару важных моментов, которые нужно учитывать:

1) Метод doInBackGround() выполняется в фоновом потоке, потому доступа к потоку UI внутри данного метода нет.
2) Методы onPostExecute() и onProgressUpdate() выполняются в потоке UI, потому мы можем смело обращаться к нашим компонентам UI.

Да, я снова применил библиотеку android-annotations, так что не пугайтесь аннотациям.

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

Данная статья это переработка доступной информации + личный опыт при реализации указанной задачи и работе с потоками.

Как всегда пожелания и замечания по поводу материала статьи в личку. Если вам есть что-то добавить или дополнить — смело пишите в комментарии.

UPD Статья обновленна добавлением более правильной версии в плане работы с диалогами.

Источник

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