从zygote到onCreate应用启动过程分析

2023-11-18

在之前的文章讲了app进程大概的启动过程(https://blog.csdn.net/qq_36063677/article/details/125638137),这篇文章细致的分析一下app进程从zygote进程fork出来到onCreate等生命周期方法被执行的过程。

Android应用程序具有两个特点:

  • 进程入口是ActivityThread.main
  • 支持IPC(进程间通信)

从zygote进程的启动过程(https://blog.csdn.net/qq_36063677/article/details/129235187)可以看到,zygote在fork出一个子进程后,handleChildProc()函数开始处理新进程初始化操作,调用ZygoteInit.zygoteInit():

//ZygoteInit.java   
   public static final Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
            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();
       // 1. 使进程支持IPC(binder进程间通信)
        ZygoteInit.nativeZygoteInit();
       // 2. 调用AcitivtyThraed.main()
        return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,
                classLoader);
    }

一、支持IPC

ZygoteInit.nativeZygoteInit()是一个jni实现的native方法,方法实现是调用AndroidRuntime对象的onZygoteInit():

//AndoridRuntime.cpp
static AndroidRuntime* gCurRuntime = NULL;

static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
    gCurRuntime->onZygoteInit();
}

AppRuntime继承了AndroidRuntime了,并且实现了onZygoteInit()方法,关于安卓runtime机制后续分析,现在这里挖个坑。

AppRuntime类在熟悉的app_process模块中定义:

// app_main.cpp
class AppRuntime : public AndroidRuntime
{
    ......
     virtual void onZygoteInit()
    {
        sp<ProcessState> proc = ProcessState::self();
        ALOGV("App process: starting thread pool.\n");
        proc->startThreadPool();
    }
}

又看到了熟悉的ProcessState,binder通信绕不开的对象,关于ProcessState和IPCThreadState,其都被定义在libbinder模块中。

回到ProcessState,startThreadPool调用spawnPooledThread()方法,创建PoolThread线程类,并且启动这个线程。

//ProcessState.cpp
class PoolThread : public Thread {
public:
    explicit PoolThread(bool isMain)
        : mIsMain(isMain)
    {}

protected:
    virtual bool threadLoop() 
    {
        IPCThreadState::self()->joinThreadPool(mIsMain);
        return false;
    }

    const bool mIsMain;
};

void ProcessState::startThreadPool() {
    AutoMutex _l(mLock);
    if (!mThreadPoolStarted) {
        mThreadPoolStarted = true;
        spawnPooledThread(true);
    }
}

void ProcessState::spawnPooledThread(bool isMain) {
    if (mThreadPoolStarted) {
        String8 name = makeBinderThreadName();
        ALOGV("Spawning new pooled thread, name=%s\n", name.string());
        sp<Thread> t = new PoolThread(isMain);
        t->run(name.string());
    }
}

这里的Thread和Java不同,在这里线程run()启动后,调用的是threadLoop()方法,关于threadLoop()是如何被调用的(https://blog.csdn.net/ch853199769/article/details/79917188),ProcessState调用IPCThreadState->joinThreadPool(true)进一步处理。

//IPCThreadState.cpp
void IPCThreadState::joinThreadPool(bool isMain)
{
    LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());

    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);

    status_t result;
    do {
        processPendingDerefs();
        // now get the next command to be processed, waiting if necessary
        result = getAndExecuteCommand();

        if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {
            LOG_ALWAYS_FATAL("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting",
                  mProcess->mDriverFD, result);
        }

        // Let this thread exit the thread pool if it is no longer
        // needed and it is not the main process thread.
        if(result == TIMED_OUT && !isMain) {
            break;
        }
    } while (result != -ECONNREFUSED && result != -EBADF);

    LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%d\n",
        (void*)pthread_self(), getpid(), result);

    mOut.writeInt32(BC_EXIT_LOOPER);
    talkWithDriver(false);
}

可以看到还是通过循环等待消息,getAndExecuteCommand()通过talkWithDriver()访问“/dev/binder”节点,处理其他进程的通信消息,这样安卓应用程序就支持IPC(Binder进程间通信)了。

二、AcitivtyThraed.main()

