https://medium.com/android-news/android-application-launch-explained-from-zygote-to-your-activity-oncreate-8a8f036864b

 

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

This article explains how Android launches your application when a user clicks an app icon. The Android system does a lot of heavy lifting…

medium.com

본 글은 해당 글을 번역한 내용을 다수 포함하고 있습니다.

 

 

Java 프로세스의 진입점

public static void main(String[] args)

JAVA로 만들어진 프로세스가 실행되면 제일 먼저 위의 main 메소드를 실행한다. 그렇다면 안드로이드 애플리케이션은 main 함수가 어디 있을까?

 

정답은 ActivityThread.java 안에 있다.

    public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
        // Install selective syscall interception
        AndroidOs.install();
        // CloseGuard defaults to true and can be quite spammy.  We
        // disable it here, but selectively enable it later (via
        // StrictMode) on debug builds, but using DropBox, not logs.
        CloseGuard.setEnabled(false);
        Environment.initForCurrentUser();
        // Make sure TrustedCertificateStore looks in the right place for CA certificates
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);
        // Call per-process mainline module initialization.
        initializeMainlineModules();
        Process.setArgV0("<pre-initialized>");
        Looper.prepareMainLooper();
        // Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
        // It will be in the format "seq=114"
        long startSeq = 0;
        if (args != null) {
            for (int i = args.length - 1; i >= 0; --i) {
                if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
                    startSeq = Long.parseLong(
                            args[i].substring(PROC_START_SEQ_IDENT.length()));
                }
            }
        }
        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);
        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }
        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

이 메서드 에서는 Activity Manager한테 프로세스가 성공적으로 실행되었다고 알린 후 Activity Manager는 새 프로세스에게 실제 작업을 수행하도록 알린다. 그리고 나서 매니페스트 정보에 따라 Activity Class를 create 하고 OnCreate를 호출한다. 이 main 함수가 호출되기 까지의 과정을 알아보고자 한다.

 

 

안드로이드 애플리케이션 시작 종류

Cold Start: 앱을 처음부터 시작하는 경우. 콜드 스타트 이전에는 시스템의 프로세스에서 앱의 프로세스를 만들지 않은 상태에서 앱이 실행됨

Warm Start: 사용자가 앱을 종료한 다음 다시 시작하는 경우. 프로세스가 계속 실행되었을 수도 있지만 onCreate() 호출을 통해 활동을 처음부터 다시 만듦 또는 시스템이 메모리에서 앱을 제거한 다음 사용자가 앱을 다시 시작할 때. 프로세스와 액티비티를 다시 시작해야 하지만 onCreate()에 전달된 saveInstanceState가 작업을 실행하는데 도움이 됨

Hot Start: 앱이 백그라운드 상태에 있다가 포그라운드 상태로 전환할 때

 

아래 과정은 Cold Start의 과정이다.

 

 

안드로이드 프로세스는 언제 시작될까?

 

안드로이드 프로세스는 필요할 때마다 시작된다. 사용자 또는 일부 다른 애플리케이션 구성 요소가 애플리케이션에 속한 구성요소가 실행되도록 요청할 때마다 Android 시스템은 앱이 아직 실행되고 있지 않은 경우 앱에 대한 새 프로세스를 실행한다. 프로세스는 시스템에 의해 종료될 때까지 계속 실행된다.

 

모든 애플리케이션은 각자의 프로세스를 가진다. 예를 들어 하나의 안드로이드 애플리케이션에서 이메일 링크를 클릭하면 브라우저 윈도우에서 웹 페이지가 오픈된다. 이메일 링크가 개시된 앱과 이메일은 서로 다른 프로세스 위에서 각각 동작된다. 클릭 이벤트는 안드로이드 플렛폼이 자체 컨텍스트에서 브라우저 활동을 인스턴스화 할 수 있도록 새로운 프로세스를 시작하도록 한다. 다른 애플리케이션 구성 요소에도 동일하게 적용된다. 

 

 

시스템 시작 프로세스

애플리케이션 실행 과정을 설명하시게 앞서 시스템 시작 프로세스를 살펴보도록 하자. 대부분의 Linux 기반 시스템과 마찬가지로 부팅 시 부트 로더는 커널을 로드하고 init 프로세스를 시작한다. 그런 다음 init은 "데몬"이라고 하는 낮은 수준의 Linux 프로세스를 생성한다. 데몬이란 리눅스 시스템이 처음 가동될 때 실행되는 백그라운드 프로세스의 일종이며  사용자의 요청을 기다리고 있다가 요청이 발생하면 적절히 대응하는 리스너 같은 역할을 한다.

 

Zygote

Init 프로세스는 안드로이드 프로세스 실행을 위해 'zygote'라는 프로세스를 시작한다. ART의 가장 첫 번째 인스턴스를 초기화 하는 프로세스이다. zygote는 시스템에 설치된 안드로이드 애플리케이션 프레임워크 및 다양한 앱에서 사용하는 모든 공통 클래스를 미리 로드하고 복제를 준비한다. 새로운 애플리케이션 프로세스를 관리하기 위해 새로운 가상 머신을 생성하기 위한 향후 요청에 대해 소켓 인터페이스에서 수신 대기한다. 새 요청을 받으면 자체적으로 분기하여 미리 초기화된 VM 인스턴스를 가져오는 새 프로세스를 만든다.

 

