图解Android - Zygote, System Server 启动分析,附项目源码

复制代码

复制代码

std::string dvmStartup(int argc, const char* const argv[],

bool ignoreUnrecognized, JNIEnv* pEnv)

{

/*

* 检查输入并准备初始化参数

*/

int cc = processOptions(argc, argv, ignoreUnrecognized);

/* 真正初始化开始,初始化各个内部模块,并创建一系列线程*/

if (!dvmAllocTrackerStartup()) {

return “dvmAllocTrackerStartup failed”;

}

if (!dvmGcStartup()) {

return “dvmGcStartup failed”;

}

if (!dvmThreadStartup()) {

return “dvmThreadStartup failed”;

}

if (!dvmInlineNativeStartup()) {

return “dvmInlineNativeStartup”;

}

if (!dvmRegisterMapStartup()) {

return “dvmRegisterMapStartup failed”;

}

if (!dvmInstanceofStartup()) {

return “dvmInstanceofStartup failed”;

}

if (!dvmClassStartup()) {

return “dvmClassStartup failed”;

}

if (!dvmNativeStartup()) {

return “dvmNativeStartup failed”;

}

if (!dvmInternalNativeStartup()) {

return “dvmInternalNativeStartup failed”;

}

if (!dvmJniStartup()) {

return “dvmJniStartup failed”;

}

if (!dvmProfilingStartup()) {

return “dvmProfilingStartup failed”;

}

if (!dvmInitClass(gDvm.classJavaLangClass)) {

return “couldn’t initialized java.lang.Class”;

}

if (!registerSystemNatives(pEnv)) {

return “couldn’t register system natives”;

}

if (!dvmCreateStockExceptions()) {

return “dvmCreateStockExceptions failed”;

}

if (!dvmPrepMainThread()) {

return “dvmPrepMainThread failed”;

}

if (dvmReferenceTableEntries(&dvmThreadSelf()->internalLocalRefTable) != 0)

{

ALOGW(“Warning: tracked references remain post-initialization”);

dvmDumpReferenceTable(&dvmThreadSelf()->internalLocalRefTable, “MAIN”);

}

if (!dvmDebuggerStartup()) {

return “dvmDebuggerStartup failed”;

}

if (!dvmGcStartupClasses()) {

return “dvmGcStartupClasses failed”;

}

if (gDvm.zygote) {

if (!initZygote()) {

return “initZygote failed”;

}

} else {

if (!dvmInitAfterZygote()) {

return “dvmInitAfterZygote failed”;

}

}

return “”;

}

复制代码

Java虚拟机的启动有太多的细节在这里无法展开,这里我们只需要知道它做了以下一些事情:

1.  从property读取一系列启动参数。

2.  创建和初始化结构体全局对象(每个进程)gDVM,及对应与JavaVM和JNIEnv的内部结构体 JavaVMExt, JNIEnvExt.

3.  初始化java虚拟机,并创建虚拟机线程。“ps -t”,你可以发现每个Android应用都有以下几个线程

复制代码

u0_a46 1284 1281 714900 57896 20 0 0 0 fg ffffffff 00000000 S GC //垃圾回收

u0_a46 1285 1281 714900 57896 20 0 0 0 fg ffffffff 00000000 S Signal Catcher

u0_a46 1286 1281 714900 57896 20 0 0 0 fg ffffffff 00000000 S JDWP //Java 调试

u0_a46 1287 1281 714900 57896 20 0 0 0 fg ffffffff 00000000 S Compiler //JIT

u0_a46 1288 1281 714900 57896 20 0 0 0 fg ffffffff 00000000 S ReferenceQueueD

u0_a46 1289 1281 714900 57896 20 0 0 0 fg ffffffff 00000000 S FinalizerDaemon //Finalizer监护

u0_a46 1290 1281 714900 57896 20 0 0 0 fg ffffffff 00000000 S FinalizerWatchd //

复制代码

4. 注册系统的JNI,Java程序通过这些JNI接口来访问底层的资源。

loadJniLibrary(“javacore”);

loadJniLibrary(“nativehelper”);

5. 为Zygote的启动做最后的准备,包括设置SID/UID, 以及mount 文件系统。

6. 返回JavaVM 给Native代码,这样它就可以向上访问Java的接口。

