Ini akan menjadi serangkaian posting tentang proses peluncuran dingin aplikasi Android, dari saat Anda mengklik ikon hingga pembuatan proses aplikasi.
Skema umum
Membuka "jendela" ...
Sebelum memulai proses aplikasi baru, system_server membuat jendela mulai menggunakan metode 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);
}
}
Jendela mulai adalah apa yang akan dilihat pengguna saat aplikasi berjalan. Jendela akan ditampilkan hingga Aktivitas diluncurkan dan bingkai pertama digambar. Begitulah, sampai awal yang dingin selesai . Pengguna dapat melihat jendela ini untuk waktu yang lama, jadi cobalah membuatnya menyenangkan.
Konten jendela peluncuran diambil dari sumber daya yang dapat digambar windowSplashscreenContent dan windowBackground dari Aktivitas yang diluncurkan . Contoh sepele dari jendela seperti itu:
Jika pengguna memulihkan Aktivitas dari mode layar Terkini , sambil mengklik ikon aplikasi, lalu system_servermemanggil metode TaskSnapshotSurface .create () untuk membuat jendela mulai dari screenshot yang sudah diambil.
Setelah jendela mulai ditampilkan kepada pengguna, system_server siap untuk memulai proses aplikasi dan memanggil metode 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);
}
}
Dalam kode tersebut, Anda dapat melihat bahwa ZygoteProcess. zygoteSendArgsAndGetResult () mengirimkan argumen startup melalui soket ke proses Zygote .
"Pemisahan" Zygote
Menurut dokumentasi Android tentang manajemen memori, berikut ini:
Setiap proses aplikasi dimulai dengan forking (pemisahan) dari proses Zygote yang ada ...Saya menulis secara singkat tentang ini di artikel sebelumnya tentang peluncuran Android . Sekarang mari kita lihat lebih dalam proses yang sedang berlangsung.
Saat sistem melakukan boot, proses Zygote dimulai dan menjalankan metode 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();
}
}
Seperti yang Anda lihat metode ZygoteInit. main () melakukan 2 hal penting:
- Memuat semua library sistem dan resource yang diperlukan dari framework Android. Pramuat seperti itu tidak hanya menghemat memori, tetapi juga menghemat waktu peluncuran aplikasi.
- Selanjutnya, ia menjalankan metode ZygoteServer.runSelectLoop (), yang pada gilirannya memulai soket dan mulai mendengarkan panggilan ke soket ini.
Ketika perintah untuk memotong proses tiba di soket, ZygoteConnection.
processOneCommand () memproses argumen menggunakan metode ZygoteArguments. parseArgs () dan menjalankan 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;
}
}
Catatan: Dimulai dengan Android 10, terdapat fitur pengoptimalan yang disebut Proses Aplikasi Tidak Khusus , yang memiliki kumpulan proses Zygote yang tidak terspesialisasi untuk meluncurkan aplikasi lebih cepat.
Aplikasi telah dimulai!
Setelah bercabang, proses anak menjalankan metode RuntimeInit. commonInit () , yang menyetel UncaughtExceptionHandler default . Selanjutnya, proses memulai metode ActivityThread. main () :
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);
}
}
}
Dua hal menarik terjadi di sini:
- ActivityThread.main() (Thread) Looper.loop(), Looper-. ( MainThread- aka UiThread) () . Looper , MessageQueue.
- , ActivityThread.attach() IPC- ActivityManagerService.attachApplication() system_server-, , MainThread .
Dalam proses system_server , ActivityManagerService. attachApplication () memanggil ActivityManagerService. attachApplicationLocked () , yang menyelesaikan konfigurasi aplikasi yang sedang diluncurkan:
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;
}
}
Beberapa poin penting:
- Proses system_server membuat permintaan IPC ke metode ActivityThread. bindApplication () dalam proses aplikasi kita, yang mengarahkan permintaan ke metode ActivityThread. handleBindApplication () di aplikasi MainThread .
- Segera setelah itu, system_server menjadwalkan peluncuran Aktivitas Tertunda, Layanan, dan BroadcastReciever dari aplikasi kita.
- ActivityThread. handleBindApplication () memuat file APK dan komponen aplikasi.
- Pengembang memiliki kemampuan untuk sedikit memengaruhi proses sebelum menjalankan metode ActivityThread. handleBindApplication () , jadi di sinilah pemantauan cold start aplikasi harus dimulai.
Mari kita lihat lebih dekat poin ketiga dan cari tahu apa dan bagaimana yang terjadi saat memuat komponen dan sumber daya aplikasi. Urutan langkah-langkahnya adalah sebagai berikut:
- Memuat dan membuat instance kelas AppComponentFactory .
- Memanggil AppComponentFactory. instantiateClassLoader () .
- Memanggil AppComponentFactory. instantiateApplication () untuk memuat dan membuat instance kelas Aplikasi .
- Untuk setiap ContentProvider yang dideklarasikan , dalam urutan prioritas, panggilan ke AppComponentFactory. instantiateProvider () untuk memuat kelasnya dan membuat instance, setelah memanggil metode ContentProvider. onCreate () .
- Terakhir, memanggil Aplikasi. onCreate () .
Epilog
Kami mulai menjelajahi cold boot dari level abstrak yang sangat umum:
Sekarang kami tahu apa yang terjadi di balik terpal:
Nah, itu posting yang panjang. Tapi itu belum semuanya! Di postingan berikutnya, kami akan melanjutkan mendalami proses peluncuran aplikasi Android. Tetaplah bersama kami!