浅谈Android之Activity相关介绍

来源:互联网 发布:照片变成素描的软件 编辑:程序博客网 时间:2024/05/29 09:08

4 Activity相关介绍

Activity是android四大组件之一,主要用于显示用户界面,通过上面的章节我们已经知道,App Client如果要向系统屏幕输出图形数据,需要通过Surface来实现,那在开发过程中,调用Activity的setContentView来设置自定义视图,这个视图的图形数据是如何关联到Surface的呢?接下去就对相关内容做简单介绍。

 

Android通过ActivityManagerService来统一管理所有App创建的Activity,通过

WindowManagerService来统一管理创建的窗口。

 

那App和AMS以及WMS三者是如何建立联系的呢?先看下面这张图:

 

从图上可以看出,每个Activity在AMS中会对应存在一个ActivityRecord,当AMS创建

ActivityRecord的同时,会通知WMS对应创建AppWindowToken,然后ViewRootImpl对应将Activity的Window和WMS的WindowState建立关联

 

接下去对这三部分做下简单介绍:

App

每个Activity都会内部关联一个Window(通过PolicyManager创建,对应PhoneWindow),window主要包含四个数据,依次是décor view,callback,window params和local window

Manager;décor view是window的关联视图,callback用来回调按键事件,windowparams则对应窗口的属性,Local WindowManager对应Activity的私有窗口管理,其实主要是在创建是传入Window并在Local Window Manager内部定义为Parent Window,从而使其默认与Activity对应的窗口绑定。

Activity关联的Window其实只是逻辑上的概念,它WMS的WindowState其实没半毛钱关系(除了window params数据)

Activity这边跟WMS建立联系,主要是通过ViewRootImpl来完成的,ViewRootImpl其实是一个控制类,它负责跟WMS通讯建立WindowState,并且管理ActivityWindow关联视图的相关操作,还有对窗口相关输入事件进行读取和转发。

 

ActivityManagerService

当App通过调用startActivity启动activity时,会在AMS创建一个对应的ActivityRecord,ActivityRecord被保存到TaskRecord,TaskRecord则被保存到ActivityStack,然后由于AMS会存在多个ActivityStack,所以又要存在ActivityStackSupervisor来进行管理,反过来讲,

AMS在接收到startActivity接着创建ActivityRecord的步骤肯定是这样的:

1)  先从ActivityStackSupervisor找到对应的ActivityStack

2)  然后根据Activity的launch mode找到或者创建所属的TaskRecord

3)  创建ActivityRecord并添加到TaskRecord

 

WindowManagerService

当AMS创建ActivityRecord时,会接着通知WMS创建与ActivityRecord对应的

AppWindowToken,AppWindowToken是parent token,Activity后续通过ViewRootImpl添加的WindowState都是作为子窗口放置到AppWindowToken对应的数据结构中的。

这样WMS就可以通过AppWindowToken来统一管理其所有子窗口了。

 

 

4.1 Activity启动之触发App进程创建

AMS和WMS的代码是非常复杂的,如果我们一开始阅读代码,就想把代码中的所有场景和细节都理解透是非常难的,所以一开始,我们尽量在不影响对代码主路线理解的前提下,定一个比较简单的场景,下面对Activity启动流程的介绍也是一样,基于如下前提:

1)  Activity launch mode为standard

2)  第一次启动需要new task

3)  没有set for result

 

一切从context.startActivity开始,context对应实现为ContextImpl,所以跳转到ContextImpl对应函数(Context的初始化过程,在后续Activity被创建的时候会介绍):

public void startActivity(Intent intent, Bundle options) {

       …….

       mMainThread.getInstrumentation().execStartActivity(

            getOuterContext(), mMainThread.getApplicationThread(), null,

            (Activity)null, intent, -1, options);

    }

 

mMainThread对应ActivityThread,接着调用instrumentation.execStartActivity:

   public ActivityResult execStartActivity(

            Context who, IBinder contextThread, IBinder token, Activity target,

            Intent intent, int requestCode, Bundle options, UserHandle user) {

        ……..

        try {

            int result = ActivityManagerNative.getDefault()

                .startActivityAsUser(whoThread, who.getBasePackageName(), intent,

                        intent.resolveTypeIfNeeded(who.getContentResolver()),

                        token, target != null ? target.mEmbeddedID : null,

                        requestCode, 0, null, options, user.getIdentifier());

            checkStartActivityResult(result, intent);

        } catch (RemoteException e) {

        }

        return null;

    }

 

ActivityManagerNative是一个代理类,负责连接ActivityManagerService,所以上述代码就通过RPC跑到了AMS里头:

    public final int startActivityAsUser(IApplicationThread caller, String callingPackage,

            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int reques,

            int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {

        ……

        return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,

                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,

                profilerInfo, null, null, options, userId, null, null);

    }

 

