Activity启动流程总结-ActivityThread

前言

对于Activity的启动流程,从事Android开发的同学都很熟悉。这里仅结合自己的理解,通过博文梳理和记录Activity启动流程关键节点,便于记忆和将来回顾。

在Activity启动流程中,当要启动的Activity所在进程未创建时,ActivityManagerService会通过socket通信请求Zygote进程fork一个子进程作为APP进程。APP进程启动后会执行ActivityThread的main入口函数做一系列的初始化操作,之后和ActivityManagerService交互响应的方法也是在这个ActivityThread类中。

源码探究

文中源码基于Android 9.0

入口函数main

[ActivityThread.java]

public static void main(String[] args) {
    // 省略性能、调试设置部分
    // ···

    // 设置当前进程名称
    Process.setArgV0("<pre-initialized>");

    // 在当前线程初始化Looper,并将其作为主线程Looper。
    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"
    // 获取启动序列号。ActivityManagerService会为待启动的进程生成一个唯一标识,以该
    // 标识为key,保存该进程对应的ProcessRecord(ProcessRecord储存进程完整信息)。
    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
    ActivityThread thread = new ActivityThread();
    // 初始化以及通知ActivityManagerService
    thread.attach(false, startSeq);

    if (sMainThreadHandler == null) {
        // 保存主线程Handler
        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无限循环,监听主线程消息任务
    Looper.loop();

    // 若执行到这里,意味着主线程Looper退出,主线程将运行退出
    throw new RuntimeException("Main thread loop unexpectedly exited");
}

ActivityThread.main作为APP进程入口,在该方法中创建了Looper并开启循环,因此将其视为APP主线程,一直运行保持不退出,监听主线程消息队列中的消息。main方法中同时实例化ActivityThread自身,调用自身的attach方法,执行后续的初始化操作和通知(AMS)ActivityManagerService进程创建完成。

attach

[ActivityThread.java]

private void attach(boolean system, long startSeq) {
    sCurrentActivityThread = this;
    mSystemThread = system;
    if (!system) {
        // 省略JIT检查部分
        // ···
        
        android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                                                UserHandle.myUserId());
        // mAppThread为IApplicationThread,在ActivityThread实例化时创建
        RuntimeInit.setApplicationObject(mAppThread.asBinder());
        // 从ActivityManager的单例成员IActivityManagerSingleton获取IActivityManager
        // 通信接口(ServiceManager.getService(Context.ACTIVITY_SERVICE))
        final IActivityManager mgr = ActivityManager.getService();
        try {
            // 通过IActivityManager binder通信接口通知到AMS,最终调用到AMS的attachApplication方法。
            // 这里将IApplicationThread和启动序列号传给AMS,用于AMS向APP进程通信和AMS匹配启动的ProcessRecord。
            mgr.attachApplication(mAppThread, startSeq);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
        // Watch for getting close to heap limit.
        // 省略堆内存监听处理部分
        // ···
    } else {
        // 省略system process启动相关
        // ···
    }

    // add dropbox logging to libcore
    DropBox.setReporter(new DropBoxReporter());

    ViewRootImpl.ConfigChangedCallback configChangedCallback
            = (Configuration globalConfig) -> {
        synchronized (mResourcesManager) {
            // We need to apply this change to the resources immediately, because upon returning
            // the view hierarchy will be informed about it.
            
            // 省略影响resource的设备配置信息改变监听以及发送
            // CONFIGURATION_CHANGED消息相关部分
            // ···
        }
    };
    ViewRootImpl.addConfigCallback(configChangedCallback);
}

attach方法中最重要的一步是执行mgr.attachApplication通知ActivityManagerService APP进程创建,并传递IApplicationThread和startSeq。

attachApplication

接下来变从APP进程调用到了SystemServer进程中的ActivityManagerService,进入ActivityManagerService的attachApplication方法:

[ActivityManagerService.java]

@Override
public final void attachApplication(IApplicationThread thread, long startSeq) {
    synchronized (this) {
        // 获取binder调用端的pid、uid
        int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();
        // 修改binder调用端的pid、uid为当前进程的pid、uid,并返回原uid和pid的组合
        final long origId = Binder.clearCallingIdentity();
        // AMS对APP进程进行检查、设置、执行后续任务等操作
        attachApplicationLocked(thread, callingPid, callingUid, startSeq);
        // 恢复pid、uid
        Binder.restoreCallingIdentity(origId);
    }
}

进入attachApplicationLocked方法:

1. 查找ProcessRecord

ProcessRecord用于记录运行的进程的完整信息,正常情况下一个ProcessRecord对应一个进程。

[ActivityManagerService.java]

private final boolean attachApplicationLocked(IApplicationThread thread,
        int pid, int callingUid, long startSeq) {
    // Find the application record that is being attached...  either via
    // the pid if we are running in multiple processes, or just pull the
    // next app record if we are emulating process with anonymous threads.
    ProcessRecord app;
    long startTime = SystemClock.uptimeMillis();
    // 当前调用端的进程非SystemServer进程
    if (pid != MY_PID && pid >= 0) {
        synchronized (mPidsSelfLocked) {
            // 根据pid获取缓存的ProcessRecord,mPidsSelfLocked中缓存了在运行的进程对应的ProcessRecord。
            app = mPidsSelfLocked.get(pid);
        }
    } else {
        app = null;
    }

    // It's possible that process called attachApplication before we got a chance to
    // update the internal state.
    if (app == null && startSeq > 0) {
        // 根据启动序列号从待启动集合中取出ProcessRecord,AMS在通知zygote创建应用进程前,
        // 会先生成启动序列号和ProcessRecord,并保存在mPendingStarts中。
        final ProcessRecord pending = mPendingStarts.get(startSeq);
        // 对pending进行检查
        if (pending != null && pending.startUid == callingUid
                && handleProcessStartedLocked(pending, pid, pending.usingWrapper,
                        startSeq, true)) {
            app = pending;
        }
    }

    // 若没有找到有效的ProcessRecord,则视为应用进程启动失败
    if (app == null) {
        Slog.w(TAG, "No pending application record for pid " + pid
                + " (IApplicationThread " + thread + "); dropping process");
        EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);
        if (pid > 0 && pid != MY_PID) {
            // 杀死应用进程
            killProcessQuiet(pid);
            //TODO: killProcessGroup(app.info.uid, pid);
        } else {
            try {
                // 触发ActivityThread.scheduleExit方法,终止主线程
                thread.scheduleExit();
            } catch (Exception e) {
                // Ignore exceptions.
            }
        }
        return false;
    }
    
    // 省略 ···
}

