Application初始化过程,基于android10

3,211 阅读6分钟

前言

​ 对于app开发来说,我们可控的,最早被调用的代码,那非Application相关生命周期莫属,也就是attachBaseContext。一般都会重写相关方法,进行分包处理、全局变量的初始化、一些sdk的初始化...

​ 如果想分析app的启动流程,那Application必定是个好的切入点,以下是对Application的onCreate、attachBaseContext的调用分析

问题

  1. Application#onCreate()、Application#attachBaseContext(context)的调用过程
  2. Application context的创建过程

总结

​ 开局一张图,内容全靠编,上图镇楼,全文基本都围绕此图进行,基于android10,大图请点击

ApplicationInit

开始

入口:ActivityManagerService#attachApplication

​ 通过BInder调用AMS#attachApplication,进行application绑定操作

attachApplication是IActivityManager.Stub的实现,大概就是调用远程服务,具体在哪里调用AMS#attachApplication在此就不详述了,有想了解的同学可自行查阅AMS、AMN、AMP相关资料。

我们看下ActivityManagerService处attachApplication的实现。参数thread,实质是ActivityThread的内部类ApplicationThread,实现了IApplicationThread。

public class ActivityManagerService extends IActivityManager.Stub
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
    @Override
    public final void attachApplication(IApplicationThread thread, long startSeq) {
        synchronized (this) {
            int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
          	//调用ActivityManagerService#attachApplicationLocked
            attachApplicationLocked(thread, callingPid, callingUid, startSeq);
            Binder.restoreCallingIdentity(origId);
        }
    }
  
    /**
    *方法超长
    *只截取关键部分
    */
    @GuardedBy("this")
    private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid, int callingUid, long startSeq) {
      	....
        //每个进程在AMS都有一个ProcessRecord,记录着进程的相关信息
        ProcessRecord app;
      	....
        final ActiveInstrumentation instr2 = app.getActiveInstrumentation();
        if (app.isolatedEntryPoint != null) {
            // This is an isolated process which should just call an entry point instead of
            // being bound to an application.
            thread.runIsolatedEntryPoint(app.isolatedEntryPoint, app.isolatedEntryPointArgs);
        } else if (instr2 != null) {
            //通过传入的ApplicationThread实例绑定Application
          	//参数很多,基本都是为了构造AppBindData,下文会看到
            thread.bindApplication(processName, appInfo, providers,
                    instr2.mClass,
                    profilerInfo, instr2.mArguments,
                    instr2.mWatcher,
                    instr2.mUiAutomationConnection, testMode,
                    mBinderTransactionTrackingEnabled, enableTrackAllocation,
                    isRestrictedBackupMode || !normalMode, app.isPersistent(),
                    new Configuration(app.getWindowProcessController().getConfiguration()),
                    app.compat, getCommonServicesLocked(app.isolated),
                    mCoreSettingsObserver.getCoreSettingsLocked(),
                    buildSerial, autofillOptions, contentCaptureOptions);
        } else {
            thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
                    null, null, null, testMode,
                    mBinderTransactionTrackingEnabled, enableTrackAllocation,
                    isRestrictedBackupMode || !normalMode, app.isPersistent(),
                    new Configuration(app.getWindowProcessController().getConfiguration()),
                    app.compat, getCommonServicesLocked(app.isolated),
                    mCoreSettingsObserver.getCoreSettingsLocked(),
                    buildSerial, autofillOptions, contentCaptureOptions);
        }
    }
}

由上可知,调用了IApplicationThread#bindApplication,接下来看下IApplicationThread的实现

ActivityThread的两个关键内部类

  1. ApplicationThread:构造AppBindData,发送message
  2. H:内部handler,继承Handler,主要接收并转发消息

ApplicationThread实现了IApplicationThread.Stub,我们看下ApplicationThread#bindApplication的实现。