接着看ActivityStackSupervisor.startActivityMayWait:

final int startActivityMayWait(IApplicationThread caller, int callingUid,

            String callingPackage, Intent intent, String resolvedType,

            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,

            IBinder resultTo, String resultWho, int requestCode, int startFlags,

            ProfilerInfo profilerInfo, WaitResult outResult, Configuration config,

            Bundle options, int userId, IActivityContainer iContainer, TaskRecord inTask) {

           ……..

        boolean componentSpecified = intent.getComponent() != null;

 

        // Don't modify the client's object!

        intent = new Intent(intent);

 

        // Collect information about the target of the Intent.

        ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags,

                profilerInfo, userId);

 

            ……..

 

            int res = startActivityLocked(caller, intent, resolvedType, aInfo,

                    voiceSession, voiceInteractor, resultTo, resultWho,

                    requestCode, callingPid, callingUid, callingPackage,

                    realCallingPid, realCallingUid, startFlags, options,

                    componentSpecified, null, container, inTask);

            ……..

            return res;

        }

    }

 

这个函数先通过调用resolveActivity并传入Intent从PMS拿到ActivityInfo,接着调用

startActivityLocked:

final int startActivityLocked(IApplicationThread caller,

            Intent intent, String resolvedType, ActivityInfo aInfo,

            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,

            IBinder resultTo, String resultWho, int requestCode,

            int callingPid, int callingUid, String callingPackage,

            int realCallingPid, int realCallingUid, int startFlags, Bundle options,

            boolean componentSpecified, ActivityRecord[] outActivity, ActivityContainer container,

            TaskRecord inTask) {

        int err = ActivityManager.START_SUCCESS;

        …….

        ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,

                intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,

                requestCode, componentSpecified, this, container, options);

        …..

        err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,

                startFlags, true, options, inTask);

        ….

        return err;

    }

 

Activity是针对App来说的,在AMS中,Activity对应的数据结构为ActivityRecord,所以函数先要为启动的Activity创建ActivityRecord,那这里会还有个问题,ActivityRecord是AMS本地的数据,那在WMS和APP端如何跨进程关联?接着看ActivityRecord的构造函数,会创建一个token:

appToken = new Token(this);

 

Token是ActivityRecord的内部类,看这个类的定义:

static class Token extends IApplicationToken.Stub

 

明白了,这是一个native binder,拿它作为ActivityRecord的唯一标识再适合不过了(不明白?回过头重温第二章节关于binder的介绍)

 

回到startActivityLocked继续往下看,在ActivityRecord创建好后,接着调用

startActivityUncheckedLocked:

//ActivityStackSupervisor.java

final int startActivityUncheckedLocked(ActivityRecord r, ActivityRecord sourceRecord,

            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags,

            boolean doResume, Bundle options, TaskRecord inTask) {

        ………

        // Should this be considered a new task?

        if (r.resultTo == null && inTask == null && !addingToTask

                && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {

            if (isLockTaskModeViolation(reuseTask)) {

                Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r);

                return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;

            }

            newTask = true;

            targetStack = adjustStackFocus(r, newTask);

            if (!launchTaskBehind) {

                targetStack.moveToFront("startingNewTask");

            }

            if (reuseTask == null) {

                r.setTask(targetStack.createTaskRecord(getNextTaskId(),

                        newTaskInfo != null ? newTaskInfo : r.info,

                        newTaskIntent != null ? newTaskIntent : intent,

                        voiceSession, voiceInteractor, !launchTaskBehind /* toTop */),

                        taskToAffiliate);

                if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r + " in new task " +

                        r.task);

            } else {

                r.setTask(reuseTask, taskToAffiliate);

            }

            if (!movedHome) {

                if ((launchFlags &

                        (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME))

                        == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME)) {

                    // Caller wants to appear on home activity, so before starting

                    // their own activity we will bring home to the front.

                    r.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);

                }

            }

        }

        ………

        targetStack.mLastPausedActivity = null;

        targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);

        if (!launchTaskBehind) {

            // Don't set focus on an activity that's going to the back.

            mService.setFocusedActivityLocked(r, "startedActivity");

        }

        return ActivityManager.START_SUCCESS;

    }

 

这个函数先调用adjustStackFocus从ActivityStackSupervisor中拿到对应的ActivityStack,接着调用targetStack.moveToFront将当前ActivityStack切换到mStacks列表的顶端,mStacks其实是ActivityStack列表,它对应的其实是activityDisplay.mStacks,也就是说它对应Display可显示的所有ActivityStack,ActivityStack在mStacks中索引越高,显示越靠前,

 

