从源码中理解Activity组件(1)-相关数据结构

前言

在之前的启动流程分析的文章中,初步分析了AMSPKMS,探索了一下应用启动从Zygote进程孵化到执行ActivityThread类中的main()方法,在main()方法中会去创建Application对象,并调用了其内部的onCreate()方法,也看到了后续流程去实例化首个Activity并调用执行到Activity的onCreate()方法,提到了在启动Activity的时候是需要从PKMS服务中取获取对应应用解析的Activity的信息,在PKMS的文章里面也分析了开机的时候操作系统会去扫描/data/app目录下的base.apk文件,解析我们在应用开发中对于一个app应用配置的AndroidManifest.xml文件

整个流程涉及的类和对象比较多,Activity对于Android开发来说又是非常重要的一个组件,自打我开发Android以来,就知道需要对Activity的生命周期的认知,页面栈的管理,视图的显示和销毁跟生命周期的关系,Activity跟window的关系有个非常明确的认知,结合前面的文章,接下来就继续从源码的角度去深入剖析一下我们能看到的Activity对象

startActivity

通过前面的文章分析,当执行startActivity方法后,会通过一连串的对象方法调用,执行到ActivityStarter这个关键类里面的execute()方法,先附上这段流程的调用时序图

startActivity跨进程调用.png

这里可以看到,startActivity方法的执行调用会执行到ATMS服务,所以即使是我们平时开发的应用进程内部,要跳转我们自己开发的Activity也是一个跨进程通信的行为,ATMS服务是在system_server进程中,跨进程通信在Android中使用的就是binder通信

接下来进入源码阶段

从PKMS获取Activity信息
//ActivityStarter.java
class ActivityStarter {
    //mRequest是Starter对象的内部属性
    Request mRequest = new Request();

  int excute(){
      //启动Activity首先会进入这个判断,mRequest里面是没有赋值activityInfo的
      if (mRequest.activityInfo == null) {
          mRequest.resolveActivity(mSupervisor);
      }
  }
  
  //Request是Starter类里面声明的内部类
  static class Request {
    ActivityInfo activityInfo;
    Request() {
      reset();
    }
    void reset() {
      activityInfo = null;
    }
    void set(Request request) {
      activityInfo = request.activityInfo;
    }
  }
}

//ActivityStartController.java
ActivityStarter obtainStarter(Intent intent, String reason) {
  return mFactory.obtain().setIntent(intent).setReason(reason);
}

//DefaultFactory.java
public ActivityStarter obtain() {
  ActivityStarter starter = mStarterPool.acquire();

  if (starter == null) {
    starter = new ActivityStarter(mController, mService, mSupervisor, mInterceptor);
  }

  return starter;
}
//ActivityStarter对象回收的时候会情况之前的request内容
public void recycle(ActivityStarter starter) {
  starter.reset(true /* clearRequest*/);
  mStarterPool.release(starter);
}

ActivityStarter对象内部实例化了一个Request对象,ActivityStarter是由ActivityStartController去进行管理,里面维护了一个ActivityStarter的对象池,对象池复用对象在回收的时候会复位内部的成员属性,每次调用startActivity都会从对象池里面取出一个ActivityStarter,并且里面的mRequest对象是初始默认空状态

对象池的使用在源码里面经常能看到,在对象频繁创建使用的场景下,要学会用源码的设计方式去使用对象池管理这些短生命周期又需要频繁创建的对象,频繁的去创建回收对象会引发内存抖动,类似Handler里面的Message对象,startActivity也是一个调用次数会很高的方法

由于ActivityStarter内部的Request是没有内容的,所以会继续去解析出对应的activityInfo

//Request.java
void resolveActivity(ActivityStackSupervisor supervisor) {
  resolveInfo = supervisor.resolveIntent();
  // Collect information about the target of the Intent.
  activityInfo = supervisor.resolveActivity();
}

可以看到,解析工作是通过ActivityStackSupervisor进行的,ActivityStackSupervisor这个对象的作用就是用来管理相关的配置信息

//ActivityStackSupervisor.java
final ActivityTaskManagerService mService;

ResolveInfo resolveIntent(Intent intent, String resolvedType, int userId, int flags,int filterCallingUid) {
        //getPackageManagerInternalLocked就是通过ATMS去获取PKMS
    return mService.getPackageManagerInternalLocked().resolveIntent();
}

ActivityInfo resolveActivity(Intent intent, ResolveInfo rInfo, int startFlags,ProfilerInfo profilerInfo) {
    final ActivityInfo aInfo = rInfo != null ? rInfo.activityInfo : null;
    return aInfo;
}

