App启动流程:App进程内部操作-2

App进程在接收到来自ApplicationThread的发送的LAUNCH_ACTIVITY消息后,进而会通过ActivityThread.handleLaunchActivity()进行后续操作。


3.4.ActivityThread.handleLaunchActivity()

总结:
1:从空闲消息处理器列表中 移除 “在主线程空闲时,执行强制GC操作的空闲消息处理器” 。
2:在创建待启动Activity之前,先获取WMS服务在本进程的Binder代理并保存至WindowManagerGlobal。
3:通过performLaunchActivity()初始化ContextImpl实例、对目标Activity进行初始化、执行Activity的绑定操作、执行Activity的相应生命周期方法、等Activity执行完Resume之后,才开始对Activity的View树进行App进程内部的测量、摆放、绘制等操作。并通过ViewRootImpl内部的“编舞者来接收IO硬件产生的“Vsync”刷新信号,进而对PhoneView维护的视图树进行周期性的刷新操作。
4:根据AMS传递给App 进程的startsNotResumed,来决定是否需要“禁止Resume待启动Activity,如果禁止就会执行该Activity的pasue操作”。
5:如果初始化Activity实例失败,告诉AMS需要 “移除” 此Activity对应保存在AMS 服务中的Activity栈中的ActivityRecord。

源码

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
        //如果App被切换到了后台,且已经准备好了GC,此时因为启动App进程内的Activity被切换到了前台,需要移除GC_WHEN_IDLE去执行GC操作。
        //见小节[3.5]
        unscheduleGcIdler();
        ......

        // 在创建待启动Activity之前,先获取WMS服务在本进程的Binder代理。
        WindowManagerGlobal.initialize();
   
        //见小节[3.6]
        Activity a = performLaunchActivity(r, customIntent);

        if (a != null) {
            ......
            //见小节[3.7]
            handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
            
            //在scheduleLaunchActivity()首先会保存AMS传递来的参数信息,而startsNotResumed的值为false,表示需要Resume待启动Activity。
           //不会走这里。
            if (!r.activity.mFinished && r.startsNotResumed) {
               ......
                performPauseActivityIfNeeded(r, reason);
                ......
            }
        } else {
            //如果初始化Activity实例失败,告诉AMS需要 “移除” 此Activity对应保存在AMS 服务中的Activity栈中的ActivityRecord。
            try {
                ActivityManager.getService()
                    .finishActivity(r.token, Activity.RESULT_CANCELED, null,
                            Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        }
    }

3.5.ActivityThread.unscheduleGcIdler()

总结:从空闲消息处理列表中 移除 “在主线程空闲时,执行强制GC操作的空闲消息处理器” 。

1:此空闲消息处理程序,内部通过doGcIfNeeded() 执行“强制GC操作”。
2:doGcIfNeeded() 内部会判断“上次GC发生的时间距离现在为止是否超过了 5 秒钟”,如果超过了则通过BinderInternal.forceGc()通知VM执行GC操作。

源码

void unscheduleGcIdler() {
        //如果已经往空闲消息处理器列表中添加了“在主线程空闲时,执行强制GC操作的空闲消息处理器”。那么无论此处理器是否已经执行了,尝试从空闲消息处理列表中 移除 此空闲消息处理器()。
        if (mGcIdlerScheduled) {
            mGcIdlerScheduled = false;
            Looper.myQueue().removeIdleHandler(mGcIdler);
        }
        //如果此消息还未执行,还在主线程的MessageQueue派对等待执行的话,从此 MessageQueue 中移除此消息。
        mH.removeMessages(H.GC_WHEN_IDLE);
    }

final class GcIdler implements MessageQueue.IdleHandler {
        @Override
        public final boolean queueIdle() {
            doGcIfNeeded();
            return false;
        }
    }

void doGcIfNeeded() {
        mGcIdlerScheduled = false;
        final long now = SystemClock.uptimeMillis();
        if ((BinderInternal.getLastGcTime()+MIN_TIME_BETWEEN_GCS) < now) {
            BinderInternal.forceGc("bg");
        }
    }

3.6.ActivityThread.performLaunchActivity()

总结:
1:从待启动Activity的Intent中获取ComponentName(ComponentName中包括待启动Activity的包名+类名信息)。
2:创建ContextImpl实例。
3:通过反射实例化待启动Activity实例。
4:执行Activity的绑定操作(具体请查看 小节[3.6.2])。
5:通过Instrumentation.callActivityOnCreate()执行Activity.onCreate()。
6:通过Instrumentation.callActivityOnStart()执行Activity.onStart()。
7:把创建的Activity实例缓存至ActivityClientRecord中(ActivityClientRecord用于记录App进程内关于Activity的相关信息)。并把此ActivityClientRecord缓存至ActivityThread内部的ArrayMap集合中。关于ActivityClentRecord的介绍请查看 App进程内部操作(1)-重要类说明-ActivityClientRecord

源码

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ......
        //从待启动Activity的Intent中获取ComponentName
        //ComponentName中包括待启动Activity的包名+类名信息
        ComponentName component = r.intent.getComponent();
        if (component == null) {
            component = r.intent.resolveActivity(
                mInitialApplication.getPackageManager());
            r.intent.setComponent(component);
        }

        ......
        //创建ContextImpl实例。
        ContextImpl appContext = createBaseContextForActivity(r);
        Activity activity = null;
        try {
            //通过Instrumentation实例化待启动Activity实例
            //见小节[3.6.1]
            java.lang.ClassLoader cl = appContext.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
            //通过Instrumentation实例化Activity失败的话,则抛出RuntimeException
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to instantiate activity " + component
                    + ": " + e.toString(), e);
            }
        }

        try {
            //从LoadApk中获取已经实例化的Application实例.
            //具体请查看小节[2.7]
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);
            ......
            if (activity != null) {
                //执行Activity.attach()
                //见小节[3.6.2]
                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);
                ......
                //设置Activity.mStartedActivity为false.
                activity.mStartedActivity = false;
                ......
                //通过Instrumentation回调Activity.onCreate()
                //见小节[3.6.3]
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
                ......
                //把创建的Activity实例缓存至ActivityClientRecord中(ActivityClientRecord用于记录App进程内关于Activity的相关信息)。
                r.activity = activity;
                ......
                //回调Activity.onStart()
               //见小节[3.6.4]
                if (!r.activity.mFinished) {
                    activity.performStart();
                    r.stopped = false;
                }
                ......
                }
            }
            ......
          //把App进程用于记录Activity信息的ActivityClientRecord缓存至ActivityThread内部的ArrayMap集合中。
          mActivities.put(r.token, r);
        } catch (SuperNotCalledException e) {
            ......
        } catch (Exception e) {
            ......
        }

        return activity;
    }

