Android activity启动流程分析

       前端时间看了一下framework的源码,把activity启动流程系统的学习了一下,涉及的源代码较多,本文是基于Android 8.1.0,从Launcher点击启动一个应用作为例子,我们分阶段来详细分析一下Activity启动流程:

一.Launcher到AMS阶段

       当在Launcher上点击应用图标后,会通过startActivity()来启动该应用的主activity,Launcher本身也是一个activity,调用startActivity()后,会调用到ContextThemeWrapper.startActivity()--->ContextWrapper.startActivity()--->
ContextImpl.startActivity(),看一下ContextImpl.java里面的逻辑:

a.ContextImpl.java

public void startActivity(Intent intent, Bundle options) {
    .......
    mMainThread.getInstrumentation().execStartActivity(
            getOuterContext(), mMainThread.getApplicationThread(), null,
            (Activity) null, intent, -1, options);
}

       在startActivity()内部会调用Instrumentation的execStartActivity()方法,可以看到:Instrumentation对象是通过mMainThread.getInstrumentation()来获取的,此处的mMainThread是指ActivityThread实例,即Launcher进程的主线程,是在进程创建时就启动了,ActivityThread启动后在创建Launcher activity时会创建Instrumentation对象。接着分析Instrumentation的execStartActivity()方法:

b.Instrumentation.java

public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
    ......
    try {
        intent.migrateExtraStreamToClipData();
        intent.prepareToLeaveProcess(who);
        int result = ActivityManager.getService().startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()),token, target != null ? target.mEmbeddedID : null,requestCode, 0, null, options);
            checkStartActivityResult(result, intent);
    } catch (RemoteException e) {
    }
}

       可以看到:在Instrumentation的execStartActivity()内部会调用到AMS的startActivity()方法,接下来就会进入下一阶段。

c.调用流程图

image.png

二.AMS到preApp pause完成阶段

a.执行流程

       通过ActivityManagerService.startActivity(),会调用到ActivityStarter.startActivity(),然后经过ActivityStack一系列调用处理,会调用到ActivityStackSupervisor里面,然后再调用到ActivityStack里面。具体代码就不贴了,想了解的可以直接看源码。
      我们知道,在新的activity启动前,必须先将前一个activity pause,本实例中即在Launcher pause完成后才能启动新的应用activity,在ActivityStack里面调用前一个应用ActivityThread里面的ApplicationThread的schedulePauseActivity()来进行pause,pause完成后通知ActivityManagerService,再由ActivityManagerService通知ActivityStack来启动新的应用activity。

b.调用流程图

image.png

       注意一下:在前一个app的activity通知执行完completePausedLocked()中,会执行finishCurrentActivityLocked()方法,在该方法中会执行addToStopping将preApp的ActivityRecord加入到ActivityStackSupervisor的mStoppingActivities变量里面,然后执行scheduleIdleLocked(),发送IDLE_NOW_MSG[该msg不会立即执行,会在空闲时执行,确保先执行current app的onCreate()、onStart()、onResume()],执行activityIdleInternal(),然后执activityIdleInternalLocked(),最后调用到ActivityStack的stopActivityLocked(),调用到AppThread的scheduleStopActivity(),然后跟AMS交互。

三.ASS到新应用ApplicationThread阶段

       在阶段二中,当前一个activity pause完成通知ActivityStack后,ActivityStack会调用ActivityStackSupervisor里面,一系列调用后,会调用到startSpecificActivityLocked(),一起看一下该方法:

void startSpecificActivityLocked(ActivityRecord r,boolean andResume, boolean checkConfig) {
    // Is this activity's application already running?
    // 判断该activity对应的进程是否已经启动
    ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);
    r.getStack().setLaunchTime(r);

    if (app != null && app.thread != null) {
        try {
            if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
                        || !"android".equals(r.info.packageName)) {
                app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
                            mService.mProcessStats);
            }
             //如果进程已经启动了,直接跟ApplicationThread进程通信启动该activity
             realStartActivityLocked(r, app, andResume, checkConfig);
             return;
        } catch (RemoteException e) {
        }
    }
    //进程没有启动,需要先启动应用进程
    mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
}

       从上面可以看到,在启动前先判断app进程是否启动,如果启动了,直接调用realStartActivityLocked()来启动activity;否则,需要先启动进程。

