title: Atlas之启动过程(二)

date: 2017-05-03 15:00:00

概述

接上篇 Atlasz之启动过程(一) ,继续 6-10 步的启动过程。

Atlas之启动过程(二) - 图1

6. onCreate

AtlasBridgeApplication.java

  1. @Override
  2. public void onCreate() {
  3. super.onCreate();
  4. Method method = mBridgeApplicationDelegate.getClass().getDeclaredMethod("onCreate");
  5. method.invoke(mBridgeApplicationDelegate);
  6. }

直接反射调用mBridgeApplicationDelegateonCreate方法.

7. BridgeApplicationDelegate.onCreate

BridgeApplicationDelegate.java

  1. public void onCreate(){
  2. // 7.1 实例application
  3. mRealApplication = (Application) mRawApplication.getBaseContext()
  4. .getClassLoader().loadClass(mRealApplicationName).newInstance();
  5. //7.2 replace xxx
  6. AtlasHacks.ContextImpl_setOuterContext.invoke(
  7. mRawApplication.getBaseContext(), mRealApplication);
  8. //...
  9. //7.3 mRealApplication.attach
  10. AtlasHacks.Application_attach
  11. .invoke(mRealApplication,mRawApplication.getBaseContext());
  12. //7.4 install content providers
  13. Object mBoundApplication = AtlasHacks.ActivityThread_mBoundApplication.get(activityThread);
  14. AtlasHacks.ActivityThread$AppBindData_providers.set(mBoundApplication,mBoundApplication_provider);
  15. AtlasHacks.ActivityThread_installContentProviders.invoke(activityThread,mRealApplication,mBoundApplication_provider);
  16. //7.5. startup
  17. Atlas.getInstance().startup(mRealApplication,mIsUpdated);
  18. //7.6 onCreate
  19. mRealApplication.onCreate();
  20. }

函数有点长,不过内容大概分为6块

  1. 实例化app工程中指定的mRealApplication
  2. 替换application
  3. 反射执行mRealApplication的attach方法
  4. 加载provider
  5. Atlas.startup
  6. 调用mRealApplication.onCreate方法

7.1 实例application

  1. mRealApplication = (Application) mRawApplication.getBaseContext()
  2. .getClassLoader().loadClass(mRealApplicationName).newInstance();

mRealApplicationName实际上是指com.taobao.demo.DemoApplication。在这里,构造出了app工程中指定application的对象实例。

7.2 替换application

  1. //replace baseContext.mOuterContext
  2. AtlasHacks.ContextImpl_setOuterContext.invoke(mRawApplication.getBaseContext(), mRealApplication);
  3. //replace baseContext.mPackageInfo.mApplication
  4. Object mPackageInfo = AtlasHacks.ContextImpl_mPackageInfo.get(mRawApplication.getBaseContext());
  5. //...

7.2部分,为了保证DemoApplication能够像正常声明的application一样正常工作,做了大量的hook。这里不关注具体hook实现,只给出hook后的映射,感兴趣的童鞋可以自行研究。

替换点 实现类
ContextImpl.mOuterContextt DemoApplication
ContextImp.mPackageInfo DemoApplication
ActivityThread.mInitialApplication DemoApplication
ActivityThread.mAllApplications DemoApplication

7.3 Application.attach

  1. AtlasHacks.Application_attach.invoke(mRealApplication,mRawApplication.getBaseContext());

mRealApplication实际上就是DemoApplication,反射执行application的attach方法,即第8步。

7.4 加载provider

  1. Object mBoundApplication = AtlasHacks.ActivityThread_mBoundApplication.get(activityThread);
  2. AtlasHacks.ActivityThread$AppBindData_providers.set(mBoundApplication,mBoundApplication_provider);
  3. AtlasHacks.ActivityThread_installContentProviders.invoke(activityThread,mRealApplication,mBoundApplication_provider);

Atlas启动过程(上)的2.4小节中,为了防止在主dex中找不到bundle中的class,不得已延迟了对provider的加载。而在第5步中,atlas完成了对classloader等关键地方的hook。由于DelegateClassLoader的存在,此时进行加载provider,是不会出现问题的。

8. DemoApplication.attach

DemoApplication.java

  1. final void attach(Context context) {
  2. attachBaseContext(context);
  3. mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
  4. }

由7.3可知,mRealApplication实际上就是DemoApplication

  • 调用DemoApplication的attachBaseContext方法
  • 为DemoApplication创建一个LoadedApk对象

9. startUp

Atlas之启动过程(二) - 图2

在startup整个函数周期内,做的事情非常之多,重要的是第3、4、6、7和8步。

9.3

  1. public void init(Context context, boolean hookedJavaVM) {
  2. if(VMUtil.IS_VM_ART) {
  3. success = Boolean.valueOf(ARTUtils.init(context, hookedJavaVM));
  4. } else {
  5. success = Boolean.valueOf(DalvikUtils.init());
  6. }
  7. }