3.6.1. Instrumentation.newActivity()

总结:通过反射实例化待启动Activity实例。

源码

public Activity newActivity(ClassLoader cl, String className,
            Intent intent)
            throws InstantiationException, IllegalAccessException,
            ClassNotFoundException {
        return (Activity)cl.loadClass(className).newInstance();
    }

3.6.2.Activity.attach()

总结:执行Activity的绑定操作。

1:通过attachBaseContext(),把实例化的ContextImpl实例保存至Activity的祖先类ContextWrapper内部。
2:实例化每个Activity实例内部,用于承载整个View树的Window实例(此Window的类型为PhoneWindow)。
3:保存回调给Activity的参数,这些参数包括如下:
3.1:保存 当前线程实例(当前线程是name为“main”的线程,此线程就是我们常说的 主线程也是UI线程)。
3.2:保存 每个App进程的ActivityThread实例。
3.3:保存 每个App进程的Application实例。
3.4:保存 用于描述待启动Activity信息的ActivityRecord内部的appToken属性(该属性的类型为ActivityRecord.Token,且该类继承于IApplicationToken.Stub,这表明此类作为Binder IPC的服务端,会接收来自App进程的Binder请求)。App进程会通过此IBinder服务在本进程的代理对象,向运行在 system_server进程的ActivityRecord发起Binder请求

源码

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

        mFragments.attachHost(null /*parent*/);

        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
        if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
            mWindow.setSoftInputMode(info.softInputMode);
        }
        if (info.uiOptions != 0) {
            mWindow.setUiOptions(info.uiOptions);
        }
        mUiThread = Thread.currentThread();

        mMainThread = aThread;
        mInstrumentation = instr;
        mToken = token;
        mIdent = ident;
        mApplication = application;
        mIntent = intent;
        mReferrer = referrer;
        mComponent = intent.getComponent();
        mActivityInfo = info;
        mTitle = title;
        mParent = parent;
        mEmbeddedID = id;
        mLastNonConfigurationInstances = lastNonConfigurationInstances;
        if (voiceInteractor != null) {
            if (lastNonConfigurationInstances != null) {
                mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;
            } else {
                mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,
                        Looper.myLooper());
            }
        }

        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        if (mParent != null) {
            mWindow.setContainer(mParent.getWindow());
        }
        mWindowManager = mWindow.getWindowManager();
        mCurrentConfig = config;

        mWindow.setColorMode(info.colorMode);
    }