所以targetStack.moveToFront的代码很简单:

mStacks.remove(this);

mStacks.add(this);

 

删除旧索引,重新添加到最后,即可将当前ActivityStack切换到Display最前端显示。

 

接着调用ActivityStack.createTaskRecord创建TaskRecord并添加到ActivityStack, TaskRecord在构造时,会通过getNextTaskId获取并传入唯一的task id,这个id的分配由ActivityStackSupervisor统一管理;接着将新创建的TaskRecord通过setTask设置到ActivityRecord里头,不过这里还未将ActivityRecord添加到TaskRecord,接着看targetStack.startActivityLocked:

//ActivityStack.java

Final void startActivityLocked(ActivityRecord r, boolean newTask,

            boolean doResume, boolean keepCurTransition, Bundle options) {

        TaskRecord rTask = r.task;

        ……..

        task = r.task;

        task.addActivityToTop(r);

        task.setFrontOfTask();

 

        r.putInHistory();

        if (!isHomeStack() || numActivities() > 0) {

            // We want to show the starting preview window if we are

            // switching to a new task, or the next activity's process is

            // not currently running.

            boolean showStartingIcon = newTask;

            ProcessRecord proc = r.app;

            if (proc == null) {

              proc = mService.mProcessNames.get(r.processName, r.info.applicationInfo.uid);

            }

            if (proc == null || proc.thread == null) {

                showStartingIcon = true;

            }

            ………

            mWindowManager.addAppToken(task.mActivities.indexOf(r),

                    r.appToken, r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,

                    (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId,

                    r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind);

            boolean doShow = true;

         }

        ……..

        if (doResume) {

            mStackSupervisor.resumeTopActivitiesLocked(this, r, options);

        }

    }

 

先调用addActivityToTop将Activity加到所属TaskRecord的顶端,由于我们不属于Home stack并且numActivities是肯定大于0的,所以这里肯定为true,接着调用WMS. addAppToken让WMS为新添加的ActivityRecord创建对应的AppWindowToken,这是一个RPC调用,直接跳到WMS对应函数:

//WindowManagerService.java

 @Override

    public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,

            int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId,

            int configChanges, boolean voiceInteraction, boolean launchTaskBehind) {

        ……..

        synchronized(mWindowMap) {

            AppWindowToken atoken = findAppWindowToken(token.asBinder());

            if (atoken != null) {

                Slog.w(TAG, "Attempted to add existing app token: " + token);

                return;

            }

            atoken = new AppWindowToken(this, token, voiceInteraction);

            atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;

            atoken.groupId = taskId;

            atoken.appFullscreen = fullscreen;

            atoken.showWhenLocked = showWhenLocked;

            atoken.requestedOrientation = requestedOrientation;

            atoken.layoutConfigChanges = (configChanges &

                    (ActivityInfo.CONFIG_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION)) != 0;

            atoken.mLaunchTaskBehind = launchTaskBehind;

            if (true || DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, "addAppToken: " + atoken

                    + " to stack=" + stackId + " task=" + taskId + " at " + addPos);

 

            Task task = mTaskIdToTask.get(taskId);

            if (task == null) {

                createTask(taskId, stackId, userId, atoken);

            } else {

                task.addAppToken(addPos, atoken);

            }

 

            mTokenMap.put(token.asBinder(), atoken);

 

            // Application tokens start out hidden.

            atoken.hidden = true;

            atoken.hiddenRequested = true;

 

            //dump();

        }

    }

 

先为ActivityRecord创建对应的AppWindowToken, 接着创建对应的Task并保存到TaskStack,最后将ActivityRecord的appToken作为key,对应的AppWindowToken作为value保存到

mTokenMap中。

 

接着回到ActivityStack. startActivityLocked(),在调用mWindowManager.addAppToken添加

AppWindowToken成功后,继续调用

mStackSupervisor.resumeTopActivitiesLocked(this,r, options):

//ActivityStackSupervisor.java

boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target,

            Bundle targetOptions) {

        if (targetStack == null) {

            targetStack = getFocusedStack();

        }

        // Do targetStack first.

        boolean result = false;

        if (isFrontStack(targetStack)) {

            result = targetStack.resumeTopActivityLocked(target, targetOptions);

        }

        ……..

        return result;

    }

 

先看isFrontStack的代码:

   boolean isFrontStack(ActivityStack stack) {

        final ActivityRecord parent = stack.mActivityContainer.mParentActivity;

        if (parent != null) {

            stack = parent.task.stack;

        }

        ArrayList<ActivityStack> stacks = stack.mStacks;

        if (stacks != null && !stacks.isEmpty()) {

            return stack == stacks.get(stacks.size() - 1);

        }

        return false;

    }

 