接下来看RuntimeInit.applicationInit()方法做了什么,其实就是找到参数类中的main方法,返回给一个Runnable执行:

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

    static class MethodAndArgsCaller implements Runnable {
        /** method to call */
        private final Method mMethod;

        /** argument array */
        private final String[] mArgs;

        public MethodAndArgsCaller(Method method, String[] args) {
            mMethod = method;
            mArgs = args;
        }

        public void run() {
            try {
                mMethod.invoke(null, new Object[] { mArgs });
            } catch (IllegalAccessException ex) {
                throw new RuntimeException(ex);
            } catch (InvocationTargetException ex) {
                Throwable cause = ex.getCause();
                if (cause instanceof RuntimeException) {
                    throw (RuntimeException) cause;
                } else if (cause instanceof Error) {
                    throw (Error) cause;
                }
                throw new RuntimeException(ex);
            }
        }
    }

这个参数就是"android.app.ActivityThread"。

重点分析ActivityThread.main()函数:

// ActivityThread.java
public static void main(String[] args) {
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");

    // Install selective syscall interception
    AndroidOs.install();

    // CloseGuard defaults to true and can be quite spammy.  We
    // disable it here, but selectively enable it later (via
    // StrictMode) on debug builds, but using DropBox, not logs.
    CloseGuard.setEnabled(false);

    Environment.initForCurrentUser();

    // Make sure TrustedCertificateStore looks in the right place for CA certificates
    final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
    TrustedCertificateStore.setDefaultUserDirectory(configDir);

    // Call per-process mainline module initialization.
    initializeMainlineModules();

    Process.setArgV0("<pre-initialized>");

    Looper.prepareMainLooper();

    // Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
    // It will be in the format "seq=114"
    long startSeq = 0;
    if (args != null) {
        for (int i = args.length - 1; i >= 0; --i) {
            if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
                startSeq = Long.parseLong(
                        args[i].substring(PROC_START_SEQ_IDENT.length()));
            }
        }
    }
    ActivityThread thread = new ActivityThread();
    thread.attach(false, startSeq);

    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }

    if (false) {
        Looper.myLooper().setMessageLogging(new
                LogPrinter(Log.DEBUG, "ActivityThread"));
    }

    // End of event ActivityThreadMain.
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    Looper.loop();

    throw new RuntimeException("Main thread loop unexpectedly exited");
}

主要操作:

  1. Looper.prepareMainLooper();
  2. ActivityThread thread = new ActivityThread();
    thread.attach(false, startSeq);
  3. Looper.loop();

启动Looper开启消息循环机制,关于Looper可参考(https://blog.csdn.net/qq_36063677/article/details/129369042),这里重点关注操作 2.

因为main()函数是static静态的,先实例化ActivityThread对象,类变量mH在这时被初始化,用于驱动各个事件的Handler,类变量mAppThread也被初始化,它是ActivityThread的内部类ApplicationThread extends IApplicationThread.Stub,是一个binder对象,用于system_server进程和新的App进程通信管理:

    @UnsupportedAppUsage
    final ApplicationThread mAppThread = new ApplicationThread();
    @UnsupportedAppUsage
    final Looper mLooper = Looper.myLooper();
    @UnsupportedAppUsage
    final H mH = new H();

调用thread.attach():

private void attach(boolean system, long startSeq) {
    //......
    		RuntimeInit.setApplicationObject(mAppThread.asBinder());
            final IActivityManager mgr = ActivityManager.getService();
            try {
                mgr.attachApplication(mAppThread, startSeq);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
            // Watch for getting close to heap limit.
            BinderInternal.addGcWatcher(new Runnable() {
                @Override public void run() {
                    if (!mSomeActivitiesChanged) {
                        return;
                    }
                    Runtime runtime = Runtime.getRuntime();
                    long dalvikMax = runtime.maxMemory();
                    long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();
                    if (dalvikUsed > ((3*dalvikMax)/4)) {
                        if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024)
                                + " total=" + (runtime.totalMemory()/1024)
                                + " used=" + (dalvikUsed/1024));
                        mSomeActivitiesChanged = false;
                        try {
                            ActivityTaskManager.getService().releaseSomeActivities(mAppThread);
                        } catch (RemoteException e) {
                            throw e.rethrowFromSystemServer();
                        }
                    }
                }
            });
}

mgr.attachApplication(mAppThread, startSeq);开始和AMS通信,BinderInternal.addGcWatcher()在内存大于3/4的时候告诉ActivityTaskManager释放内存。

attachApplication()后续调用attachApplicationLocked()执行下一步操作:

