Android c/s模式分析Activity启动机制

android中大家经常要接触Activity,比如startActivity或者在Activity的生命周期函数onResume,onPause中做一些事情,既然Activity很重要那我们就来从源码来分析下Activity启动机制

涉及到的类

先看图


Activity启动涉及到的类.png

我以server,client,server与client桥接者三个维度对这些类进行了一个划分。
为啥是这三个维度呢?因为应用程序进程在与系统进程之间进行通信的时候其实它就是一个c/s的模式,系统进程被称为server端,应用程序进程称为client端,当然了android中进程之间的通信用的是binder机制,c与s之间进行通信需要定义一些协议,因此就出现了server与client桥接者。

那我们通过一张图来先对Activity启动有一个大概了解


c/s交互.png

从上图可知:启动一个Activity,就是client进程与server进程之间进行交互的一个过程,client进程通过ActivityManagerNative给server进程发送启动request,server进程中的ActivityManagerService处理完毕后通过ApplicationThread给Client进程response

那我们就从client给server发送request, server处理request,
server给client发送response, client处理response来进行分析

client给server发送request

那我们就先找一个发起启动命令的入口activity.startActivity(intent)方法,那我们就从这个方法入手开始分析

public void startActivity(Intent intent) {
    this.startActivity(intent, null);
}

public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
    if (mParent == null) {
        Instrumentation.ActivityResult ar =
            mInstrumentation.execStartActivity(
                this, mMainThread.getApplicationThread(), mToken, this,
                intent, requestCode, options);
        if (ar != null) {
            mMainThread.sendActivityResult(
                mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                ar.getResultData());
        }
    }
        ......省略代码
}

上面代码展示activity.startActivity(intent)方法最终是调用mInstrumentation.execStartActivity方法来进行启动的,那我们来看这方法

 public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, Activity target,
        Intent intent, int requestCode, Bundle options) {
    IApplicationThread whoThread = (IApplicationThread) contextThread;
    ......省略代码
    try {
        intent.migrateExtraStreamToClipData();
        intent.prepareToLeaveProcess();
        int result = ActivityManagerNative.getDefault()
            .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) {
    }
    return null;
}

上面代码中出现了ActivityManagerNative这个类,这个类是client给server端的ActivityManagerService发送命令的桥接者,ActivityManagerNative.getDefault() .startActivity其实最终通过binder机制调用ActivityManagerServicestartActivity方法

server处理request

现在client端的命令server端已经收到了,那来看下ActivityManagerServicestartActivity方法

@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle options) {
    return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
        resultWho, requestCode, startFlags, profilerInfo, options,
        UserHandle.getCallingUserId());
}

@Override
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {
    enforceNotIsolatedCaller("startActivity");
    userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
            false, ALLOW_FULL_ONLY, "startActivity", null);
    // TODO: Switch to user app stacks here.
    return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
            resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
            profilerInfo, null, null, options, userId, null, null);
}

mStackSupervisor.startActivityMayWait这行代码表明最终是调用ActivityStackSupervisorstartActivityMayWait方法来执行启动Activity,看代码

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) {
    ......省略代码
    // 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);

    ActivityContainer container = (ActivityContainer)iContainer;
    synchronized (mService) {
        ......省略代码

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

看下这函数

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;
    //调用者的进程信息
    ProcessRecord callerApp = null;
    if (caller != null) {
        callerApp = mService.getRecordForAppLocked(caller);
       ......省略代码
    }

    .......省略代码
   
    //启动当前activity的activity
    ActivityRecord sourceRecord = null;
    ActivityRecord resultRecord = null;
    //同理也是启动当前activity的activity,只不过它需要当前activity把处理结果返回,即通过startActivityForResult方式启动
    if (resultTo != null) {
        sourceRecord = isInAnyStackLocked(resultTo);
        if (DEBUG_RESULTS) Slog.v(
            TAG, "Will send result to " + resultTo + " " + sourceRecord);
        if (sourceRecord != null) {
            if (requestCode >= 0 && !sourceRecord.finishing) {
                resultRecord = sourceRecord;
            }
        }
    }

   ......省略掉的代码  进行了各种异常的判断还有各种权限判断
    
    //创建一个启动activity的记录信息
    ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
            intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
            requestCode, componentSpecified, this, container, options);

    ......省略代码

    /*把挂起的处理掉*/
    doPendingActivityLaunchesLocked(false);

    //调用该方法进行启动
    err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
            startFlags, true, options, inTask);

    if (err < 0) {
        // If someone asked to have the keyguard dismissed on the next
        // activity start, but we are not actually doing an activity
        // switch...  just dismiss the keyguard now, because we
        // probably want to see whatever is behind it.
        notifyActivityDrawnForKeyguard();
    }
    return err;
}

上面的代码做的事情有:做了各种异常判断,权限判断;同时创建了ActivityRecord实例,该实例记录了server端启动的Activity的信息,ActivityRecordmToken属性很重要;最终调用startActivityUncheckedLocked方法,那我们来看下该方法

final int startActivityUncheckedLocked(ActivityRecord r, ActivityRecord sourceRecord,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags,
        boolean doResume, Bundle options, TaskRecord inTask) {
   ......省略代码
    /*在ActivityStack种开始启动*/
    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;
}