3.6.3.Instrumentation.callActivityOnCreate()

总结:执行Activity.onCreate()。

源码

public void callActivityOnCreate(Activity activity, Bundle icicle) {
        ......
        activity.performCreate(icicle);
        ......
    }

final void performCreate(Bundle icicle) {
        ......
        onCreate(icicle);
        ......
    }

3.6.4.Activity.performStart()

总结:通过Instrumentation.callActivityOnStart()执行Activity.onStart()。

源码

final void performStart() {
        //Fragment相关操作
        mFragments.noteStateNotSaved();
        mCalled = false;
        mFragments.execPendingActions();

        //通过Instrumentation执行Activity.onStart()
        mInstrumentation.callActivityOnStart(this);
        ......
         //Fragment相关操作
        mFragments.dispatchStart();
        mFragments.reportLoaderStart();
        ......
    }

public void callActivityOnStart(Activity activity) {
        activity.onStart();
    }

3.7.ActivityThread.handleResumeActivity()

总结:
1:从空闲消息处理列表中 移除 “在主线程空闲时,执行强制GC操作的空闲消息处理器” 。
2:通过Instrumentation.callActivityOnResume()执行Activity.onResume()。
3:等Activity执行完Resume之后,才开始对Activity的View树进行App进程内部的测量、摆放、绘制等操作。并通过ViewRootImpl内部的“编舞者来接收IO硬件产生的“Vsync”刷新信号,进而对PhoneView维护的视图树进行周期性的刷新操作。
4:通知AMS待启动Activity已经启动完毕。
5:如果在Resume待启动Activity过程中出现了什么异常,则需要通知AMS finish此 Activity。

源码