除了系统的JNI接口(”javacore", “nativehelper”), android framework 还有大量的Native实现,Android将所有这些接口一次性的通过start_reg()来完成,

  • startReg()

复制代码

int AndroidRuntime::startReg(JNIEnv* env){

androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc); //创建JVM能访问的线程必须通过特定的接口。

env->PushLocalFrame(200);

if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {

env->PopLocalFrame(NULL);

return -1;

}

env->PopLocalFrame(NULL);

return 0;

}

复制代码

Android native层有两种Thread的创建方式:

复制代码

#threads.cpp

status_t Thread::run(const char* name, int32_t priority, size_t stack)

{

if (mCanCallJava) {

res = createThreadEtc(_threadLoop, this, name, priority, stack, &mThread);

} else {

res = androidCreateRawThreadEtc(_threadLoop,this, name, priority, stack, &mThread);

}

}

复制代码

它们的区别在是是否能够调用Java端函数,普通的thread就是对pthread_create的简单封装。

复制代码

int androidCreateRawThreadEtc(android_thread_func_t entryFunction,

void *userData,

const char* threadName,

int32_t threadPriority,

size_t threadStackSize,

android_thread_id_t *threadId)

{

int result = pthread_create(&thread, &attr,android_pthread_entry)entryFunction, userData);

}

复制代码

而能够访问Java端的thread需要跟JVM进行绑定,下面是具体的实现函数

复制代码

#AndroidRuntime.cpp

int AndroidRuntime::javaCreateThreadEtc(

android_thread_func_t entryFunction,

void* userData,

const char* threadName,

int32_t threadPriority,

size_t threadStackSize,

android_thread_id_t* threadId)

{

args[0] = (void*) entryFunction; //将entryFunc 暂存在args[0]

args[1] = userData;

args[2] = (void*) strdup(threadName);

result =AndroidCreateRawThreadEtc(AndroidRuntime::javaThreadShell, args, threadName, threadPriority, threadStackSize, threadId); //entryFunc变成javaThreadShell.

return result;

}

复制代码

复制代码

int AndroidRuntime::javaThreadShell(void* args) {

void* start = ((void**)args)[0];

void* userData = ((void **)args)[1];

char* name = (char*) ((void **)args)[2]; // we own this storage

JNIEnv* env;

/* 跟 VM 绑定 */

if (javaAttachThread(name, &env) != JNI_OK)

return -1;

/* 运行真正的’entryFunc’ */

result = (*(android_thread_func_t)start)(userData);

/* unhook us */

javaDetachThread();

return result;

}

复制代码

attachVM() 到底做什么事情? 篇幅有限无法展开,这里只需要知道这么几点:

    • 一个进程里有一个Java 虚拟机,Java 虚拟机内部有很多线程,如上面列到的 GC, FinalizeDaemon, 以及用户创建的线程等等.
  • 每个Java线程都维护一个JNIEnvExt对象,里面存放一个指向DVM 内部Thread对象的指针,也就是说,所有从native到Java端的调用,都会引用到这个对象。

  • 所有通过JVM创建的线程都会在VM内部记录在案,但是当前,我们还没有进入Java世界,本地创建的线程VM自然就不知道,因此我们需要通过attach来通知VM来创建相应的内部数据结构。

看看下面代码,你就知道,其实Attach()做的一件重要的事情就是 创建thread和JNIEnvExt.

复制代码

bool dvmAttachCurrentThread(const JavaVMAttachArgs* pArgs, bool isDaemon)

{

Thread* self = NULL;

self = allocThread(gDvm.stackSize);

self->jniEnv = dvmCreateJNIEnv(self);

gDvm.threadList->next = self;

threadObj = dvmAllocObject(gDvm.classJavaLangThread, ALLOC_DEFAULT);

vmThreadObj = dvmAllocObject(gDvm.classJavaLangVMThread, ALLOC_DEFAULT);

self->threadObj = threadObj;

}

复制代码

完了,就开始注册本地的JNI接口函数了- register_jni_procs(), 这个函数其实就是对一个全局数组gRegJni[] 进行遍历调用,这个数组展开可以得到以下的结果

static const RegJNIRec gRegJNI[] = {

{register_android_debug_JNITest},

{register_com_android_internal_os_RuntimeInit}.

}

每个 register_xxx是一个函数指针

int jniRegisterNativeMethods(

C_JNIEnv* env,

const char* className,

const JNINativeMethod* gMethods,

int numMethods);