ActivityStackSupervisor对象解析Activity信息是通过ATMS去调用到PKMS中的方法,看到PKMS的调用,就能联想到之前开机的时候分析了PKMS会去解析相关应用的四大组件信息,感觉离目标更近了

//PackageMangerService.java
public ResolveInfo resolveIntent(Intent intent, String resolvedType,int flags, int userId) {
  return resolveIntentInternal();
}

private ResolveInfo resolveIntentInternal() {
    try {
        //继续调用去查询相关的Activity信息
        final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType,
                flags, privateResolveFlags, filterCallingUid, userId, resolveForStart,
                true /*allowDynamicSplits*/);
     
        final boolean queryMayBeFiltered =
                UserHandle.getAppId(filterCallingUid) >= Process.FIRST_APPLICATION_UID
                        && !resolveForStart;
                //对列表进行进一步查询过滤
        final ResolveInfo bestChoice =
                chooseBestActivity(
                        intent, resolvedType, flags, privateResolveFlags, query, userId,
                        queryMayBeFiltered);
                //最终返回的是一个ResolveInfo对象
        return bestChoice;
    } 
}

//返回了List<ResolveInfo>一个列表对象
private List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,...) {
    final String pkgName = intent.getPackage();
  //ComponentName就是包含了目标目标Activity的全类名
    ComponentName comp = intent.getComponent();
    if (comp == null) {
        if (intent.getSelector() != null) {
            intent = intent.getSelector();
            comp = intent.getComponent();
        }
    }

    if (comp != null) {
        final List<ResolveInfo> list = new ArrayList<>(1);
      //会调用内部private的getActivityInfoInternal()方法
        final ActivityInfo ai = getActivityInfo(comp, flags, userId);

        List<ResolveInfo> result = applyPostResolutionFilter(
                list, instantAppPkgName, allowDynamicSplits, filterCallingUid, resolveForStart,
                userId, intent);
        return result;
    }
  
private ActivityInfo getActivityInfoInternal(ComponentName component, int flags,
        int filterCallingUid, int userId) {
    synchronized (mLock) {
        //会从mComponentResolver里面去获取缓存的内容信息
        ParsedActivity a = mComponentResolver.getActivity(component);
        AndroidPackage pkg = a == null ? null : mPackages.get(a.getPackageName());
        //会从Settings对象里面去匹配是否已经解析了对应的Activity信息,然后返回
        if (pkg != null && mSettings.isEnabledAndMatchLPr(pkg, a, flags, userId)) {
            PackageSetting ps = mSettings.getPackageLPr(component.getPackageName());
            if (ps == null) return null;
            if (shouldFilterApplicationLocked(
                    ps, filterCallingUid, component, TYPE_ACTIVITY, userId)) {
                return null;
            }
            return PackageInfoUtils.generateActivityInfo(pkg,
                    a, flags, ps.readUserState(userId), userId, ps);
        }
        if (mResolveComponentName.equals(component)) {
            return PackageParser.generateActivityInfo(
                    mResolveActivity, flags, new PackageUserState(), userId);
        }
    }
    return null;
}

从前面的PMKS解析开机过程中对APK的分析可以看出,当解析了manifest文件里面的activity标签后,会生成一个ParsedActivity数据结构的对象去存储Activity相关的配置信息,而在这里从PKMS取Activity信息的时候,通过一级一级的缓存去取出一个ParsedActivity类型的对象出来,也就是之前解析的activity信息

小结

到这里就分析到了,当startActivity方法执行的时候,会从PKMS中获取对应的Activity信息,这里面涉及到一些列的数据结构对象,在PKMS解析的最原始的Activity是用ParsedActivity对象是存储信息,然后当Intent解析后,会将里面的内容传递封装成ActivityInfo对象,这两个对象里面的内容基本一致,再往上传递就会将ActivityInfo对象封装到ResolveInfo对象中,这个对象是为了兼容四大组件,里面有不同组件的成员属性,具体的内容如下

//ParsedActivity.java
public class ParsedActivity extends ParsedMainComponent {
   private String targetActivity;
   String taskAffinity;    
   private String permission;
   int launchMode;
   int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
}

//ActivityInfo.java
public class ActivityInfo extends ComponentInfo implements Parcelable {
  public int theme;
  public int launchMode;
  public String permission;
  public String taskAffinity;
  public String targetActivity;
  public int screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
}

//ResolveInfo.java
public class ResolveInfo implements Parcelable {
    public ActivityInfo activityInfo;
    public ServiceInfo serviceInfo;
    public ProviderInfo providerInfo;
    public IntentFilter filter;
}

到这里就把Activity信息的获取过程告一段落,Request对象里面就持有了ActivityInfo对目标Activity的数据封装,接下来就继续回到ActivityStarter对象里面的execute()方法,去看后续的执行动作

executeRequest

当request对象里面解析了对象的数据,就进入继续的处理过程

//ActivityStarter.java
int execute() {
    if (mRequest.activityInfo == null) {
      mRequest.resolveActivity(mSupervisor);
    }
    int res;
    synchronized (mService.mGlobalLock) {
      res = executeRequest(mRequest);
    }
}

private int executeRequest(Request request) {
    //一堆参数的处理
    final IApplicationThread caller = request.caller;
    Intent intent = request.intent;
    ActivityInfo aInfo = request.activityInfo;
    ResolveInfo rInfo = request.resolveInfo;
    final int launchFlags = intent.getFlags();
    //创建出目标ActivityRecord对象
    final ActivityRecord r = new ActivityRecord();
    final ActivityStack stack = mRootWindowContainer.getTopDisplayFocusedStack();
        //下一步执行的关键方法
    mLastStartActivityResult = startActivityUnchecked(r,...);
    return mLastStartActivityResult;
}

这个executeRequest方法里面有很多我们熟悉的对象,比如IApplicationThread在前面的文章中提过是应用ActivityThread的binder对象,处理了launchFlag启动模式等,将我们上面解析的ActivityInfo通过构造函数赋值到了一个ActivityRecord对象中,通过类名可以知道这个对象跟Activity有很密切的关系,那么又跟上面的ActivityInfo有什么不同

ActivityRecord
/**
 * An entry in the history stack, representing an activity.
 * 通过注释可以看出这个类就是历史栈中一条记录,也就是我们页面Activity的一个代表
 */
final class ActivityRecord extends WindowToken implements WindowManagerService.AppFreezeListener {
    final ActivityTaskManagerService mAtmService;//关联了ATMS
    // activity info provided by developer in AndroidManifest
    final ActivityInfo info; //从AndroidManifest解析后封装的数据
    final ActivityRecord.Token appToken;//WMS用到的token
    final String taskAffinity; // 设置Task名字
    // the task this is in.
    private Task task; //ActivityRecord记录所在的Task任务栈         
    
    //省略一大堆成员变量
  
    //ActivityRecord对象的构造方法里面传递了大量的数据,包括我们前面解析的ActivityInfo
    ActivityRecord(ActivityTaskManagerService _service, WindowProcessController _caller,
                 int _launchedFromPid, int _launchedFromUid, String _launchedFromPackage,
                 @Nullable String _launchedFromFeature, Intent _intent, String _resolvedType,
                 ActivityInfo aInfo, Configuration _configuration, ActivityRecord _resultTo,
                 String _resultWho, int _reqCode, boolean _componentSpecified,
                 boolean _rootVoiceInteraction, ActivityStackSupervisor supervisor,
                 ActivityOptions options, ActivityRecord sourceRecord) {}
}

通过这个数据结构的成员变量分析,可以得知在应用进程服务之间传递的Activity页面的属性和状态相关的数据包装类就是ActivityRecord,记录了前面通过manifest解析出来的我们配置的标签属性ActivityInfo和一堆跟Activity状态相关的成员变量

总结

到这里我们就基本上把跟Activity相关的数据类梳理了一遍,从应用开发的角度,我们会写一个继承自Activity的java类,并且在Androidmanifest.xml文件中进行配置,配置后首先会通过PKMS解析成ParsedActivity对象,然后通过包名缓存在内存中,当调用startActivity方法的时候,通过方法调用从PKMS取出解析好的ParsedActivity对象并且将内部属性赋值给一个ActivityInfo类型的对象,为了兼容四大组件,ActivityInfo类型的对象又会作为成员属性封装在一个ResolveInfo类型对象中,当准备好了ActivityInfo数据会赋值在一个Request对象中,在后续的startActiviy流程中,会取出对应的ActivityInfo数据实例化一个ActivityRecord类型的对象,这个对象就是我们所写的Activity在系统服务中进行传递和管理的真正代表,内部包含了当前页面的状态,页面所属的任务栈等各种跟Activity运行状态相关的属性

接下来的文章继续去分析跟ActivityRecord相关管理的任务栈Task对象和启动模式相关的内容,对涉及的数据结构有个整体的认知,在后续的源码分析中不容易迷路

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

推荐阅读更多精彩内容