// ActivityManagerService.java
@GuardedBy("this")
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
        int pid, int callingUid, long startSeq) {
    
    ProcessRecord app;
    app = mPidsSelfLocked.get(pid);
    
    // App死亡回调
            AppDeathRecipient adr = new AppDeathRecipient(
                    app, pid, thread);
            thread.asBinder().linkToDeath(adr, 0);
    
    // 告知App配置信息
                thread.bindApplication(processName, appInfo, providerList, null, profilerInfo,
                        null, null, null, testMode,
                        mBinderTransactionTrackingEnabled, enableTrackAllocation,
                        isRestrictedBackupMode || !normalMode, app.isPersistent(),
                        new Configuration(app.getWindowProcessController().getConfiguration()),
                        app.compat, getCommonServicesLocked(app.isolated),
                        mCoreSettingsObserver.getCoreSettingsLocked(),
                        buildSerial, autofillOptions, contentCaptureOptions,
                        app.mDisabledCompatChanges);
    
    // 将IApplicationThread关联到ProcessRecord,WindowProcessController
    app.makeActive(thread, mProcessStats);
}

AMS先是通过pid拿到ProcessRecord对象,它保存着正在运行的进程的所有信息,在ProcessList->newProcessRecordLocked()方法中被实例化并返回,ProcessList->handleProcessStartedLocked()方法中调用mService.addPidLocked(app);添加到AMS的mPidsSelfLocked变量中管理。

    @GuardedBy("mService")
    final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,
            boolean isolated, int isolatedUid, HostingRecord hostingRecord) {
        //......
        final ProcessRecord r = new ProcessRecord(mService, info, proc, uid);
        
        return r;
    }

    @GuardedBy("mService")
    boolean handleProcessStartedLocked(ProcessRecord app, int pid, boolean usingWrapper,
            long expectedStartSeq, boolean procAttached) {
        //......
        mService.addPidLocked(app);
        
        return true;
    }

成功获取到ProcessRecord对象后,注册app死亡回调,计算初始化一些app相关的配置信息,并通过IApplicationThread接口的bindApplication()通知给app端,关键的是app.makeActive()函数,它告诉system_server进程的ProcessRecord、WindowProcessController对象app进程已经启动了,可以通过IApplicationThread执行下一步操作,如执行Activity的生命周期方法,广播onReceive()等:

// ProcessRecord.java
class ProcessRecord implements WindowProcessListener {
    
    IApplicationThread thread;  // the actual proc...  may be null only if
                                    // 'persistent' is true (in which case we
                                    // are in the process of launching the app)
    public void makeActive(IApplicationThread _thread, ProcessStatsService tracker) {
        //......
            thread = _thread;
            mWindowProcessController.setThread(thread);
    }
}

// WindowProcessController.java
public class WindowProcessController extends ConfigurationContainer<ConfigurationContainer>
        implements ConfigurationContainerListener {
    
    // The actual proc...  may be null only if 'persistent' is true (in which case we are in the
    // process of launching the app)
    private IApplicationThread mThread;
}

在makeActive()方法被调用前,ProcessRecord和WindowProcessController对象的IApplicationThread变量都为null,除非是persistent app,在被赋值后,system_server进程有了和app进程沟通的工具,可以回调Activity对象的onCreate(), onResume, onReceive()等:

// ActivityStackSupervisor.java
boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
        boolean andResume, boolean checkConfig) throws RemoteException {
    			//......
    
                // Create activity launch transaction.
                final ClientTransaction clientTransaction = ClientTransaction.obtain(
                        proc.getThread(), r.appToken); 		

                final DisplayContent dc = r.getDisplay().mDisplayContent;
                clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
                        System.identityHashCode(r), r.info,
                        // TODO: Have this take the merged configuration instead of separate global
                        // and override configs.
                        mergedConfiguration.getGlobalConfiguration(),
                        mergedConfiguration.getOverrideConfiguration(), r.compat,
                        r.launchedFromPackage, task.voiceInteractor, proc.getReportedProcState(),
                        r.getSavedState(), r.getPersistentSavedState(), results, newIntents,
                        dc.isNextTransitionForward(), proc.createProfilerInfoIfNeeded(),
                        r.assistToken, r.createFixedRotationAdjustmentsIfNeeded()));

                // Set desired final state.
                final ActivityLifecycleItem lifecycleItem;
                if (andResume) {
                    lifecycleItem = ResumeActivityItem.obtain(dc.isNextTransitionForward());
                } else {
                    lifecycleItem = PauseActivityItem.obtain();
                }
                clientTransaction.setLifecycleStateRequest(lifecycleItem);
}