attachApplicationLocked方法中首先从缓存集合中取出在启动进程前保存的ProcessRecord,当ProcessRecord有效的情况下,才认为应用进程启动成功。

其中handleProcessStartedLocked方法对ProcessRecord进行检查:
[ActivityManagerService.java]

private boolean handleProcessStartedLocked(ProcessRecord app, int pid, boolean usingWrapper,
        long expectedStartSeq, boolean procAttached) {
    // 从待启动集合中移除对应ProcessRecord
    mPendingStarts.remove(expectedStartSeq);
    // isProcStartValidLocked方法中会检查是否有am指令杀死该进程、存在之前的ProcessRecord
    // 和当前的不一致、该ProcessRecord未被标记待启动、ProcessRecord保存的启动序列号不匹配。
    // 若检查不过,将返回对应的原因。
    final String reason = isProcStartValidLocked(app, expectedStartSeq);
    if (reason != null) {
        Slog.w(TAG_PROCESSES, app + " start not valid, killing pid=" + pid
                + ", " + reason);
        app.pendingStart = false;
        // 杀死进程组
        Process.killProcessQuiet(pid);
        Process.killProcessGroup(app.uid, app.pid);
        return false;
    }
    // BatteryStatsService埋点统计
    mBatteryStatsService.noteProcessStart(app.processName, app.info.uid);
    checkTime(app.startTime, "startProcess: done updating battery stats");

    // 省略系统日志和监视相关部分
    // ···
    // 省略脏ProcessRecord缓存的清理部分
    // ···
    
    synchronized (mPidsSelfLocked) {
        // 将ProcessRecord保存进mPidsSelfLocked缓存集合中
        this.mPidsSelfLocked.put(pid, app);
        
        // 省略超时监听消息相关部分
        // ····
    }
    checkTime(app.startTime, "startProcess: done updating pids map");
    return true;
}

handleProcessStartedLocked方法中对ProcessRecord进行检查,检查通过后会保存进mPidsSelfLocked缓存,以便后续可以通过pid获取。

回到ActivityManagerService.attachApplicationLocked方法中,在获取到ProcessRecord后继续往下执行。

2. APP进程死亡监听

[ActivityManagerService.java]