zygote

 

System-Server

zygote가 프로세스를 포크하면 system server를 호출한다. 시스템 서버는 자체 context 안에서 모든 코어 플랫폼 서비스(액티비티 매니저 서비스 혹은 하드웨어 서비스)를 시작한다. 이 시점에서 전체 스택은 첫 번 째 앱 프로세스(런처 애플리케이션이라고도 하는 홈 화면 표시하는 홈 앱)을 시작할 준비가 되었다.

 

 

 

런처에서 앱 아이콘 클릭 후 앱 실행 과정

 

ActivityManagerService

 

클릭 이벤트는 startActivity(intent)로 변환되고 바인터 IPC(Inter Process Communication)를 통해 ActivityManagerService로 라우팅된다. ActivityManagerService는 여러 단계를 수행한다.

 

1. Intent 객체의 대상 앱에 대한 정보를 수집한다. 이것은 PackageManager 객체에 resolveIntent() 메서드를 사용하여 수행된다. PackageManager.MATCH_DEFAULT_ONLY 및 PackageManager.GET_SHARED_LIBRARY_FILES 플래그가 기본적으로 사용된다.

2. 대상 앱에 대한 정보는 1 단계를 다시 수행하지 않도록 Intent 객체에 다시 저장된다.

3. Intent 의 대상 앱 구성 요소를 호출할 수 있는 권한이 있는 지 확인한다. 이는 grantUriPermissionLocked() 메소드를 호출하여 수행한다.

4. 사용자에게 충분한 권한이 있는 경우 ActivityManagerService는 대상 앱의 Activity를 새 Task에서 시작해야 할 지 확인한다. Task 생성은 FLAG_ACTIVITY_NEW_TASK 와 같은 Intent 플래그 및 FLAG_ACTIVITY_CLEAR_TOP와 같은 기타 플래그에 따라 달라진다.

5. ProcessRecord가 이 애플리케이션에 대한 프로세스에 대해 이미 존재하는 지 확인한다. ProcessRecord가 null이면 ActivityManager는 대상 애플리케이션의 구성요소를 인스턴스화하기 위해 새 프로세스를 생성해야 한다.

 

 

 

프로세스 시작 단계

 

1. 프로세스 생성

 

ActivityManagerService는 소켓 연결을 통해 Zygote 프로세스에 인수를 보내는 startProcessLocked() 메서드를 호출하여 새 프로세스를 만든다. Zygote는 스스로를 분기하고 ZygoteInit.main()을 호출하여 ActivityThread 객체를 인스턴스화 하고 새로 생성된 프로세스의 프로세스 ID를 반환한다. 모든 프로세스는 기본적으로 하나의 스레드를 얻는다. 메인 스레드에서는 메시지 큐의 메시지를 처리하는 Lopper 인스턴스가 있으며 run() 메서드를 반복할 때마다 Loop.loop()을 호출한다. 메시지 큐에서 메시지를 꺼내고 해당 메소드를 호출하여 처리하는 것이 루퍼의 작업이다. 그런 다음 ActivityThread는 Looper.prepareLooper.loop()를 연속적으로 호출하여 메시지 루프를 시작한다.

 

2. 애플리케이션 바인딩

 

다음 단계는 새로 생성된 프로세스를 특정 애플리케이션에 연결하는 것이다. 이것은 스레드 객체에서 bindApplication() 을 호출하여 수행한다. 이 메소드는 BIND_APPLICATION 메시지를 메시지 큐에 보낸다. 이 메시지는 Handler 객체 에 의해 검색되며, 이 객체는 handleMessage() 메서드를 호출하여 메시지 특정 작업인 handleBindApplication() 을 트리거한다. 이 메서드는 앱 특정 클래스를 메모리에 로드하는 makeApplication() 메서드를 호출한다.

 

3. 액티비티 시작

 

실제 실행 프로세는 응용 프로그램 스레드 객체에서 sheduleLaunchActivity()를 호출하는 realStartActivity() 메서드에서 시작된다. 이 메소드는 LAUNCH_ACTIVITY 메시지를 메시지 큐에 보낸다.

 

안드로이드 앱 실행: LAUNCH_ACTIVITY 메세지 핸들링

 

 

 

위에서 설명한 과정을 요약한 그래프이다

 

애플리케이션 실행 전체 과정

 

 

 

 

참고

https://preludez.tistory.com/8

https://medium.com/android-news/android-application-launch-explained-from-zygote-to-your-activity-oncreate-8a8f036864b

'안드로이드 > 기초' 카테고리의 다른 글

Android 런타임 — Dalvik과 ART  (0) 2022.07.19
안드로이드 빌드 프로세스  (0) 2022.07.14
복사했습니다!