Activity是如何显示出来的?(上)

如题所示,Activity是如何显示出来的呢?简单,调用startActivity就可以启动目标Activity了。很方便,但其实也隐藏了很多细节。startActivity后发生了什么事?怎么一个简单的接口就能启动一个界面,且该界面所在进程还未启动过。本篇文章承接《我是怎么把一个个App进程创建起来的》,描述接下来发生的事。

概述

想要启动一个Activity,首先得启动它的进程,由AMS将启动进程的需求发给Zygote,由这位大佬fork出一个进程,然后启动。启动的入口是ActivityThread类的main方法,分析从这里开始。

ActivityThread的main方法

我们总说UI的刷新是在主线程进行的,但却没找到相关主线程的痕迹。今天它来了,UI主线程就在此处。这里列出main方法关键代码进行分析。

//frameworks/base/core/java/android/app/ActivityThread.java
public static void main(String[] args) {

    ....
    //①创建一个Loop实体,用于消息处理
    Looper.prepareMainLooper();
    ....
    //②创建ActivityThread对象,然后在attach方法中会完成Application对象的初始化,然后调用Application的onCreate()方法
    ActivityThread thread = new ActivityThread();
    thread.attach(false, startSeq);
    //③获取Handler对象
    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }

    ....
    ④启动Loop,表示可以接收Handler发过来的消息
    Looper.loop();

}
复制代码

如上按照注释,main方法中做的事情主要有三件,创建Loop实体,获取Handler,用于消息处理,创建ActivityThread对象,然后调用attach方法完成Application的初始化。我们先看看attach方法做了什么事:

//frameworks/base/core/java/android/app/ActivityThread.java
private void attach(boolean system, long startSeq) {
    sCurrentActivityThread = this;
    mSystemThread = system;
    if (!system) {
        ViewRootImpl.addFirstDrawHandler(new Runnable() {
            @Override
            public void run() {
                //启动JIT编译器,开始编译
                ensureJitEnabled();
            }
        });
        
        //设置进程名
        android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                                                UserHandle.myUserId());
        RuntimeInit.setApplicationObject(mAppThread.asBinder());
        final IActivityManager mgr = ActivityManager.getService();
        try {
            mgr.attachApplication(mAppThread, startSeq);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
        // Watch for getting close to heap limit.
        //看app进程内存情况,如果太大则释放内存
        BinderInternal.addGcWatcher(new Runnable() {
            @Override public void run() {
                if (!mSomeActivitiesChanged) {
                    return;
                }
                Runtime runtime = Runtime.getRuntime();
                long dalvikMax = runtime.maxMemory();
                long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();
                //使用的内存超过最大内存的四分之三,则请求释放内存
                if (dalvikUsed > ((3*dalvikMax)/4)) {
                    if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024)
                            + " total=" + (runtime.totalMemory()/1024)
                            + " used=" + (dalvikUsed/1024));
                    mSomeActivitiesChanged = false;
                    try {
                        mgr.releaseSomeActivities(mAppThread);
                    } catch (RemoteException e) {
                        throw e.rethrowFromSystemServer();
                    }
                }
            }
        });
    } else {
    
        ....
    }
    
    ....

}
复制代码

应用进程调用的attach方法传入的第一个参数为false,所以我们这里主要看false分支的代码就好了。这里面主要做了如下几件事:

1.启动JIT编译器,开始编译; //这是啥,我也不清楚,后面再找时间补充学习
2.设置进程名;
3.通过ActivityManager获取AMS服务代理对象IActivityManager,通过它来完成一次跨进程操作,主要是用来绑定ApplicationThread对象;
4.内存使用检测,若发现使用的内存超过最大内存的四分之三,则申请进行内存释放;
复制代码

bind Application