private final boolean attachApplicationLocked(IApplicationThread thread,
        int pid, int callingUid, long startSeq) {
    // 省略 ···
    
    // If this application record is still attached to a previous
    // process, clean it up now.
    // 若此时ProcessRecord中持有IApplicationThread,意味着还保留着旧的应用进程的信息,
    // 需要清理和尝试关闭应用进程组件。
    if (app.thread != null) {
        handleAppDiedLocked(app, true, true);
    }

    // Tell the process all about itself.

    if (DEBUG_ALL) Slog.v(
            TAG, "Binding process pid " + pid + " to record " + app);

    final String processName = app.processName;
    try {
        // 创建死亡讣告回调
        AppDeathRecipient adr = new AppDeathRecipient(
                app, pid, thread);
        // 设置监听应用进程死亡通知
        thread.asBinder().linkToDeath(adr, 0);
        app.deathRecipient = adr;
    } catch (RemoteException e) {
        // 设置死亡监听期间发送异常,重新执行startProcessLocked
        app.resetPackageList(mProcessStats);
        startProcessLocked(app, "link fail", processName);
        return false;
    }
    
    // 省略 ···
}

ActivityManagerService中依赖Binder死亡监听机制,监听应用进程是否死亡。若应用进程被杀死,则会触发AppDeathRecipient.binderDied回调,在该回调中调用appDiedLocked方法,执行清理动作。

3. 绑定到APP进程

[ActivityManagerService.java]

private final boolean attachApplicationLocked(IApplicationThread thread,
        int pid, int callingUid, long startSeq) {
    // 省略 ···
       
    // 省略ProcessRecord内成员初始设置部分 ···
    // 省略超时消息相关部分 ···
    
    try {
        // 省略调试设置相关部分 ···
        // 省略适配设置相关部分 ···
        // ···
      
        if (app.isolatedEntryPoint != null) {
            // This is an isolated process which should just call an entry point instead of
            // being bound to an application.
            thread.runIsolatedEntryPoint(app.isolatedEntryPoint, app.isolatedEntryPointArgs);
        } else if (app.instr != null) {
            // instr类型为ActiveInstrumentation,Instrument测试框架相关,可通过
            // AMS的startInstrumentation方法注册ActiveInstrumentation。
            thread.bindApplication(processName, appInfo, providers,
                    app.instr.mClass,
                    profilerInfo, app.instr.mArguments,
                    app.instr.mWatcher,
                    app.instr.mUiAutomationConnection, testMode,
                    mBinderTransactionTrackingEnabled, enableTrackAllocation,
                    isRestrictedBackupMode || !normalMode, app.persistent,
                    new Configuration(getGlobalConfiguration()), app.compat,
                    getCommonServicesLocked(app.isolated),
                    mCoreSettingsObserver.getCoreSettingsLocked(),
                    buildSerial, isAutofillCompatEnabled);
        } else {
            // 调用IApplicationThread.bindApplication方法将信息传给应用进程进行绑定
            thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
                    null, null, null, testMode,
                    mBinderTransactionTrackingEnabled, enableTrackAllocation,
                    isRestrictedBackupMode || !normalMode, app.persistent,
                    new Configuration(getGlobalConfiguration()), app.compat,
                    getCommonServicesLocked(app.isolated),
                    mCoreSettingsObserver.getCoreSettingsLocked(),
                    buildSerial, isAutofillCompatEnabled);
        }
    } catch (Exception e) {
        // 省略异常处理部分 ···
        return false;
    }
    
    // 省略检查Activity、Service、Broadcast部分(当要启动的目标组件所在进程未启动情况下,会先启动进程,之后再启动组件) ···
    // 省略oom_adj更新部分 ···
    // ···
}

ActivityManagerService最终会将应用信息和各种配置信息通过IApplicationThread binder通信接口传递给APP进程。

其中getCommonServicesLocked方法还会将一些常用的系统服务IBinder保存在ArrayMap中,一并传给APP进程,提高APP在使用这些服务时的效率。

bindApplication

回到APP进程,IApplicationThread.bindApplication方法将调用ActivityThread.bindApplication方法:
[ActivityThread.java]