该方法的代码实在是太多了,该方法主要做了以下的事情:

  • 找当前正在启动的Activity的存放任务栈

  • SingleTask,SingleTop,SingleInstance启动模式进行处理

  • 找到目标ActivityStack来启动Activity
    targetStack.startActivityLocked方法就是调用ActivityStackstartActivityLocked方法,那来看下该方法

    final void startActivityLocked(ActivityRecord r, boolean newTask,
    boolean doResume, boolean keepCurTransition, Bundle options) {
    TaskRecord rTask = r.task;
    final int taskId = rTask.taskId;
    ......省略的代码主要是把task加入activitystack栈中

    if (doResume) {
        mStackSupervisor.resumeTopActivitiesLocked(this, r, options);
    }
    

    }
    该方法做的事情是:把ActivityRecord加入TaskRecord中;mStackSupervisor.resumeTopActivitiesLocked(this, r, options)又到ActivityStackSupervisor类中的resumeTopActivitiesLocked方法来进行,那看下这方法:

    boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target,
        Bundle targetOptions) {
    
        ......省略代码
    
        result = targetStack.resumeTopActivityLocked(target, targetOptions);
    
        ......省略代码
        return result;
    

    }
    又再次调用ActivityStackresumeTopActivityLocked方法,看该方法

    final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
     
        ......省略代码
        boolean result = false;
        try {
         ......省略代码
        result = resumeTopActivityInnerLocked(prev, options);
    } finally {
        mStackSupervisor.inResumeTopActivity = false;
    }
    return result;
    

    }

resumeTopActivityInnerLocked(prev, options)调用了该方法

  final boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {
   
        ......省略一大堆代码

        mStackSupervisor.startSpecificActivityLocked(next, true, true);
   
    return true;
}

该方法大致做了通知WindmanagerService进行页面切换等操作,最终还是调用了ActivityStackSupervisor类的startSpecificActivityLocked方法来启动activity,那就来看下这方法

  void startSpecificActivityLocked(ActivityRecord r,
        boolean andResume, boolean checkConfig) {
    // Is this activity's application already running?
    ProcessRecord app = mService.getProcessRecordLocked(r.processName,
            r.info.applicationInfo.uid, true);

    r.task.stack.setLaunchTime(r);

    if (app != null && app.thread != null) {
        try {
            ......省略代码
            //开始真正的启动一个Activity
            realStartActivityLocked(r, app, andResume, checkConfig);
            return;
        } catch (RemoteException e) {
            Slog.w(TAG, "Exception when starting activity "
                    + r.intent.getComponent().flattenToShortString(), e);
        }

        // If a dead object exception was thrown -- fall through to
        // restart the application.
    }
    /*进程根本就没启动,这时候进行启动操作*/
    mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
            "activity", r.intent.getComponent(), false, false, true);
}

该方法所做的事情是:查找当前的activity的所在进程是否启动了,没启动则进行启动;否则开始启动activity;针对没启动的情况我们暂时不分析,realStartActivityLocked方法来真正的执行启动activity任务,那来看下代码

  final boolean realStartActivityLocked(ActivityRecord r,
        ProcessRecord app, boolean andResume, boolean checkConfig)
        throws RemoteException {

        ......省略一大堆代码

        /*通知activitythread开始启动activity*/
        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);

    ......省略一小堆代码
    return true;
}

上面的代码我们来详细的分析下:app是一个ProcessRecord对象,app.thread这里的thread就是IApplicationThread的子类ApplicationThread,其实这时候通过binder机制最终调用了ActivityThread里的ApplicationThreadscheduleLaunchActivity方法,这时候会把intent等参数传递给client,参数中又一个很重要的参数r.appToken它是server端的ActivityRecord与client端的ActivityClientRecord对应关系的一个依据

现在server已经给client发送了response

client接收response,处理response

ActivityThreadApplicationThreadscheduleLaunchActivity方法会接收server发过来的response,我们来看下代码

    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对象,该对象是client端的activity封装类,最终会通过Handler的方式来调用ActivityThread里的handleLaunchActivity方法,看下该方法

  private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ......省略代码
    Activity a = performLaunchActivity(r, customIntent);
    .......省略其他代码
}

调用performLaunchActivity方法,看下该方法

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {

          ......省略代码

           Activity activity = null;
 
           java.lang.ClassLoader cl = r.packageInfo.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);

            ......省略代码

            if (r.isPersistable()) {
                mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
            } else {
                mInstrumentation.callActivityOnCreate(activity, r.state);
            }
            //必须调用onCreate方法否则抛异常
            if (!activity.mCalled) {
                throw new SuperNotCalledException(
                    "Activity " + r.intent.getComponent().toShortString() +
                    " did not call through to super.onCreate()");
            }

          ......省略代码

        return activity;
}

代码是在太长了,我就总结下这方法所做的事情:

  • 调用InstrumentationnewActivity方法构造一个Activity实例
  • 若Application没初始化,进行初始化
  • 创建title,appContext等实例
  • 调用Activityattach方法进行初始化
  • 调用InstrumentationcallActivityOnCreate方法,其实最终调用ActivityonCreate方法

到此为止一个Activity就被创建,并且正常调用了,剩下的代码大家感兴趣可以在自行研究,整个Activity启动机制分析到此。

总结

  • 我们最终生成的Activity的实例是在client端存储着,也就是在ActivityThread的mActivities属性中存储着
  • ActivityClientRecord是client端的activity的封装类
  • ActivityRecord是server端的activity的封装类
  • ActivityClientRecord与ActivityRecord之间是一一对应关系,是通过toke即ActivityRecord里的Token对应起来的

下图是ActivityStackSupervisor,ActivityStack,TaskRecord,ActivityRecord之间的关系图


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