通过proc.getThread(), r.appToken参数构造ClientTransaction类对象,proc.getThread()就是WindowProcessController的mThread变量,判断当前的生命周期,LaunchActivityItem执行onCreate(),ResumeActivityItem执行onResume(),PauseActivityItem执行onPause(),那么这个事务ClientTransaction是怎么被执行的呢?接着往下看

proc.getThread()被赋值给ClientTransaction的mClient变量,ClientTransaction的执行方法schedule()就是通过mClient实现的:

// ClientTransaction.java

/** Target client. */
private IApplicationThread mClient;

public void schedule() throws RemoteException {
    mClient.scheduleTransaction(this);
}

mClient就是system_server进程和app进程沟通的桥梁,从此就回到了app进程,回到ActivityThread查看进一步操作:

// ActivityThread.java
public final class ActivityThread extends ClientTransactionHandler {
    
    private class ApplicationThread extends IApplicationThread.Stub {
        
		@Override
        public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
            ActivityThread.this.scheduleTransaction(transaction);
        }
    }
}

// ClientTransactionHandler.java
public abstract class ClientTransactionHandler {

    void scheduleTransaction(ClientTransaction transaction) {
        transaction.preExecute(this);
        sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
    }
}

ActivityThread继承了ClientTransactionHandler,scheduleTransaction()方法是通过mH handler发送EXECUTE_TRANSACTION:

class H extends Handler {
	public void handleMessage(Message msg) {
        case EXECUTE_TRANSACTION:
            final ClientTransaction transaction = (ClientTransaction) msg.obj;
            mTransactionExecutor.execute(transaction);
            if (isSystem()) {
                // Client transactions inside system process are recycled on the client side
                // instead of ClientLifecycleManager to avoid being cleared before this
                // message is handled.
                transaction.recycle();
            }
            // TODO(lifecycler): Recycle locally scheduled transactions.
            break;
    }
}

在EXECUTE_TRANSACTION消息被接收时处理了ClientTransaction事务,接下去就是执行生命周期方法了。