RegisterNativeMethods 在VM内部到底发生了什么? 同样,这里只需要知道以下几点即可:

gRegJni[]

好了,经过了千辛万苦,Android的运行时环境都已经准备就绪了,让我们再回顾一下AndroidRuntime的初始化都做了哪些工作,

  1. 创建了Dalvik VM.

  2. 获取Native 访问Java的两个接口对象,JavaVM 和 JNIENV。

  3. 注册了一批 (见gRegJni[]) native接口给VM。

这些操作都是相对耗时的工作,如果每个进程都做同样的工作势必会影响到启动速度,这也是为什么我们需要通过Zygote来创建Android 应用,因为通过Linux fork 的 copy_on_write的机制,子进程可以将这些初始化好的内存空间直接映射到自己的进程空间里,不在需要做重复的工作,从而提高了应用启动的速度。

可以是,Android系统只需要基本的运行时环境就够了吗? 答案显然是No。AndriodRuntime 只是提供了语言层面的基础支持,在一个多任务,多用户的图形操作系统上快速的孵化和运行应用程序,我们需要更多。这就是Zygote,这就是为什么在图2中,ZygoteInit会比RuntimeInit做更多的事情。那接下来,让我们真正进入Zygote的世界。

3. ZygoteInit

==============

当VM准备就绪,就可以运行Java代码了,系统也将在此第一次进入Java世界,还记得app_main.cpp里面调到的 Runtime.start()的参数吗, 那就是我们要运行的Java类。Android支持两个类做为起点,一个是‘com.android.internal.os.ZygoteInit’, 另一个是’com.android.internal.os.RuntimeInit’。

此外Runtime_Init 类里还定义了一个ZygoteInit() 静态方法。它在Zygote 创建一个新的应用进程的时候被创建,它和RuntimeInit 类的main() 函数做了以下相同的事情:

  • redirectLogStreams(): 将System.out 和 System.err 输出重定向到Android 的Log系统(定义在 android.util.Log).

  • commonInit(): 初始化了一下系统属性,其中最重要的一点就是设置了一个未捕捉异常的handler,当代码有任何未知异常,就会执行它,调试过Android代码的同学经常看到的"*** FATAL EXCEPTION IN SYSTEM PROCESS" 打印就出自这里:

复制代码

Runtime_init.java

Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());

private static class UncaughtHandler implements Thread.UncaughtExceptionHandler {

public void uncaughtException(Thread t, Throwable e) {

try {

// Don’t re-enter – avoid infinite loops if crash-reporting crashes.

if (mCrashing) return;

mCrashing = true;

if (mApplicationObject == null) {

Slog.e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e);

} else {

Slog.e(TAG, "FATAL EXCEPTION: " + t.getName(), e);

}

ActivityManagerNative.getDefault().handleApplicationCrash(

mApplicationObject, new ApplicationErrorReport.CrashInfo(e));

} catch (Throwable t2) {

} finally {

Process.killProcess(Process.myPid());

System.exit(10);

}

}

}

复制代码

接下来,RuntimeInit::main() 和 RuntimeInit::ZygoteInit() 分别调用里nativeFinishInit() 和 nativeZygoteInit(), 由此开始分道扬镳,RuntimeInit 的nativeFinishInit() 最终会调用到 app_main.cpp 里的 onStarted() 函数,里面调用Java类的main() 函数,然后结束进程退出。

复制代码

virtual void onStarted()

{

sp proc = ProcessState::self();

proc->startThreadPool();

AndroidRuntime* ar = AndroidRuntime::getRuntime();

ar->callMain(mClassName, mClass, mArgC, mArgV);

IPCThreadState::self()->stopProcess();

}

复制代码

而 RuntimeInit::ZygoteInit() 则会调到 app_main.cpp 的 onZygoteInit()

复制代码

virtual void onZygoteInit()

{

// Re-enable tracing now that we’re no longer in Zygote.

atrace_set_tracing_enabled(true);

sp proc = ProcessState::self();

proc->startThreadPool();

}

复制代码

它仅仅是启动了一个ThreadPool, 剩下的工作则回到Java端由RuntimeInit::applicationInit()完成。