由于在创建TaskRecord前,已经调用ActivityStack.movetofront将ActivityStack添加到mStacks的末端,所以这边返回肯定为true

 

接着走到targetStack.resumeTopActivityLocked,这个函数就做了重入限制,接着直接调用

resumeTopActivityInnerLocked:

final boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {

       …….

      // Find the first activity that is not finishing.

        final ActivityRecord next = topRunningActivityLocked(null);

 

        ……..

        if (mResumedActivity != null) {

            if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Pausing " + mResumedActivity);

            pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);

        }

        ……

        ActivityStack lastStack = mStackSupervisor.getLastStack();

        if (next.app != null && next.app.thread != null) {

           ……

        } else {

           ……

            mStackSupervisor.startSpecificActivityLocked(next, true, true);

        }

        return true;

   

 

先调用topRunningActivityLocked从ActivityStack的TaskRecord列表中找到最顶端未finish的ActivityRecord,也就是上面我们新添加的ActivityRecord,接着调用startPausingLocked将pause当前resumed的Activity,startPausingLocked内部,会将mResumedActivity置为null,接着判断next.app是否为空,因为Activity是新创建的,所以其对应的ProcessRecord进程还未被创建,所以这里肯定为空,代码接着走到mStackSupervisor.startSpecificActivityLocked:

//ActivityStackSupervisor.java

void startSpecificActivityLocked(ActivityRecord r,

            boolean andResume, boolean checkConfig) {

        ProcessRecord app = mService.getProcessRecordLocked(r.processName,

                r.info.applicationInfo.uid, true);

        r.task.stack.setLaunchTime(r);

        if (app != null && app.thread != null) {

                …….

                realStartActivityLocked(r, app, andResume, checkConfig);

                return;

            } catch (RemoteException e) {

                Slog.w(TAG, "Exception when starting activity "

                        + r.intent.getComponent().flattenToShortString(), e);

            }

        }

        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,

                "activity", r.intent.getComponent(), false, false, true);

    }

 

先判断Activity对应的ProcessRecord是否已经创建,如果创建了,调用realStartActivityLocked做后续启动操作,否则,调用mService.startProcessLocked启动Activity对应进程:

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

        long startTime = SystemClock.elapsedRealtime();

        ProcessRecord app;

        ……

        if (app == null) {

            app = newProcessRecordLocked(info, processName, isolated, isolatedUid);

            if (app == null) {

                Slog.w(TAG, "Failed making new process record for "

                        + processName + "/" + info.uid + " isolated=" + isolated);

                return null;

            }

            app.crashHandler = crashHandler;

            mProcessNames.put(processName, app.uid, app);

            if (isolated) {

                mIsolatedProcesses.put(app.uid, app);

            }

        }

        ……

startProcessLocked(

                app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);

        return (app.pid != 0) ? app : null;

    }

 

先通过newProcessRecordLocked创建ProcessRecord,接着添加到mProcessNames这个Map中,最后调用startProcessLocked:

private final void startProcessLocked(ProcessRecord app, String hostingType,

            String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {

app.gids = gids;

            app.requiredAbi = requiredAbi;

            ……..

            Process.ProcessStartResult startResult = Process.start(entryPoint,

                    app.processName, uid, uid, gids, debugFlags, mountExternal,

                    app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,

                    app.info.dataDir, entryPointArgs);

            ……..

app.setPid(startResult.pid);

……

}

 

调用Process.start启动进程,进程的uid和gids都是从PMS那里获取的,Process.start内部通过连上Zygote fork出即将启动的进程,在启动成功后,将新进程的pid设置到ProcessRecord

到目前为止,AMS这边的调用就结束了,接下去,代码运行场景切换到新创建的App进程那边。

 

4.2 Activity启动之初始化

ActivityThread 是Android App的入口和事件传输中心,入口嘛,很好理解,进程被创建后,默认会执行ActivityThread.main函数;那事件传输中心是啥意思:

1)  main函数在最后,会调用Looper.loop();阻塞主线程,也就说后续如果代码要在主线程跑,都要通过ActivityThread.mH这个handle来发消息来触发

2)  谁来触发呢?当然是AMS,那ActivityThread必然会存在一个native binder,对应

ApplicationThreadmAppThread

3)  很多组件事件要触发回调,那ActivityThread必然要保存已经创建的组件信息,然后在收到对应RPC调用时做相应的回调操作

 

当然它还包含了App运行所必须的数据,比如LoadedApk,用于Apk相关资源的加载。

 