看函数名,是针对art和dalvik工具类进行初始化。

  1. //DalvikUtils.java
  2. public static boolean init() {
  3. System.loadLibrary("dalvikhack");
  4. nativeInit();
  5. }
  6. //ARTUtils.java
  7. public static boolean init(Context context, boolean hookedJavaVM) {
  8. System.loadLibrary("dexinterpret");
  9. nativeInit(...);
  10. }

9.4

  1. public static int patchIfPossible() {
  2. System.loadLibrary("dalvikpatch");
  3. if(isDalvik()) {
  4. int ingored = adjustLinearAlloc();
  5. }
  6. return 0;
  7. }

首先加载dalvikpatchso,用途: todo

接着执行 adjustLinearAlloc方法 ,用途 todo

9.7

  1. private synchronized void InitBundleInfoByVersionIfNeed(){
  2. String bundleInfoStr = (String)RuntimeVariables.getFrameworkProperty("bundleInfo");
  3. if(!TextUtils.isEmpty(bundleInfoStr)) {
  4. LinkedHashMap<String,BundleListing.BundleInfo> infos = BundleListingUtil.parseArray(bundleInfoStr);
  5. BundleListing listing = new BundleListing();
  6. listing.setBundles(infos);
  7. mCurrentBundleListing = listing;
  8. }
  9. }

可以看到,函数是从RuntimeVariables读取字符串,之后解析成对象存储。很明显,这个字符串应该是配置之类的信息。在atals从gradle到apk中,我们提到过,atlas会在编译期间会分析bundle和gradle配置,将一些配置写入RuntimeVariables中。

  1. package android.taobao.atlas.framework;
  2. public class FrameworkProperties
  3. {
  4. public static String autoStartBundles;
  5. public static String bundleInfo = "[{\"activities\":[\"com.taobao.firstbundle.FirstBundleActivity\"],\"contentProviders\":[],\"dependency\":[],\"isInternal\":true,\"pkgName\":\"com.taobao.firstbundle\",\"receivers\":[],\"services\":[\"com.taobao.firstbundle.FirstBundleService\"],\"version\":\"1.0.0@unspecified\"},{\"activities\":[\"com.taobao.secondbundle.SecondBundleActivity\",\"com.taobao.secondbundlelibrary.SecondbundleShareActivity\"],\"contentProviders\":[],\"dependency\":[],\"isInternal\":true,\"pkgName\":\"com.taobao.secondbundle\",\"receivers\":[],\"services\":[],\"version\":\"1.0.0@unspecified\"},{\"activities\":[\"com.taobao.remotebunle.RemoteBundleActivity\"],\"contentProviders\":[],\"dependency\":[],\"isInternal\":false,\"pkgName\":\"com.taobao.remotebunle\",\"receivers\":[],\"services\":[],\"version\":\"1.0.0@unspecified\"},{\"activities\":[],\"contentProviders\":[],\"dependency\":[],\"isInternal\":true,\"pkgName\":\"com.taobao.publicBundle\",\"receivers\":[],\"services\":[],\"version\":\"1.0.0@unspecified\"}]";
  6. static
  7. {
  8. autoStartBundles = "com.taobao.firstbundle";
  9. }
  10. }

可以看到,bundleInfo 字段是一堆json字段,解析后格式BundleInfo,保存着bundle的信息。

  1. public static class BundleInfo{
  2. private String pkgName;
  3. private String applicationName
  4. private List<String> dependency;
  5. private HashMap<String,Boolean> activities;
  6. private HashMap<String,Boolean> services;
  7. private HashMap<String,Boolean> receivers;
  8. private HashMap<String,Boolean> contentProviders;
  9. //...
  10. }

也就是说,在这一步, atlas获得了所有bundle的信息

9.8

  1. private void started(){
  2. //读取配置
  3. String autoStartBundle = (String) RuntimeVariables.getFrameworkProperty("autoStartBundles");
  4. String[] bundles = autoStartBundle.split(",");
  5. //异步安装bundle
  6. for (int x = 0; x < bundles.length; x++) {
  7. final String bundleName = bundles[x];
  8. BundleInstaller.startDelayInstall(bundleName, ...);
  9. }
  10. }

简化了大部分代码,只关注核心逻辑。代码读取RuntimeVariables上的字段autoStartBundles,这个值是在gradle中配置的com.taobao.firstbundle,然后开始异步加载firstbundle

bundle的加载过程和加载触发时机请参考 Atlas之bundle加载过程,这里不在讨论。

10. DemoApplication.onCreate

DemoApplication.java

  1. public void onCreate() {
  2. super.onCreate();
  3. //...
  4. }

执行app工程定义的DemoApplication的onCreate方法。


至此,Atlas启动过程的分析完成。