这里还看不出Activity的显示相关,还需要进入AMS进行查看attachApplication方法:

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public final void attachApplication(IApplicationThread thread, long startSeq) {
    synchronized (this) {
        int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();
        final long origId = Binder.clearCallingIdentity();
        attachApplicationLocked(thread, callingPid, callingUid, startSeq);
        Binder.restoreCallingIdentity(origId);
    }
}
复制代码

这里又封装了一层,调用attachApplicationLocked方法:

private final boolean attachApplicationLocked(IApplicationThread thread,
        int pid, int callingUid, long startSeq) {
        
    ....
    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);
    ....
    
    
    // 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;
        }
    }
    
    ....
}
复制代码

attachApplicationLocked方法比较长,在进行bind之前,前面部分在进行一些app的准备工作。一切准备就绪,会回调ActivityThread对象本身的bindApplication方法进行绑定。接着如果这个进程有待显示的Activity在栈顶,则会调用ActivityStackSupervisor类的attachApplicationLocked方法进行显示。

realStartActivityLocked

/frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {

    ....
    try {
        if (realStartActivityLocked(activity, app,
                top == activity /* andResume */, true /* checkConfig */)) {
            didSomething = true;
        }
    } catch (RemoteException e) {
        Slog.w(TAG, "Exception in new application when starting activity "
                + top.intent.getComponent().flattenToShortString(), e);
        throw e;
    }
    ....
}
复制代码

最终调用realStartActivityLocked方法:

final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
        boolean andResume, boolean checkConfig) throws RemoteException {
        
    ...
    // Create activity launch transaction.
    final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,
            r.appToken);
    clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
            System.identityHashCode(r), r.info,
            // TODO: Have this take the merged configuration instead of separate global
            // and override configs.
            mergedConfiguration.getGlobalConfiguration(),
            mergedConfiguration.getOverrideConfiguration(), r.compat,
            r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
            r.persistentState, results, newIntents, mService.isNextTransitionForward(),
            profilerInfo));
    ...
    // Schedule transaction.
    mService.getLifecycleManager().scheduleTransaction(clientTransaction);
    ...
}
复制代码

该方法创建了一个加载Activity的事务,等一切状态就绪,调用ClientLifecycleManager类的scheduleTransaction方法开始处理事务。

处理启动Activity的事务

/frameworks/base/services/core/java/com/android/server/am/ClientLifecycleManager.java
void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
    final IApplicationThread client = transaction.getClient();
    transaction.schedule();
    if (!(client instanceof Binder)) {
        // If client is not an instance of Binder - it's a remote call and at this point it is
        // safe to recycle the object. All objects used for local calls will be recycled after
        // the transaction is executed on client in ActivityThread.
        transaction.recycle();
    }
}
复制代码

最终调用了ClientTransaction对象的schedule方法,ClientTransaction对象在上个方法中被创建,即上述所说的事务。回到ClientTransaction的实现:

frameworks/base/core/java/android/app/servertransaction/ClientTransaction.java
public void schedule() throws RemoteException {
    mClient.scheduleTransaction(this);
}
复制代码

mClient又是什么?这是一个IApplicationThread类型的变量,该变量在创建事务的时候被赋值:

public static ClientTransaction obtain(IApplicationThread client, IBinder activityToken) {
    ClientTransaction instance = ObjectPool.obtain(ClientTransaction.class);
    if (instance == null) {
        instance = new ClientTransaction();
    }
    instance.mClient = client;
    instance.mActivityToken = activityToken;

    return instance;
}
复制代码

兜兜转转,我们需要返回realStartActivityLocked方法中查看client到底是个啥:

final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,
            r.appToken);
复制代码

创建启动Activity事务时,传入了一个IApplicationThread引用,这只是个代理,真正的实现在ApplicationThread类中,这是ActivityThread类的内部类,看看具体实现:

frameworks/base/core/java/android/app/ActivityThread.java
public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
        ActivityThread.this.scheduleTransaction(transaction);
}
复制代码

这里直接调用ActivityThread父类的方法,发出一个处理事务的msg:

