現在是:
廣告熱線:  |  設為首頁 | 加入收藏
登陸用戶名:
密碼:
您現在的位置北京足球指数 > 汽車 > >正文內容

爱波网足球指数:Android Framework啟動流程淺析

來源: 發布時間:2020-03-30 19:24:51 閱讀:-

北京足球指数 www.zwtnp.com.cn 作者:北斗星_And

前言

對于Android開發,干上幾年后,都要進階,或者直接轉行了。如果你還在干Android,想要進階 對Framework的了解是必不可少的過程,下面就開始進入今天的主題吧。

我們知道,對于任何程序語言而言,入口一般都是main函數。

那Android的程序入口在哪呢? 他的main函數是怎么啟動起來的呢?

可能熟悉Android的同學,知道一個應用程序的入口在ActivityThread中,那有個問題,ActivityThread中的main函數是何時被誰被調用的呢?

將從本文中找到以上答案,如果已經熟悉了此過程的同學,可以再溫習一下。

Android架構

Android 平臺的基礎是 Linux 內核。Android Runtime (ART/Dalvik) 依靠 Linux 內核來執行底層功能,例如線程和低層內存管理等。

而在Android Runtime之上就是我們經常接觸的Java API Framework層, 如下圖是Android的系統架構圖

今天的主題不是此架構圖的各個部分解釋,而是離應用層更近的Framework層啟動過程分析。

Android Framework概述

如果我們這里拋開Android架構圖,那狹義的Framewrok主要包含那些內容呢?

按我的理解,可以分為三個部分 服務端,客戶端,和依賴Linux底層能力的驅動部分。

服務端

主要是ActivityManagerService(AMS), WindowManagerService(WMS),PackageM anerService(PMS)

  • AMS 主要用于管理所有應用程序的Activity
  • WMS 管理各個窗口,隱藏,顯示等
  • PMS 用來管理跟蹤所有應用APK,安裝,解析,控制權限等.

還有用來處理觸摸消息的兩個類KeyInputQueue和InputDispatchThread,一個用來讀消息,一個用來分發消息.

客戶端

主要包括ActivityThread,Activity,DecodeView及父類View,PhoneWindow,ViewRootImpl及內部類W等

  • ActivityThread主要用來和AMS通訊的客戶端,Activity是我們編寫應用比較熟悉的類

依賴Linux底層能力的驅動

主要是SurfaceFlingger(SF)和Binder驅動

  • 每一個窗口都對應一個Surface,SF驅動的作用就是把每一個Surface顯示到同一個屏幕上
  • Binder 內核驅動的作用,就是為上面的服務端和客戶端(或者服務端和服務端之間),提供IPC通訊用的。

Zygote

系統中運行的第一個Dalvik虛擬機程序叫做zygote,該名稱的意義是“一個卵”,,因為接下來的所有 Dalvik虛擬機進程都是通過這個“卵” 孵化出來的。

zygote進程中包含兩個主要???,分別如下:

  • Socket服務端。該 Socket服務端用于接收啟動新的Dalvik進程的命令。
  • Framework共享類及共享資源。當zygote進程啟動后,會裝載一些共享的類及資源,其中共享類是在preload-classes文件中被定義,共享資源是在preload-resources中被定義。因為zygote進程用于孵化出其他Dalvik進程,因此,這些類和資源裝載后,新的Dalvik進程就不需要再裝載這些類和資源了,這也就是所謂的共享。

zygote進程對應的具體程序是app_rocess,該程序存在于system/bin目錄下,啟動該程序的指令是 在 init.rc中進行配置的。

Zygote 有?兩個優秀的特點

  • 每fork出的一個進程都是一個Dalvik虛擬機,獨立的進程可以防止一個程序的崩潰導致所有程序都崩潰,這種虛擬機類似Java虛擬機,對于程序員來說,可以直接使用Java開發應用
  • zygote進程預先會裝載共享類和共享資源,這些類及資源實際上就是SDK中定義的大部分類和資源。因此,當通過zygote孵化出新的進程后,新的APK進程只需要去裝載A PK 自身包含的類和資源即可,這就有效地解決了多個APK共享Framework資源的問題。

SystemServer

zygote孵化出的第一個Dalvik進程叫做SystemServer,SystemServer僅僅是該進程的別名,而該進程具體對應的程序依然是app_process,因為SystemServer是從app_process中孵化出來的。