在IApplicationThread.aidl文件中定义了system_server进程和app进程的通信方法。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从zygote到onCreate应用启动过程分析 的相关文章

  • Unix 域套接字如何区分多个客户端?

    TCP 具有元组对 IP 地址 端口 类型 来区分一个客户端和另一个客户端 UDP 传递客户端 IP 和端口 unix 域如何跟踪不同的客户端 换句话说 服务器创建一个绑定到某个路径 例如 tmp socket 的套接字 2 个或更多客户端
  • C、没有 malloc 的 fork 泄漏

    我试图了解内存分配如何在 fork 上工作 即使是静态或动态分配 我很难理解一些泄漏 如下所示 通过这个程序 include
  • 附加进程时提升删除 Managed_shared_memory

    我有 2 个进程 进程 1 创建一个 boost Managed shared memory 段 进程 2 打开该段 然后进程 1 重新启动 进程 1 的启动如下 struct vshm remove vshm remove boost i
  • 如何杀死shell的所有子进程?

    我正在编写一个 bash 脚本 它可以完成几件事 一开始它会启动几个监视脚本 每个脚本都运行一些其他工具 在我的主脚本结束时 我想杀死从我的外壳中产生的所有东西 所以 它可能看起来像这样 bin bash some monitor1 sh
  • 更新 Github 上分叉存储库的多个分支

    我有一个分叉的 github 存储库 称为 repo O 称为我的分叉 repo F 其中包含大约 8 个分支 其他贡献者已在 repo O 的多个分支上对 repo O 进行了多次 100 次 提交 我现在想将这些更改放入我的分叉存储库
  • IPC 的共享内存和线程的共享内存有什么区别?

    让我们使用 POSIX 共享内存 例如 shmget 协调进程间通信的常见调用 调用 shmget 并协调共享内存段上的通信与 Linux 在单个进程中实现共享内存和线程之间的同步有何不同 其中之一更轻吗 SHM适用于多进程中的IPC 在现
  • 使用 setjmp / longjmp 的通信协议和本地环回

    我使用共享内存和共享互斥体编写了一些相对简单的通信协议 但后来我想扩展支持以在使用不同运行时的两个 dll 之间进行通信 很明显 如果你有一些std vector lt int64 gt 和两个 dll 一个 vs2010 一个 vs201
  • fork:关闭所有打开的套接字

    我在用multiprocessing Pool map 它分叉当前进程 我的理解是 默认情况下 所有文件描述符包括插座分叉时从主进程复制 主进程本身是一个Web服务器 使用cherrypy http cherrypy org 所以这会对开放
  • Maven Surefire:无法分叉并行测试执行

    使用 Maven Surefire 我无法分叉并行测试执行 也就是说 我的每个测试用例都必须在单独的 JVM 中运行 因此需要分叉 此外 我希望我的测试用例并行运行 第一部分工作没有问题 我能够在自己的 JVM 中运行每个测试用例 然而 第
  • GCC 声明: typedef __pid_t pid_t?

    我对 例如 pid t 的声明感到困惑 pid t 是什么意思 它是其他地方定义的另一种类型吗 如果是 在哪里 为什么我的 types h 在 ubuntu 13 04 64 位中定义 pid t 如下 ifndef pid t defin
  • 为什么分叉我的进程会导致文件被无限读取

    我已经将整个程序简化为一个简短的主程序来复制该问题 所以请原谅我它没有任何意义 input txt 是一个文本文件 其中包含几行文本 这个简化的程序应该打印这些行 但是 如果调用 fork 程序就会进入无限循环 一遍又一遍地打印文件的内容
  • iOS 应用程序可以通过套接字进行通信吗?

    我将为 iOS 开发一些应用程序 他们可以通过套接字相互通信吗 假设一个应用程序作为服务器运行 即使在后台模式下 另一个应用程序作为客户端连接到服务器应用程序并执行一些通信 它是否违反了任何 App Store 规则 如果我的想法由于某种原
  • 使用 python os.fork() 可以创建多少个进程

    如果我在下面这样做 for i in range 10000 os fork 这是怎么回事 不考虑收获 我只是想知道os fork 在linux中可以创建多少个进程 如果它像windows一样 只能创建大约2000个进程 那么接下来的800
  • 如何从单独的进程监控应用程序崩溃

    我有一个特定的 net 应用程序 偶尔会因以下 Windows 错误之一而崩溃 application name has encountered a problem and needs to close We are sorry for t
  • Java 和 C/C++ 之间进程间通信的最快(低延迟)方法

    我有一个Java应用程序 通过TCP套接字连接到用C C 开发的 服务器 应用程序和服务器都在同一台机器 Solaris 机器 上运行 但我们最终正在考虑迁移到 Linux 交换的数据类型是简单消息 登录 登录ACK 然后客户端请求某些内容
  • Pipe、Fork 和 Exec - 父进程和子进程之间的双向通信

    我的操作系统类中的作业要求我通过在同一程序上递归调用 exec 来构建二进制进程树 目标是将某些任意任务拆分为单独的进程 父级应与子级通信 子级应仅通过无名管道与父级通信 这个想法是 父级向每个子级发送一半的工作 并且递归地继续 直到满足基
  • 首选的跨平台 IPC Perl 模块是什么?

    我想创建一个简单的 IO 对象 它代表一个向另一个程序打开的管道 我可以在应用程序运行时定期写入另一个程序的 STDIN 我希望它是防弹的 因为它可以捕获所有错误 并且是跨平台的 我能找到的最佳选择是 open sub io read lo
  • bash fork 炸弹的另一个版本是如何工作的?

    我大致了解如何这个通用版本 https stackoverflow com questions 991142 how does this bash fork bomb work bash fork 炸弹的工作原理 然而 我见过另一个版本 特
  • 使用PM2时如何配置master进程

    我在 NodeJS 中遇到 PM2 问题 如果没有 PM2 我们总是有如下几行代码来配置主进程 if cluster isMaster master process configuration else worker process con
  • 更改子进程中的 iostream

    现在 我正在开发一个项目 其中我需要启动一个子进程来使用 C 在 Linux 中执行一个新程序 并且我需要重定向标准输入和输出 就像在 C 中一样 它们是cin and cout 到一个文件 这意味着在子进程中 标准输入和输出都是文件 子进

随机推荐