public final void bindApplication(String processName, ApplicationInfo appInfo,
        List<ProviderInfo> providers, ComponentName instrumentationName,
        ProfilerInfo profilerInfo, Bundle instrumentationArgs,
        IInstrumentationWatcher instrumentationWatcher,
        IUiAutomationConnection instrumentationUiConnection, int debugMode,
        boolean enableBinderTracking, boolean trackAllocation,
        boolean isRestrictedBackupMode, boolean persistent, Configuration config,
        CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
        String buildSerial, boolean autofillCompatibilityEnabled) {

    // 若AMS传来的常用Service不为空,则添加进ServiceManager保存
    if (services != null) {
        // 省略日志相关部分 ··· 
        // Setup the service cache in the ServiceManager
        ServiceManager.initServiceCache(services);
    }

    setCoreSettings(coreSettings);

    // 用AppBindData来包装各种信息参数
    AppBindData data = new AppBindData();
    data.processName = processName;
    data.appInfo = appInfo;
    data.providers = providers;
    data.instrumentationName = instrumentationName;
    data.instrumentationArgs = instrumentationArgs;
    data.instrumentationWatcher = instrumentationWatcher;
    data.instrumentationUiAutomationConnection = instrumentationUiConnection;
    data.debugMode = debugMode;
    data.enableBinderTracking = enableBinderTracking;
    data.trackAllocation = trackAllocation;
    data.restrictedBackupMode = isRestrictedBackupMode;
    data.persistent = persistent;
    data.config = config;
    data.compatInfo = compatInfo;
    data.initProfilerInfo = profilerInfo;
    data.buildSerial = buildSerial;
    data.autofillCompatibilityEnabled = autofillCompatibilityEnabled;
    // 当前运行在binder线程中,通过mH发送到主线程处理AppBindData
    sendMessage(H.BIND_APPLICATION, data);
}

bindApplication方法中先保存了常用Service的Binder代理引用,然后将各种信息参数包装进AppBindData,通过handler发送到主线程处理。

BIND_APPLICATION这个case下会调用handleBindApplication方法:
[ActivityThread.java]

private void handleBindApplication(AppBindData data) {
    // 省略设置敏感线程、调试相关部分相关部分
    
    // 保存设备、适配配置等信息
    mBoundApplication = data;
    mConfiguration = new Configuration(data.config);
    mCompatConfiguration = new Configuration(data.config);
    
    mProfiler = new Profiler();
    // 省略mProfiler配置相关部分
    
    // 设置进程名称
    // send up app name; do this *before* waiting for debugger
    Process.setArgV0(data.processName);
    android.ddm.DdmHandleAppName.setAppName(data.processName,
                                            UserHandle.myUserId());
    VMRuntime.setProcessPackageName(data.appInfo.packageName);
    
    // 启动性能监控
    if (mProfiler.profileFd != null) {
        mProfiler.startProfiling();
    }
    
    // 省略Message、ImageDecoder等版本兼容部分
    // 省略时区初始设置部分
    // 省略更新Configuration相关部分
    
    // 获取LoadedApk对象
    data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
    
    // 省略density兼容、24Hour制、StrictMode设置等部分
    // 省略调试模式下waiting for debugger弹框相关部分
    // 省略systrace messages、http代理设置等相关部分
    // 省略InstrumentationInfo相关部分 ···
    
    // 创建ContextImpl
    final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
    
    // 省略isolated process相关部分
    // 省略NetworkSecurityConfigProvider相关部分
    
    // 创建Instrumentation,并使之持有ActivityThread引用
    mInstrumentation = new Instrumentation();
    mInstrumentation.basicInit(this);
    
    // 省略largeHeap设置相关部分
    
    // Allow disk access during application and provider setup. This could
    // block processing ordered broadcasts, but later processing would
    // probably end up doing the same disk access.
    Application app;
    final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
    final StrictMode.ThreadPolicy writesAllowedPolicy = StrictMode.getThreadPolicy();
    try {
        // If the app is being launched for full backup or restore, bring it up in
        // a restricted environment with the base application class.
        // 创建Application对象
        app = data.info.makeApplication(data.restrictedBackupMode, null);

        // Propagate autofill compat state
        app.setAutofillCompatibilityEnabled(data.autofillCompatibilityEnabled);

        mInitialApplication = app;

        // don't bring up providers in restricted mode; they may depend on the
        // app's custom Application class
        if (!data.restrictedBackupMode) {
            if (!ArrayUtils.isEmpty(data.providers)) {
                // 初始化APP注册的ContentProvider
                installContentProviders(app, data.providers);
                // For process that contains content providers, we want to
                // ensure that the JIT is enabled "at some point".
                mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
            }
        }

        // Do this after providers, since instrumentation tests generally start their
        // test thread at this point, and we don't want that racing.
        try {
            mInstrumentation.onCreate(data.instrumentationArgs);
        }
        catch (Exception e) {
            throw new RuntimeException(
                "Exception thrown in onCreate() of "
                + data.instrumentationName + ": " + e.toString(), e);
        }
        try {
            // 调用Application.onCreate生命周期方法
            mInstrumentation.callApplicationOnCreate(app);
        } catch (Exception e) {
            if (!mInstrumentation.onException(app, e)) {
                throw new RuntimeException(
                  "Unable to create application " + app.getClass().getName()
                  + ": " + e.toString(), e);
            }
        }
    } finally {
        // If the app targets < O-MR1, or doesn't change the thread policy
        // during startup, clobber the policy to maintain behavior of b/36951662
        if (data.appInfo.targetSdkVersion < Build.VERSION_CODES.O_MR1
                || StrictMode.getThreadPolicy().equals(writesAllowedPolicy)) {
            StrictMode.setThreadPolicy(savedPolicy);
        }
    }
    
    // 省略预加载字体资源部分
}