frameworks/base/core/java/android/app/ClientTransactionHandler.java
void scheduleTransaction(ClientTransaction transaction) {
    transaction.preExecute(this);
    sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}
复制代码

具体处理还是ActivityThread中:

public void handleMessage(Message msg) {

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

还未到终点,又是一个execute方法,进入看看:

frameworks/base/core/java/android/app/servertransaction/TransactionExecutor.java
public void execute(ClientTransaction transaction) {
    final IBinder token = transaction.getActivityToken();
    log("Start resolving transaction for client: " + mTransactionHandler + ", token: " + token);

    executeCallbacks(transaction);

    executeLifecycleState(transaction);
    mPendingActions.clear();
    log("End resolving transaction");
}

public void executeCallbacks(ClientTransaction transaction) {
    final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
    ....
    for (int i = 0; i < size; ++i) {
        final ClientTransactionItem item = callbacks.get(i);
        ....
        item.execute(mTransactionHandler, token, mPendingActions);
        item.postExecute(mTransactionHandler, token, mPendingActions);
        ....
    }
    ....
}
复制代码

这里如果直接进入到ClientTransactionItem类中,会发现并无具体实现,这就是个抽象类。item是从事务中获取的回调,还记得在realStartActivityLocked方法中创建事务的过程么?创建了事务之后,还做了一件事:

clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
                    System.identityHashCode(r), r.info,
                    // TODO: Have this take the merged configuration instead of separate global
                    // and override configs.
                    mergedConfiguration.getGlobalConfiguration(),
                    mergedConfiguration.getOverrideConfiguration(), r.compat,
                    r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
                    r.persistentState, results, newIntents, mService.isNextTransitionForward(),
                    profilerInfo));
复制代码

这里增加了一个LaunchActivityItem类的回调,而LaunchActivityItem正是继承ClientTransactionItem类,所以这里的execute方法应该是在LaunchActivityItem类中实现:

frameworks/base/core/java/android/app/servertransaction/LaunchActivityItem.java
public void execute(ClientTransactionHandler client, IBinder token,
        PendingTransactionActions pendingActions) {
    Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
    ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
            mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
            mPendingResults, mPendingNewIntents, mIsForward,
            mProfilerInfo, client);
    client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
    Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
复制代码

又回调了ActivityThread(继承ClientTransactionHandler抽象类)的handleLaunchActivity方法:

frameworks/base/core/java/android/app/ActivityThread.java
public Activity handleLaunchActivity(ActivityClientRecord r,
        PendingTransactionActions pendingActions, Intent customIntent) {
    ....
    final Activity a = performLaunchActivity(r, customIntent);
    ....
}
复制代码

真正处理Activity启动的地方

真正启动Activity的核心即将到来:

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ....
    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);
    
    ....
    mInstrumentation.callActivityOnPostCreate(activity, r.state);
    ....

}
复制代码

这里主要做了三件事:

1.通过Instrumentation类创建出activity;
2.调用activity的attach方法创建窗口,为onCreate方法做准备;
3.通过callActivityOnPostCreate方法,最终调用activity的onCreate方法,在该方法中,通过setContentView方法将activity具体的view树加载到窗口。
复制代码

到了这里,Activity还未真正显示出来,只是该做的准备都做好了,下一步就是将具体的view加载到窗口中进行显示。这部分内容留到下一章节分析。

结语

Activity的启动确实复杂,到现在也只是大概捋了个流程,并没有深入理解。在本章节中,大概分析了startActivity的流程。如果Activity所在进程是首次启动,则还需要通过AMS向Zygote进程发起进程创建的需求,然后在创建出来的子进程中,使用反射的方法,找到App的ActivityThread的main方法,并启动运行。

先掌握大概的流程框架,再逐步深入了解各个模块。下一个章节分析view的加载。

微信公众号

我在微信公众号也有写文章,更新比较及时,有兴趣者可以扫描如下二维码,或者微信搜索【Android系统实战开发】,关注有惊喜哦!

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章