还有Instrumentation,这个类相当于我们App运行的仪器显示表一样,我们能够通过它实现对App组件函数和系统函数的调用情况做跟踪,它的实现原理很简单,就是代理调用,然后我们可以在其代理函数内实现我们想要的逻辑;我们可以在AndroidManifest配置我们自定义的Instrumentation实现类,如果没有配置,ActivityThread在初始化时就会使用默认的

Instrumentation实现,默认实现几乎啥也没做,就是纯代理。

 

接下去通过代码来详细介绍。

进程起来后,执行ActivityThread.main入口函数:

    public static void main(String[] args) {

        ……

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

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

    }

 

先创建ActivityThread,接着调用attach,最后调用Looper.loop进入消息循环

App进程起来了,肯定要第一时间通知到AMS,接着看attach

  private void attach(boolean system) {

        sCurrentActivityThread = this;

        mSystemThread = system;

        if (!system) {

            …….

            final IActivityManager mgr = ActivityManagerNative.getDefault();

            try {

                mgr.attachApplication(mAppThread);

            } catch (RemoteException ex) {

                // Ignore

            }

        ……

}

 

调用mgr.attachApplication并传入mAppThread,mAppThread对应类型为ApplicationThread,其派生自ApplicationThreadNative,ApplicationThread是一个native binder,AMS通过保存其对应的binder proxy来与ActivityThread建立RPC通信

 

接着把代码执行环境切换到AMS,看mgr.attachApplication:

    public final void attachApplication(IApplicationThread thread) {

        synchronized (this) {

            int callingPid = Binder.getCallingPid();

            final long origId = Binder.clearCallingIdentity();

            attachApplicationLocked(thread, callingPid);

            Binder.restoreCallingIdentity(origId);

        }

    }

 

获取调用进程pid,接着调用attachApplicationLocked:

  private final boolean attachApplicationLocked(IApplicationThread thread,

            int pid) {

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

        if (pid != MY_PID && pid >= 0) {

            synchronized (mPidsSelfLocked) {

                app = mPidsSelfLocked.get(pid);

            }

        } else {

            app = null;

        }

        ……

        app.makeActive(thread, mProcessStats);

        app.curAdj = app.setAdj = -100;

        app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;

        app.forcingToForeground = null;

        updateProcessForegroundLocked(app, false, false);

        app.hasShownUi = false;

        app.debugging = false;

        app.cached = false;

        app.killedByAm = false;

        ……

ProfilerInfo profilerInfo = profileFile == null ? null

                    : new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop);

            thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,

                    profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,

                    app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,

                    isRestrictedBackupMode || !normalMode, app.persistent,

                    new Configuration(mConfiguration), app.compat,

                    getCommonServicesLocked(app.isolated),

                    mCoreSettingsObserver.getCoreSettingsLocked());

            updateLruProcessLocked(app, false, null);

            app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();

        }

        ……

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

            }

        }

        ……

        return true;

    }

 

先根据pid从mPidsSelfLocked从拿到对应的ProcessRecord,然后调用makeActive设置

ApplicationThread,接着调用thread.bindApplication向ActivityThread反馈attachApplication结果,最后调用mStackSupervisor.attachApplicationLocked(app)继续启动ActivityRecord对应的Activity。

 

先看thread.bindApplication,RPC调用,代码环境切到App:

//ActivityThread.java

//class ApplicationThread

  public final void bindApplication(String processName, ApplicationInfo appInfo,

                List<ProviderInfo> providers, ComponentName instrumentationName,

                ProfilerInfo profilerInfo, Bundle instrumentationArgs,

                IInstrumentationWatcher instrumentationWatcher,

                IUiAutomationConnection instrumentationUiConnection, int debugMode,

                boolean enableOpenGlTrace, boolean isRestrictedBackupMode, boolean persistent,

                Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services,

                Bundle coreSettings) {

            ……

            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.enableOpenGlTrace = enableOpenGlTrace;

            data.restrictedBackupMode = isRestrictedBackupMode;

            data.persistent = persistent;

            data.config = config;

            data.compatInfo = compatInfo;

            data.initProfilerInfo = profilerInfo;

            sendMessage(H.BIND_APPLICATION, data);

        }

 

先创建AppBindData对象,用于保存App全局绑定的数据,包括进程名,ApplicationInfo,还有LoadedApk,创建好后,给mH发送BIND_APPLICATION消息,mH收到消息后,紧跟着执行handleBindApplication:

//ActivityThread.java

  private void handleBindApplication(AppBindData data) {

        mBoundApplication = data;

        mConfiguration = new Configuration(data.config);

        mCompatConfiguration = new Configuration(data.config);

        ……

        data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);

        ……

        if (data.instrumentationName != null) {

            ……

        } else {

            mInstrumentation = new Instrumentation();

        }

 

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

            mInitialApplication = app;

            ……

            try {

                mInstrumentation.callApplicationOnCreate(app);

            }

            ……

    }

 