SystemServer中創建了一個Socket客戶端,并有AmS負責管理該客戶端,之后所有的Dalvik進程都將通過該Socket客戶端間接被啟動。當需要啟動新的APK進程時,AmS中會通過該Socket客戶端向 zygote進程的Socket服務端發送一個啟動命令,然 后 zygote會孵化出新的進程。 上面提到的服務端,AMS,PMS,WMS等都是在SystemServer中啟動的.

Android Framework 源頭

操作系統的一般啟動流程,分為三個步驟

  1. 開機通電后,加載bootloader程序
  2. 操作系統內核初始化
  3. 執行第一個應用程序

Android 系統是基于Linux 內核Kernel,前面Linux bootloader這里不做介紹,直接介紹操作系統內核初始化,在這個時候,它會加載init.rc文件.

init.rc文件

在Android根目錄下面,可以直接找到init.rc

generic_x86:/ # ls
acct bin cache config data dev init init.rc init.usb.rc lost+found mnt oem product sdcard sys ueventd.rc
adb_keys bugreports charger d default.prop etc init.environ.rc init.usb.configfs.rc init.zygote32.rc metadata odm proc sbin storage system vendor

打開init.rc

generic_x86:/ # cat init.rc
# ..... 省略其他
# Now we can start zygote for devices with file based encryption
trigger zygote-start

# It is recommended to put unnecessary data/ initialization from post-fs-data
# to start-zygote in device's init.rc to unblock zygote start.
on zygote-start
# A/B update verifier that marks a successful boot.
exec_start update_verifier_nonencrypted
start netd
start zygote
start zygote_secondary

on property:vold.decrypt=trigger_restart_framework
stop surfaceflinger
# 啟動SF
start surfaceflinger

# ..... 省略其他 media(媒體) network(網絡)等啟動

也就是在 init.rc時,啟動Android 內核。

app_process

Android 內核也是main方法開始,他的main方法在 frameworks/base/cmds/app_process/app_main.cpp下

int main(int argc, char* const argv[])
{
...
//初始化AndroidRuntime
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));

bool zygote = false;
bool startSystemServer = false;
bool application = false;
String8 niceName;
String8 className;

// 根據參數具體判斷啟動那個服務
++i; // Skip unused "parent dir" argument.
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) {
zygote = true;
niceName = ZYGOTE_NICE_NAME;
} else if (strcmp(arg, "--start-system-server") == 0) {
startSystemServer = true;
} else if (strcmp(arg, "--application") == 0) {
application = true;
} else if (strncmp(arg, "--nice-name=", 12) == 0) {
niceName.setTo(arg + 12);
} else if (strncmp(arg, "--", 2) != 0) {
className.setTo(arg);
break;
} else {
--i;
break;
}
}
if (!className.isEmpty()) {
args.add(application ? String8("application") : String8("tool"));
runtime.setClassNameAndArgs(className, argc - i, argv + i);
}else{
....
//啟動SystemServer
if (startSystemServer) {
args.add(String8("start-system-server"));
}
}
....
if (zygote) {
//啟動Zygote
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
} else {
fprintf(stderr, "Error: no class name or --zygote supplied.\n");
app_usage();
LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
}
}

在這個Main方法中,先初始化了AppRuntime,他的父類是AndroidRuntime。然后我們看到了啟動了Java類ZygoteInit。

那c++代碼里怎么啟動Java類呢,我們繼續看 start方法

void AndroidRuntime::start(const char* className, const Vector& options, bool zygote)
{
...
//啟動Java虛擬機
if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
return;
}
...
//找到Java 里面的Main方法
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\n", className);
/* keep going */
} else {
//執行Main方法
env->CallStaticVoidMethod(startClass, startMeth, strArray);
}
....
}

可以看到最后先創建了Java虛擬機,調用了Java的main方法,是不是感覺有些熟悉感了。

ZygoteInit

上面介紹到,會啟動Java的ZygoteInit類,那他里面干了些什么呢? 我們來看一下關鍵代碼,還是從Main方法開始