private class ApplicationThread extends IApplicationThread.Stub{
	public final void bindApplication(String processName, ApplicationInfo appInfo,
                List<ProviderInfo> providers, ComponentName instrumentationName,
                ProfilerInfo profilerInfo, Bundle instrumentationArgs,
                IInstrumentationWatcher instrumentationWatcher,
                IUiAutomationConnection instrumentationUiConnection, int debugMode,
                boolean enableBinderTracking, boolean trackAllocation,
                boolean isRestrictedBackupMode, boolean persistent, Configuration config,
                CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
                String buildSerial, AutofillOptions autofillOptions,
                ContentCaptureOptions contentCaptureOptions) {
        if (services != null) {
            if (false) {
                // Test code to make sure the app could see the passed-in services.
                for (Object oname : services.keySet()) {
                    if (services.get(oname) == null) {
                        continue; // AM just passed in a null service.
                    }
                    String name = (String) oname;

                    // See b/79378449 about the following exemption.
                    switch (name) {
                        case "package":
                        case Context.WINDOW_SERVICE:
                            continue;
                    }

                    if (ServiceManager.getService(name) == null) {
                        Log.wtf(TAG, "Service " + name + " should be accessible by this app");
                    }
                }
            }

            // Setup the service cache in the ServiceManager
            ServiceManager.initServiceCache(services);
        }

        setCoreSettings(coreSettings);
        //构造AppBindData,一些列参数的赋值,LoadApk,ApplicationInfo,instrumentation,进程名,调试模式....
        AppBindData data = new AppBindData();
        data.processName = processName;
    		//LoadedApk的实例,后续很多地方会用到
        data.appInfo = appInfo;
        data.providers = providers;
        data.instrumentationName = instrumentationName;
        data.instrumentationArgs = instrumentationArgs;
        data.instrumentationWatcher = instrumentationWatcher;
        data.instrumentationUiAutomationConnection = instrumentationUiConnection;
        data.debugMode = debugMode;
        data.enableBinderTracking = enableBinderTracking;
        data.trackAllocation = trackAllocation;
        data.restrictedBackupMode = isRestrictedBackupMode;
        data.persistent = persistent;
        data.config = config;
        data.compatInfo = compatInfo;
        data.initProfilerInfo = profilerInfo;
        data.buildSerial = buildSerial;
        data.autofillOptions = autofillOptions;
        data.contentCaptureOptions = contentCaptureOptions;

        //构造好AppBindData数据后,调用ActivityThread#sendMessage发送AppBindData,
    		//sendMessage最终发送了handler消息,在handler里分发处理H.BIND_APPLICATION消息
        sendMessage(H.BIND_APPLICATION, data);
    }
}

此方法基本就做一件事情, 创建AppBindData对象,对其进行初始化

ActivityThread

由上可知,IApplicationThread#bindApplication最终调用了ActivityThread#sendMessage,接下来看下sendMessage。

1、sendMessage最终通过mH.sendMessage发送message,mH是H的实例,H又是ActivityThread的内部,exdents Handler。

2、Lopper回调H#handleMessage,通过message.what判断处理消息,获取data(AppBindData),调用ActivityThread#handleBindApplication

3、handleBindApplication进行Application的创建、初始化、生命周期的调用

4、Application#onCreate调用入口,对应问题1,具体过程请参考 Instrumentation:Application的创建以及onCreate调用

public final class ActivityThread extends ClientTransactionHandler {
  
  final H mH = new H();
  //LoadedApk#makeApplication处会初始化实例add到list
  final ArrayList<Application> mAllApplications = new ArrayList<Application>();
  ....
  final ArrayMap<String, WeakReference<LoadedApk>> mPackages = new ArrayMap<>();
  
  void sendMessage(int what, Object obj) {
        sendMessage(what, obj, 0, 0, false);
    }
  
      private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
        Message msg = Message.obtain();
        msg.what = what;
        msg.obj = obj;
        msg.arg1 = arg1;
        msg.arg2 = arg2;
        if (async) {
            msg.setAsynchronous(true);
        }
        //1:通过handler发送消息
        mH.sendMessage(msg);
    }

  //方法很长,主要进行一系列Application的初始化,和主题无关的不做过多分析
	private void handleBindApplication(AppBindData data) {
      // Allow disk access during application and provider setup. This could
      // block processing ordered broadcasts, but later processing would
      // probably end up doing the same disk access.
      Application app;
      final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
      final StrictMode.ThreadPolicy writesAllowedPolicy = StrictMode.getThreadPolicy();
      try {
        //data.info为LoadApk,Application在此处进行初始化
        //3:间接调用了Appliocation#attachBaseContext(context)
        app = data.info.makeApplication(data.restrictedBackupMode, null);

        ........
          try {
            //4:通过Instrumentation间接调用Application#onCreate
            mInstrumentation.callApplicationOnCreate(app);
          } catch (Exception e) {
            if (!mInstrumentation.onException(app, e)) {
              throw new RuntimeException(
                "Unable to create application " + app.getClass().getName()
                + ": " + e.toString(), e);
            }
          }
      } finally {
        // If the app targets < O-MR1, or doesn't change the thread policy
        // during startup, clobber the policy to maintain behavior of b/36951662
        if (data.appInfo.targetSdkVersion < Build.VERSION_CODES.O_MR1
            || StrictMode.getThreadPolicy().equals(writesAllowedPolicy)) {
          StrictMode.setThreadPolicy(savedPolicy);
        }
      }
	}
  
  //继承Handler,主要做一些消息接收与转发
  class H extends Handler{
      public static final int BIND_APPLICATION        = 110;
      ......
      public static final int PURGE_RESOURCES = 161;

      public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                case BIND_APPLICATION:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
                    AppBindData data = (AppBindData)msg.obj;
                		//2:调用ActivityThread#handleBindApplication
                    handleBindApplication(data);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                .......
                case PURGE_RESOURCES:
                    schedulePurgeIdler();
                    break;
            }
            Object obj = msg.obj;
            if (obj instanceof SomeArgs) {
                ((SomeArgs) obj).recycle();
            }
            if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));
        }
		}
}