final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
        //在performLaunchActivity()创建完Activity实例并执行其相应生命周期方法后,会把待启动Activity添加至描述此Activity相关信息的ActivityClientRecord中。并把此ActivityClientRecord缓存至ActivityThread内部的ArrayMap集合中。
        //从缓存ActivityClientRecord的ArrayMap中获取与此Activity相关的ActivityClentRecord实例。
        ActivityClientRecord r = mActivities.get(token);
        ......

        //从空闲消息处理列表中 移除 “在主线程空闲时,执行强制GC操作的空闲消息处理器” 。
        //详情请看小节[3.5]
        unscheduleGcIdler();
        //见小节[3.8]
        r = performResumeActivity(token, clearHide, reason);

        if (r != null) {
            final Activity a = r.activity;
            ......
            final int forwardBit = isForward ?
                    WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;

            //如果窗口尚未添加到窗口管理器中,并且当前Activity没有finish它自身或启动另一个活动,则继续添加窗口。
            //willBeVisible取决于Activity.mStartedActivity属性,该属性表示“是否启动了其他Activity”,该属性只有在Activity的几个startXX()方法被重置为true。
            //如果mStartedActivity为true,则会使当前Activity不可见。如果为false,则表示可见。
            //根据mStartedActivity的值来判断是否需要显示此Activity,为true就不显示,为false就显示。
            //此时mStartedActivit为false,则willBeVisible为true。
            boolean willBeVisible = !a.mStartedActivity;
            if (!willBeVisible) {
                ......
            }
            //Activity执行完Resume之后,才开始对Activity的View树进行App进程内部的测量、摆放、绘制等操作。具体View树是如何绘制到屏幕上的将来以后来分析。
            if (r.window == null && !a.mFinished && willBeVisible) {
                ......
            } else if (!willBeVisible) {
                // 在onCreate()至onResume()过程中启动了其他Activity。则willBeVisible则会false。
                ......
                r.hideForNow = true;
            }

            ......

            if (!r.onlyLocalRequest) {
                r.nextIdle = mNewActivities;
                mNewActivities = r;
                if (localLOGV) Slog.v(
                    TAG, "Scheduling idle handler for " + r);
                Looper.myQueue().addIdleHandler(new Idler());
            }
            r.onlyLocalRequest = false;

            //此值为true,该值是ActivityClientRecord.startsNotResumed的值相反数,该值表示“是否禁止Resume待启动Activity”。
            if (reallyResume) {
                try {
                    //告诉AMS待启动Activity已经Resume完毕。
                    ActivityManager.getService().activityResumed(token);
                } catch (RemoteException ex) {
                    throw ex.rethrowFromSystemServer();
                }
            }

        } else {
            //在执行Resume Activity 过程中出现了异常,则通知AMS finish此Activity。
            try {
                ActivityManager.getService()
                    .finishActivity(token, Activity.RESULT_CANCELED, null,
                            Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        }
    }

3.8.ActivityThread.performResumeActivity()

总结:通过Instrumentation.callActivityOnResume()执行Activity.onResume()。

源码

public final ActivityClientRecord performResumeActivity(IBinder token,
            boolean clearHide, String reason) {
        //从缓存ActivityClientRecord的ArrayMap中获取与此Activity相关的ActivityClentRecord实例。
        ActivityClientRecord r = mActivities.get(token);
        ......
        if (r != null && !r.activity.mFinished) {
            //clearHide为false,不会走这里
            if (clearHide) {
                r.hideForNow = false;
                r.activity.mStartedActivity = false;
            }
            try {
                ......
                //见小节[3.8.1]
                r.activity.performResume();
                ......
            } catch (Exception e) {
                ......
            }
        }
        return r;

3.8.1.Activity.performResume()

总结:通过Instrumentation.callActivityOnResume()执行Activity.onResume()。

源码

final void performResume() {
        performRestart();
        ......
        mInstrumentation.callActivityOnResume(this);
        ......
    }

public void callActivityOnResume(Activity activity) {
        activity.mResumed = true;
        //执行Activity.onResume()
        activity.onResume();
        ......
    }

final void performRestart() {
        ......
        //只有Activity被执行stop操作后,mStopped才会被赋值为true。
        //此时不走这里。
        if (mStopped) {
            mStopped = false;
            ......
            performStart();
        }
    }

4.1.ActivityStack.minimalResumeActivityLocked()

总结:
1:待启动Activity在App进程内启动完毕后,需要更新其在system_server进程内AMS服务维护的“Activity栈”结构中的一些状态信息。
2:通过ActivityStack.setResumedActivityLocked(), “更新与之对应的ActivityRecord.state为RESUMED”、“更新ActivityStack内部的mResumedActivity为启动完毕的ActivityRecord(表示现在处于启动状态的那个Activity已经发生了更改)” 等等操作。
3:通过ActivityStack.setLaunchTime()更新ActivityStack的启动时间。

源码

void minimalResumeActivityLocked(ActivityRecord r) {
        if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to RESUMED: " + r + " (starting new instance)"
                + " callers=" + Debug.getCallers(5));
        //见小节[4.2]
        setResumedActivityLocked(r, "minimalResumeActivityLocked");
        r.completeResumeLocked();
        //见小节[4.3]
        setLaunchTime(r);
        if (DEBUG_SAVED_STATE) Slog.i(TAG_SAVED_STATE,
                "Launch completed; removing icicle of " + r.icicle);
    }

4.2.ActivityStack.setResumedActivityLocked()

总结:
1:待启动Activity启动完毕后,需要更新与之对应的ActivityRecord.state为RESUMED。
2:更新ActivityStack内部的mResumedActivity为启动完毕的ActivityRecord,表示现在处于启动状态的那个Activity已经发生了更改。
3:AMS做状态更新操作。
4:更新ActivityStack内部的firstActiveTime(首次激活此ActivityStack的时间)、lastActiveTime(最近一次激活时间)属性记录的时间。
5:其它操作。

源码

void setResumedActivityLocked(ActivityRecord r, String reason) {
        //mResumedActivity表示:在当前栈中处于Resume状态的Activity,也就是当前在屏幕中正在显示的那个Activity。
        //把待启动Activity对应的ActivityRecord赋值给mResumedActivity,表示待启动Activity已经启动完毕,现在处于启动状态的那个Activity已经发生了更改。
        mResumedActivity = r;
        
        //更改待启动Activity对应的ActivityRecord的状态为RESUMED。
        r.state = ActivityState.RESUMED;
        
        //当待启动Activity启动完毕后,通知AMS做状态更新操作。
        mService.setResumedActivityUncheckLocked(r, reason);
        
        final TaskRecord task = r.getTask();
        //更新ActivityStack内部的firstActiveTime、lastActiveTime属性记录的时间。
        task.touchActiveTime();
        //??
        mRecentTasks.addLocked(task);
    }

4.3.ActivityStack.setLaunchTime()

总结:“记录下执行Activity启动操作的时间点”。具体的可查看 App启动流程:为目标App启动做准备--1.2 小节


关于 “App进程内部操作”的分析就到这里了,有不对的地方希望大家在留言区批评指正,一起努力一起进步。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,198评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,663评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,985评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,673评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,994评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,399评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,717评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,407评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,112评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,371评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,891评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,255评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,881评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,010评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,764评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,412评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,299评论 2 260