//ZygoteInit.java
public static void main(String argv[]) {
ZygoteServer zygoteServer = new ZygoteServer();
ZygoteHooks.startZygoteNoThreadCreation();

//創建socket
zygoteServer.createZygoteSocket(socketName);
Zygote.createBlastulaSocket(blastulaSocketName);

if (!enableLazyPreload) {
bootTimingsTraceLog.traceBegin("ZygotePreload");
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
//預加載系統資源
preload(bootTimingsTraceLog);
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
bootTimingsTraceLog.traceEnd(); // ZygotePreload
} else {
Zygote.resetNicePriority();
}

//fork SystemServer進程
if (startSystemServer) {
Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
// child (system_server) process.
if (r != null) {
r.run();
return;
}
}

//等待Socket的接入
if (caller == null) {
Log.i(TAG, "Accepting command socket connections");
// The select loop returns early in the child process after a fork and
// loops forever in the zygote.
caller = zygoteServer.runSelectLoop(abiList);
}

注釋寫了大概Zygote 啟動里面的初始化內容

  • 創建Socket
  • 加載系統資源
  • 啟動SystemServer
  • runSelectLoop 等待socket接入,開始執行fork新的進程.

SystemServer

下面繼續看SystemServer 啟動的過程,從Main方法開始

//SystemServer.java
/**
* The main entry point from zygote.
*/
public static void main(String[] args) {
new SystemServer().run();
}

很簡單,創建一個自己的對象,并執行run方法,看一下run方法

private void run() {
...
if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
Slog.w(TAG, "System clock is before 1970; setting to 1970.");
SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
}

VMRuntime.getRuntime().clearGrowthLimit();
// The system server has to run all of the time, so it needs to be
// as efficient as possible with its memory usage.
VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);

android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_FOREGROUND);
android.os.Process.setCanSelfBackground(false);
Looper.prepareMainLooper();

// Create the system service manager.
mSystemServiceManager = new SystemServiceManager(mSystemContext);
mSystemServiceManager.setStartInfo(mRuntimeRestart,
mRuntimeStartElapsedTime, mRuntimeStartUptime);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);

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");
}

run方法里面主要進行了設置手機時間,設置虛擬機內存大小,創建消息循環Looper,創建SystemServiceManager等,最主要的是啟動了各類服務,我們接著看一下startBootstrapServices ,startCoreServices,startOtherServices方法

private void startBootstrapServices() {
Installer installer = mSystemServiceManager.startService(Installer.class);
mSystemServiceManager.startService(DeviceIdentifiersPolicyService.class);

mActivityManagerService = mSystemServiceManager.startService(
ActivityManagerService.Lifecycle.class).getService();
mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
mActivityManagerService.setInstaller(installer);
....
}

private void startCoreServices() {
...
mSystemServiceManager.startService(BatteryService.class);
...
}

private void startOtherServices() {
final Context context = mSystemContext;
VibratorService vibrator = null;
DynamicAndroidService dynamicAndroid = null;
IStorageManager storageManager = null;
NetworkManagementService networkManagement = null;
IpSecService ipSecService = null;
NetworkStatsService networkStats = null;
NetworkPolicyManagerService networkPolicy = null;
ConnectivityService connectivity = null;
NsdService serviceDiscovery= null;
WindowManagerService wm = null;
SerialService serial = null;
NetworkTimeUpdateService networkTimeUpdater = null;
InputManagerService inputManager = null;
TelephonyRegistry telephonyRegistry = null;
ConsumerIrService consumerIr = null;
MmsServiceBroker mmsService = null;
HardwarePropertiesManagerService hardwarePropertiesService = null;
....
}

在這些方法中啟動了,我們的核心服務,和常用服務。 代碼中也可以看到AMS,PMS,WMS等相關服務.

Launcher啟動介紹

一般服務啟動完成后,就會想繼調用systemReady()方法。 在SysytemServer startOtherServices中看到一個監聽回調

mActivityManagerService.systemReady(() -> {
try {
startSystemUi(context, windowManagerF);
} catch (Throwable e) {
reportWtf("starting System UI", e);
}
}
}

static final void startSystemUi(Context context, WindowManagerService windowManager) {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.android.systemui",
"com.android.systemui.SystemUIService"));
intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
//Slog.d(TAG, "Starting service: " + intent);
context.startServiceAsUser(intent, UserHandle.SYSTEM);
windowManager.onSystemUiStarted();
}

而Ams啟動完成后,顯示Launcher