LoadedApk

顾名思义,就是已经加载了的apk,由上边代码3处可知,最终调用了LoadedApk#makeApplication

1处:进行Application context的创建,对应了问题2,具体创建过程参考Application context创建

2处:Application创建入口

public final class LoadedApk {
	public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
        if (mApplication != null) {
            return mApplication;
        }

        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");

        Application app = null;

        String appClass = mApplicationInfo.className;
        if (forceDefaultAppClass || (appClass == null)) {
            appClass = "android.app.Application";
        }

        try {
            java.lang.ClassLoader cl = getClassLoader();
            if (!mPackageName.equals("android")) {
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                        "initializeJavaContextClassLoader");
                initializeJavaContextClassLoader();
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            }
          	//1:创建Application的context
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            //2:通过Instrumentation创建Application实例
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            appContext.setOuterContext(app);
        } catch (Exception e) {
            if (!mActivityThread.mInstrumentation.onException(app, e)) {
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                throw new RuntimeException(
                    "Unable to instantiate application " + appClass
                    + ": " + e.toString(), e);
            }
        }
    		//将Application添加进ActivityThread里的mAllApplications集合里,在上面ActivityThread处有描述
        mActivityThread.mAllApplications.add(app);
        mApplication = app;

        if (instrumentation != null) {
            try {
            	//调用Application.onCreate(context)入口
                instrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {
                if (!instrumentation.onException(app, e)) {
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    throw new RuntimeException(
                        "Unable to create application " + app.getClass().getName()
                        + ": " + e.toString(), e);
                }
            }
        }

    		//重写R
        // Rewrite the R 'constants' for all library apks.
        SparseArray<String> packageIdentifiers = getAssets().getAssignedPackageIdentifiers();
        final int N = packageIdentifiers.size();
        for (int i = 0; i < N; i++) {
            final int id = packageIdentifiers.keyAt(i);
            if (id == 0x01 || id == 0x7f) {
                continue;
            }

            rewriteRValues(getClassLoader(), packageIdentifiers.valueAt(i), id);
        }

        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

        return app;
    }

    public void callApplicationOnCreate(Application app) {
        app.onCreate();
    }
}

Instrumentation:Application的创建以及onCreate调用

LoadedApk#makeApplication调用了Instrumentation#newApplication,Application创建以及初始化就在此处

public class Instrumentation {
    public Application newApplication(ClassLoader cl, String className, Context context)
              throws InstantiationException, IllegalAccessException, 
              ClassNotFoundException {
          Application app = getFactory(context.getPackageName())
                  .instantiateApplication(cl, className);
          //1:调用Application的attach
          app.attach(context);
          return app;
     }
    public void callApplicationOnCreate(Application app) {
     	 app.onCreate();
    }
}

Application#attachBaseContext

上处代码1,调用了Application#attach,attach接着调用了attachBaseContext,对应了问题1的attachBaseContext调用

public class Application extends ContextWrapper implements ComponentCallbacks2 {
	final void attach(Context context) {
		//调用attachBaseContext
        attachBaseContext(context);
        mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
    }
}

Application context创建

在ContextImpl#createAppContext处创建context,然后设置resources

class ContextImpl extends Context {
		//Application context创建
    static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
        return createAppContext(mainThread, packageInfo, null);
    }
    
    static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo,
            String opPackageName) {
        if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
      //直接new ContextImpl(),设置resources
        ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0,
                null, opPackageName);
      	//设置context的资源
        context.setResources(packageInfo.getResources());
        return context;
    }
}

Todo

根据文章的一些线索,接下来会写下AMS相关的,最后可能会写一下dex加固

这是第一次写技术文章,有错误欢迎各位大佬斧正。最近看见费曼学习法,深受感悟,打算开始写技术文章,这算是一个开始吧。一直没有写作文笔,希望借此也能提升下自己吧。