所以,我们不妨这样理解RuntimeInit::main(), RuntimeInit::ZygoteInit(), ZygoteInit::main()三者关系, RuntimeInit的main() 方法提供标准的Java程序运行方式,而RuntimeInit的ZygoteInit() 则是关门为Android应用启动的方法,它是在Zygote 创建一个新的应用进程的时候调用的,这部分代码实现在ZygoteInit 类里。除了上面描述的差别,ZygoteInit 类里还多做了如下几件事情,让我们一一详细解析。

  1. registerZygoteSocket();

  2. startSystemServer();

  3. runSelectLoopMode();

RegisterZygoteSocket()


其实做的事情很简单,就是初始化Server端(也就是Zygote)的socket。值得一提的是,这里用到的socket类型是LocalSocket, 它是Android对Linux 的 Local Socket的一个封装。Local Socket 是Linux提供的一种基于Socket的进程间通信方式,对Server端来讲,唯一的区别就是bind到一个本地的文件描述符(fd)而不是某个IP地址和端口号。Android里很多地方用到了Local Socket做进程间的通信,搜索一下init.rc, 你会看到很多这样的语句:

复制代码

socket adbd stream 660 system system

socket vold stream 0660 root mount

socket netd stream 0660 root system

socket dnsproxyd stream 0660 root inet

socket mdns stream 0660 root system

socket rild stream 660 root radio

socket rild-debug stream 660 radio system

socket zygote stream 660 root system

socket installd stream 600 system system

socket racoon stream 600 system system

socket mtpd stream 600 system system

socket dumpstate stream 0660 shell log

socket mdnsd stream 0660 mdnsr inet

复制代码