a.直接启动activity

//ActivityStackSupervisor.java
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
            boolean andResume, boolean checkConfig) throws RemoteException {
    ......
    ......
    app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                        System.identityHashCode(r), r.info,mergedConfiguration.getGlobalConfiguration(),
                        mergedConfiguration.getOverrideConfiguration(), r.compat,
                        r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
                        r.persistentState, results, newIntents, !andResume,mService.isNextTransitionForward(), profilerInfo);
    ......
    ......
}

       在realStartActivityLocked()里面调用到ApplicationThread的scheduleLaunchActivity()。
       app是ProcessRecord对象,包含了该应用进程的所有信息,thread是指该进程中ActivityThread中的ApplicationThread对象,该变量是在ActivityThread的main()--->ActivityManagerService.attachAppliaction()--->
ActivityManagerService.attachAppliactionLocked()中的app.makeActive()中将ApplicationThread赋值给ProcessRecord。

b.先启动进程后启动activity

//ActivityManagerService.java
final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
            boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName,
            boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,
            String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
    ......
    ......
    //创建ProcessRecord对象
    app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
    ......
    //启动Process
    startProcessLocked(
                app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);
}

       在startProcessLocked()里面会先创建一ProcessRecord,然后执行startProcessLocked()来执行下一步逻辑处理;

private final void startProcessLocked(ProcessRecord app, String hostingType,
            String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
    ......
    ......
    startResult = Process.start(entryPoint,
                        app.processName, uid, uid, gids, debugFlags, mountExternal,
                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                        app.info.dataDir, invokeWith, entryPointArgs);
    ......
    ......
}

       在startProcessLocked()内部调用到Process.start(),最终调用到ZygoteProcess.zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote),通过socket与Zygote进程通信,然后Zygote创建process。
       process创建完成后,会调用到ActivityThread.main()方法:

public static void main(String[] args) {
    ......................
    Looper.prepareMainLooper();

    ActivityThread thread = new ActivityThread();
    thread.attach(false);

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

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

       在main()方法内部会先执行Looper.prepareMainLooper()来创建主线程的Looper,然后创建ActivityThread实例,执行attach(),最后执行Looper.loop()来开启消息队列处理,主线程的Looper是不能退出的,否则会抛异常;

private void attach(boolean system) {
    sCurrentActivityThread = this;
    mSystemThread = system;
    if (!system) {
        .........
        final IActivityManager mgr = ActivityManager.getService();
        try {
            mgr.attachApplication(mAppThread);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
        ........................
    } else {
        .........................
    }
    ...................
}

       在attach()内部,会调用到ActivityManagerService的attachApplication()方法,将ApplicationThread实例引用作为参数传入,AMS用该引用来通知ActivityThread对Activity生命周期进行处理;

public final void attachApplication(IApplicationThread thread) {
    synchronized (this) {
        int callingPid = Binder.getCallingPid();
        final long origId = Binder.clearCallingIdentity();
        attachApplicationLocked(thread, callingPid);
        Binder.restoreCallingIdentity(origId);
    }
}

       根据调用关系,会调用到attachApplicationLocked()方法:

private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid) {
    .........................
    try {
        AppDeathRecipient adr = new AppDeathRecipient(app, pid, thread);
        thread.asBinder().linkToDeath(adr, 0);
        app.deathRecipient = adr;
    } catch (RemoteException e) {
        app.resetPackageList(mProcessStats);
        startProcessLocked(app, "link fail", processName);
        return false;
    }
    .........................
    .........................
    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);
    ........
    // See if the top visible activity is waiting to run in this process...
    if (normalMode) {
        try {
            if (mStackSupervisor.attachApplicationLocked(app)) {
                didSomething = true;
            }
        } catch (Exception e) {
            Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
            badApp = true;
        }
    }

    // Find any services that should be running in this process...
    if (!badApp) {
        try {
            didSomething |= mServices.attachApplicationLocked(app, processName);
            checkTime(startTime, "attachApplicationLocked: after mServices.attachApplicationLocked");
         } catch (Exception e) {
             Slog.wtf(TAG, "Exception thrown starting services in " + app, e);
             badApp = true;
         }
    }
    // Check if a next-broadcast receiver is in this process...
     if (!badApp && isPendingBroadcastProcessLocked(pid)) {
        try {
            didSomething |= sendPendingBroadcastsLocked(app);
            checkTime(startTime, "attachApplicationLocked: after sendPendingBroadcastsLocked");
        } catch (Exception e) {
            // If the app died trying to launch the receiver we declare it 'bad'
            Slog.wtf(TAG, "Exception thrown dispatching broadcasts in " + app, e);
            badApp = true;
        }
    }
    ................
    return true;
}

       在attachApplicationLocked()方法内部主要做了以下几件事:
       1.创建AppDeathRecipient对象,监听进程Dead;
       2.调用ApplicationThread的bindApplication()方法来通知ActivityThread来进行初始化工作;
       ApplicationThread的bindApplication()会调用ActivityThread的handleBindApplication()方法,该方法里面主要执行了以下逻辑:
          a:通过getPackageInfo()创建LoadedApk[用于广播接收回调,进程间通信ServiceConnection回调,创建application等];
          b:通过ContextImpl.createAppContext创建ContextImpl;
          c:通过反射创建Instrumentation实例mInstrumentation;
          d:通过LoadedApk的makeApplication创建Application,然后执行mInstrumentation.callApplicationOnCreate(app),调用了Application的onCreate()方法。