//AMS.java
public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {
...
startHomeActivityLocked(currentUserId, "systemReady");
//
mStackSupervisor.resumeFocusedStackTopActivityLocked();
...

復制代碼

其實到這里大致流程就介紹完了,但是文章開始的ActivityThread的main方法是何時被調用的,還沒回答,這里不詳細展開,簡略回答一些.

ActivityThread的main方法如何被調用的?

AMS是管理Activity的啟動結束等,查看AMS代碼,當當前啟動的APP沒有創建進程時,會最終調用到ZygoteProcess,然后向 Zygote發送一個socket請求。

resumeTopActivityLocked -> startProcessLocked -> Process.start() -> ZygoteProcess.start() -> ZygoteProcess.startViaZygote() —> ZygoteProcess.zygoteSendArgsAndGetResult()

接下來,看一下大致代碼

//AMS.java
private final boolean startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, boolean disableHiddenApiChecks, String abiOverride) {
//這里entryPoint為ActivityThread
final String entryPoint = "android.app.ActivityThread";

return startProcessLocked(hostingType, hostingNameStr, entryPoint, app, uid, gids,
runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith,
startTime);
}
//ZygoteProcess.java
private Process.ProcessStartResult startViaZygote(final String processClass,... ){
ArrayList argsForZygote = new ArrayList();
argsForZygote.add("--runtime-args");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
argsForZygote.add("--runtime-flags=" + runtimeFlags);
argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
if (startChildZygote) {
argsForZygote.add("--start-child-zygote");
}
argsForZygote.add(processClass);
synchronized(mLock) {
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi),
useBlastulaPool,
argsForZygote);
}
}

//發起Socket請求,給Zygote
private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
ArrayList args,..){
blastulaSessionSocket = zygoteState.getBlastulaSessionSocket();

final BufferedWriter blastulaWriter = new BufferedWriter(
new OutputStreamWriter(blastulaSessionSocket.getOutputStream()),
Zygote.SOCKET_BUFFER_SIZE);
final DataInputStream blastulaReader =
new DataInputStream(blastulaSessionSocket.getInputStream());
blastulaWriter.write(msgStr);
blastulaWriter.flush();
...
}

最終 Zygote收到請求調用ZygoteInit中zygoteinit方法

//ZygoteInit.java
public static final Runnable zygoteInit(int targetSdkVersion, String[] argv,
ClassLoader classLoader) {
if (RuntimeInit.DEBUG) {
Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
}

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
RuntimeInit.redirectLogStreams();

RuntimeInit.commonInit();
ZygoteInit.nativeZygoteInit();
return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}

在 RuntimeInit中findStaticMain,最后在ZygoteInit中執行最終返回的這個Runnable,達到調用main方法的目的.

protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
ClassLoader classLoader) {
nativeSetExitWithoutCleanup(true);
VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
final Arguments args = new Arguments(argv);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
return findStaticMain(args.startClass, args.startArgs, classLoader);
}

protected static Runnable findStaticMain(String className, String[] argv,
ClassLoader classLoader) {
..
m = cl.getMethod("main", new Class[] { String[].class });
return new MethodAndArgsCaller(m, argv);
}

總結

如果你都看到這了,希望幫忙點個贊,謝謝啦。 因為本人水平有限,各路大佬如看到文中有錯誤,歡迎指出,在此表示感謝。


感謝大家能耐著性子,看完我啰哩啰嗦的文章

在這里我也分享一份自己收錄整理的Android學習PDF+架構視頻+面試文檔+源碼筆記,還有高級架構技術進階腦圖、Android開發面試專題資料,高級進階架構資料幫助大家學習提升進階,也節省大家在網上搜索資料的時間來學習,也可以分享給身邊好友一起學習

如果你有需要的話,可以點贊+評論+轉發,關注我,然后私信我【進階】我發給你

(正文已結束)

推薦閱讀:運動app推薦

免責聲明及提醒:此文內容為本網所轉載企業宣傳資訊,該相關信息僅為宣傳及傳遞更多信息之目的,不代表本網站觀點,文章真實性請瀏覽者慎重核實!任何投資加盟均有風險,提醒廣大民眾投資需謹慎!

網站簡介 - 聯系我們 - 營銷服務 - 老版地圖 - 版權聲明 - 北京足球指数
Copyright.2002-2019 北京足球指数 版權所有 本網拒絕一切非法行為 歡迎監督舉報 如有錯誤信息 歡迎糾正
{ganrao} 河南11选5中奖奖金 方道配资 美月安洁莉亚 女热大陆 nba季前赛录像回 互联网赚钱的方法 为什么手机麻将天天 天齐网p3试机号 上海十一选五基本走 秒速飞艇算法加减5公式 一本道潮喷qvod 上马麻里子喷奶在线观看 街机千炮捕鱼3.0版本 天津麻将游戏下载 四川熊猫麻将电脑版 广东潮汕麻将 体彩新11选5怎么玩