先将AppBindData保存到mBoundApplication,接着基于ApplicationInfo,调用

getPackageInfoNoCheck创建LoadedApk保存到data.info;假定我们没有在AndroidManifest配置instrumentation,这里直接创建默认的Instrumentation实例保存到mInstrumentation,最后通过调用LoadedApk的makeApplication创建app对应的Application对象,最后调用大家都非常熟悉的Application.onCreate, App开发所提供的入口函数就这样被回调了。

 

那就这样结束了?当然不是,别忘了AMS在调用bindApplication之后,还调用了

mStackSupervisor.attachApplicationLocked(app),那个之前被我们加到TaskRecord的栈顶的

ActivityRecord还在等待启动呢

 

所以,接下去将代码运行环境切回AMS,继续看attachApplicationLocked的实现:

//ActivityStackSupervisor.java

boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {

        final String processName = app.processName;

        boolean didSomething = false;

        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {

            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;

            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {

                final ActivityStack stack = stacks.get(stackNdx);

                if (!isFrontStack(stack)) {

                    continue;

                }

                ActivityRecord hr = stack.topRunningActivityLocked(null);

                if (hr != null) {

                    if (hr.app == null && app.uid == hr.info.applicationInfo.uid

                            && processName.equals(hr.processName)) {

                        try {

                            if (realStartActivityLocked(hr, app, true, true)) {

                                didSomething = true;

                            }

                        } catch (RemoteException e) {

                        ……

                        }

        }

        ……

        return didSomething;

}

 

还记得之前在ActivityStackSupervisor.startActivityUncheckedLocked中我们将新添加的

ActivityRecord对应的ActivityStack.movetofront了吗?这个函数其实就是从Display的mTasks拿到front task,接着再通过topRunningActivityLocked拿到ActivityStack的topActivityRecord,即之前添加的,也就是App即将要启动的Activity

 

到这里,准备工作基本已经结束,接下去就开始真正的启动了,什么是真正的启动?

1)  通过RPC调用通知WMS这个Activity要显示了

2)  设置AMS中对应ActivityRecord的内部数据

3)  通过RPC调用通知ActivityThread,可以创建Activity并执行onCreate回调了

 

上述操作都是在realStartActivityLocked中完成的:

//ActivityStackSupervisor.java 

final boolean realStartActivityLocked(ActivityRecord r,

            ProcessRecord app, boolean andResume, boolean checkConfig)

            throws RemoteException {

        ……

        r.startFreezingScreenLocked(app, 0);

        if (false) Slog.d(TAG, "realStartActivity: setting app visibility true");

        mWindowManager.setAppVisibility(r.appToken, true);

        ……

        r.app = app;

        app.waitingToKill = null;

        r.launchCount++;

        r.lastLaunchTime = SystemClock.uptimeMillis();

        ……

        int idx = app.activities.indexOf(r);

        if (idx < 0) {

            app.activities.add(r);

        }

        mService.updateLruProcessLocked(app, true, null);

        mService.updateOomAdjLocked();

 

        final ActivityStack stack = r.task.stack;

        try {

            if (app.thread == null) {

                throw new RemoteException();

            }

            ……

            mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());

            r.sleeping = false;

            r.forceNewConfig = false;

            ……

            app.hasShownUi = true;

            app.pendingUiClean = true;

            ……

            app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,

                    System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),

                    r.compat, r.launchedFromPackage, r.task.voiceInteractor, app.repProcState,

                    r.icicle, r.persistentState, results, newIntents, !andResume,

                    mService.isNextTransitionForward(), profilerInfo);

             ……

            }

 

        }

 

        ……

        r.launchFailed = false;

        if (stack.updateLRUListLocked(r)) {

            Slog.w(TAG, "Activity " + r

                  + " being launched, but already in LRU list");

        }

 

        if (andResume) {

            // As part of the process of launching, ActivityThread also performs

            // a resume.

            stack.minimalResumeActivityLocked(r);

        } else {

            r.state = ActivityState.STOPPED;

            r.stopped = true;

        }

        ……

        return true;

    }

 

这个函数先调用mWindowManager.setAppVisibility将传入r.appToken对应的

AppWindowToken设置为显示状态,接着将ProcessRecord保存到r.app, 然后调用

app.thread.scheduleLaunchActivity通知App端创建Activity,最后由于androidResume为true,执行stack.minimalResumeActivityLocked(r);

