MTKシステム起動プロセス
ブートROM -> プリローダー ->lk -> カーネル -> ネイティブ -> Android
1. ブート ROM:システムの電源がオンになると、最初に実行されるのはチップ内に固定されたブート ROM です. その主な機能は次のとおりです:
a. ISRAM と EMMC の初期化
b. システムが完全に消去されると、USB も消去されますイメージをダウンロードするために USB ポートをシミュレートするように構成されています。
c. プリローダーを EMMC から ISRAM にロードして実行します。
2. プリローダー: 主に、DDR やその他のハードウェアなどのプラットフォームの基本機器の初期化を完了し、ハンドシェイク接続をダウンロードし、lk を DDR にロードし、lk にジャンプします。
3. Lk : MMU を開き、lk の実行を加速し、ログと課金関連を表示し、emmc のブート パーティションから boot.img を抽出して解凍し、ルート ファイル システムと Linux カーネルを Dram にロードし、カーネルとカーネル (start_kernel) をプルアップします。
4.カーネル: スケジューリング、メモリ管理、IO、割り込みなどの Linux オペレーティング システムの基本機能を初期化し、OTBO を識別し、init プロセスを作成し、モジュールの初期化を完了し、init メイン プログラムを実行します。
5.ネイティブ: 主要なシステムプロセス init、void、surfaceflingerなどを開始します。
init プロセスの役割は大きく 3 つの部分に分かれています。
1. バックアップ ノード、マウント、ファイル システムを作成します。
2. selinux セキュリティ ポリシーを有効にし、リソース ファイルを初期化し、属性サービスを開始します。
3. initrc ファイルを解析します。
6. Android: init が zygote プロセスをフォークし、zygote がすべての Android アプリケーション プロセスを作成します
基本的なフローチャートは次のとおりです。
プロパティをチェックして、初めて電源がオンになったかどうかを確認します。
persist.sys.device_provisionedブート ウィザードが完了したかどうか?
persist.sys.device_first_boot は初めての起動です
1.プリローダー(アッセンブリー/C)
1.1 機能
1. DDR やその他のハードウェアなどのプラットフォームの基本機器の初期化を完了します。
2. flashtoolUSB とのハンドシェイク、ダウンロード関連の検出と秒ブート検出。
3. lk を DRAM にロードする
4. Ik にジャンプ
1.2 エントリーコード
/MTXXXX_13_Master/vnd/vendor/mediatek/proprietary/bootable/bootloader/preloader/platform/mtXXXX/src/init/init.s
init.s: レジスタの初期化、bss セグメントのクリア、スタックの初期化、CPSR の設定、SVC モードへの切り替え、割り込みの無効化、上記の基本的な初期化の完了後にメインにジャンプ
setup_stk : /* セットアップスタック */ LDR r0, stack LDR r1, stacksz /* バッファオーバーフロー検出パターン */ LDR r2, =0xDEADBEFF STR r2, [r0] LDR r1, [r1] SUB r1, r1, #0x04 ADD r1 , r0, r1 MOV sp, r1 エントリ : LDR r0, =bldr_args_addr B main .globl ジャンプ
/MTXXXX_13_Master/vnd/vendor/mediatek/proprietary/bootable/bootloader/preloader/platform/mtXXXX/src/core/main.c
static void bldr_pre_process(void) { int isLocked = 0; int tempnoboot = 0; uint32_t ret = 0; ...... //初化timer/pll/gpio/uart/WDT/storage/PMIC platform_pre_init(); pal_log_info("\n%s ビルド時間: %s\n", MOD, BUILD_TIME); ...... /* ハードウェアの初期化 */ //初期化RTC/PM/batter/DDR/storage platform_init(); tempnoboot = oplus_bq28z610_temp(); no_boot_log_to_storage(tempnoboot); ...... } void main(u32 *arg) { struct bldr_command_handler ハンドラー; u32 ジャンプアドレス、ジャンプ引数; ...... //プラットフォーム環境を初期化する bldr_pre_process(); ...... BOOTING_TIME_PROFILING_LOG("before bldr_handshake"); //ダウンロードツールとのハンドシェイク接続 bldr_handshake(&handler); BOOTING_TIME_PROFILING_LOG("bldr_handshake"); //セキュリティ環境を初期化 trustzone_pre_init(); BOOTING_TIME_PROFILING_LOG("trustzone pre init" ); #endif #if !(CFG_BYPASS_LOAD_IMG_FORCE_ATF) /* ATF、lkをロードしない、JTAGでロード */ //LKイメージをDRAMにロード if (0 != bldr_load_images(&jump_addr)) { pal_log_err("%s Secondブートローダーのロードに失敗しました\n", MOD); #if !CFG_BYPASS_EMI goto error; #endif //SLT ...... //lk にジャンプします //プリローダーの残りの初期化を完了し、主にバッテリーを初期化します bldr_post_process(); bldr_jump64(jump_addr,jump_arg,sizeof(boot_arg_t)); …… }
bldr_pre_process はプラットフォーム環境を初期化します。
platform_pre_init: timer/pll/gpio/uart/WDT/storage/PMIC を初期化します。
platform_init: RTC/PM/batter/DDR/storage を初期化します。
bldr_handshake ダウンロードツールによるハンドシェイク接続
trustzone_pre_init セキュリティ環境の初期化
bldr_load_images は LK イメージを DRAM にロードします
bldr_post_process は、主にバッテリーの初期化など、プリローダーの残りの初期化を完了します。
bldr_jump64 lk にジャンプ
2.LK(アッセンブリー/C)
2.1 機能
1. MMU を開き、I/D キャッシュを有効にし、lk 実行を加速し、ロゴと充電関連を表示します。
·2. emmc のブート パーティションから bootimg を削除して解凍し、ルート ファイル システム (RAM ディスク) と Linux カーネルを DRAM にロードします。
3. dtb を解析し、DRAM の指定された領域に書き込みます。
4. MMU を閉じ、irg /fg、ID キャッシュを閉じ、カーネルをプルアップします (startkemel)。
2.2 エントリーコード:
/MTXXXX_13_Master/vnd/vendor/mediatek/proprietary/bootable/bootloader/lk/arch/arm/crt0.S
crt0.s: TZ シンボルを追加し、スタックの中止およびその他の初期化操作を実行します。メインにジャンプ
2.3キロメイン
/MTXXXX_13_Master/vnd/vendor/mediatek/proprietary/bootable/bootloader/lk/kernel/main.c
void kmain(void) { // ブートストラップ スレッドの作成後にワーク キュー、スレッド テーブルを初期化し、 thread_init_early()を初期化 ; //MMU を初期化し、キャッシュ Arch_early_init(); //プラットフォームの初期化。timmer、gpio、pmic など、lk の基本動作環境を確立します platform_early_init(); ...... #if (!ENABLE_NANDWRITE) // システムの初期化を完了するためのスレッドを作成します dprintf(SPEW, "creating bootstrap 完了スレッド\n "); //thread_bs2: 後続の初期化を完了し、アプリをロードするため にブートストラップ 2 スレッド を作成します 。
1. システムタスクに必要なスレッド、リンクリスト、関連キューを初期化します。
2. ハードウェアプラットフォームを初期化し、lk 基本動作環境を構築します。
3. タイマーなどを初期化します
。 4. 新しいスレッド bootstrap2 を作成し、実行します。現在のスレッドはアイドル状態になります
2.4 ブートストラップ2
static int bootstrap2(void *arg) { dprintf(SPEW, "bootstrap2() の先頭\n"); print_stack_of_current_thread(); アーチ_init(); // XXX はこれを別の場所に置きます #if WITH_LIB_BIO bio_init(); #endif #if WITH_LIB_FS fs_init(); #endif // LK メモリを mb から割り当て、カーネルにジャンプする前に解放します mboot_allocate_lk_scratch_from_mblock(); // 残りのプラットフォームを初期化します dprintf(SPEW, "初期化プラットフォーム\n"); platform_init(); // ターゲットを初期化します dprintf(SPEW, "ターゲットの初期化\n"); target_init(); dprintf(SPEW, "apps_init() の呼び出し\n"); apps_init(); 0を返します。 }
bootstrap2 スレッドのメイン関数: bio、fs、プラットフォーム、アプリの初期化
app_init はアプリを 1 つずつ初期化して実行します
mt_boot は後続の起動プロセスを実行し、最後にカーネル アプリをロードします
3. カーネル (アセンブリ/C)
3.1 機能
スケジューリング、メモリ管理、IO、割り込みなどの Linux オペレーティング システムの基本機能の初期化、DTBO の識別、init プロセスの作成、モジュールの初期化の完了、init メイン プログラムの実行
3.2 エントリーコード
/MTXXXX_13_Master/vnd/kernel/kernel-5.10/arch/arm64/kernel/head.S
MMU、CPU、ページテーブル、キャッシュなどが初期化され、start_kernelにジャンプします
3.3 スタートカーネル
/MTXXXX_13_Master/vnd/kernel/kernel-5.10/init/main.c
一連の基本的な初期化が完了すると、rest_init->kernel_init によって init プロセスが作成され、/sbin/etc/bin で init 実行可能ファイルが順番に検索されます。
3.4 DTBO 識別プロセス
start_kernel -> setup_arch -> un flatten_device_tree -> un flatten_device_tree -> un flatten_dt_nodes
un flatten_dt_nodes 内の各ノードを走査し、各ノードで Populate_node を呼び出し、各ノードの情報を device_node 構造体に変換します。
un flatten_dt_alloc は device_node 構造を作成します
Populate_propertites はプロパティ構造体を作成し、それに device_node 属性を追加します。
3.5 プラットフォームバスの初期化プロセス
do_basic_setup->driver_init
devices_init: 2 つのデバイス ルート ノード /sys/devices /sys/dev を作成し、/sys/dev/block /sys/dev/char を作成します。
bus_init: /sys/bus バス ルート ノードを作成します。
platform_bus_init
platform_bus デバイスを登録し、/sys/devices/plaform ノードを作成します。このノードはすべてのプラットフォーム デバイスのルート ノードです。
platform_bus_type バス タイプを登録し、/sys/bus/platfrom ノードを作成します。このノードは、すべてのプラットフォーム デバイスのバス タイプのルート ノードです。
3.6 デバイス ツリーからプラットフォーム デバイスにデバイスを追加します。
エントリー機能
/MTXXXX_13_Master/vnd/kernel-5.10/drivers/of/platform.c
この関数を、arch_initcall_sync を通じて設定されたカーネル初期化関数に追加します。
of_platform_default_populate->of_plattform_populate->platform_bus_create 呼び出しプロセスを通じて、プラットフォーム バスに参加する適切なデバイスを選択します。
最後に、of_plaform_device_create_pdata->of_device_add を使用してデバイスをプラットフォーム デバイスに追加します。
4. ネイティブ (C/C++)
4.1 機能
システムキープロセスinit、void、surfaceflingerを開始します。
4.2 初期エントリコード
/MTXXXX_13_Master/sys/system/core/init/main.cpp
int main(int argc, char** argv) { ...... if (argc > 1) { if (!strcmp(argv[1], "サブコンテキスト")) { android::base::InitLogging(argv) 、&android::base::KernelLogger); const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap(); return SubcontextMain(argc, argv, &function_map); if (!strcmp(argv[1], "selinux_setup")) { return SetupSelinux(argv); if (!strcmp(argv[1], "first_stage " )) { return SecondStageMain(argc, argv); // init第一阶段 return FirstStageMain(argc, argv) ; }
4.3 init FirstStageMain の最初のステージ
/MTXXXX_13_Master/sys/system/core/init/first_stage_main.cpp
1. システムディレクトリを作成し、対応するパーティションをマウントします。
2. 初期化フェーズのログをカーネル ログに初期化します。
3. SElinux セキュリティ ポリシーをロードする
// system/core/init/first_stage_init.cpp int FirstStageMain(int argc, char** argv){ if(REBOOT_BOOTLOADER_ON_PANIC){ InstallRebootSignalHandlers(); } boot_clock::time_point start_time = boot_clock::now(); std::vector<std::pair<std::string, int>> errors; #define CHECKCALL(x) \ if (x != 0) errors.emplace_back(#x " failed", errno); umask(0); // 创建于挂载相关文件系统 CHECKCALL(clearenv()); CHECKCALL(setenv("PATH", _PATH_DEFPATH, 1)); // Get the basic filesystem setup we need put together in the initramdisk // on / and then we'll let the rc file figure out the rest. CHECKCALL(mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755")); CHECKCALL(mkdir("/dev/pts", 0755)); CHECKCALL(mkdir("/dev/socket", 0755)); CHECKCALL(mount("devpts", "/dev/pts", "devpts", 0, NULL)); #define MAKE_STR(x) __STRING(x) CHECKCALL(mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC))); #undef MAKE_STR // 原始命令不可暴露给没有特权的进程 CHECKCALL(chmod("/proc/cmdline", 0440)); gid_t groups[] = {AID_READPROC}; CHECKCALL(setgroups(arraysize(groups), groups)); CHECKCALL(mount("sysfs", "/sys", "sysfs", 0, NULL)); CHECKCALL(mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL)); // tmpfs已经挂载在/dev下,并且已生成/dev/kmsg,故可以与外界通信 // 初始化日志系统 InitKernelLogging(argv); // 进入下一步 const char* path = "/system/bin/init"; const char* args[] = {path, "selinux_setup", nullptr}; execv(path, const_cast<char**>(args)); // 只有在错误发生的情况下execv()函数才会返回 PLOG(FATAL) << "execv(\"" << path << "\") failed"; return 1; }
4.4 init SecondStageMain の第 2 ステージ
/MTXXXX_13_Master/sys/system/core/init/init.cpp
1. プロパティ システムを初期化し、指定された場所からプロパティ設定を読み取ります: -->Propertyinit()
2. apex/パーティションをマウント --> MountExtraFilesystem s ()
3. SElinux の第 2 段階 -->SelinuxRestoreContext():
4. プロパティ サービスを開始して、プロパティを追加、変更、取得します -->StartPropertyService ()
5. ファイルコンテキストの初期化 -->InitializeSubcontext()
6. 後続の実行のために am と sm をコレクションに順番に追加します --> LoadBootscripts (am, sm)
7. init.rcを実行する
// system/core/init/init.cpp int SecondStageMain(int argc, char** argv) { SetStdioToDevNull(argv); // 初始化本阶段内核日志 InitKernelLogging(argv); // 系统属性初始化 property_init(); // 建立 Epoll Epoll epoll; // 注册信号处理 InstallSignalFdHandler(&epoll); // 加载默认的系统属性 property_load_boot_defaults(load_debug_prop); // 启动属性服务 StartPropertyService(&epoll); subcontexts = InitializeSubcontexts(); //加载系统启动脚本"/init.rc" ActionManager& am = ActionManager::GetInstance(); ServiceList& sm = ServiceList::GetInstance(); LoadBootScripts(am, sm); // 触发early-init,,init,late-init流程 am.QueueEventTrigger("early-init"); am.QueueEventTrigger("init"); am.QueueBuiltinAction(InitBinder, "InitBinder"); am.QueueEventTrigger("late-init"); //解析启动脚本 while (true) { // 执行 Action am.ExecuteOneCommand(); // 还有就是重启死掉的子进程 auto next_process_action_time = HandleProcessActions(); } }
4.5 initrc 構文: Android 起動スクリプト固有の構文
四要素:Action、Command、Service、Option
4.5.1 アクション
コマンドの集合とトリガーで構成されます トリガー文はonで始まります on以降の条件で実行のタイミングが決まります いくつかの条件がトリガーの条件を満たした場合、アクションに定義したコマンドがコマンドに追加されます実行するキュー コマンドの末尾 (この一連のコマンドがすでにキューにある場合、再度追加されることはありません)。
一般的に使用されるトリガーは次のとおりです。
- Early-init は初期化の初期段階でトリガーされます
- late-init は後期初期化フェーズ中にトリガーされます
- init は初期化フェーズ中にトリガーされます
- late-init は後期初期化フェーズ中にトリガーされます
- boot/charger システムの起動/充電時にトリガーされます。
- property:<key>=<value> プロパティ値が次のような条件を満たす場合にトリガーされます。 on property:ro.debuggable=1
- mtd パーティションをマウントするときの fs トリガー
- ブートは、基本的なネットワークの初期化、メモリ管理などをトリガーします。
- post-fs は、システム ディレクトリのアクセス権限が変更されたときにトリガーされます。
- device-added-<path> デバイス ノードが追加されたときにトリガーされます
- device-removed-<path> デバイス ノードが削除されるとトリガーされます。
- service-exited-<name> は、特定のサービス (サービス) が終了するとトリガーされます。
on Earty-init はファイル ディレクトリを作成し、プロセス (nice、fd) に制限を設定し、ueventd を開始します。
init では、ファイル ディレクトリが作成され、ユーザー グループが各ノードに割り当てられ、logd、Imkd、servicemanager などのサービスが開始されます。
遅い初期化で
early-fs:start voId
fs 上: マウントファイルディレクトリ
on postfs: ファイルシステム rootfs をマウントします (再マウント)。
on late-fs: (keyasten) などの暗号化とロック解除の前に必要な HAL を保存します。
post-fs-data: データのマウント、apexd の開始、最初のユーザーの初期化、fuse の開始、
zygote-start: 暗号化ステータスとともに zygote.netdzygote-secondnary を開始する必要があります
起動時: hal を開始、コアサービスを開始
4.5.2 コマンド
よく使用されるコマンド:
1).import <filename> 导入init.XX.rc、xxx.conf などの文件 init 設定ファイルを解析し、現在の設定を拡張します。 2).chmod <octal-mode> <path> ファイルのアクセス権限を変更します。 3).chown <所有者> <グループ> <パス> ファイルの所有者とグループを変更します。 4).chdir <ディレクトリ> 作業ディレクトリを変更します。 5).chroot <directory> 改变进程根目录 6).insmod <path> 加下XX.ko驱动模块 7).start <service> サービスがまだ実行されていない場合は、実行を開始します。 8).stop <service> サービスが現在実行中の場合は、実行を停止します。 9).class_start <サービスクラス> exec <path> [ <argument> ]* <path> で指定されたプログラムを実行します。実行パラメータを持つことができます。 exec は呼び出しプロセス内で実行可能ファイルを実行し、実行が完了するまで現在のプロセスをブロックします。 14).trigger <event> アクションをトリガーします。 別のアクションからのアクションをキューに入れるために使用されます。 例:trigger post-fs-data 15).exec <path> [ <argument> ]* これらの組み込みコマンドのような exec コマンドの使用は避けるのが最善です。そうしないと、ブロッキングやスタックが発生しやすくなります (タイムアウトが発生する可能性があります)。 ?) 16) .ifup <interface> は、 特定のネットワーク インターフェイスを開始し、それを up 状態にし、netcfg を通じて表示できます。ifup eth0 は netcfg eth0 up と同等であり、同じ機能を持ちます。 17).hostname <name> デバイスのホスト名を設定します。通常、デフォルト設定は localhost です。端末で hostname new_name を使用して変更できます 18).domainname <name> ネットワーク ドメイン名を設定します localdomain 19).mount <type> <device> < dir> [ <mountoption> ]* デバイスを dir ディレクトリにマウントします。ファイル システム タイプは type です。 <mountoption> には、「ro」、「rw」、「remount」、「noatime」、「nosuid」などが含まれます。[linux](http://lib.csdn. 。21) setrlimit <resource> <cur> <max>このサービスプロセスのリソース上限を設定します。(使用例??) 22).symlink <target> <path> パスは ---》ターゲットにリンクします; シンボリック リンクを作成します 23).sysclktz <mins_west_of_gmt> システムのタイム ゾーンを設定します (システム クロックが GMT の場合は 0) 24).wait <path > [ < timeout> ] 指定されたファイル パスが存在するかどうかを調べるためにポーリングします。見つかった場合、またはタイムアウトした場合は、戻ります。デフォルトのタイムアウトは 5 秒です。(使用例???) 25).write <path> <string> [ <string> ]* ファイルを開き、write コマンドを使用して 1 つ以上の文字列を書き込みます
4.5.3 サービス
サービスは、service で開始され、init プロセスによって開始されるプログラムであり、通常は別の init サブプロセスで実行されるため、サービスを開始する前に、対応する実行可能ファイルが存在するかどうかを確認する必要があります。initで生成される子プロセスはrcファイルに定義されており、各サービスは起動時にforkにより子プロセスを生成します。サービスの形式は次のとおりです。
サービスとは、システムの初期化時に開始する必要があるプログラム、またはシステムの終了時に自動的に再起動する必要があるプログラムを指します。
その文法構造は次のとおりです。
1. サービス <名前> <パス名> [ <引数> ]* 2. <オプション > 3. <オプション> 4. ...
パス名: 実行可能権限が必要です。サービス名: すべての rc ファイルで繰り返すことはできません。
4.5.4 オプション オプション
- class <class_name> は
、サービスがクラス class_name に属していることを示します。デフォルトのサービスは「デフォルト」クラスに属します。同じクラスの下にあるサービスは、一緒に開始または停止できます。 - Disabled は
、サービスが配置されているクラスが開始されるときに、サービスが自動的に開始されないことを意味します。
開始するには、startserver_name または property_set("ctl.start",server_name); を使用する必要があります。 - Oneshot は
サービスの終了後に再起動されません。このオプションが追加されていない場合、デフォルトでサービスは終了後に再起動されます。 - user <username> は、
サービスを実行する前にサービスのユーザー名を宣言します。デフォルト値は root ユーザーです。 - group <グループ名> [ <グループ名> ]*
サービスを実行する前に、サービスが所属するグループ名を宣言します (一度に複数のグループに所属することを宣言できます)。
複数のグループを宣言する場合、最初のグループ名を除いて、残りはサービスの補助的なグループ名になります (インターフェイス setgroups() を呼び出します)。 - onrestart + command
サービスが再起動されると、onrestart 以降のコマンドが実行されます (
例: onrestart restart media) media という名前のサービスが再起動されます。 - setenv <name> <value>
環境変数名の値を現在のサービス プロセスの value に設定します。
注: setenv で定義された環境変数は、このプロセス内でのみ有効です。プロセスを終了するか、対応するプログラム実行ウィンドウを閉じると、環境変数は無効になります。) この環境変数の値は、getenv(" name") プログラム内のインターフェース
setenv
エクスポートとの違い:
setenv csh、このプロセスで有効になります。終了後、変数は無効になります。
エクスポート bash、グローバルに有効になり、常に存在します。
形式:
export key=value
setenv key価値 - Critical は
クリティカルなサービスを宣言します。サービスが 4 分以内に 4 回終了すると、デバイスはリカバリ モードに入ります。 - ソケット <name> <type> <perm> [ <user> [ <group> ] ]
/dev/socket/<name> という名前の UNIX ドメイン ソケットを作成し、そのハンドル fd をこのサービス プロセス
<type> に渡します。「dgram」である必要があります。 "、"stream"、または "seqpacket"。ユーザーとグループのデフォルトは 0、つまり root です。 - seclablel はサービスを実行する前にセキュリティ コンテキストを変更します
5. アンドロイド(JAVA)
init は zygote プロセスをフォークし、zygote はすべての Android アプリケーション プロセスを作成します。
5.1 ZygoteInit
フレームワーク/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) { //1、创建ZygoteServer ZygoteServer zygoteServer = new ZygoteServer(); ......... 試してください { .... boolean startSystemServer = false; 文字列ソケット名 = "ザイゴット"; 文字列 abiList = null; ブール値enableLazyPreload = false; // 2、解析app_main.cpp のパラメータ for (int i = 1; i < argv.length; i++) { if ("start-system-server".equals(argv[i])) { startSystemServer = true ; else if (argv[i].startsWith(ABI_LIST_ARG)) { else if ("--enable-lazy-preload".equals(argv[i])) { EnableLazyPreload = true; zygoteServer.registerServerSocket(socketName); abiList = argv[i].substring(ABI_LIST_ARG.length()); else if (argv[i].startsWith(SOCKET_NAME_ARG)) { ソケット名 = argv[i].substring(SOCKET_NAME_ARG.length()); } else { throw new RuntimeException("不明なコマンドライン引数: " + argv[I]); if (abiList == null) { throw new RuntimeException("ABI リストが提供されていませ ん 。"); } //3、サーバー端末のソケットを構築 // そのような場合は、最初のフォークの前にプリロードします。 // 一部の構成では、リソースとクラスを積極的にプリロードすることを避けます。 if (!enableLazyPreload) { bootTimingsTraceLog.traceBegin("ZygotePreload"); EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START, SystemClock.uptimeMillis()); //4、ダウンロード処理のソースとクラス preload(bootTimingsTraceLog); EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, SystemClock.uptimeMillis()); bootTimingsTraceLog.traceEnd(); // ZygotePreload } else { Zygote.resetNicePriority(); } …… if (startSystemServer) { //5. SystemServer プロセスを開始します startSystemServer(abiList,ソケット名, zygoteServer); } Log.i(TAG, "コマンドソケット接続の受け入れ"); //6. クライアントからのメッセージをリッスンするための無限ループを開始します zygoteServer.runSelectLoop(abiList); //7. Close SystemServer Socket zygoteServer.closeServerSocket(); } catch (Zygote.MethodAndArgsCaller caller) { //8. ここで、この例外をキャッチし、MethodAndArgsCaller の run メソッドを呼び出します。 caller.run(); } catch (Throwable ex) { Log.e(TAG, "システム zygote が例外で停止しました", ex); zygoteServer.closeServerSocket(); throw ex; } }
5.2 受精卵のプロセス
①
1. Java仮想マシンを作成する
2. Java仮想マシンのネイティブメソッドを登録する
3. com.android.initernal.os.ZygoteInit の Java クラスの main メソッドを呼び出します。
4. Zygotelnit クラスをロードする
5.ザイゴットソッカーを登録する
6. プリロードクラスをロードする
7. プリロードリソースファイルをロードします
8. Zygote::forkSystemServer を呼び出し、新しいプロセスをフォークし、SystemServer の main メソッドを呼び出し、SystemServer プロセスを開始します。
②
1. init.zygote.rc のパラメータを解析し、AppRuntime を作成し、AppRuntime.start() メソッドを呼び出します。
2. AndroidRuntime の startVM() メソッドを呼び出して仮想マシンを作成し、startReg() を呼び出して JNI 関数を登録します
3. JNI を通じて Zygotelnitmain0) を呼び出し、初めて Java の世界に入ります
4.registerZygoteSocket() はソケット チャネルを確立し、zygote はクライアントの要求に応答する通信サーバーとして機能します。
5.preload() は、アプリの起動効率を向上させるために、共通クラス、ドローアブルおよびカラー リソース、openGL、共有ライブラリ、および WebView をプリロードします。
6. startSystemServer() を通じて、fork の強力なヘルパー system_server プロセス
7. runSelectLoop0() を呼び出し、新しいプロセスの作成要求を受信すると、すぐに起動して対応する作業を実行します。
③受精卵機能
システムサーバーの作成
アプリケーションプロセスをインキュベートする
5.3 関連するプロセス
init プロセス: Nessot が init プロセスを作成すると、init が実行されます。init プロセスの最終段階では、init.rc スクリプトが解析され、さまざまなプロセス サービスが開始されます。最も重要なものは、zygote プロセスの開始です。
zygote プロセス: zygote プロセスは、システムによって開始され、フレームワーク層で実行される最初の Java プロセスであり、主にシステムサーバーを含むすべてのアプリケーションの作成と仮想マシンのオペレーティング環境の作成を担当します。
systemserver プロセス: Binder スレッド プールと SystemServiceNanager を開始します。
systemServiceManager は主にシステムサービスの作成、起動、ライフサイクル管理を担当し、さまざまなシステムサービスを起動します。(Android のコア サービスである AMS は、SystemServer プロセスで開始されます)
ランチャー プロセス: ランチャー プロセスは Android システム起動の最後のステップであり、主にインストールされているアプリケーションをインターフェイスに表示する役割を果たします。
5.4 SystemServer 起動関連のコードは次のとおりです。
// frameworks/base/services/java/com/android/server/SystemServer.java
public static void main(String[] args) {
new SystemServer().run();
}
private void run() {
try {
Looper.prepareMainLooper();
// 初始化本地服务
System.loadLibrary("android_servers");
// 初始化系统上下文
createSystemContext();
// 创建SystemServiceManager
mSystemServiceManager = new SystemServiceManager(mSystemContext);
mSystemServiceManager.setStartInfo(mRuntimeRestart,
mRuntimeStartElapsedTime, mRuntimeStartUptime);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
// 构建线程池,以便并行执行一些初始化任务
SystemServerInitThreadPool.get();
} finally {
traceEnd(); // InitBeforeStartServices
}
// 开启服务
try {
traceBeginAndSlog("StartServices");
startBootstrapServices();// 启动引导服务
startCoreServices();// 启动核心服务
startOtherServices();// 启动其他服务
SystemServerInitThreadPool.shutdown();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
} finally {
traceEnd();
}
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
ご覧のとおり、SystemServer の最も重要な仕事は、3 つのメソッドを実行してすべてのサービスを開始することです。
- startBootstrapServices();
- startCoreServices();
- startOtherServices();
ブート サービス、コア サービス、その他のサービスにそれぞれ対応します。
- ブートストラップ サービス: このようなサービスには、Installer、ActivityManagerService
PowerManagerService、DisplayManagerService、PackageManagerService、UserManagerService などが含まれます。 - コア サービス: このようなサービスには、LightsService、BatteryService、UsageStatsServtce、
WebViewUpdateService などが含まれます。 - その他のサービス: その他すべてのサービス
startOtherServices() メソッドで SystemUI が起動され、SystemServer が AMS にシステムの準備ができたことを通知し、この時点で AMS はデスクトップを起動し、BOOT_COMPLETED ブロードキャストを送信します。この時点で、システム レベルの起動プロセスは終了します。
5.5 Google公式のブート最適化情報
https://source.android.com/devices/tech/perf/boot-times