handleBindApplication方法中进行了一系列的应用初始化配置,并先后创建了LoadedApkContextImplInstrumentationApplication

makeApplication

在handleBindApplication方法中调用了LoadedApk的makeApplication方法来创建Application,进入这个方法看看内部创建的过程:

[LoadedApk.java]

public Application makeApplication(boolean forceDefaultAppClass,
        Instrumentation instrumentation) {
    if (mApplication != null) {
        return mApplication;
    }

    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");

    Application app = null;

    // 获取Androidmanifest中定义的自定义Application的类名
    String appClass = mApplicationInfo.className;
    if (forceDefaultAppClass || (appClass == null)) {
        // 使用系统默认Application
        appClass = "android.app.Application";
    }

    try {
        java.lang.ClassLoader cl = getClassLoader();
        if (!mPackageName.equals("android")) {
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                    "initializeJavaContextClassLoader");
            initializeJavaContextClassLoader();
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        }
        // 创建ContextImpl
        ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
        // 通过反射实例化Application,并调用Application的attach方法,attach方法中又调用
        // attachBaseContext方法,在attachBaseContext方法中将ContextImpl赋值给mBase。
        app = mActivityThread.mInstrumentation.newApplication(
                cl, appClass, appContext);
        // 使ContextImpl持有Application引用
        appContext.setOuterContext(app);
    } catch (Exception e) {
        if (!mActivityThread.mInstrumentation.onException(app, e)) {
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            throw new RuntimeException(
                "Unable to instantiate application " + appClass
                + ": " + e.toString(), e);
        }
    }
    mActivityThread.mAllApplications.add(app);
    mApplication = app;

    // 此时传入的instrumentation为null
    if (instrumentation != null) {
        try {
            instrumentation.callApplicationOnCreate(app);
        } catch (Exception e) {
            if (!instrumentation.onException(app, e)) {
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                throw new RuntimeException(
                    "Unable to create application " + app.getClass().getName()
                    + ": " + e.toString(), e);
            }
        }
    }

    // Rewrite the R 'constants' for all library apks.
    SparseArray<String> packageIdentifiers = getAssets().getAssignedPackageIdentifiers();
    final int N = packageIdentifiers.size();
    for (int i = 0; i < N; i++) {
        final int id = packageIdentifiers.keyAt(i);
        if (id == 0x01 || id == 0x7f) {
            continue;
        }

        rewriteRValues(getClassLoader(), packageIdentifiers.valueAt(i), id);
    }

    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

    return app;
}

总结

ActivityThread的main方法中在当前所在线程创建Looper,并将当前线程其指定为主线程。之后实例化ActivityThread,并调用其attach方法。最后开启Looper循环,不断监听处理主线程消息队列中的消息。

在attach方法中,创建IApplicationThread binder通信接口,之后通过IActivityManager执行ActivityManagerService的attachApplication方法,并将IApplicationThread传递过去。

ActivityManagerService.attachApplication中对新启动进程校验通过后,通过IApplicationThread调用ActivityThread的bindApplication方法,并将应用信息参数传递过来。bindApplication方法中将信息参数打包发送到主线程执行handleBindApplication方法。

在handleBindApplication方法中,进行应用进程的初始配置,实例化LoadedApk、ContextImpl、Instrumentation、Application并设置互相持有引用,最后回调Application.onCreate生命周期方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章