void minimalResumeActivityLocked(ActivityRecord r) {

        r.state = ActivityState.RESUMED;

        if (DEBUG_STATES) Slog.v(TAG, "Moving to RESUMED: " + r

                + " (starting new instance)");

        r.stopped = false;

        mResumedActivity = r;

        r.task.touchActiveTime();

        mService.addRecentTaskLocked(r.task);

        completeResumeLocked(r);

        mStackSupervisor.checkReadyForSleepLocked();

        setLaunchTime(r);

}

 

将ActivityRecord的状态设置为RESUMED,接着将其设置为mResumedActivity

看到这里可能会有一个疑问,没看到哪里调用app.thread.scheduleResumeActivity啊,这里怎么就直接把状态设置为resume了呢?那是因为对于Activity第一次创建启动,

在app.thread.scheduleLaunchActivity被调用后,App端onCreate,onStart和onResume是顺序直接调用的,无须AMS这边触发onResume,后续分析这块代码就会非常清楚

 

好吧,接着让我们再次把运行环境切到App端

 

4.3 Activity启动之Activity和窗口的创建

Activity肯定要attach一个窗口,即PhoneWindow, 但是有一点要注意,这个窗口是Activity在App的本地窗口,它主要提供:

1)  设置窗口属性(Window Parameters)

2)  对一些事件处理,实现窗口的默认行为

3)  实现Décor View,Activity可以将自己的ContentView 添加到Décor View之上

4)  关联App进程的Local Window Manager

 

前三项最终都是为设置窗口形态,内容以及一些行为的默认处理方式,但是这些数据能够展示的前提是,要连上WMS,然后将其输出到WMS

 

那如何连上WMS,就是通过第四项设置的Local Window Manager,接下去介绍跟其相关的两个类:

§  WindowManagerGlobal implements WindowManager

App进程全局窗口管理类,它负责管理App进程内所有要添加到WMS的窗口视图,添加方法为addView(View view, ViewGroup.LayoutParams params,Display display,Window parentWindow)

§  WindowManagerImpl implements WindowManager

WindowMananagerGlobal是全局的,那我们如果要关联一些非全局的数据咋办?

WindowManagerImpl就是为了解决这个问题,它在创建的时候,会关联特定的Display或者Window,然后内部实现都是代理转发到WindowMananagerGlobal。

 

上述第四项描述的Local WindowManager其实就是WindowManagerImpl实例,只不过初始化WindowManagerImpl时传入了Window作为关联。

 

接下去我们继续基于代码层面来分析,4.2结束的时候,AMS调用

app.thread.scheduleLaunchActivity来通知App端启动对应Activity,接着ActivityThread.

scheduleLaunchActivity被RPC调用:

  public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,

                ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,

                String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state,

                PersistableBundle persistentState, List<ResultInfo> pendingResults,

                List<ReferrerIntent> pendingNewIntents, boolean notResumed, boolean isForward,

                ProfilerInfo profilerInfo) {

 

            updateProcessState(procState, false);

 

            ActivityClientRecord r = new ActivityClientRecord();

 

            r.token = token;

            r.ident = ident;

            r.intent = intent;

            r.referrer = referrer;

            r.voiceInteractor = voiceInteractor;

            r.activityInfo = info;

            r.compatInfo = compatInfo;

            r.state = state;

            r.persistentState = persistentState;

 

            r.pendingResults = pendingResults;

            r.pendingIntents = pendingNewIntents;

 

            r.startsNotResumed = notResumed;

            r.isForward = isForward;

 

            r.profilerInfo = profilerInfo;

 

            updatePendingConfiguration(curConfig);

 

            sendMessage(H.LAUNCH_ACTIVITY, r);

 

先创建ActivityClientRecord,用于在ActivityThread记录要新创建的Activity相关数据,包括token,接着发送LAUNCH_ACTIVITY消息到mH,mH收到消息后,对应调用handleLaunchActivity

  private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {

        ……

        // Initialize before creating the activity

        WindowManagerGlobal.initialize();

 

        Activity a = performLaunchActivity(r, customIntent);

 

        if (a != null) {

            r.createdConfig = new Configuration(mConfiguration);

            Bundle oldState = r.state;

            handleResumeActivity(r.token, false, r.isForward,

                    !r.activity.mFinished && !r.startsNotResumed);

            ……

        } else {

            ……

        }

    }

 

WindowManagerGlobal.initialize()其实就是内部初始化对WMS的连接,接着调用

performLaunchActivity,最后调用handleResumeActivity。

 

先看performLaunchActivity:

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {

        ……

        ActivityInfo aInfo = r.activityInfo;

        if (r.packageInfo == null) {

            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,

                    Context.CONTEXT_INCLUDE_CODE);

        }

 

        ComponentName component = r.intent.getComponent();

        if (component == null) {

            component = r.intent.resolveActivity(

                mInitialApplication.getPackageManager());

            r.intent.setComponent(component);

        }

 

        if (r.activityInfo.targetActivity != null) {

            component = new ComponentName(r.activityInfo.packageName,

                    r.activityInfo.targetActivity);

        }

 

        Activity activity = null;

        try {

            java.lang.ClassLoader cl = r.packageInfo.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) {

            ……

        }

        try {

            Application app = r.packageInfo.makeApplication(false, mInstrumentation);

            ……

            if (activity != null) {

                Context appContext = createBaseContextForActivity(r, activity);

                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());

                Configuration config = new Configuration(mCompatConfiguration);

                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "

                        + r.activityInfo.name + " with config " + config);

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

 

                if (customIntent != null) {

                    activity.mIntent = customIntent;

                }

                r.lastNonConfigurationInstances = null;

                activity.mStartedActivity = false;

                int theme = r.activityInfo.getThemeResource();

                if (theme != 0) {

                    activity.setTheme(theme);

                }

 

                activity.mCalled = false;

                if (r.isPersistable()) {

                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);

                } else {

                    mInstrumentation.callActivityOnCreate(activity, r.state);

                }

                if (!activity.mCalled) {

                    throw new SuperNotCalledException(

                        "Activity " + r.intent.getComponent().toShortString() +

                        " did not call through to super.onCreate()");

                }

                r.activity = activity;

                r.stopped = true;

                if (!r.activity.mFinished) {

                    activity.performStart();

                    r.stopped = false;

                }

                ……

 

            r.paused = true;

            mActivities.put(r.token, r);

        }

        ……

        return activity;

    }

 