public Application makeApplication(boolean forceDefaultAppClass,Instrumentation instrumentation) {
    .......
    .......
    try {
        java.lang.ClassLoader cl = getClassLoader();
        .......
        ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
        app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);
            appContext.setOuterContext(app);
    } ......
    .......
    return app;
}

      最终还是通过Instrumentation来进行创建application,先创建application,然后调用application的attach()方法,传入context,最后返回application:

static public Application newApplication(Class clazz, Context context)throws InstantiationException, IllegalAccessException, ClassNotFoundException {
    Application app = (Application)clazz.newInstance();
    app.attach(context);
    return app;
}

       3.调用ActivityStackSupervisor的attachApplicationLocked()方法;

boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
    final String processName = app.processName;
    boolean didSomething = false;
    for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
        ArrayList stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
            final ActivityStack stack = stacks.get(stackNdx);
            if (!isFocusedStack(stack)) {
                continue;
            }
            stack.getAllRunningVisibleActivitiesLocked(mTmpActivityList);
            final ActivityRecord top = stack.topRunningActivityLocked();
            final int size = mTmpActivityList.size();
            for (int i = 0; i < size; i++) {
                final ActivityRecord activity = mTmpActivityList.get(i);
                if (activity.app == null && app.uid == activity.info.applicationInfo.uid
                            && processName.equals(activity.processName)) {
                    try {
                       if (realStartActivityLocked(activity, app, top == activity /* andResume */, true /* checkConfig */)) {
                            didSomething = true;
                       }
                    } catch (RemoteException e) {
                        throw e;
                    }
                }
            }
        }
    }
    ................
    return didSomething;
}

       可以看到在ActivityStackSupervisor的attachApplicationLocked()会启动startActivity()时要启动的Activity,最终会调用到ActivityThread的scheduleLaunchActivity()方法;
       4.启动Service(启动进程也可以通过startService来启动,此处会启动要启动的Service);
       5.发送pending Broadcast;
       6.最后返回true;

c.调用流程图

image.png

       前面讲到,realStartActivity()会调用到ActivityThread的scheduleLaunchActivity()方法,接下来一起看一下:

