Acitivity与ActivityRecord的关系

ActivityRecord是AMS调度Activity的基本单位,它需要记录AndroidManifest.xml中所定义Activity的静态特征,同时, 也需要记录Activity在被调度时的状态变化,因此ActivityRecord这个类的属性比较多。

属性 描述
ActivityInfo 标签中解析出来的信息,包含launchMode,permission,taskAffinity等
mActivityType Activity的类型有三种:APPLICATION_ACTIVITY_TYPE(应用)、HOME_ACTIVITY_TYPE(桌面)、RECENTS_ACTIVITY_TYPE(最近使用)
appToken 当前ActivityRecord的标识
packageName 当前所属的包名,这是由静态定义的
processName 当前所属的进程名,大部分情况都是由静态定义的,但也有例外
taskAffinity 相同taskAffinity的Activity会被分配到同一个任务栈中
intent 启动当前Activity的Intent
launchedFromUid 启动当前Activity的UID,即发起者的UID
launchedFromPackage 启动当前Activity的包名,即发起者的包名
resultTo 在当前ActivityRecord看来,resultTo表示上一个启动它的ActivityRecord,当需要启动另一个ActivityRecord,会把自己作为resultTo,传递给下一个ActivityRecord
state ActivityRecord所处的状态,初始值是ActivityState.INITIALIZING
app ActivityRecord的宿主进程
task ActivityRecord的宿主任务
inHistory 标识当前的ActivityRecord是否已经置入任务栈中
frontOfTask 标识当前的ActivityRecord是否处于任务栈的根部,即是否为进入任务栈的第一个ActivityRecord
newIntents Intent数组,用于暂存还没有调度到应用进程Activity的Intent

由于ActivityRecord是一个最基本的数据结构,所以其行为相对较少,大都是一些用于判定和更新当前ActivityRecord状态的函数:

行为 描述
putInHistory(), takeFromHistory(), isInHistory() 基于inHistory属性,来判定和更新ActivityRecord是否在任务栈的状态值
isHomeActivity(), isRecentsActivity(), isApplicationActivity() 基于mActivityType属性,判定Activity的类型
setTask() 设置ActivityRecord的宿主任务
deliverNewIntentLocked() 向当前ActivityRecord继续派发Intent。在一些场景下,位于任务栈顶的ActivityRecord会继续接受新的Intent(譬如以singleTop方式启动的同一个Activity),这时候,会触发调度Activity.onNewIntent()函数
addNewIntentLocked() 如果Intent没有派发到应用进程,则通过该函数往newIntents数组中添加一个元素。

要理解ActivityRecord这个数据结构,可以从其构造函数出发,理解其属性在什么场景下会发生变化。 每次需要启动一个新的Activity时,都会构建一个ActivityRecord对象,这在ActivityStackSupervisor.startActivityLocked()函数中完成,构造一个ActivityRecord要传入的参数是相当多的:

 

ActivityRecord(ActivityManagerService _service, ProcessRecord _caller,
      int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType,
      ActivityInfo aInfo, Configuration _configuration,
      ActivityRecord _resultTo, String _resultWho, int _reqCode,
      boolean _componentSpecified, ActivityStackSupervisor supervisor,
      ActivityContainer container, Bundle options) {
    service = _service; // AMS对象
    appToken = new Token(this); //appToken可以进行跨进程传递,标识一个AR对象
    info = aInfo; //从AndroidManifest.xml中解析得到的Activity信息
    launchedFromUid = _launchedFromUid; //譬如从浏览器启动当前AR,那么该属性记录的就是浏览器的UID
    launchedFromPackage = _launchedFromPackage;
    userId = UserHandle.getUserId(aInfo.applicationInfo.uid);
    intent = _intent; //启动当前AR的Intent
    shortComponentName = _intent.getComponent().flattenToShortString();
    resolvedType = _resolvedType;
    componentSpecified = _componentSpecified;
    configuration = _configuration;
    resultTo = _resultTo; //记录上一个AR对象
    resultWho = _resultWho; //reslutTo的字符串标识
    requestCode = _reqCode; //上一个AR对象设定的Request Code
    state = ActivityState.INITIALIZING; //AR的状态,Activity调度时发生改变
    frontOfTask = false; //是否处于Task的根部,调整任务栈中AR顺序时,可能发生改变
    launchFailed = false;
    stopped = false; //pause操作完成状态位
    delayedResume = false;
    finishing = false; //stoped到finished之间的过渡状态位
    configDestroy = false;
    keysPaused = false; //如果置为true,则当前AR不再接受用户输入
    inHistory = false; //将AR压入任务栈后,该状态位被置为true
    visible = true;
    waitingVisible = false;
    nowVisible = false;
    idle = false;
    hasBeenLaunched = false;
    mStackSupervisor = supervisor;
    mInitialActivityContainer = container;
    if (options != null) {
        pendingOptions = new ActivityOptions(options);
        mLaunchTaskBehind = pendingOptions.getLaunchTaskBehind();
    }
    haveState = true;
    if (aInfo != null) {
        //根据aInfo给realActivity, taskAffinity, processName等属性赋值
        ...
    } else {
        //没有aInfo的情况下,赋予默认值
        realActivity = null;
        taskAffinity = null;
        stateNotNeeded = false;
        appInfo = null;
        processName = null;
        packageName = null;
        fullscreen = true;
        noDisplay = false;
        mActivityType = APPLICATION_ACTIVITY_TYPE;
        immersive = false;
    }
}