流程很清晰,顺序如下:

1)  先调用mInstrumentation.newActivity创建Activity

2)  调用activity.attach初始化activity

3)  如果有配置默认主题,则调用activity.setTheme(theme);设置主题数据

4)  调用mInstrumentation.callActivityOnCreate,Activity.onCreate被调用

5)  调用activity.performStart();,Activity.onStart被调用

6)  最后调用mActivities.put(r.token, r)将新创建的ActivityClientRecord对象添加到mActivities这个map中,key为AMS中对应ActivityRecord的appToken.

 

重点看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) {

        attachBaseContext(context);

 

        mFragments.attachActivity(this, mContainer, null);

 

        mWindow = PolicyManager.makeNewWindow(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;

    }

 

初始化一堆东西,这里主要介绍窗口相关的:

1)  先调用mWindow = PolicyManager.makeNewWindow(this);创建PhoneWindow实例

2)  调用mWindow.setCallback(this);将Activity设置为窗口回调

3)  调用mWindow.setWindowManager,传入Activity(实际为ActivityRecord)对应的appToken

 

因为PhoneWindow没有实现setWindowManager,所以走Window类的默认实现:

  public void setWindowManager(WindowManager wm, IBinder appToken, String appName,

            boolean hardwareAccelerated) {

        mAppToken = appToken;

        mAppName = appName;

        mHardwareAccelerated = hardwareAccelerated

                || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);

        if (wm == null) {

            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);

        }

        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);

}

 

保存appToken,接着调用WindowManagerImpl. createLocalWindowManager:

public WindowManagerImpl createLocalWindowManager(Window parentWindow) {

        return new WindowManagerImpl(mDisplay, parentWindow);

}

 

其实就是基于mDisplay和Window对象创建了一个WindowManagerImpl实例。

 

到这里,performLaunchActivity基本算结束了,接着看handleResumeActivity:

final void handleResumeActivity(IBinder token,

            boolean clearHide, boolean isForward, boolean reallyResume) {

        ……

        ActivityClientRecord r = performResumeActivity(token, clearHide);

        if (r != null) {

            final Activity a = r.activity;

            ……

            if (r.window == null && !a.mFinished && willBeVisible) {

                r.window = r.activity.getWindow();

                View decor = r.window.getDecorView();

                decor.setVisibility(View.INVISIBLE);

                ViewManager wm = a.getWindowManager();

                WindowManager.LayoutParams l = r.window.getAttributes();

                a.mDecor = decor;

                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;

                l.softInputMode |= forwardBit;

                if (a.mVisibleFromClient) {

                    a.mWindowAdded = true;

                    wm.addView(decor, l);

                }

                ……

           }

}

 

先调用performResumeActivity,执行Activity.onResume,接着,从activityattach的Window中,依次拿到décor view,WindowManager和WindowManager.LayoutParams,然后将l.type设置为TYPE_BASE_APPLICATION,最后,调用wm.addView(decor, l)

 

到这里,Activity生命周期的那几个函数基本走完了,剩下就是将窗口视图添加到WMS并且完成跟Surface的绑定,这一切都是通过wm.addView(decor, l)来触发并完成的

 

0 0