四.ApplicationThread到Activity onCreate()阶段

       调用scheduleLaunchActivity后,通过sendMessage()会调用ActivityThread的handleLaunchActivity():

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
    ......
    Activity a = performLaunchActivity(r, customIntent);

    if (a != null) {
        r.createdConfig = new Configuration(mConfiguration);
        reportSizeConfigurations(r);
        Bundle oldState = r.state;
        handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
    }
    .....
}

       以上可以看到,在方法内会调用performLaunchActivity()方法:

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ......
    try {
        java.lang.ClassLoader cl = appContext.getClassLoader();
        activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
        ......
    }
    ......
    activity.attach(appContext, this, getInstrumentation(), r.token, r.ident, app, r.intent, r.activityInfo, title, r.parent,r.embeddedID, r.lastNonConfigurationInstances, config,r.referrer, r.voiceInteractor, window, r.configCallback);
    ......
    if (r.isPersistable()) {
       mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
    } else {
       mInstrumentation.callActivityOnCreate(activity, r.state);
    }
    ........
}

       通过Instrumentation来new activity,然后调用activity.attach()方法(后面会有介绍),接下来调用Instrumentation.callActivityOnCreate(),调用activity.performCreate(),最终会调用activity.onCreate(),至此activity创建完成。
       在执行activity.onCreate()之前会先调用activity.attach(),在其内部会执行以下逻辑:

final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,CharSequence title, Activity parent, String id,NonConfigurationInstances lastNonConfigurationInstances,Configuration config, String referrer, IVoiceInteractor voiceInteractor,Window window, 
            ActivityConfigCallback activityConfigCallback) {
        
    attachBaseContext(context);
    ......
    //创建PhoneWindow,后续在setContentView时会用到
    mWindow = new PhoneWindow(this, window, activityConfigCallback);
    .......
    .......
    //赋值
    .......
    //给PhoneWindow设置setWindowManager
    mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
    ......
    //再将值给activity,后续在ActivityThread的handleResumeActivity()显示界面会用到
    mWindowManager = mWindow.getWindowManager();
}

       在handleLaunchActivity()内部执行完performLaunchActivity(),会执行handleResumeActivity()来执行onResume()及页面绘制流程,详情可以参考文章:Android View 显示原理分析

执行流程图

image.png

六.Activity启动模式

      activity有四种启动模式,分别为standard,singleTop,singleTask,singleInstance。如果要使用这四种启动模式,必须在manifest文件中标签中的launchMode属性中配置。

singleTask

       启动模式设置为singleTask,framework在启动该activity时只会把它标示为可在一个新任务中启动,至于是否在一个新任务中启动,还要受其他条件的限制,即taskAffinity属性。
       taskAffinity:默认情况下,一个应用中的所有activity具有相同的taskAffinity,即应用程序的包名。我们可以通过设置不同的taskAffinity属性给应用中的activity分组,也可以把不同的应用中的activity的taskAffinity设置成相同的值,当两个不同应用中的activity设置成相同的taskAffinity时,则两个activity会属于同一个TaskRecord。
       在启动一个singleTask的Activity实例时,如果系统中已经存在这样一个实例,就会将这个实例调度到任务栈的栈顶,并清除它当前所在任务中位于它上面的所有的activity;如果这个已存在的任务中不存在一个要启动的Activity的实例,则在这个任务的顶端启动一个实例;若这个任务不存在,则会启动一个新的任务,在这个新的任务中启动这个singleTask模式的Activity的一个实例。

singleInstance

       以singleInstance模式启动的Activity具有全局唯一性,即整个系统中只会存在一个这样的实例,如果在启动这样的Activiyt时,已经存在了一个实例,那么会把它所在的任务调度到前台,重用这个实例。
       以singleInstance模式启动的Activity具有独占性,即它会独自占用一个任务,被他开启的任何activity都会运行在其他任务中(官方文档上的描述为,singleInstance模式的Activity不允许其他Activity和它共存在一个任务中)。
       被singleInstance模式的Activity开启的其他activity,能够开启一个新任务,但不一定开启新的任务,也可能在已有的一个任务中开启,受条件的限制,这个条件是:当前系统中是不是已经有了一个activity B的taskAffinity属性指定的任务。

你可能感兴趣的:(Android activity启动流程分析)