ActivityRecord的Token

在Activity类中有一个IBinder类型的属性:

private IBinder mToken;

IBinder类型表示这个属性是一个远程对象的引用,取了一个恰如其分的变量名:mToken。 为什么叫Token呢?这个名字源自于IApplicationToken.aidl这个接口, 最终ActivityRecord中的一个内部类Token实现了这个接口:

static class Token extends IApplicationToken.Stub {
    final WeakReference weakActivity;

    Token(ActivityRecord activity) {
        weakActivity = new WeakReference(activity);
    }
    ...
}

Token持有了一个ActivityRecord实例的弱引用。在创建一个ActivityRecord的时候,就会创建了一个Token类型的对象:

ActivityRecord(ActivityManagerService _service, ProcessRecord _caller,
    int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType,
    ActivityInfo aInfo, Configuration _configuration,
    ActivityRecord _resultTo, String _resultWho, int _reqCode,
    boolean _componentSpecified, ActivityStackSupervisor supervisor,
    ActivityContainer container, Bundle options) {
    service = _service
    appToken = new Token(this);
    ...
}

构造一个ActivityRecord时,会将自己(this)传给Token,变量ActivityRecord.appToken存的就是最终创建出来的Token。

将Token传递给Activity

在启动一个新的Activity时,AMS会将ActivityRecord的Token传递给应用进程,调用关系如下所示:

ActivityStackSupervisor.realStartActivityLocked(ActivityRecord, ...)
└── IApplicationThread.scheduleLaunchActivity(...token, ...)
    // 将ActivityRecord的Token跨进程传递给应用进程
    └── Binder.transact()

ActivityStackSupervisor.realStartActivityLocked()表示要启动一个Activity实例,ActivityRecord作为参数。从ActivityRecord中提取出Token对象,作为跨进程调用的参数,通过IApplicationThread.scheduleLaunchActivity()传递到应用进程。

应用进程这一侧,会收到启动Activity的跨进程调用,触发以下一系列的函数调用:

ApplicationThread.onTransact()
└── ApplicationThread.scheduleLaunchActivity(...token, ...)
    // token将被封装进ActivityClientRecord这个数据结构中
    └── ActivityThread.H.handleMessage()
        └── ActivityThread.handleLaunchActivity(LAUNCH_ACTIVITY)
            └── ActivityThread.performLaunchActivity(ActivityClientRecord, ...)
                // 从ActivityRecord取出token
                └── Activity.attch(...token, ...)

标准的Binder服务端处理流程,收到AMS传递过来的Token对象,进行一下数据封装(ActivityClientRecord),然后通过Handler抛出一个LAUNCH_ACTIVITY消息。这个消息显然也是抛到了应用进程的主线程去执行,所以ActivityThread.performLaunchActivity()函数会在主线程上执行,该函数从封装的数据结构ActivityClientRecord中取出Token对象,调用Activity.attach()函数,将其绑定到Activity上,如此一来,就建立应用进程的Activity与系统进程中ActivityRecord的关联。

系统进程维护的是ActivityRecord,应用进程维护的是Activity,两者之间的映射关系就是利用Token来维系的。 应用进程的Activity在创建的时候,就被赋予了一个Token,拿着这个Token就能完成后续与系统进程的通信。 在发生Activity切换时,应用进程会将上一个Activity的Token(AMS.startActivity()的输入参数resultTo)传递给系统进程,系统进程会根据这个Token找到ActivityRecord,对其完成调度后,再通知应用进程:Activity状态发生了变化。

Token就像一个令牌,揣着这个令牌,就是游走江湖的身份象征。 Activity出生的时候,管理者(AMS)就会登记Activity的真实身份(ActivityRecord),并颁发一个令牌(Token)给Activity。 以后这个Activity要有什么行为,都要交出令牌,让管理者核实一下真实身份。

 

你可能感兴趣的:(Android)