これは、アイコンをクリックした瞬間からアプリケーションプロセスの作成まで、Androidアプリケーションをコールドローンチするプロセスに関する一連の投稿になります。
一般的なスキーム
「ウィンドウ」を開く..。
新しいアプリケーションプロセスを開始する前に、system_serverはPhoneWindowManager .addSplashScreen()メソッドを使用して開始ウィンドウを作成します。
public class PhoneWindowManager implements WindowManagerPolicy {
public StartingSurface addSplashScreen(...) {
...
PhoneWindow win = new PhoneWindow(context);
win.setIsStartingWindow(true);
win.setType(TYPE_APPLICATION_STARTING);
win.setTitle(label);
win.setDefaultIcon(icon);
win.setDefaultLogo(logo);
win.setLayout(MATCH_PARENT, MATCH_PARENT);
addSplashscreenContent(win, context);
WindowManager wm = (WindowManager) context.getSystemService(
WINDOW_SERVICE
);
View view = win.getDecorView();
wm.addView(view, params);
...
}
private void addSplashscreenContent(PhoneWindow win,
Context ctx) {
TypedArray a = ctx.obtainStyledAttributes(R.styleable.Window);
int resId = a.getResourceId(
R.styleable.Window_windowSplashscreenContent,
0
);
a.recycle();
Drawable drawable = ctx.getDrawable(resId);
View v = new View(ctx);
v.setBackground(drawable);
win.setContentView(v);
}
}
開始ウィンドウは、アプリケーションの実行中にユーザーに表示されるウィンドウです。ウィンドウは、アクティビティが起動されて最初のフレームが描画されるまで表示されます。つまり、コールドスタートが完了するまでです。ユーザーはこのウィンドウを長時間見ることができるので、快適にするようにしてください。
起動ウィンドウの内容は、描画可能資源から取られwindowSplashscreenContentとのwindowBackground立ち上げ活動。このようなウィンドウの簡単な例:
ユーザーがアプリケーションアイコンをクリックしているときに、最近の画面モードからアクティビティを復元した場合、system_serverTaskSnapshotSurface .create()メソッドを呼び出して、すでに撮影したスクリーンショットから開始ウィンドウを作成します。
開始ウィンドウがユーザーに表示されると、system_serverはアプリケーションプロセスを開始する準備が整い、ZygoteProcessメソッドを呼び出します。startViaZygote():
public class ZygoteProcess {
private Process.ProcessStartResult startViaZygote(...) {
ArrayList<String> argsForZygote = new ArrayList<>();
argsForZygote.add("--runtime-args");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
argsForZygote.add("--runtime-flags=" + runtimeFlags);
...
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi),
zygotePolicyFlags,
argsForZygote);
}
}
コードでは、ZygoteProcessであることがわかります。zygoteSendArgsAndGetResult()は、ソケットを介して起動引数をZygoteプロセスに送信します。
Zygoteの「分離」
メモリ管理に関するAndroidのドキュメントによると、次のようになります。
各アプリケーションプロセスは、既存のZygoteプロセスからフォーク(分割)することによって開始されます...これについては、Androidの起動に関する前回の記事で簡単に説明しました。それでは、進行中のプロセスを詳しく見ていきましょう。
システムが起動すると、Zygoteプロセスが開始され、ZygoteInit .main()メソッドが実行されます。
public class ZygoteInit {
public static void main(String argv[]) {
...
if (!enableLazyPreload) {
preload(bootTimingsTraceLog);
}
// The select loop returns early in the child process after
// a fork and loops forever in the zygote.
caller = zygoteServer.runSelectLoop(abiList);
// We're in the child process and have exited the
// select loop. Proceed to execute the command.
if (caller != null) {
caller.run();
}
}
static void preload(TimingsTraceLog bootTimingsTraceLog) {
preloadClasses();
cacheNonBootClasspathClassLoaders();
preloadResources();
nativePreloadAppProcessHALs();
maybePreloadGraphicsDriver();
preloadSharedLibraries();
preloadTextResources();
WebViewFactory.prepareWebViewInZygote();
warmUpJcaProviders();
}
}
ご覧のとおり、ZygoteInitメソッドです。main()は2つの重要なことを行います:
- Androidフレームワークに必要なすべてのシステムライブラリとリソースをロードします。このようなプリロードは、メモリを節約するだけでなく、アプリケーションの起動時間を節約します。
- 次に、ZygoteServer.runSelectLoop()メソッドを実行します。このメソッドは、ソケットを開始し、このソケットへの呼び出しのリッスンを開始します。
プロセスをフォークするコマンドがソケット、ZygoteConnectionに来ると。
processOneCommand()は、ZygoteArgumentsメソッドを使用して引数を処理します。parseArgs()を実行し、Zygoteを実行します。forkAndSpecialize():
public final class Zygote {
public static int forkAndSpecialize(...) {
ZygoteHooks.preFork();
int pid = nativeForkAndSpecialize(...);
// Set the Java Language thread priority to the default value.
Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
ZygoteHooks.postForkCommon();
return pid;
}
}
注: Android 10以降、Unspecialized App Processと呼ばれる最適化機能があります。これには、アプリケーションをさらに高速に起動するための非特殊なZygoteプロセスのプールがあります。
アプリケーションが起動しました!
フォークの後、子プロセスはRuntimeInitメソッドを実行します。commonInit()。デフォルトのUncaughtExceptionHandlerを設定します。次に、プロセスはActivityThreadメソッドを開始します。メイン():
public final class ActivityThread {
public static void main(String[] args) {
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
Looper.loop();
}
final ApplicationThread mAppThread = new ApplicationThread();
private void attach(boolean system, long startSeq) {
if (!system) {
IActivityManager mgr = ActivityManager.getService();
mgr.attachApplication(mAppThread, startSeq);
}
}
}
ここでは2つの興味深いことが起こります。
- 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()。これにより、起動するアプリケーションの構成が完了します。
public class ActivityManagerService extends IActivityManager.Stub {
private boolean attachApplicationLocked(
IApplicationThread thread, int pid, int callingUid,
long startSeq) {
thread.bindApplication(...);
// See if the top visible activity is waiting to run
// in this process...
mAtmInternal.attachApplication(...);
// Find any services that should be running in this process...
mServices.attachApplicationLocked(app, processName);
// Check if a next-broadcast receiver is in this process...
if (isPendingBroadcastProcessLocked(pid)) {
sendPendingBroadcastsLocked(app);
}
return true;
}
}
重要なポイントのいくつか:
- system_serverプロセスは、ActivityThreadメソッドに対してIPC要求を行います。リクエストをActivityThreadメソッドにルーティングするアプリケーションプロセスのbindApplication()。handleBindApplication()内MainThreadのアプリケーション。
- その直後に、system_serverは、アプリケーションの保留中のアクティビティ、サービス、およびBroadcastRecieverの起動をスケジュールします。
- ActivityThread。handleBindApplication()は、APKファイルとアプリケーションコンポーネントをロードします。
- 開発者は、ActivityThreadメソッドを実行する前に、プロセスにわずかに影響を与えることができます。handleBindApplication()なので、ここからアプリケーションのコールドスタート監視を開始する必要があります。
3番目のポイントを詳しく見て、アプリケーションのコンポーネントとリソースをロードするときに何がどのように発生するかを調べてみましょう。手順の順序は次のとおりです。
- AppComponentFactoryクラスをロードしてインスタンス化します。
- AppComponentFactoryを呼び出します。instanceiateClassLoader()。
- AppComponentFactoryを呼び出します。instanceiateApplication()を使用して、Applicationクラスをロードしてインスタンス化します。
- 宣言されたContentProviderごとに、優先順位に従って、AppComponentFactoryへの呼び出し。instanceiateProvider ()は、ContentProviderメソッドを呼び出した後、そのクラスをロードしてインスタンスを作成します。onCreate()。
- 最後に、アプリケーションを呼び出します。onCreate()。
エピローグ
私たちは非常に一般的な抽象レベルからコールドブーツの調査を開始しました。
これで、内部で何が起こっているかがわかりました。
まあ、それは長い投稿でした。しかし、それだけではありません!次の投稿では、Androidアプリケーションを起動するプロセスについて詳しく説明します。私たちと居て!