当init 解析到这样一条语句,它将做这么几件事:

  1. 调用 create_socket() (system/core/init/util.c), 创建一个Socket fd, 将这个fd 与某个文件(/dev/socket/xxx, xxx 就是上面列到的名字,比如,zygote) 绑定(bind), 根据init.rc 里面定义来设定相关的用户,组和权限。最后返回这个fd。

  2. 将socket 名字(带‘ANDROID_SOCKET_'前缀)(比如 zygote) 和 fd 注册到init 进程的环境变量里,这样所有的其他进程(所有进程都是init的子进程)都可以通过 getenv(name)获取到这个fd.

ZygoteInit 通过以下代码来完成Socket Server端的配置:

复制代码

private static final String ANDROID_SOCKET_ENV = “ANDROID_SOCKET_zygote”;

private static void registerZygoteSocket() {

String env = System.getenv(ANDROID_SOCKET_ENV);

fileDesc = Integer.parseInt(env);

sServerSocket = new LocalServerSocket(

createFileDescriptor(fileDesc));

}

复制代码

Server端创建完毕,接下来就可以相应客户端连接请求了。我们前面讲过,AndroidRuntime 一系列复杂的初始化工作可以通过fork来帮助子进程来简化这个过程,对了,Zygote创建Socket server 端就是用来响应这个fork的请求。那发起请求的是谁?Zygote fork的子进程又是谁?答案是ActivityManagerService 和 Android Application. 这个过程是怎样的? 答案就在Andriod System Server的启动过程中。

Preload


preload() 做了两件事情:

static void preload() {

preloadClasses();

preloadResources();

}

这是Android启动过程中最耗时间的两件事情。preloadClassess 将framework.jar里的preloaded-classes 定义的所有class load到内存里,preloaded-classes 编译Android后可以在framework/base下找到。而preloadResources 将系统的Resource(不是在用户apk里定义的resource)load到内存。

资源preload到Zygoted的进程地址空间,所有fork的子进程将共享这份空间而无需重新load, 这大大减少了应用程序的启动时间,但反过来增加了系统的启动时间。通过对preload 类和资源数目进行调整可以加快系统启动。

GC


复制代码

static void gc() {

final VMRuntime runtime = VMRuntime.getRuntime();

System.gc();

runtime.runFinalizationSync();

System.gc();

runtime.runFinalizationSync();

System.gc();

runtime.runFinalizationSync();

}

复制代码

为什么调了3次System.gc()和runFinalizationSync()? 这是因为gc()调用只是通知VM进行垃圾回收,是否回收,什么时候回收全又VM内部算法决定。GC的回收有一个复杂的状态机控制,通过多次调用,可以使得尽可能多的资源得到回收。gc()必须在fork之前完成(接下来的StartSystemServer就会有fork操作),这样将来被复制出来的子进程才能有尽可能少的垃圾内存没有释放。

Start SystemServer


想起init.rc 里面启动zygote的参数了吗, “–start-system-server”, System Server 是Zygote fork 的第一个Java 进程, 这个进程非常重要,因为他们有很多的系统线程,提供所有核心的系统服务,我们可以用 'ps -t |grep '来看看都有哪些线程,排除前面列出的几个Java 虚拟机线程,还有

复制代码

system 1176 1163 774376 51144 00000000 b76c4ab6 S SensorService

system 1177 1163 774376 51144 00000000 b76c49eb S er.ServerThread

system 1178 1163 774376 51144 00000000 b76c49eb S UI

system 1179 1163 774376 51144 00000000 b76c49eb S WindowManager

system 1180 1163 774376 51144 00000000 b76c49eb S ActivityManager

system 1182 1163 774376 51144 00000000 b76c4d69 S ProcessStats

system 1183 1163 774376 51144 00000000 b76c2bb6 S FileObserver

system 1184 1163 774376 51144 00000000 b76c49eb S PackageManager

system 1185 1163 774376 51144 00000000 b76c49eb S AccountManagerS

system 1187 1163 774376 51144 00000000 b76c49eb S PackageMonitor

system 1188 1163 774376 51144 00000000 b76c4ab6 S UEventObserver

system 1189 1163 774376 51144 00000000 b76c4d69 S BatteryUpdateTi

system 1190 1163 774376 51144 00000000 b76c49eb S PowerManagerSer

system 1191 1163 774376 51144 00000000 b76c2ff6 S AlarmManager

system 1192 1163 774376 51144 00000000 b76c4d69 S SoundPool

system 1193 1163 774376 51144 00000000 b76c4d69 S SoundPoolThread

system 1194 1163 774376 51144 00000000 b76c49eb S InputDispatcher

system 1195 1163 774376 51144 00000000 b76c49eb S InputReader

system 1196 1163 774376 51144 00000000 b76c49eb S BluetoothManage

system 1197 1163 774376 51144 00000000 b76c49eb S MountService

system 1198 1163 774376 51144 00000000 b76c4483 S VoldConnector

system 1199 1163 774376 51144 00000000 b76c49eb S CallbackHandler

system 1201 1163 774376 51144 00000000 b76c4483 S NetdConnector

system 1202 1163 774376 51144 00000000 b76c49eb S CallbackHandler

system 1203 1163 774376 51144 00000000 b76c49eb S NetworkStats

system 1204 1163 774376 51144 00000000 b76c49eb S NetworkPolicy

system 1205 1163 774376 51144 00000000 b76c49eb S WifiP2pService

system 1206 1163 774376 51144 00000000 b76c49eb S WifiStateMachin

system 1207 1163 774376 51144 00000000 b76c49eb S WifiService

system 1208 1163 774376 51144 00000000 b76c49eb S ConnectivitySer

system 1214 1163 774376 51144 00000000 b76c49eb S WifiManager

system 1215 1163 774376 51144 00000000 b76c49eb S Tethering

system 1216 1163 774376 51144 00000000 b76c49eb S CaptivePortalTr

system 1217 1163 774376 51144 00000000 b76c49eb S WifiWatchdogSta

system 1218 1163 774376 51144 00000000 b76c49eb S NsdService

system 1219 1163 774376 51144 00000000 b76c4483 S mDnsConnector

system 1220 1163 774376 51144 00000000 b76c49eb S CallbackHandler

system 1227 1163 774376 51144 00000000 b76c49eb S SyncHandlerThre

system 1228 1163 774376 51144 00000000 b76c49eb S AudioService

system 1229 1163 774376 51144 00000000 b76c49eb S backup

system 1233 1163 774376 51144 00000000 b76c49eb S AppWidgetServic

system 1240 1163 774376 51144 00000000 b76c4d69 S AsyncTask #1

system 1244 1163 774376 51144 00000000 b76c42a3 S Thread-64

system 1284 1163 774376 51144 00000000 b76c4d69 S AsyncTask #2

system 1316 1163 774376 51144 00000000 b76c2bb6 S UsbService host

system 1319 1163 774376 51144 00000000 b76c4d69 S watchdog

system 1330 1163 774376 51144 00000000 b76c49eb S LocationManager

system 1336 1163 774376 51144 00000000 b76c2ff6 S Binder_3

system 1348 1163 774376 51144 00000000 b76c49eb S CountryDetector

system 1354 1163 774376 51144 00000000 b76c49eb S NetworkTimeUpda

system 1360 1163 774376 51144 00000000 b76c2ff6 S Binder_4

system 1391 1163 774376 51144 00000000 b76c2ff6 S Binder_5

system 1395 1163 774376 51144 00000000 b76c2ff6 S Binder_6

system 1397 1163 774376 51144 00000000 b76c2ff6 S Binder_7

system 1516 1163 774376 51144 00000000 b76c4d69 S SoundPool

system 1517 1163 774376 51144 00000000 b76c4d69 S SoundPoolThread

system 1692 1163 774376 51144 00000000 b76c4d69 S AsyncTask #3

system 1694 1163 774376 51144 00000000 b76c4d69 S AsyncTask #4

system 1695 1163 774376 51144 00000000 b76c4d69 S AsyncTask #5

system 1791 1163 774376 51144 00000000 b76c4d69 S pool-1-thread-1

system 2758 1163 774376 51144 00000000 b76c4d69 S AudioTrack

system 2829 1163 774376 51144 00000000 b76c49eb S KeyguardWidgetP

复制代码

看到大名鼎鼎的WindowManager, ActivityManager了吗?对了,它们都是运行在system_server的进程里。还有很多“Binder-x"的线程,它们是各个Service为了响应应用程序远程调用请求而创建的。除此之外,还有很多内部的线程,比如 ”UI thread", “InputReader”, “InputDispatch” 等等,我们将在后续的文章里将这些模块具体分析。本文,我们只关心System Server是如何创建起来的。

4. System Server 启动流程

======================

这个过程代码很多,涉及到很多类,我们用一张时序图来描述这个过程。图中不同的颜色代表运行在不同的线程中。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1.  ZygoteInit fork 出一个新的进程,这个进程就是SystemServer进程。

  1. fork出来的子进程在handleSystemServerProcess 里开始初始化工作,初始化分两步,一部在native 完成,另外一部分(大部分)在Java端完成。 native端的工作在AppRuntime(AndroidRuntime的子类)::onZygoteInit()完成,做的一件事情就是启动了一个Thread, 这个Thread是SystemServer的主线程(最左边的粉色方块), 负责接收来至其他进程的Binder调用请求。代码如下

复制代码

void ProcessState::spawnPooledThread(bool isMain)

{

if (mThreadPoolStarted) {

String8 name = makeBinderThreadName(); //“Binder_1"

sp t = new PoolThread(isMain);

t->run(name.string());

}

}

virtual bool threadLoop() {

IPCThreadState::self()->joinThreadPool(mIsMain); //阻塞知道被Binder driver唤醒

return false;

}

复制代码

  1. nativeZygoteInit() 完成后, 接下来开始Java层的初始化,这个流程比较长,也比较复杂,我们分成很多步进行讲解。初始化的入口是SystemServer的main() 函数,这里又调用了Native的 Init1(). Init1实现在com_android_server_SystemServer.cpp,   最终调用到的函数是system_init(). system_init()的实现如下:

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
img

isMain)

{

if (mThreadPoolStarted) {

String8 name = makeBinderThreadName(); //“Binder_1"

sp t = new PoolThread(isMain);

t->run(name.string());

}

}

virtual bool threadLoop() {

IPCThreadState::self()->joinThreadPool(mIsMain); //阻塞知道被Binder driver唤醒

return false;

}

[外链图片转存中…(img-cHOJD9I0-1710935982326)]

  1. nativeZygoteInit() 完成后, 接下来开始Java层的初始化,这个流程比较长,也比较复杂,我们分成很多步进行讲解。初始化的入口是SystemServer的main() 函数,这里又调用了Native的 Init1(). Init1实现在com_android_server_SystemServer.cpp,   最终调用到的函数是system_init(). system_init()的实现如下:

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-L5uypc6g-1710935982326)]
[外链图片转存中…(img-Pfm8x55C-1710935982327)]
[外链图片转存中…(img-mXIsX7Jr-1710935982327)]
[外链图片转存中…(img-lOs8jBdR-1710935982327)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
[外链图片转存中…(img-LPWDfgc5-1710935982328)]

  • 12
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值